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.

583 lines
11 KiB

  1. /*++
  2. Microsoft Windows NT RPC Name Service
  3. Copyright (C) Microsoft Corporation, 1995 - 1999
  4. Module Name:
  5. mutex.hxx
  6. Abstract:
  7. This file contains definitions of classes which provide several variations
  8. on mutexes, including shared and private mutexes, reader/writer mutexes,
  9. and semaphores in the NT sense (which for us are mutexes which can be
  10. acquired and released by different threads).
  11. Author:
  12. Satish Thatte (SatishT) 09/01/95 Created all the code below except where
  13. otherwise indicated.
  14. --*/
  15. #ifndef __MUTEX_HXX__
  16. #define __MUTEX_HXX__
  17. /*++
  18. Class Definition:
  19. CPrivateCriticalSection
  20. Abstract:
  21. This class implements an intra process critical section which allows
  22. only one thread in the process at a time to gain access to resources.
  23. Rather than being the CRITICAL_SECTION itself, the CSharedCriticalSection
  24. contains a pointer to the CRITICAL_SECTION. This isolates the system
  25. dependent code at a tiny expense in compilation speed since all the code
  26. for the methods is inline.
  27. It seems strange to talk of a private critical section -- if it is
  28. really private why use it? The sense in which this class of object is
  29. meant to be private is that CPrivateCriticalSection objects are expected
  30. to have a single reference and a single destruction point and therefore
  31. do not need reference counting.
  32. --*/
  33. class CPrivateCriticalSection {
  34. CRITICAL_SECTION * pNTCS; // Reference to system CRITICAL_SECTION object
  35. // we are impersonating
  36. public:
  37. CPrivateCriticalSection(
  38. );
  39. virtual ~CPrivateCriticalSection(
  40. );
  41. void
  42. Enter(
  43. ) ;
  44. void
  45. Leave(
  46. );
  47. };
  48. /*++
  49. Class Definition:
  50. SimpleCriticalSection
  51. Abstract:
  52. A convenient way to acquire and release a lock on a CPrivateCriticalSection.
  53. Entry occurs on creation and exit on destruction of this object, and hence
  54. can be made to coincide with a local scope. Especially convenient when
  55. there are multiple exit points from the scope (returns, breaks, etc.).
  56. --*/
  57. class SimpleCriticalSection {
  58. CPrivateCriticalSection& MyPCS;
  59. public:
  60. SimpleCriticalSection(CPrivateCriticalSection& PCS) : MyPCS(PCS)
  61. {
  62. MyPCS.Enter();
  63. }
  64. ~SimpleCriticalSection()
  65. {
  66. MyPCS.Leave();
  67. }
  68. };
  69. /*++
  70. Class Definition:
  71. CSharedCriticalSection
  72. Abstract:
  73. This class implements an intra process critical section which allows
  74. only one thread in the process at a time to gain access to resources.
  75. Continuing the remarks in relation to CPrivateCriticalSection, this
  76. class of object is shared as in "referenced, and released in multiple
  77. other objects" such as guarded lists and iterators, for instance.
  78. Using the primary (impersonated) CRITICAL_SECTION for locking the
  79. reference count is cute but not viable. If the CRITICAL_SECTION
  80. is being held for real locking, just acquiring a reference to the
  81. CSharedCriticalSection object becomes a blocking operation.
  82. --*/
  83. class CSharedCriticalSection : public CRefCounted {
  84. CPrivateCriticalSection PCSprimary; // Reference to system CRITICAL_SECTION object
  85. // we are impersonating
  86. CPrivateCriticalSection PCScount; // CRITICAL_SECTION object used for ref counting
  87. public:
  88. void
  89. Enter(
  90. ) ;
  91. void
  92. Leave(
  93. );
  94. virtual void
  95. hold(
  96. );
  97. virtual void
  98. release(
  99. );
  100. };
  101. /*++
  102. Class Definition:
  103. CPrivateSemaphore
  104. Abstract:
  105. This class implements an intra process semaphore which allows
  106. multiple and shared access to resources. The enter and leave
  107. operators are delinked -- they do not have to be performed
  108. by the same thread.
  109. As in the case of a private critical section, a private semaphore
  110. is not meant to be shared as an object, and is not reference counted.
  111. --*/
  112. class CPrivateSemaphore {
  113. HANDLE pNTSem; // Reference to system semaphore object
  114. // we are impersonating
  115. public:
  116. CPrivateSemaphore(long lMaxCount = 1);
  117. ~CPrivateSemaphore();
  118. void Enter() ;
  119. void Leave(long lIncrement = 1);
  120. };
  121. /*++
  122. Class Definition:
  123. CReadWriteSection
  124. Abstract:
  125. This class implements a simple solution of the usual readers/writers
  126. problem. The writer block is a semaphore rather than critical section
  127. because it is acquired by the first reader thread and released by the
  128. last one, hence it is not "owned" by any thread at any time.
  129. --*/
  130. class CReadWriteSection : public CRefCounted {
  131. /* PCSReaderBlock: mutex used by writers to block readers and by readers
  132. to guard access to ulReaderCount and PSemWriterBlock.
  133. */
  134. CPrivateCriticalSection PCSReaderBlock;
  135. /* PSemWriterBlock: semaphore used by readers to block writers. This is a
  136. semaphore because the first reader blocks it and the last one releases it,
  137. which doesn't work with critical sections!
  138. */
  139. CPrivateSemaphore PSemWriterBlock;
  140. /* The reason we use an explicit lock instead of InterlockedIncrement etc is
  141. that we need to lock out access to reader count not only to change its
  142. value but also to decide on taking or releasing the writer block.
  143. */
  144. CPrivateCriticalSection PCSCountBlock;
  145. long ulReaderCount;
  146. public:
  147. CReadWriteSection();
  148. int
  149. readerEnter(
  150. ) ;
  151. int
  152. readerLeave(
  153. );
  154. void
  155. writerEnter(
  156. ) ;
  157. void
  158. writerLeave(
  159. );
  160. };
  161. /*++
  162. Class Definition:
  163. CriticalWriter
  164. Abstract:
  165. A convenient way to acquire and release a writer-lock on a CReadWriteSection.
  166. Entry occurs on creation and exit on destruction of this object, and hence
  167. can be made to coincide with a local scope. Especially convenient when
  168. there are multiple exit points from the scope (returns, breaks, etc.).
  169. --*/
  170. class CriticalWriter {
  171. CReadWriteSection& rwHost;
  172. public:
  173. CriticalWriter(CReadWriteSection& rw) : rwHost(rw) {
  174. DBGOUT(SEM1, "Starting Construction of Critical Writer\n\n");
  175. rwHost.writerEnter();
  176. DBGOUT(SEM1, "Ending Construction of Critical Writer\n\n");
  177. }
  178. ~CriticalWriter() {
  179. DBGOUT(SEM1, "Starting Destruction of Critical Writer\n\n");
  180. rwHost.writerLeave();
  181. DBGOUT(SEM1, "Ending Destruction of Critical Writer\n\n");
  182. }
  183. };
  184. /*++
  185. Class Definition:
  186. CriticalReader
  187. Abstract:
  188. A convenient way to acquire and release a reader-lock on a CReadWriteSection.
  189. Entry occurs on creation and exit on destruction of this object, and hence
  190. can be made to coincide with a local scope. Especially convenient when
  191. there are multiple exit points from the scope (returns, breaks, etc.).
  192. --*/
  193. class CriticalReader {
  194. CReadWriteSection& rwHost;
  195. public:
  196. CriticalReader(CReadWriteSection& rw) : rwHost(rw) {
  197. DBGOUT(SEM1, "Starting Construction of Critical Reader\n\n");
  198. rwHost.readerEnter();
  199. DBGOUT(SEM1, "Ending Construction of Critical Reader\n\n");
  200. }
  201. ~CriticalReader() {
  202. DBGOUT(SEM1, "Starting Destruction of Critical Reader\n\n");
  203. rwHost.readerLeave();
  204. DBGOUT(SEM1, "Ending Destruction of Critical Reader\n\n");
  205. }
  206. };
  207. /******** inline methods for CPrivateCriticalSection ********/
  208. inline
  209. CPrivateCriticalSection::CPrivateCriticalSection (
  210. )
  211. /*++
  212. Routine Description:
  213. Rather than being the CRITICAL_SECTION itself, the CPrivateCriticalSection
  214. contains a pointer to the CRITICAL_SECTION. This isolates the system
  215. dependent code at a tiny expense in compilation speed since all the code
  216. for the methods is inline.
  217. Results:
  218. None unless an exception occurs.
  219. --*/
  220. {
  221. if ((pNTCS = new RTL_CRITICAL_SECTION))
  222. InitializeCriticalSection(pNTCS);
  223. else RaiseException(
  224. NSI_S_OUT_OF_MEMORY,
  225. EXCEPTION_NONCONTINUABLE,
  226. 0,
  227. NULL
  228. );
  229. }
  230. inline
  231. CPrivateCriticalSection::~CPrivateCriticalSection (
  232. )
  233. /*++
  234. Routine Description:
  235. Delete the NT critical section object and the memory it uses.
  236. --*/
  237. {
  238. DeleteCriticalSection(pNTCS);
  239. delete pNTCS;
  240. }
  241. inline void
  242. CPrivateCriticalSection::Leave (
  243. )
  244. /*++
  245. Routine Description:
  246. Clear the CPrivateCriticalSection indicating that the current thread is done with it.
  247. --*/
  248. {
  249. LeaveCriticalSection(pNTCS);
  250. }
  251. inline void
  252. CPrivateCriticalSection::Enter (
  253. )
  254. /*++
  255. Routine Description:
  256. Request exclusive access to the CPrivateCriticalSection. This routine will
  257. not return until the current thread has exclusive access to the
  258. CSharedCriticalSection.
  259. --*/
  260. {
  261. EnterCriticalSection(pNTCS);
  262. }
  263. /******** inline methods for CSharedCriticalSection ********/
  264. inline void
  265. CSharedCriticalSection::Leave (
  266. )
  267. /*++
  268. Routine Description:
  269. Clear the CSharedCriticalSection indicating that the current thread is done with it.
  270. --*/
  271. {
  272. PCSprimary.Leave();
  273. }
  274. inline void
  275. CSharedCriticalSection::Enter (
  276. )
  277. /*++
  278. Routine Description:
  279. Request exclusive access to the CSharedCriticalSection. This routine will
  280. not return until the current thread has exclusive access to the
  281. CSharedCriticalSection.
  282. --*/
  283. {
  284. PCSprimary.Enter();
  285. }
  286. inline void
  287. CSharedCriticalSection::hold (
  288. )
  289. /*++
  290. Routine Description:
  291. We need this new implementation of hold to make sure the reference
  292. counts are accurate. For instance, suppose two iterators are
  293. being created for the same list in different threads. Unless we
  294. use locking, there is a chance that the references will be
  295. undercounted due to race conditions.
  296. --*/
  297. {
  298. CRefCounted::hold();
  299. }
  300. inline void
  301. CSharedCriticalSection::release (
  302. )
  303. /*++
  304. Routine Description:
  305. See above. Note that we cannot call the parent release method
  306. because it may cause self-destruct before we can perform Leave
  307. on PCScount! However, we are using a "cooperative" rather than
  308. "opportunistic" sharing model here -- we don't deal with the
  309. situation where an opportunistic thread may grab this object
  310. and bump up its ulRefCount after it has dropped to zero.
  311. --*/
  312. {
  313. PCScount.Enter();
  314. ASSERT(ulRefCount, "Decrementing nonpositive reference count\n");
  315. ulRefCount--;
  316. PCScount.Leave();
  317. if (!ulRefCount)
  318. delete this;
  319. }
  320. /******** inline methods for CReadWriteSection ********/
  321. inline
  322. CReadWriteSection::CReadWriteSection()
  323. /*++
  324. Routine Description:
  325. Simple constructor for CReadWriteSection.
  326. Results:
  327. None.
  328. --*/
  329. {
  330. ulReaderCount = 0;
  331. }
  332. inline void
  333. CReadWriteSection::writerEnter()
  334. /*++
  335. Routine Description:
  336. The writer must block new readers from entering otherwise it
  337. may starve. Must also wait for current readers to leave.
  338. Blocking other writers is a simple side-effect of these.
  339. Results:
  340. None.
  341. --*/
  342. {
  343. DBGOUT(SEM, "Entering writerEnter\n");
  344. PCSReaderBlock.Enter(); // block any further readers
  345. DBGOUT(SEM, "Got Past PCSReaderBlock\n");
  346. PSemWriterBlock.Enter(); // wait for current readers to leave
  347. DBGOUT(SEM, "Leaving writerEnter\n");
  348. }
  349. inline void
  350. CReadWriteSection::writerLeave()
  351. /*++
  352. Routine Description:
  353. Release everything and go away.
  354. Results:
  355. None.
  356. --*/
  357. {
  358. DBGOUT(SEM, "Performing writerLeave\n");
  359. PSemWriterBlock.Leave(); // this order "levels the playing field"
  360. PCSReaderBlock.Leave(); // between readers and writers for entry
  361. }
  362. #endif // __MUTEX_HXX__