Bug 830290: Execute DBus send operation in DBus thread r=bent,qdot
authorThomas Zimmermann <tdz@users.sourceforge.net>
Fri, 01 Mar 2013 13:43:45 +0100
changeset 133755 e6d4f6af9cb7bb4808749ac39bdb52dfd819f55b
parent 133754 8f293286c7f646a7cfd498ea783bd69c422293af
child 133756 f3536ccef114b61f0678a604f1b9edee9d8228be
push id1702
push userryanvm@gmail.com
push dateMon, 03 Jun 2013 19:58:42 +0000
treeherderfx-team@c8b95e4bf23c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent, qdot
bugs830290
milestone24.0a1
Bug 830290: Execute DBus send operation in DBus thread r=bent,qdot The DBus send operation simply sends a DBus message without further processing of replies. If the sender is interested in a reply, the respective serial number can be returned. In this case, the sending operation (and only the sending) is serialized with the calling thread.
ipc/dbus/DBusUtils.cpp
ipc/dbus/DBusUtils.h
--- a/ipc/dbus/DBusUtils.cpp
+++ b/ipc/dbus/DBusUtils.cpp
@@ -14,16 +14,17 @@
 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 ** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
 
 #include "DBusUtils.h"
 #include "DBusThread.h"
 #include "nsThreadUtils.h"
+#include "mozilla/Monitor.h"
 #include "nsAutoPtr.h"
 #include <cstdio>
 #include <cstring>
 
 #undef LOG
 #if defined(MOZ_WIDGET_GONK)
 #include <android/log.h>
 #define LOG(args...)  __android_log_print(ANDROID_LOG_INFO, "Gonk", args);
@@ -65,16 +66,174 @@ protected:
 
   virtual ~DBusConnectionSendRunnableBase()
   { }
 
   DBusConnection*   mConnection;
   DBusMessageRefPtr mMessage;
 };
 
