|
1 /* -*- Mode: C++; tab-width: 12; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #ifndef mozilla_SyncRunnable_h |
|
7 #define mozilla_SyncRunnable_h |
|
8 |
|
9 #include "nsThreadUtils.h" |
|
10 #include "mozilla/Monitor.h" |
|
11 |
|
12 namespace mozilla { |
|
13 |
|
14 /** |
|
15 * This class will wrap a nsIRunnable and dispatch it to the main thread |
|
16 * synchronously. This is different from nsIEventTarget.DISPATCH_SYNC: |
|
17 * this class does not spin the event loop waiting for the event to be |
|
18 * dispatched. This means that you don't risk reentrance from pending |
|
19 * messages, but you must be sure that the target thread does not ever block |
|
20 * on this thread, or else you will deadlock. |
|
21 * |
|
22 * Typical usage: |
|
23 * nsRefPtr<SyncRunnable> sr = new SyncRunnable(new myrunnable...()); |
|
24 * sr->DispatchToThread(t); |
|
25 * |
|
26 * We also provide a convenience wrapper: |
|
27 * SyncRunnable::DispatchToThread(new myrunnable...()); |
|
28 * |
|
29 */ |
|
30 class SyncRunnable : public nsRunnable |
|
31 { |
|
32 public: |
|
33 SyncRunnable(nsIRunnable* r) |
|
34 : mRunnable(r) |
|
35 , mMonitor("SyncRunnable") |
|
36 , mDone(false) |
|
37 { } |
|
38 |
|
39 void DispatchToThread(nsIEventTarget* thread, |
|
40 bool forceDispatch = false) |
|
41 { |
|
42 nsresult rv; |
|
43 bool on; |
|
44 |
|
45 if (!forceDispatch) { |
|
46 rv = thread->IsOnCurrentThread(&on); |
|
47 MOZ_ASSERT(NS_SUCCEEDED(rv)); |
|
48 if (NS_SUCCEEDED(rv) && on) { |
|
49 mRunnable->Run(); |
|
50 return; |
|
51 } |
|
52 } |
|
53 |
|
54 rv = thread->Dispatch(this, NS_DISPATCH_NORMAL); |
|
55 if (NS_SUCCEEDED(rv)) { |
|
56 mozilla::MonitorAutoLock lock(mMonitor); |
|
57 while (!mDone) { |
|
58 lock.Wait(); |
|
59 } |
|
60 } |
|
61 } |
|
62 |
|
63 static void DispatchToThread(nsIEventTarget* thread, |
|
64 nsIRunnable* r, |
|
65 bool forceDispatch = false) |
|
66 { |
|
67 nsRefPtr<SyncRunnable> s(new SyncRunnable(r)); |
|
68 s->DispatchToThread(thread, forceDispatch); |
|
69 } |
|
70 |
|
71 protected: |
|
72 NS_IMETHODIMP Run() |
|
73 { |
|
74 mRunnable->Run(); |
|
75 |
|
76 mozilla::MonitorAutoLock lock(mMonitor); |
|
77 MOZ_ASSERT(!mDone); |
|
78 |
|
79 mDone = true; |
|
80 mMonitor.Notify(); |
|
81 |
|
82 return NS_OK; |
|
83 } |
|
84 |
|
85 private: |
|
86 nsCOMPtr<nsIRunnable> mRunnable; |
|
87 mozilla::Monitor mMonitor; |
|
88 bool mDone; |
|
89 }; |
|
90 |
|
91 } // namespace mozilla |
|
92 |
|
93 #endif // mozilla_SyncRunnable_h |