1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_SyncRunnable_h
8 #define mozilla_SyncRunnable_h
12 #include "mozilla/AbstractThread.h"
13 #include "mozilla/Monitor.h"
14 #include "mozilla/dom/JSExecutionManager.h"
15 #include "nsThreadUtils.h"
20 * This class will wrap a nsIRunnable and dispatch it to the target thread
21 * synchronously. This is different from
22 * NS_DispatchAndSpinEventLoopUntilComplete: this class does not spin the event
23 * loop waiting for the event to be dispatched. This means that you don't risk
24 * reentrance from pending messages, but you must be sure that the target thread
25 * does not ever block on this thread, or else you will deadlock.
28 * RefPtr<SyncRunnable> sr = new SyncRunnable(new myrunnable...());
29 * sr->DispatchToThread(t);
31 * We also provide convenience wrappers:
32 * SyncRunnable::DispatchToThread(pThread, new myrunnable...());
33 * SyncRunnable::DispatchToThread(pThread, NS_NewRunnableFunction(...));
36 class SyncRunnable
: public Runnable
{
38 explicit SyncRunnable(nsIRunnable
* aRunnable
)
39 : Runnable("SyncRunnable"),
41 mMonitor("SyncRunnable"),
44 explicit SyncRunnable(already_AddRefed
<nsIRunnable
> aRunnable
)
45 : Runnable("SyncRunnable"),
46 mRunnable(std::move(aRunnable
)),
47 mMonitor("SyncRunnable"),
50 nsresult
DispatchToThread(nsIEventTarget
* aThread
,
51 bool aForceDispatch
= false) {
55 if (!aForceDispatch
) {
56 rv
= aThread
->IsOnCurrentThread(&on
);
57 MOZ_ASSERT(NS_SUCCEEDED(rv
));
58 if (NS_SUCCEEDED(rv
) && on
) {
64 rv
= aThread
->Dispatch(this, NS_DISPATCH_NORMAL
);
65 if (NS_SUCCEEDED(rv
)) {
66 mozilla::MonitorAutoLock
lock(mMonitor
);
67 // This could be synchronously dispatching to a thread currently waiting
68 // for JS execution clearance. Yield JS execution.
69 dom::AutoYieldJSThreadExecution yield
;
78 nsresult
DispatchToThread(AbstractThread
* aThread
,
79 bool aForceDispatch
= false) {
80 if (!aForceDispatch
&& aThread
->IsCurrentThreadIn()) {
85 // Check we don't have tail dispatching here. Otherwise we will deadlock
86 // ourself when spinning the loop below.
87 MOZ_ASSERT(!aThread
->RequiresTailDispatchFromCurrentThread());
89 nsresult rv
= aThread
->Dispatch(RefPtr
<nsIRunnable
>(this).forget());
90 if (NS_SUCCEEDED(rv
)) {
91 mozilla::MonitorAutoLock
lock(mMonitor
);
99 static nsresult
DispatchToThread(nsIEventTarget
* aThread
,
100 nsIRunnable
* aRunnable
,
101 bool aForceDispatch
= false) {
102 RefPtr
<SyncRunnable
> s(new SyncRunnable(aRunnable
));
103 return s
->DispatchToThread(aThread
, aForceDispatch
);
106 static nsresult
DispatchToThread(AbstractThread
* aThread
,
107 nsIRunnable
* aRunnable
,
108 bool aForceDispatch
= false) {
109 RefPtr
<SyncRunnable
> s(new SyncRunnable(aRunnable
));
110 return s
->DispatchToThread(aThread
, aForceDispatch
);
113 static nsresult
DispatchToThread(nsIEventTarget
* aThread
,
114 already_AddRefed
<nsIRunnable
> aRunnable
,
115 bool aForceDispatch
= false) {
116 RefPtr
<SyncRunnable
> s(new SyncRunnable(std::move(aRunnable
)));
117 return s
->DispatchToThread(aThread
, aForceDispatch
);
120 static nsresult
DispatchToThread(AbstractThread
* aThread
,
121 already_AddRefed
<nsIRunnable
> aRunnable
,
122 bool aForceDispatch
= false) {
123 RefPtr
<SyncRunnable
> s(new SyncRunnable(std::move(aRunnable
)));
124 return s
->DispatchToThread(aThread
, aForceDispatch
);
127 // These deleted overloads prevent accidentally (if harmlessly) double-
128 // wrapping SyncRunnable, which was previously a common anti-pattern.
129 static nsresult
DispatchToThread(nsIEventTarget
* aThread
,
130 SyncRunnable
* aRunnable
,
131 bool aForceDispatch
= false) = delete;
132 static nsresult
DispatchToThread(AbstractThread
* aThread
,
133 SyncRunnable
* aRunnable
,
134 bool aForceDispatch
= false) = delete;
137 NS_IMETHOD
Run() override
{
140 mozilla::MonitorAutoLock
lock(mMonitor
);
150 nsCOMPtr
<nsIRunnable
> mRunnable
;
151 mozilla::Monitor mMonitor
;
152 bool mDone
MOZ_GUARDED_BY(mMonitor
);
155 } // namespace mozilla
157 #endif // mozilla_SyncRunnable_h