summaryrefslogtreecommitdiffstats
path: root/xpcom/threads/RecursiveMutex.h
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/threads/RecursiveMutex.h')
-rw-r--r--xpcom/threads/RecursiveMutex.h120
1 files changed, 120 insertions, 0 deletions
diff --git a/xpcom/threads/RecursiveMutex.h b/xpcom/threads/RecursiveMutex.h
new file mode 100644
index 0000000000..dde21c9a35
--- /dev/null
+++ b/xpcom/threads/RecursiveMutex.h
@@ -0,0 +1,120 @@
+/* -*- 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/. */
+
+// A lock that can be acquired multiple times on the same thread.
+
+#ifndef mozilla_RecursiveMutex_h
+#define mozilla_RecursiveMutex_h
+
+#include "mozilla/ThreadSafety.h"
+#include "mozilla/BlockingResourceBase.h"
+
+#ifndef XP_WIN
+# include <pthread.h>
+#endif
+
+namespace mozilla {
+
+class MOZ_CAPABILITY("recursive mutex") RecursiveMutex
+ : public BlockingResourceBase {
+ public:
+ explicit RecursiveMutex(const char* aName);
+ ~RecursiveMutex();
+
+#ifdef DEBUG
+ void Lock() MOZ_CAPABILITY_ACQUIRE();
+ void Unlock() MOZ_CAPABILITY_RELEASE();
+#else
+ void Lock() MOZ_CAPABILITY_ACQUIRE() { LockInternal(); }
+ void Unlock() MOZ_CAPABILITY_RELEASE() { UnlockInternal(); }
+#endif
+
+#ifdef DEBUG
+ /**
+ * AssertCurrentThreadIn
+ **/
+ void AssertCurrentThreadIn() const MOZ_ASSERT_CAPABILITY(this);
+ /**
+ * AssertNotCurrentThreadIn
+ **/
+ void AssertNotCurrentThreadIn() const MOZ_EXCLUDES(this) {
+ // Not currently implemented. See bug 476536 for discussion.
+ }
+#else
+ void AssertCurrentThreadIn() const MOZ_ASSERT_CAPABILITY(this) {}
+ void AssertNotCurrentThreadIn() const MOZ_EXCLUDES(this) {}
+#endif
+
+ private:
+ RecursiveMutex() = delete;
+ RecursiveMutex(const RecursiveMutex&) = delete;
+ RecursiveMutex& operator=(const RecursiveMutex&) = delete;
+
+ void LockInternal();
+ void UnlockInternal();
+
+#ifdef DEBUG
+ PRThread* mOwningThread;
+ size_t mEntryCount;
+#endif
+
+#if !defined(XP_WIN)
+ pthread_mutex_t mMutex;
+#else
+ // We eschew including windows.h and using CRITICAL_SECTION here so that files
+ // including us don't also pull in windows.h. Just use a type that's big
+ // enough for CRITICAL_SECTION, and we'll fix it up later.
+ void* mMutex[6];
+#endif
+};
+
+class MOZ_RAII MOZ_SCOPED_CAPABILITY RecursiveMutexAutoLock {
+ public:
+ explicit RecursiveMutexAutoLock(RecursiveMutex& aRecursiveMutex)
+ MOZ_CAPABILITY_ACQUIRE(aRecursiveMutex)
+ : mRecursiveMutex(&aRecursiveMutex) {
+ NS_ASSERTION(mRecursiveMutex, "null mutex");
+ mRecursiveMutex->Lock();
+ }
+
+ ~RecursiveMutexAutoLock(void) MOZ_CAPABILITY_RELEASE() {
+ mRecursiveMutex->Unlock();
+ }
+
+ private:
+ RecursiveMutexAutoLock() = delete;
+ RecursiveMutexAutoLock(const RecursiveMutexAutoLock&) = delete;
+ RecursiveMutexAutoLock& operator=(const RecursiveMutexAutoLock&) = delete;
+ static void* operator new(size_t) noexcept(true);
+
+ mozilla::RecursiveMutex* mRecursiveMutex;
+};
+
+class MOZ_RAII MOZ_SCOPED_CAPABILITY RecursiveMutexAutoUnlock {
+ public:
+ explicit RecursiveMutexAutoUnlock(RecursiveMutex& aRecursiveMutex)
+ MOZ_SCOPED_UNLOCK_RELEASE(aRecursiveMutex)
+ : mRecursiveMutex(&aRecursiveMutex) {
+ NS_ASSERTION(mRecursiveMutex, "null mutex");
+ mRecursiveMutex->Unlock();
+ }
+
+ ~RecursiveMutexAutoUnlock(void) MOZ_SCOPED_UNLOCK_REACQUIRE() {
+ mRecursiveMutex->Lock();
+ }
+
+ private:
+ RecursiveMutexAutoUnlock() = delete;
+ RecursiveMutexAutoUnlock(const RecursiveMutexAutoUnlock&) = delete;
+ RecursiveMutexAutoUnlock& operator=(const RecursiveMutexAutoUnlock&) = delete;
+ static void* operator new(size_t) noexcept(true);
+
+ mozilla::RecursiveMutex* mRecursiveMutex;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_RecursiveMutex_h