AsyncBlockers.h (2864B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set sw=2 ts=8 et ft=cpp : */ 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 file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_ipc_AsyncBlockers_h 8 #define mozilla_ipc_AsyncBlockers_h 9 10 #include "mozilla/MozPromise.h" 11 #include "mozilla/ThreadSafety.h" 12 #include "nsTArray.h" 13 14 // FIXME: when bug 1760855 is fixed, it should not be required anymore 15 16 namespace mozilla::ipc { 17 18 /** 19 * AsyncBlockers provide a simple registration service that allows to suspend 20 * completion of a particular task until all registered entries have been 21 * cleared. This can be used to implement a similar service to 22 * nsAsyncShutdownService in processes where it wouldn't normally be available. 23 * This class is thread-safe. 24 */ 25 class AsyncBlockers { 26 public: 27 AsyncBlockers() 28 : mLock("AsyncRegistrar"), 29 mPromise(new GenericPromise::Private(__func__)) {} 30 void Register(void* aBlocker) { 31 MutexAutoLock lock(mLock); 32 mBlockers.InsertElementSorted(aBlocker); 33 } 34 void Deregister(void* aBlocker) { 35 MutexAutoLock lock(mLock); 36 MOZ_ASSERT(mBlockers.ContainsSorted(aBlocker)); 37 MOZ_ALWAYS_TRUE(mBlockers.RemoveElementSorted(aBlocker)); 38 MaybeResolve(); 39 } 40 RefPtr<GenericPromise> WaitUntilClear(uint32_t aTimeOutInMs = 0) { 41 { 42 MutexAutoLock lock(mLock); 43 MaybeResolve(); 44 } 45 46 if (aTimeOutInMs > 0) { 47 GetCurrentSerialEventTarget()->DelayedDispatch( 48 NS_NewRunnableFunction("AsyncBlockers::WaitUntilClear", 49 [promise = mPromise]() { 50 // The AsyncBlockers object may have been 51 // deleted by now and the object isn't 52 // refcounted (nor do we want it to be). We 53 // can unconditionally resolve the promise 54 // even it has already been resolved as 55 // MozPromise are thread-safe and will just 56 // ignore the action if already resolved. 57 promise->Resolve(true, __func__); 58 }), 59 aTimeOutInMs); 60 } 61 62 return mPromise; 63 } 64 65 virtual ~AsyncBlockers() { mPromise->Resolve(true, __func__); } 66 67 private: 68 void MaybeResolve() MOZ_REQUIRES(mLock) { 69 mLock.AssertCurrentThreadOwns(); 70 if (!mBlockers.IsEmpty()) { 71 return; 72 } 73 mPromise->Resolve(true, __func__); 74 } 75 Mutex mLock; 76 nsTArray<void*> mBlockers MOZ_GUARDED_BY(mLock); 77 const RefPtr<GenericPromise::Private> mPromise; 78 }; 79 80 } // namespace mozilla::ipc 81 82 #endif // mozilla_ipc_AsyncBlockers_h