diff options
Diffstat (limited to 'ipc/glue/AsyncBlockers.h')
-rw-r--r-- | ipc/glue/AsyncBlockers.h | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/ipc/glue/AsyncBlockers.h b/ipc/glue/AsyncBlockers.h new file mode 100644 index 0000000000..da1d710bac --- /dev/null +++ b/ipc/glue/AsyncBlockers.h @@ -0,0 +1,82 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 ts=8 et ft=cpp : */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_AsyncBlockers_h +#define mozilla_ipc_AsyncBlockers_h + +#include "mozilla/MozPromise.h" +#include "mozilla/ThreadSafety.h" +#include "nsTArray.h" + +// FIXME: when bug 1760855 is fixed, it should not be required anymore + +namespace mozilla::ipc { + +/** + * AsyncBlockers provide a simple registration service that allows to suspend + * completion of a particular task until all registered entries have been + * cleared. This can be used to implement a similar service to + * nsAsyncShutdownService in processes where it wouldn't normally be available. + * This class is thread-safe. + */ +class AsyncBlockers { + public: + AsyncBlockers() + : mLock("AsyncRegistrar"), + mPromise(new GenericPromise::Private(__func__)) {} + void Register(void* aBlocker) { + MutexAutoLock lock(mLock); + mBlockers.InsertElementSorted(aBlocker); + } + void Deregister(void* aBlocker) { + MutexAutoLock lock(mLock); + MOZ_ASSERT(mBlockers.ContainsSorted(aBlocker)); + MOZ_ALWAYS_TRUE(mBlockers.RemoveElementSorted(aBlocker)); + MaybeResolve(); + } + RefPtr<GenericPromise> WaitUntilClear(uint32_t aTimeOutInMs = 0) { + { + MutexAutoLock lock(mLock); + MaybeResolve(); + } + + if (aTimeOutInMs > 0) { + GetCurrentEventTarget()->DelayedDispatch( + NS_NewRunnableFunction("AsyncBlockers::WaitUntilClear", + [promise = mPromise]() { + // The AsyncBlockers object may have been + // deleted by now and the object isn't + // refcounted (nor do we want it to be). We + // can unconditionally resolve the promise + // even it has already been resolved as + // MozPromise are thread-safe and will just + // ignore the action if already resolved. + promise->Resolve(true, __func__); + }), + aTimeOutInMs); + } + + return mPromise; + } + + virtual ~AsyncBlockers() { mPromise->Resolve(true, __func__); } + + private: + void MaybeResolve() MOZ_REQUIRES(mLock) { + mLock.AssertCurrentThreadOwns(); + if (!mBlockers.IsEmpty()) { + return; + } + mPromise->Resolve(true, __func__); + } + Mutex mLock; + nsTArray<void*> mBlockers MOZ_GUARDED_BY(mLock); + const RefPtr<GenericPromise::Private> mPromise; +}; + +} // namespace mozilla::ipc + +#endif // mozilla_ipc_AsyncBlockers_h |