1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 // A lock that can be acquired multiple times on the same thread.
8 
9 #ifndef mozilla_RecursiveMutex_h
10 #define mozilla_RecursiveMutex_h
11 
12 #include "mozilla/BlockingResourceBase.h"
13 
14 #ifndef XP_WIN
15 #  include <pthread.h>
16 #endif
17 
18 namespace mozilla {
19 
20 class RecursiveMutex : public BlockingResourceBase {
21  public:
22   explicit RecursiveMutex(const char* aName);
23   ~RecursiveMutex();
24 
25 #ifdef DEBUG
26   void Lock();
27   void Unlock();
28 #else
Lock()29   void Lock() { LockInternal(); }
Unlock()30   void Unlock() { UnlockInternal(); }
31 #endif
32 
33 #ifdef DEBUG
34   /**
35    * AssertCurrentThreadIn
36    **/
37   void AssertCurrentThreadIn();
38   /**
39    * AssertNotCurrentThreadIn
40    **/
AssertNotCurrentThreadIn()41   void AssertNotCurrentThreadIn() {
42     // Not currently implemented. See bug 476536 for discussion.
43   }
44 #else
AssertCurrentThreadIn()45   void AssertCurrentThreadIn() {}
AssertNotCurrentThreadIn()46   void AssertNotCurrentThreadIn() {}
47 #endif
48 
49  private:
50   RecursiveMutex() = delete;
51   RecursiveMutex(const RecursiveMutex&) = delete;
52   RecursiveMutex& operator=(const RecursiveMutex&) = delete;
53 
54   void LockInternal();
55   void UnlockInternal();
56 
57 #ifdef DEBUG
58   PRThread* mOwningThread;
59   size_t mEntryCount;
60 #endif
61 
62 #if !defined(XP_WIN)
63   pthread_mutex_t mMutex;
64 #else
65   // We eschew including windows.h and using CRITICAL_SECTION here so that files
66   // including us don't also pull in windows.h.  Just use a type that's big
67   // enough for CRITICAL_SECTION, and we'll fix it up later.
68   void* mMutex[6];
69 #endif
70 };
71 
72 class MOZ_RAII RecursiveMutexAutoLock {
73  public:
RecursiveMutexAutoLock(RecursiveMutex & aRecursiveMutex)74   explicit RecursiveMutexAutoLock(RecursiveMutex& aRecursiveMutex)
75       : mRecursiveMutex(&aRecursiveMutex) {
76     NS_ASSERTION(mRecursiveMutex, "null mutex");
77     mRecursiveMutex->Lock();
78   }
79 
~RecursiveMutexAutoLock(void)80   ~RecursiveMutexAutoLock(void) { mRecursiveMutex->Unlock(); }
81 
82  private:
83   RecursiveMutexAutoLock() = delete;
84   RecursiveMutexAutoLock(const RecursiveMutexAutoLock&) = delete;
85   RecursiveMutexAutoLock& operator=(const RecursiveMutexAutoLock&) = delete;
86   static void* operator new(size_t) noexcept(true);
87 
88   mozilla::RecursiveMutex* mRecursiveMutex;
89 };
90 
91 class MOZ_RAII RecursiveMutexAutoUnlock {
92  public:
RecursiveMutexAutoUnlock(RecursiveMutex & aRecursiveMutex)93   explicit RecursiveMutexAutoUnlock(RecursiveMutex& aRecursiveMutex)
94       : mRecursiveMutex(&aRecursiveMutex) {
95     NS_ASSERTION(mRecursiveMutex, "null mutex");
96     mRecursiveMutex->Unlock();
97   }
98 
~RecursiveMutexAutoUnlock(void)99   ~RecursiveMutexAutoUnlock(void) { mRecursiveMutex->Lock(); }
100 
101  private:
102   RecursiveMutexAutoUnlock() = delete;
103   RecursiveMutexAutoUnlock(const RecursiveMutexAutoUnlock&) = delete;
104   RecursiveMutexAutoUnlock& operator=(const RecursiveMutexAutoUnlock&) = delete;
105   static void* operator new(size_t) noexcept(true);
106 
107   mozilla::RecursiveMutex* mRecursiveMutex;
108 };
109 
110 }  // namespace mozilla
111 
112 #endif  // mozilla_RecursiveMutex_h
113