From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- xpcom/threads/SyncRunnable.h | 129 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 xpcom/threads/SyncRunnable.h (limited to 'xpcom/threads/SyncRunnable.h') diff --git a/xpcom/threads/SyncRunnable.h b/xpcom/threads/SyncRunnable.h new file mode 100644 index 000000000..d96bac7ba --- /dev/null +++ b/xpcom/threads/SyncRunnable.h @@ -0,0 +1,129 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_SyncRunnable_h +#define mozilla_SyncRunnable_h + +#include "nsThreadUtils.h" +#include "mozilla/AbstractThread.h" +#include "mozilla/Monitor.h" +#include "mozilla/Move.h" + +namespace mozilla { + +/** + * This class will wrap a nsIRunnable and dispatch it to the main thread + * synchronously. This is different from nsIEventTarget.DISPATCH_SYNC: + * this class does not spin the event loop waiting for the event to be + * dispatched. This means that you don't risk reentrance from pending + * messages, but you must be sure that the target thread does not ever block + * on this thread, or else you will deadlock. + * + * Typical usage: + * RefPtr sr = new SyncRunnable(new myrunnable...()); + * sr->DispatchToThread(t); + * + * We also provide a convenience wrapper: + * SyncRunnable::DispatchToThread(new myrunnable...()); + * + */ +class SyncRunnable : public Runnable +{ +public: + explicit SyncRunnable(nsIRunnable* aRunnable) + : mRunnable(aRunnable) + , mMonitor("SyncRunnable") + , mDone(false) + { + } + + explicit SyncRunnable(already_AddRefed aRunnable) + : mRunnable(Move(aRunnable)) + , mMonitor("SyncRunnable") + , mDone(false) + { + } + + void DispatchToThread(nsIEventTarget* aThread, bool aForceDispatch = false) + { + nsresult rv; + bool on; + + if (!aForceDispatch) { + rv = aThread->IsOnCurrentThread(&on); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + if (NS_SUCCEEDED(rv) && on) { + mRunnable->Run(); + return; + } + } + + rv = aThread->Dispatch(this, NS_DISPATCH_NORMAL); + if (NS_SUCCEEDED(rv)) { + mozilla::MonitorAutoLock lock(mMonitor); + while (!mDone) { + lock.Wait(); + } + } + } + + void DispatchToThread(AbstractThread* aThread, bool aForceDispatch = false) + { + if (!aForceDispatch && aThread->IsCurrentThreadIn()) { + mRunnable->Run(); + return; + } + + // Check we don't have tail dispatching here. Otherwise we will deadlock + // ourself when spinning the loop below. + MOZ_ASSERT(!aThread->RequiresTailDispatchFromCurrentThread()); + + aThread->Dispatch(RefPtr(this).forget()); + mozilla::MonitorAutoLock lock(mMonitor); + while (!mDone) { + lock.Wait(); + } + } + + static void DispatchToThread(nsIEventTarget* aThread, + nsIRunnable* aRunnable, + bool aForceDispatch = false) + { + RefPtr s(new SyncRunnable(aRunnable)); + s->DispatchToThread(aThread, aForceDispatch); + } + + static void DispatchToThread(AbstractThread* aThread, + nsIRunnable* aRunnable, + bool aForceDispatch = false) + { + RefPtr s(new SyncRunnable(aRunnable)); + s->DispatchToThread(aThread, aForceDispatch); + } + +protected: + NS_IMETHOD Run() override + { + mRunnable->Run(); + + mozilla::MonitorAutoLock lock(mMonitor); + MOZ_ASSERT(!mDone); + + mDone = true; + mMonitor.Notify(); + + return NS_OK; + } + +private: + nsCOMPtr mRunnable; + mozilla::Monitor mMonitor; + bool mDone; +}; + +} // namespace mozilla + +#endif // mozilla_SyncRunnable_h -- cgit v1.2.3