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 #ifndef mozilla_ReentrantMonitor_h 8 #define mozilla_ReentrantMonitor_h 9 10 #include "prmon.h" 11 12 #ifdef MOZILLA_INTERNAL_API 13 #include "GeckoProfiler.h" 14 #endif //MOZILLA_INTERNAL_API 15 16 #include "mozilla/BlockingResourceBase.h" 17 18 // 19 // Provides: 20 // 21 // - ReentrantMonitor, a Java-like monitor 22 // - ReentrantMonitorAutoEnter, an RAII class for ensuring that 23 // ReentrantMonitors are properly entered and exited 24 // 25 // Using ReentrantMonitorAutoEnter is MUCH preferred to making bare calls to 26 // ReentrantMonitor.Enter and Exit. 27 // 28 namespace mozilla { 29 30 31 /** 32 * ReentrantMonitor 33 * Java-like monitor. 34 * When possible, use ReentrantMonitorAutoEnter to hold this monitor within a 35 * scope, instead of calling Enter/Exit directly. 36 **/ 37 class ReentrantMonitor : BlockingResourceBase 38 { 39 public: 40 /** 41 * ReentrantMonitor 42 * @param aName A name which can reference this monitor 43 */ ReentrantMonitor(const char * aName)44 explicit ReentrantMonitor(const char* aName) 45 : BlockingResourceBase(aName, eReentrantMonitor) 46 #ifdef DEBUG 47 , mEntryCount(0) 48 #endif 49 { 50 MOZ_COUNT_CTOR(ReentrantMonitor); 51 mReentrantMonitor = PR_NewMonitor(); 52 if (!mReentrantMonitor) { 53 NS_RUNTIMEABORT("Can't allocate mozilla::ReentrantMonitor"); 54 } 55 } 56 57 /** 58 * ~ReentrantMonitor 59 **/ ~ReentrantMonitor()60 ~ReentrantMonitor() 61 { 62 NS_ASSERTION(mReentrantMonitor, 63 "improperly constructed ReentrantMonitor or double free"); 64 PR_DestroyMonitor(mReentrantMonitor); 65 mReentrantMonitor = 0; 66 MOZ_COUNT_DTOR(ReentrantMonitor); 67 } 68 69 #ifndef DEBUG 70 /** 71 * Enter 72 * @see prmon.h 73 **/ Enter()74 void Enter() { PR_EnterMonitor(mReentrantMonitor); } 75 76 /** 77 * Exit 78 * @see prmon.h 79 **/ Exit()80 void Exit() { PR_ExitMonitor(mReentrantMonitor); } 81 82 /** 83 * Wait 84 * @see prmon.h 85 **/ 86 nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT) 87 { 88 #ifdef MOZILLA_INTERNAL_API 89 GeckoProfilerSleepRAII profiler_sleep; 90 #endif //MOZILLA_INTERNAL_API 91 return PR_Wait(mReentrantMonitor, aInterval) == PR_SUCCESS ? 92 NS_OK : NS_ERROR_FAILURE; 93 } 94 95 #else // ifndef DEBUG 96 void Enter(); 97 void Exit(); 98 nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT); 99 100 #endif // ifndef DEBUG 101 102 /** 103 * Notify 104 * @see prmon.h 105 **/ Notify()106 nsresult Notify() 107 { 108 return PR_Notify(mReentrantMonitor) == PR_SUCCESS ? NS_OK : 109 NS_ERROR_FAILURE; 110 } 111 112 /** 113 * NotifyAll 114 * @see prmon.h 115 **/ NotifyAll()116 nsresult NotifyAll() 117 { 118 return PR_NotifyAll(mReentrantMonitor) == PR_SUCCESS ? NS_OK : 119 NS_ERROR_FAILURE; 120 } 121 122 #ifdef DEBUG 123 /** 124 * AssertCurrentThreadIn 125 * @see prmon.h 126 **/ AssertCurrentThreadIn()127 void AssertCurrentThreadIn() 128 { 129 PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor); 130 } 131 132 /** 133 * AssertNotCurrentThreadIn 134 * @see prmon.h 135 **/ AssertNotCurrentThreadIn()136 void AssertNotCurrentThreadIn() 137 { 138 // FIXME bug 476536 139 } 140 141 #else AssertCurrentThreadIn()142 void AssertCurrentThreadIn() {} AssertNotCurrentThreadIn()143 void AssertNotCurrentThreadIn() {} 144 145 #endif // ifdef DEBUG 146 147 private: 148 ReentrantMonitor(); 149 ReentrantMonitor(const ReentrantMonitor&); 150 ReentrantMonitor& operator=(const ReentrantMonitor&); 151 152 PRMonitor* mReentrantMonitor; 153 #ifdef DEBUG 154 int32_t mEntryCount; 155 #endif 156 }; 157 158 159 /** 160 * ReentrantMonitorAutoEnter 161 * Enters the ReentrantMonitor when it enters scope, and exits it when 162 * it leaves scope. 163 * 164 * MUCH PREFERRED to bare calls to ReentrantMonitor.Enter and Exit. 165 */ 166 class MOZ_STACK_CLASS ReentrantMonitorAutoEnter 167 { 168 public: 169 /** 170 * Constructor 171 * The constructor aquires the given lock. The destructor 172 * releases the lock. 173 * 174 * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. 175 **/ ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor & aReentrantMonitor)176 explicit ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor& aReentrantMonitor) 177 : mReentrantMonitor(&aReentrantMonitor) 178 { 179 NS_ASSERTION(mReentrantMonitor, "null monitor"); 180 mReentrantMonitor->Enter(); 181 } 182 ~ReentrantMonitorAutoEnter(void)183 ~ReentrantMonitorAutoEnter(void) 184 { 185 mReentrantMonitor->Exit(); 186 } 187 188 nsresult Wait(PRIntervalTime aInterval = PR_INTERVAL_NO_TIMEOUT) 189 { 190 return mReentrantMonitor->Wait(aInterval); 191 } 192 Notify()193 nsresult Notify() { return mReentrantMonitor->Notify(); } NotifyAll()194 nsresult NotifyAll() { return mReentrantMonitor->NotifyAll(); } 195 196 private: 197 ReentrantMonitorAutoEnter(); 198 ReentrantMonitorAutoEnter(const ReentrantMonitorAutoEnter&); 199 ReentrantMonitorAutoEnter& operator=(const ReentrantMonitorAutoEnter&); 200 static void* operator new(size_t) CPP_THROW_NEW; 201 202 mozilla::ReentrantMonitor* mReentrantMonitor; 203 }; 204 205 /** 206 * ReentrantMonitorAutoExit 207 * Exit the ReentrantMonitor when it enters scope, and enters it when it leaves 208 * scope. 209 * 210 * MUCH PREFERRED to bare calls to ReentrantMonitor.Exit and Enter. 211 */ 212 class MOZ_STACK_CLASS ReentrantMonitorAutoExit 213 { 214 public: 215 /** 216 * Constructor 217 * The constructor releases the given lock. The destructor 218 * acquires the lock. The lock must be held before constructing 219 * this object! 220 * 221 * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. It 222 * must be already locked. 223 **/ ReentrantMonitorAutoExit(ReentrantMonitor & aReentrantMonitor)224 explicit ReentrantMonitorAutoExit(ReentrantMonitor& aReentrantMonitor) 225 : mReentrantMonitor(&aReentrantMonitor) 226 { 227 NS_ASSERTION(mReentrantMonitor, "null monitor"); 228 mReentrantMonitor->AssertCurrentThreadIn(); 229 mReentrantMonitor->Exit(); 230 } 231 ~ReentrantMonitorAutoExit(void)232 ~ReentrantMonitorAutoExit(void) 233 { 234 mReentrantMonitor->Enter(); 235 } 236 237 private: 238 ReentrantMonitorAutoExit(); 239 ReentrantMonitorAutoExit(const ReentrantMonitorAutoExit&); 240 ReentrantMonitorAutoExit& operator=(const ReentrantMonitorAutoExit&); 241 static void* operator new(size_t) CPP_THROW_NEW; 242 243 ReentrantMonitor* mReentrantMonitor; 244 }; 245 246 } // namespace mozilla 247 248 249 #endif // ifndef mozilla_ReentrantMonitor_h 250