summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/DataMutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/DataMutex.h')
-rw-r--r--xpcom/threads/DataMutex.h130
1 files changed, 130 insertions, 0 deletions
diff --git a/xpcom/threads/DataMutex.h b/xpcom/threads/DataMutex.h
new file mode 100644
index 0000000000..44f0a35762
--- /dev/null
+++ b/xpcom/threads/DataMutex.h
@@ -0,0 +1,130 @@
+/* -*- 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 DataMutex_h__
+#define DataMutex_h__
+
+#include <utility>
+#include "mozilla/Mutex.h"
+#include "mozilla/StaticMutex.h"
+
+namespace mozilla {
+
+// A template to wrap a type with a mutex so that accesses to the type's
+// data are required to take the lock before accessing it. This ensures
+// that a mutex is explicitly associated with the data that it protects,
+// and makes it impossible to access the data without first taking the
+// associated mutex.
+//
+// This is based on Rust's std::sync::Mutex, which operates under the
+// strategy of locking data, rather than code.
+//
+// Examples:
+//
+// DataMutex<uint32_t> u32DataMutex(1, "u32DataMutex");
+// auto x = u32DataMutex.Lock();
+// *x = 4;
+// assert(*x, 4u);
+//
+// DataMutex<nsTArray<uint32_t>> arrayDataMutex("arrayDataMutex");
+// auto a = arrayDataMutex.Lock();
+// auto& x = a.ref();
+// x.AppendElement(1u);
+// assert(x[0], 1u);
+//
+template <typename T, typename MutexType>
+class DataMutexBase {
+ public:
+ template <typename V>
+ class MOZ_STACK_CLASS AutoLockBase {
+ public:
+ V* operator->() const& { return &ref(); }
+ V* operator->() const&& = delete;
+
+ V& operator*() const& { return ref(); }
+ V& operator*() const&& = delete;
+
+ // Like RefPtr, make this act like its underlying raw pointer type
+ // whenever it is used in a context where a raw pointer is expected.
+ operator V*() const& { return &ref(); }
+
+ // Like RefPtr, don't allow implicit conversion of temporary to raw pointer.
+ operator V*() const&& = delete;
+
+ V& ref() const& {
+ MOZ_ASSERT(mOwner);
+ return mOwner->mValue;
+ }
+ V& ref() const&& = delete;
+
+ AutoLockBase(AutoLockBase&& aOther) : mOwner(aOther.mOwner) {
+ aOther.mOwner = nullptr;
+ }
+
+ ~AutoLockBase() {
+ if (mOwner) {
+ mOwner->mMutex.Unlock();
+ mOwner = nullptr;
+ }
+ }
+
+ private:
+ friend class DataMutexBase;
+
+ AutoLockBase(const AutoLockBase& aOther) = delete;
+
+ explicit AutoLockBase(DataMutexBase<T, MutexType>* aDataMutex)
+ : mOwner(aDataMutex) {
+ MOZ_ASSERT(!!mOwner);
+ mOwner->mMutex.Lock();
+ }
+
+ DataMutexBase<T, MutexType>* mOwner;
+ };
+
+ using AutoLock = AutoLockBase<T>;
+ using ConstAutoLock = AutoLockBase<const T>;
+
+ explicit DataMutexBase(const char* aName) : mMutex(aName) {}
+
+ DataMutexBase(T&& aValue, const char* aName)
+ : mMutex(aName), mValue(std::move(aValue)) {}
+
+ AutoLock Lock() { return AutoLock(this); }
+ ConstAutoLock ConstLock() { return ConstAutoLock(this); }
+
+ const MutexType& Mutex() const { return mMutex; }
+
+ private:
+ MutexType mMutex;
+ T mValue;
+};
+
+// Craft a version of StaticMutex that takes a const char* in its ctor.
+// We need this so it works interchangeably with Mutex which requires a const
+// char* aName in its ctor.
+class StaticMutexNameless : public StaticMutex {
+ public:
+ explicit StaticMutexNameless(const char* aName) : StaticMutex() {}
+
+ private:
+ // Disallow copy construction, `=`, `new`, and `delete` like BaseStaticMutex.
+#ifdef DEBUG
+ StaticMutexNameless(StaticMutexNameless& aOther);
+#endif // DEBUG
+ StaticMutexNameless& operator=(StaticMutexNameless* aRhs);
+ static void* operator new(size_t) noexcept(true);
+ static void operator delete(void*);
+};
+
+template <typename T>
+using DataMutex = DataMutexBase<T, Mutex>;
+template <typename T>
+using StaticDataMutex = DataMutexBase<T, StaticMutexNameless>;
+
+} // namespace mozilla
+
+#endif // DataMutex_h__