summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/Monitor.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/Monitor.h')
-rw-r--r--xpcom/threads/Monitor.h119
1 files changed, 119 insertions, 0 deletions
diff --git a/xpcom/threads/Monitor.h b/xpcom/threads/Monitor.h
new file mode 100644
index 0000000000..ff8204b5ad
--- /dev/null
+++ b/xpcom/threads/Monitor.h
@@ -0,0 +1,119 @@
+/* -*- 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_Monitor_h
+#define mozilla_Monitor_h
+
+#include "mozilla/CondVar.h"
+#include "mozilla/Mutex.h"
+
+namespace mozilla {
+
+/**
+ * Monitor provides a *non*-reentrant monitor: *not* a Java-style
+ * monitor. If your code needs support for reentrancy, use
+ * ReentrantMonitor instead. (Rarely should reentrancy be needed.)
+ *
+ * Instead of directly calling Monitor methods, it's safer and simpler
+ * to instead use the RAII wrappers MonitorAutoLock and
+ * MonitorAutoUnlock.
+ */
+class Monitor {
+ public:
+ explicit Monitor(const char* aName)
+ : mMutex(aName), mCondVar(mMutex, "[Monitor.mCondVar]") {}
+
+ ~Monitor() = default;
+
+ void Lock() { mMutex.Lock(); }
+ [[nodiscard]] bool TryLock() { return mMutex.TryLock(); }
+ void Unlock() { mMutex.Unlock(); }
+
+ void Wait() { mCondVar.Wait(); }
+ CVStatus Wait(TimeDuration aDuration) { return mCondVar.Wait(aDuration); }
+
+ void Notify() { mCondVar.Notify(); }
+ void NotifyAll() { mCondVar.NotifyAll(); }
+
+ void AssertCurrentThreadOwns() const { mMutex.AssertCurrentThreadOwns(); }
+
+ void AssertNotCurrentThreadOwns() const {
+ mMutex.AssertNotCurrentThreadOwns();
+ }
+
+ private:
+ Monitor();
+ Monitor(const Monitor&);
+ Monitor& operator=(const Monitor&);
+
+ Mutex mMutex;
+ CondVar mCondVar;
+};
+
+/**
+ * Lock the monitor for the lexical scope instances of this class are
+ * bound to (except for MonitorAutoUnlock in nested scopes).
+ *
+ * The monitor must be unlocked when instances of this class are
+ * created.
+ */
+class MOZ_STACK_CLASS MonitorAutoLock {
+ public:
+ explicit MonitorAutoLock(Monitor& aMonitor) : mMonitor(&aMonitor) {
+ mMonitor->Lock();
+ }
+
+ ~MonitorAutoLock() { mMonitor->Unlock(); }
+
+ void Wait() { mMonitor->Wait(); }
+ CVStatus Wait(TimeDuration aDuration) { return mMonitor->Wait(aDuration); }
+
+ void Notify() { mMonitor->Notify(); }
+ void NotifyAll() { mMonitor->NotifyAll(); }
+
+ private:
+ MonitorAutoLock();
+ MonitorAutoLock(const MonitorAutoLock&);
+ MonitorAutoLock& operator=(const MonitorAutoLock&);
+ static void* operator new(size_t) noexcept(true);
+
+ friend class MonitorAutoUnlock;
+
+ Monitor* mMonitor;
+};
+
+/**
+ * Unlock the monitor for the lexical scope instances of this class
+ * are bound to (except for MonitorAutoLock in nested scopes).
+ *
+ * The monitor must be locked by the current thread when instances of
+ * this class are created.
+ */
+class MOZ_STACK_CLASS MonitorAutoUnlock {
+ public:
+ explicit MonitorAutoUnlock(Monitor& aMonitor) : mMonitor(&aMonitor) {
+ mMonitor->Unlock();
+ }
+
+ explicit MonitorAutoUnlock(MonitorAutoLock& aMonitorLock)
+ : mMonitor(aMonitorLock.mMonitor) {
+ mMonitor->Unlock();
+ }
+
+ ~MonitorAutoUnlock() { mMonitor->Lock(); }
+
+ private:
+ MonitorAutoUnlock();
+ MonitorAutoUnlock(const MonitorAutoUnlock&);
+ MonitorAutoUnlock& operator=(const MonitorAutoUnlock&);
+ static void* operator new(size_t) noexcept(true);
+
+ Monitor* mMonitor;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_Monitor_h