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 133751 e6d4f6af9cb7bb4808749ac39bdb52dfd819f55b
parent 133750 8f293286c7f646a7cfd498ea783bd69c422293af
child 133752 f3536ccef114b61f0678a604f1b9edee9d8228be
push idunknown
push userunknown
push dateunknown
reviewersbent, qdot
bugs830290
milestone24.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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,