Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

472 lines
9.4 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1990 - 1999
  3. Module Name:
  4. mutex.hxx
  5. Abstract:
  6. This file contains the system independent mutex classes. A mutex is an
  7. object which is used to serialize access to a resource. Besides
  8. construction and destruction, a mutex can have two operations performed on
  9. it: Clear and Request. Request is a request for exclusive access to the
  10. mutex; the method will not complete until the calling thread has exclusive
  11. access to the mutex. Clear indicates that the thread with exclusive
  12. access to the mutex is done.
  13. Three MUTEX classes exist here, each for a particular purpose:
  14. MUTEX - a simple wrapper around WIN32 critical sections
  15. - fastest
  16. - better MP behavior
  17. - optimized for each platform
  18. - general purpose
  19. - recursive Request() calls allowed
  20. - good debugger support, !locks, critical section timeouts, etc
  21. MUTEX2 - basic lock used only for context handle dispatch serialization.
  22. - specific purpose.
  23. - may not be recursivly Request()'ed.
  24. - allows any thread to release the lock.
  25. - harder to debug
  26. MUTEX3 - basic lock used around connection oriented bind requests
  27. - behavior similar to MUTEX
  28. - slower
  29. - will not timeout
  30. - harder to debug
  31. Helper classes:
  32. CLAIM_MUTEX - designed as a local class wrapping a MUTEX
  33. Usage:
  34. MUTEX GlobalMutex;
  35. foo() {
  36. CLAIM_MUTEX lockit(GlobalMutex);
  37. // GlobalMutex is now held
  38. if (blah)
  39. return;
  40. bleh;
  41. return;
  42. } // GlobalMutex is released when "lockit" goes out of scope.
  43. EVENT - simple wrapper around a WIN32 event object
  44. Author:
  45. MikeMon
  46. Revision History:
  47. mikemon ??-??-?? The starting line.
  48. mikemon 12-31-90 Upgraded the comments.
  49. MazharM 9/1998 MUTEX2
  50. MarioGo 11/1/1998 MUTEX3
  51. --*/
  52. #ifndef __MUTEX_HXX__
  53. #define __MUTEX_HXX__
  54. #include "util.hxx"
  55. #ifdef DEBUGRPC
  56. #define INCREMENT_CRITSECT_COUNT
  57. #endif
  58. class MUTEX
  59. {
  60. BOOL IsSuccessfullyInitialized(void)
  61. {
  62. return (CriticalSection.DebugInfo != 0);
  63. }
  64. CRITICAL_SECTION CriticalSection;
  65. void EnumOwnedCriticalSections();
  66. void CommonConstructor(
  67. IN OUT RPC_STATUS PAPI * RpcStatus,
  68. IN DWORD dwSpinCount
  69. );
  70. public:
  71. MUTEX (
  72. IN OUT RPC_STATUS PAPI * RpcStatus,
  73. IN DWORD dwSpinCount = 0
  74. )
  75. {
  76. CommonConstructor(RpcStatus, dwSpinCount);
  77. }
  78. MUTEX (
  79. IN OUT RPC_STATUS PAPI * RpcStatus,
  80. IN BOOL fPreallocateSemaphore,
  81. IN DWORD dwSpinCount = 0
  82. )
  83. {
  84. CommonConstructor(RpcStatus,
  85. fPreallocateSemaphore ? (dwSpinCount | PREALLOCATE_EVENT_MASK) :
  86. dwSpinCount);
  87. }
  88. inline ~MUTEX ()
  89. {
  90. Free();
  91. }
  92. void Free(void);
  93. BOOL
  94. TryRequest()
  95. {
  96. BOOL Result = RtlTryEnterCriticalSection(&CriticalSection);
  97. #ifdef CHECK_MUTEX_INVERSION
  98. if (Result)
  99. {
  100. LogEvent(SU_MUTEX, EV_INC, this);
  101. }
  102. #endif
  103. return Result;
  104. }
  105. void Request ()
  106. {
  107. #if 0
  108. EnumOwnedCriticalSections();
  109. #endif
  110. NTSTATUS status;
  111. status = RtlEnterCriticalSection(&CriticalSection);
  112. ASSERT(NT_SUCCESS(status));
  113. #ifdef CHECK_MUTEX_INVERSION
  114. LogEvent(SU_MUTEX, EV_INC, this);
  115. #endif
  116. #ifdef DEBUGRPC
  117. if (CriticalSection.RecursionCount > 100)
  118. {
  119. DbgPrint("thread %x has recursively taken mutex %x %d times\n",
  120. GetCurrentThreadId(), &CriticalSection, CriticalSection.RecursionCount);
  121. RpcpBreakPoint();
  122. }
  123. #endif
  124. }
  125. RPC_STATUS RequestSafe (void)
  126. {
  127. RPC_STATUS RetVal = RPC_S_OK;
  128. RpcTryExcept
  129. {
  130. Request();
  131. }
  132. RpcExcept((RpcExceptionCode() == STATUS_INSUFFICIENT_RESOURCES)
  133. ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH )
  134. {
  135. RetVal = RpcExceptionCode();
  136. }
  137. RpcEndExcept
  138. return RetVal;
  139. }
  140. void Clear ()
  141. {
  142. #ifdef CHECK_MUTEX_INVERSION
  143. LogEvent(SU_MUTEX, EV_DEC, this);
  144. #endif
  145. NTSTATUS status;
  146. VerifyOwned();
  147. status = RtlLeaveCriticalSection(&CriticalSection);
  148. ASSERT(NT_SUCCESS(status));
  149. }
  150. inline void
  151. VerifyOwned()
  152. {
  153. ASSERT(CriticalSection.OwningThread == ULongToPtr(GetCurrentThreadId()));
  154. }
  155. inline BOOL OwnedByMe()
  156. {
  157. if (CriticalSection.OwningThread == ULongToPtr(GetCurrentThreadId()) &&
  158. CriticalSection.RecursionCount != -1)
  159. {
  160. return TRUE;
  161. }
  162. return FALSE;
  163. }
  164. inline void
  165. VerifyNotOwned()
  166. {
  167. ASSERT(CriticalSection.OwningThread != ULongToPtr(GetCurrentThreadId()) ||
  168. CriticalSection.RecursionCount == -1);
  169. }
  170. DWORD
  171. SetSpinCount(
  172. unsigned long Count
  173. )
  174. {
  175. return SetCriticalSectionSpinCount(&CriticalSection, Count);
  176. }
  177. };
  178. extern RTL_CRITICAL_SECTION GlobalMutex;
  179. #ifdef NO_RECURSIVE_MUTEXES
  180. extern unsigned int RecursionCount;
  181. #endif // NO_RECURSIVE_MUTEXES
  182. #ifdef DBG
  183. extern long lGlobalMutexCount;
  184. #endif
  185. inline void GlobalMutexRequest(void)
  186. /*++
  187. Routine Description:
  188. Request the global mutex.
  189. --*/
  190. {
  191. #ifdef DBG
  192. InterlockedIncrement(&lGlobalMutexCount);
  193. #endif
  194. NTSTATUS Status;
  195. Status = RtlEnterCriticalSection(&GlobalMutex);
  196. ASSERT(NT_SUCCESS(Status));
  197. #ifdef NO_RECURSIVE_MUTEXES
  198. ASSERT(RecursionCount == 0);
  199. RecursionCount += 1;
  200. #endif // NO_RECURSIVE_MUTEXES
  201. }
  202. inline void GlobalMutexClear(void)
  203. /*++
  204. Routine Description:
  205. Clear the global mutex.
  206. --*/
  207. {
  208. #ifdef DBG
  209. InterlockedDecrement(&lGlobalMutexCount);
  210. #endif
  211. NTSTATUS Status;
  212. Status = RtlLeaveCriticalSection(&GlobalMutex);
  213. ASSERT(NT_SUCCESS(Status));
  214. #ifdef NO_RECURSIVE_MUTEXES
  215. RecursionCount -= 1;
  216. #endif // NO_RECURSIVE_MUTEXES
  217. }
  218. inline BOOL GlobalMutexTryRequest(void)
  219. {
  220. BOOL Result = RtlTryEnterCriticalSection(&GlobalMutex);
  221. if (Result)
  222. {
  223. #ifdef DBG
  224. InterlockedIncrement(&lGlobalMutexCount);
  225. #endif
  226. #ifdef NO_RECURSIVE_MUTEXES
  227. ASSERT(RecursionCount == 0);
  228. RecursionCount += 1;
  229. #endif // NO_RECURSIVE_MUTEXES
  230. }
  231. return Result;
  232. }
  233. inline void GlobalMutexVerifyOwned(void)
  234. {
  235. ASSERT(GlobalMutex.OwningThread == ULongToPtr(GetCurrentThreadId()));
  236. }
  237. inline void GlobalMutexVerifyNotOwned(void)
  238. {
  239. ASSERT(GlobalMutex.OwningThread != ULongToPtr(GetCurrentThreadId()) ||
  240. GlobalMutex.RecursionCount == -1);
  241. }
  242. inline DWORD GlobalMutexSetSpinCount(unsigned long Count)
  243. {
  244. return SetCriticalSectionSpinCount(&GlobalMutex, Count);
  245. }
  246. class EVENT
  247. {
  248. public:
  249. HANDLE EventHandle;
  250. EVENT (
  251. IN OUT RPC_STATUS PAPI * RpcStatus,
  252. IN int ManualReset = 1,
  253. IN BOOL fDelayInit = FALSE
  254. );
  255. ~EVENT ( // Destructor.
  256. );
  257. void
  258. Raise ( // Raise the event.
  259. )
  260. {
  261. BOOL status;
  262. if (NULL == EventHandle)
  263. {
  264. InitializeEvent();
  265. }
  266. status = SetEvent(EventHandle);
  267. ASSERT(status == TRUE);
  268. }
  269. void
  270. Lower ( // Lower the event.
  271. )
  272. {
  273. BOOL status;
  274. status = ResetEvent(EventHandle);
  275. ASSERT(status == TRUE);
  276. }
  277. int
  278. Wait ( // Wait until the event is raised.
  279. IN long timeout = -1
  280. );
  281. void
  282. Request (
  283. ) {Wait(-1);}
  284. int
  285. RequestWithTimeout (
  286. IN long timeout = -1
  287. ) {return(Wait(timeout));}
  288. void
  289. Clear (
  290. ) {Raise();}
  291. private:
  292. void InitializeEvent();
  293. };
  294. class CLAIM_MUTEX {
  295. private:
  296. MUTEX & Resource;
  297. public:
  298. CLAIM_MUTEX(
  299. MUTEX & ClaimedResource
  300. )
  301. : Resource(ClaimedResource)
  302. {
  303. Resource.Request();
  304. }
  305. ~CLAIM_MUTEX(
  306. )
  307. {
  308. Resource.Clear();
  309. }
  310. };
  311. class MUTEX2
  312. {
  313. EVENT mutexEvent;
  314. INTERLOCKED_INTEGER guard;
  315. DWORD OwningThread;
  316. public:
  317. MUTEX2 (
  318. IN OUT RPC_STATUS PAPI * RpcStatus
  319. ) : mutexEvent(RpcStatus, FALSE, TRUE), guard(0)
  320. {
  321. OwningThread = 0;
  322. // Don't set *RpcStatus to RPC_S_OK
  323. }
  324. void
  325. Request ()
  326. {
  327. if (guard.Increment() > 1)
  328. {
  329. mutexEvent.Wait();
  330. }
  331. ASSERT(OwningThread == 0);
  332. OwningThread = GetCurrentThreadId();
  333. }
  334. void
  335. Clear ()
  336. {
  337. OwningThread = 0;
  338. if (guard.Decrement() > 0)
  339. {
  340. mutexEvent.Raise();
  341. }
  342. }
  343. };
  344. class MUTEX3
  345. {
  346. private:
  347. EVENT event;
  348. INTERLOCKED_INTEGER guard;
  349. DWORD owner;
  350. DWORD recursion;
  351. public:
  352. MUTEX3(RPC_STATUS *RpcStatus) : event(RpcStatus, FALSE, TRUE), guard(-1)
  353. {
  354. owner = 0;
  355. recursion = 0;
  356. // Don't set *RpcStatus to RPC_S_OK
  357. }
  358. void Request();
  359. void Clear();
  360. BOOL TryRequest();
  361. };
  362. #endif // __MUTEX_HXX__