Bug 853998 - Add a common "SyncRunnable" class which dispatches events totally synchronously, avoiding event loop spinning or automatic promotion of this event to a nsThread, r=bsmedberg
authorBenjamin Smedberg <benjamin>
Tue, 26 Mar 2013 09:11:00 -0700
changeset 126513 9a04c4a506dfe80e08f2fc66dfbb26d3b301c253
parent 126512 bc6dfc2e65f07c10eb63c9970a8d0c63b8b04adc
child 126514 687b479332b3d1fbdf184d7eb855ccc9a8b02275
push id24485
push userryanvm@gmail.com
push dateThu, 28 Mar 2013 12:31:20 +0000
treeherdermozilla-central@293498096b28 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbsmedberg
bugs853998
milestone22.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 853998 - Add a common "SyncRunnable" class which dispatches events totally synchronously, avoiding event loop spinning or automatic promotion of this event to a nsThread, r=bsmedberg
xpcom/threads/Makefile.in
xpcom/threads/SyncRunnable.h
--- a/xpcom/threads/Makefile.in
+++ b/xpcom/threads/Makefile.in
@@ -33,16 +33,17 @@ EXPORTS		= \
 		nsThread.h \
 		nsProcess.h \
 		nsEventQueue.h \
 		$(NULL)
 
 EXPORTS_mozilla = \
   HangMonitor.h \
   LazyIdleThread.h \
+  SyncRunnable.h \
   $(NULL)
 
 EXPORTS		:= $(addprefix $(srcdir)/, $(EXPORTS))
 
 LOCAL_INCLUDES	= -I$(srcdir)/../components
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
new file mode 100644
--- /dev/null
+++ b/xpcom/threads/SyncRunnable.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 12; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_SyncRunnable_h
+
+#include "nsThreadUtils.h"
+#include "mozilla/Monitor.h"
+
+namespace mozilla {
+
+/**
+ * This class will wrap a nsIRunnable and dispatch it to the main thread
+ * synchronously. This is different from nsIEventTarget.DISPATCH_SYNC:
+ * this class does not spin the event loop waiting for the event to be
+ * dispatched. This means that you don't risk reentrance from pending
+ * messages, but you must be sure that the target thread does not ever block
+ * on this thread, or else you will deadlock.
+ *
+ * Typical usage:
+ * nsRefPtr<SyncRunnable> sr = new SyncRunnable(new myrunnable...());
+ * sr->DispatchToThread(t);
+ *
+ * We also provide a convenience wrapper:
+ * SyncRunnable::DispatchToThread(new myrunnable...());
+ *
+ */
+class SyncRunnable : public nsRunnable
+{
+public:
+  SyncRunnable(nsIRunnable* r)
+    : mRunnable(r)
+    , mMonitor("SyncRunnable")
+  { }
+
+  void DispatchToThread(nsIEventTarget* thread)
+  {
+    nsresult rv;
+    bool on;
+
+    rv = thread->IsOnCurrentThread(&on);
+    MOZ_ASSERT(NS_SUCCEEDED(rv));
+    if (NS_SUCCEEDED(rv) && on) {
+      mRunnable->Run();
+      return;
+    }
+
+    mozilla::MonitorAutoLock lock(mMonitor);
+    rv = thread->Dispatch(this, NS_DISPATCH_NORMAL);
+    if (NS_SUCCEEDED(rv)) {
+      lock.Wait();
+    }
+  }
+
+  static void DispatchToThread(nsIEventTarget* thread,
+                               nsIRunnable* r)
+  {
+    nsRefPtr<SyncRunnable> s(new SyncRunnable(r));
+    s->DispatchToThread(thread);
+  }
+
+protected:
+  NS_IMETHODIMP Run()
+  {
+    mRunnable->Run();
+    mozilla::MonitorAutoLock(mMonitor).Notify();
+    return NS_OK;
+  }
+
+private:
+  nsCOMPtr<nsIRunnable> mRunnable;
+  mozilla::Monitor mMonitor;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_SyncRunnable_h