Bug 1919083 - [ci] Enable os-integration variant for more suites, r=jmaher
[gecko.git] / xpcom / threads / SyncRunnable.h
blob77f82ba313894d2bc6f2f01fb70596229fdc3650
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
10 #include <utility>
12 #include "mozilla/AbstractThread.h"
13 #include "mozilla/Monitor.h"
14 #include "mozilla/dom/JSExecutionManager.h"
15 #include "nsThreadUtils.h"
17 namespace mozilla {
19 /**
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.
27 * Typical usage:
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 {
37 public:
38 explicit SyncRunnable(nsIRunnable* aRunnable)
39 : Runnable("SyncRunnable"),
40 mRunnable(aRunnable),
41 mMonitor("SyncRunnable"),
42 mDone(false) {}
44 explicit SyncRunnable(already_AddRefed<nsIRunnable> aRunnable)
45 : Runnable("SyncRunnable"),
46 mRunnable(std::move(aRunnable)),
47 mMonitor("SyncRunnable"),
48 mDone(false) {}
50 nsresult DispatchToThread(nsIEventTarget* aThread,
51 bool aForceDispatch = false) {
52 nsresult rv;
53 bool on;
55 if (!aForceDispatch) {
56 rv = aThread->IsOnCurrentThread(&on);
57 MOZ_ASSERT(NS_SUCCEEDED(rv));
58 if (NS_SUCCEEDED(rv) && on) {
59 mRunnable->Run();
60 return NS_OK;
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;
71 while (!mDone) {
72 lock.Wait();
75 return rv;
78 nsresult DispatchToThread(AbstractThread* aThread,
79 bool aForceDispatch = false) {
80 if (!aForceDispatch && aThread->IsCurrentThreadIn()) {
81 mRunnable->Run();
82 return NS_OK;
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);
92 while (!mDone) {
93 lock.Wait();
96 return rv;
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;
136 protected:
137 NS_IMETHOD Run() override {
138 mRunnable->Run();
140 mozilla::MonitorAutoLock lock(mMonitor);
141 MOZ_ASSERT(!mDone);
143 mDone = true;
144 mMonitor.Notify();
146 return NS_OK;
149 private:
150 nsCOMPtr<nsIRunnable> mRunnable;
151 mozilla::Monitor mMonitor;
152 bool mDone MOZ_GUARDED_BY(mMonitor);
155 } // namespace mozilla
157 #endif // mozilla_SyncRunnable_h