+class DBusConnectionSendSyncRunnable : public DBusConnectionSendRunnableBase
+{
+public:
+  bool WaitForCompletion()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    MonitorAutoLock autoLock(mCompletedMonitor);
+    while (!mCompleted) {
+      mCompletedMonitor.Wait();
+    }
+    return mSuccess;
+  }
+
+protected:
+  DBusConnectionSendSyncRunnable(DBusConnection* aConnection,
+                                 DBusMessage* aMessage)
+  : DBusConnectionSendRunnableBase(aConnection, aMessage),
+    mCompletedMonitor("DBusConnectionSendSyncRunnable.mCompleted"),
+    mCompleted(false),
+    mSuccess(false)
+  { }
+
+  virtual ~DBusConnectionSendSyncRunnable()
+  { }
+
+  // Call this function at the end of Run() to notify waiting
+  // threads.
+  void Completed(bool aSuccess)
+  {
+    MonitorAutoLock autoLock(mCompletedMonitor);
+    MOZ_ASSERT(!mCompleted);
+    mSuccess = aSuccess;
+    mCompleted = true;
+    mCompletedMonitor.Notify();
+  }
+
+private:
+  Monitor mCompletedMonitor;
+  bool    mCompleted;
+  bool    mSuccess;
+};
+
+//
+// Sends a message and returns the message's serial number to the
+// disaptching thread. Only run it in DBus thread.
+//
+class DBusConnectionSendRunnable : public DBusConnectionSendSyncRunnable
+{
+public:
+  DBusConnectionSendRunnable(DBusConnection* aConnection,
+                             DBusMessage* aMessage,
+                             dbus_uint32_t* aSerial)
+  : DBusConnectionSendSyncRunnable(aConnection, aMessage),
+    mSerial(aSerial)
+  { }
+
+  NS_IMETHOD Run()
+  {
+    MOZ_ASSERT(!NS_IsMainThread());
+
+    dbus_bool_t success = dbus_connection_send(mConnection, mMessage, mSerial);
+    Completed(success == TRUE);
+
+    NS_ENSURE_TRUE(success == TRUE, NS_ERROR_FAILURE);
+
+    return NS_OK;
+  }
+
+protected:
+  ~DBusConnectionSendRunnable()
+  { }
+
+private:
+  dbus_uint32_t* mSerial;
+};
+
+dbus_bool_t
+dbus_func_send(DBusConnection* aConnection, dbus_uint32_t* aSerial,
+               DBusMessage* aMessage)
+{
+  nsRefPtr<DBusConnectionSendRunnable> t(
+    new DBusConnectionSendRunnable(aConnection, aMessage, aSerial));
+  MOZ_ASSERT(t);
+
+  nsresult rv = DispatchToDBusThread(t);
+
+  if (NS_FAILED(rv)) {
+    if (aMessage) {
+      dbus_message_unref(aMessage);
+    }
+    return FALSE;
+  }
+
+  if (aSerial && !t->WaitForCompletion()) {
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static dbus_bool_t
+dbus_func_args_send_valist(DBusConnection* aConnection,
+                           dbus_uint32_t* aSerial,
+                           const char* aPath,
+                           const char* aInterface,
+                           const char* aFunction,
+                           int aFirstArgType,
+                           va_list aArgs)
+{
+  // Compose the command...
+  DBusMessage* message = dbus_message_new_method_call(BLUEZ_DBUS_BASE_IFC,
+                                                      aPath,
+                                                      aInterface,
+                                                      aFunction);
+  if (!message) {
+    LOG("Could not allocate D-Bus message object!");
+    goto done;
+  }
+
+  // ... and append arguments.
+  if (!dbus_message_append_args_valist(message, aFirstArgType, aArgs)) {
+    LOG("Could not append argument to method call!");
+    goto done;
+  }
+
+  return dbus_func_send(aConnection, aSerial, message);
+
+done:
+  if (message) {
+    dbus_message_unref(message);
+  }
+  return FALSE;
+}
+
+dbus_bool_t
+dbus_func_args_send(DBusConnection* aConnection,
+                    dbus_uint32_t* aSerial,
+                    const char* aPath,
+                    const char* aInterface,
+                    const char* aFunction,
+                    int aFirstArgType, ...)
+{
+  va_list args;
+  va_start(args, aFirstArgType);
+
+  dbus_bool_t success = dbus_func_args_send_valist(aConnection,
+                                                   aSerial,
+                                                   aPath,
+                                                   aInterface,
+                                                   aFunction,
+                                                   aFirstArgType,
+                                                   args);
+  va_end(args);
+
+  return success;
+}
+
 //
 // Sends a message and executes a callback function for the reply. Only
 // run it in DBus thread.
 //
 class DBusConnectionSendWithReplyRunnable : public DBusConnectionSendRunnableBase
 {
 private:
   class NotifyData
--- a/ipc/dbus/DBusUtils.h
+++ b/ipc/dbus/DBusUtils.h
@@ -52,16 +52,27 @@ private:
 
 typedef void (*DBusCallback)(DBusMessage *, void *);
 
 
 void log_and_free_dbus_error(DBusError* err,
                              const char* function,
                              DBusMessage* msg = NULL);
 
+dbus_bool_t dbus_func_send(DBusConnection *aConnection,
+                           dbus_uint32_t *aSerial,
+                           DBusMessage *aMessage);
+
+dbus_bool_t dbus_func_args_send(DBusConnection *aConnection,
+                                dbus_uint32_t *aSerial,
+                                const char *aPath,
+                                const char *aInterface,
+                                const char *aFunction,
+                                int aFirstArgType, ...);
+
 dbus_bool_t dbus_func_send_async(DBusConnection* conn,
                                  DBusMessage* msg,
                                  int timeout_ms,
                                  DBusCallback user_cb,
                                  void* user);
 
 dbus_bool_t dbus_func_args_async(DBusConnection* conn,
                                  int timeout_ms,