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/. */
6 
7 #ifndef nsThreadSyncDispatch_h_
8 #define nsThreadSyncDispatch_h_
9 
10 #include "mozilla/Atomics.h"
11 #include "mozilla/DebugOnly.h"
12 
13 #include "nsThreadUtils.h"
14 #include "LeakRefPtr.h"
15 
16 class nsThreadSyncDispatch : public mozilla::Runnable {
17  public:
nsThreadSyncDispatch(already_AddRefed<nsIEventTarget> aOrigin,already_AddRefed<nsIRunnable> && aTask)18   nsThreadSyncDispatch(already_AddRefed<nsIEventTarget> aOrigin,
19                        already_AddRefed<nsIRunnable>&& aTask)
20       : Runnable("nsThreadSyncDispatch"),
21         mOrigin(aOrigin),
22         mSyncTask(std::move(aTask)),
23         mIsPending(true) {}
24 
IsPending()25   bool IsPending() {
26     // This is an atomic acquire on the origin thread.
27     return mIsPending;
28   }
29 
30  private:
Run()31   NS_IMETHOD Run() override {
32     if (nsCOMPtr<nsIRunnable> task = mSyncTask.take()) {
33       MOZ_ASSERT(!mSyncTask);
34 
35       mozilla::DebugOnly<nsresult> result = task->Run();
36       MOZ_ASSERT(NS_SUCCEEDED(result), "task in sync dispatch should not fail");
37 
38       // We must release the task here to ensure that when the original
39       // thread is unblocked, this task has been released.
40       task = nullptr;
41 
42       // This is an atomic release on the target thread.
43       mIsPending = false;
44 
45       // unblock the origin thread
46       mOrigin->Dispatch(this, NS_DISPATCH_NORMAL);
47     }
48 
49     return NS_OK;
50   }
51 
52   nsCOMPtr<nsIEventTarget> mOrigin;
53   // The task is leaked by default when Run() is not called, because
54   // otherwise we may release it in an incorrect thread.
55   mozilla::LeakRefPtr<nsIRunnable> mSyncTask;
56   mozilla::Atomic<bool, mozilla::ReleaseAcquire> mIsPending;
57 };
58 
59 #endif  // nsThreadSyncDispatch_h_
60