Source code of Windows XP (NT5)
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.

414 lines
7.9 KiB

  1. /*++
  2. rwnew.h
  3. This file defines several variations of Reader/Writer locks
  4. with different properties regarding handles used, and other
  5. implementation details.
  6. Also defined are some variations of CRITICAL_SECTIONS which use
  7. fewer or no handles.
  8. --*/
  9. #ifndef _RWNEW_H
  10. #define _RWNEW_H
  11. #ifdef _RW_IMPLEMENTATION_
  12. #define _RW_INTERFACE_ __declspec( dllexport )
  13. #else
  14. #define _RW_INTERFACE_ __declspec( dllimport )
  15. #endif
  16. #pragma warning( disable:4251 )
  17. #include <limits.h>
  18. #include "lockq.h"
  19. #include "rwintrnl.h"
  20. class _RW_INTERFACE_ CCritSection {
  21. private :
  22. //
  23. // Handle of thread owning the lock !
  24. //
  25. HANDLE m_hOwner ;
  26. //
  27. // Count of Recursive Calls
  28. //
  29. long m_RecursionCount ;
  30. //
  31. // Count used to see who gets the lock next !
  32. //
  33. long m_lock ;
  34. //
  35. // Queue of waiting threads
  36. //
  37. CSingleReleaseQueue m_queue ;
  38. //
  39. // Copying of these objects is not allowed !!!!
  40. //
  41. CCritSection( CCritSection& ) ;
  42. CCritSection& operator=( CCritSection& ) ;
  43. public :
  44. #ifdef DEBUG
  45. DWORD m_dwThreadOwner ;
  46. #endif
  47. //
  48. // Construct a critical section object
  49. //
  50. CCritSection( ) :
  51. m_queue( FALSE ),
  52. m_hOwner( INVALID_HANDLE_VALUE ),
  53. m_RecursionCount( 0 ),
  54. m_lock( -1 ) {
  55. }
  56. //
  57. // Acquire the critical section
  58. //
  59. void
  60. Enter(
  61. CWaitingThread& myself
  62. ) ;
  63. //
  64. // Another version which acquires the critical section -
  65. // creates its own CWaitingThread object !
  66. //
  67. void
  68. Enter() ;
  69. //
  70. // REturns TRUE if the lock is available right now !
  71. //
  72. BOOL
  73. TryEnter(
  74. CWaitingThread& myself
  75. ) ;
  76. //
  77. // Returns TRUE if we can get the lock right now !
  78. //
  79. BOOL
  80. TryEnter() {
  81. CWaitingThread myself ;
  82. return TryEnter( myself ) ;
  83. }
  84. //
  85. // Release the critical section !
  86. //
  87. void
  88. Leave() ;
  89. } ;
  90. //
  91. // This version of critical section is more like an event - doesn't
  92. // care who releases locks - and doesn't handle recursive grabs !
  93. //
  94. class _RW_INTERFACE_ CSimpleCritSection {
  95. private :
  96. //
  97. // Count used to see who gets the lock next !
  98. //
  99. long m_lock ;
  100. //
  101. // Queue of waiting threads
  102. //
  103. CSingleReleaseQueue m_queue ;
  104. //
  105. // Copying of these objects is not allowed !!!!
  106. //
  107. CSimpleCritSection( CCritSection& ) ;
  108. CSimpleCritSection& operator=( CCritSection& ) ;
  109. public :
  110. #ifdef DEBUG
  111. DWORD m_dwThreadOwner ;
  112. #endif
  113. //
  114. // Construct a critical section object
  115. //
  116. CSimpleCritSection( ) :
  117. m_queue( FALSE ),
  118. #ifdef DEBUG
  119. m_dwThreadOwner( 0 ),
  120. #endif
  121. m_lock( -1 ) {
  122. }
  123. //
  124. // Acquire the critical section
  125. //
  126. void
  127. Enter(
  128. CWaitingThread& myself
  129. ) ;
  130. //
  131. // Another version which acquires the critical section -
  132. // creates its own CWaitingThread object !
  133. //
  134. void
  135. Enter() ;
  136. //
  137. // REturns TRUE if the lock is available right now !
  138. //
  139. BOOL
  140. TryEnter(
  141. CWaitingThread& myself
  142. ) ;
  143. //
  144. // Returns TRUE if we can get the lock right now !
  145. //
  146. BOOL
  147. TryEnter() {
  148. CWaitingThread myself ;
  149. return TryEnter( myself ) ;
  150. }
  151. //
  152. // Release the critical section !
  153. //
  154. void
  155. Leave() ;
  156. } ;
  157. //
  158. // Another class which tries to create Reader/Write locks with
  159. // no handles !!
  160. //
  161. class _RW_INTERFACE_ CShareLockNH {
  162. private :
  163. //
  164. // Lock grabbed by writers to have exclusive access
  165. //
  166. CSimpleCritSection m_lock ;
  167. //
  168. // Number of readers who have grabbed the Read Lock -
  169. // Negative if a writer is waiting !
  170. //
  171. volatile long m_cReadLock ;
  172. //
  173. // Number of Readers who have left the lock since a
  174. // writer tried to grab it !
  175. //
  176. volatile long m_cOutReaders ;
  177. //
  178. // Number of readers who are entering the lock after
  179. // being blocked !!!
  180. //
  181. volatile long m_cOutAcquiringReaders ;
  182. //
  183. // Number of threads needing m_lock to be held right now !
  184. //
  185. volatile long m_cExclusiveRefs ;
  186. //
  187. // Handle that all the readers who are waiting try to grab !
  188. //
  189. volatile HANDLE m_hWaitingReaders ;
  190. //
  191. // Handle that the single writer waiting for the lock is trying
  192. // to grab !
  193. //
  194. volatile HANDLE m_hWaitingWriters ;
  195. void inline
  196. WakeReaders() ;
  197. //
  198. // The internal work of ShareLock - does a lot more of the stuff required
  199. // when a writer is present !!!
  200. //
  201. void
  202. ShareLockInternal() ;
  203. //
  204. // The internal work of ShareLock - does a lot more of the stuff required
  205. // when a writer is present !!!
  206. //
  207. void
  208. ShareUnlockInternal() ;
  209. //
  210. // You may not copy these objects - so this lock is private !
  211. //
  212. CShareLockNH( CShareLockNH& ) ;
  213. //
  214. // You may not copy through assignment - so this operator is private !
  215. //
  216. CShareLockNH& operator=( CShareLockNH& ) ;
  217. public :
  218. //
  219. // Construction of CShareLockNH() objects always succeeds and there
  220. // are no error cases !
  221. //
  222. CShareLockNH() ;
  223. //
  224. // Grab the lock Shared - other threads may pass through ShareLock() as well
  225. //
  226. void ShareLock() ;
  227. //
  228. // Releases the lock - if we are the last reader to leave writers may
  229. // start to enter the lock !
  230. //
  231. void ShareUnlock() ;
  232. //
  233. // Grab the lock Exclusively - no other readers or writers may enter !!
  234. //
  235. void ExclusiveLock() ;
  236. //
  237. // Release the Exclusive Locks - if there are readers waiting they
  238. // will enter before other waiting writers !
  239. //
  240. void ExclusiveUnlock() ;
  241. //
  242. // Convert an ExclusiveLock to a Shared - this cannot fail !
  243. //
  244. void ExclusiveToShared() ;
  245. //
  246. // Convert a Shared Lock to an Exclusive one - this can fail - returns
  247. // TRUE if successfull !
  248. //
  249. BOOL SharedToExclusive() ;
  250. //
  251. // Return TRUE if we can get the lock shared. Only fails when
  252. // somebody is attempting or has the lock exclusively, we will enter
  253. // if there are only other readers in the lock.
  254. //
  255. BOOL TryShareLock() ;
  256. //
  257. // Return TRUE if we can get the lock Exclusively. Only succeeds
  258. // when nobody else is near the lock.
  259. //
  260. BOOL TryExclusiveLock() ;
  261. //
  262. // PartialLocks -
  263. //
  264. // Partial Locks are similar to Exclusive Locks - only one thread
  265. // can successfully call PartialLock(), any other threads calling
  266. // PartialLock() or ExclusiveLock() will block.
  267. // HOWEVER - while a PartialLock() is held, Readers (threads calling
  268. // ShareLock()) may enter the lock.
  269. //
  270. void PartialLock() ;
  271. //
  272. // Release the PartialLock - Other Exclusive() or Partial lock acquirers
  273. // may now enter.
  274. //
  275. void PartialUnlock() ;
  276. //
  277. // Convert a Partial Lock to an Exclusive Lock. This function is
  278. // guaranteed to succeed, HOWEVER a lock can only be converted with
  279. // this function once, i.e. a thread doing
  280. // PartialLock() ;
  281. // FirstPartialToExclusive() ;
  282. // ExclusiveToPartial() ;
  283. // FirstPartialToExclusive() ;
  284. // will have problems - the second call to FirstPartialToExclusive()
  285. // may mess up the lock state and cause the lock to fail horribly.
  286. // If a user wishes to convert as above they must have a call sequence like :
  287. //
  288. // PartialLock() ;
  289. // FirstPartialToExclusive() or PartialToExclusive() ;
  290. // ExclusiveToPartial() ;
  291. // PartialToExclusive() ;
  292. //
  293. // If you change lock states more than once - you take your chances !
  294. //
  295. void FirstPartialToExclusive() ;
  296. //
  297. // Returns TRUE if we can get the lock Exclusively, otherwise
  298. // we return FALSE with the lock remaining in the Partially held state.
  299. //
  300. // NOTE : NYI in CShareLockNH - will always return FALSE !
  301. //
  302. BOOL PartialToExclusive() ;
  303. //
  304. // We can always go from an ExclusiveLock() to a PartialLock() state.
  305. //
  306. void ExclusiveToPartial() ;
  307. //
  308. // We can always go from a PartialLock() state to a SharedLock() state
  309. //
  310. void PartialToShared() ;
  311. //
  312. // Returns TRUE if we can get the lock Partially !
  313. // If it returns FALSE we remain with the lock held Shared()
  314. //
  315. BOOL SharedToPartial() ;
  316. //
  317. // Returns TRUE only if no other threads are trying to get the lock
  318. // ExclusiveLy or Partially !
  319. //
  320. BOOL TryPartialLock() ;
  321. } ;
  322. //
  323. // This is a utility function to get an Event Handle we save
  324. // for each thread - the handle is Created as:
  325. // CreateEvent( NULL,
  326. // FALSE,
  327. // FALSE,
  328. // NULL ) ;
  329. // This results in an auto-reset event which goes back to non signalled whenever a thread
  330. // is released.
  331. //
  332. HANDLE
  333. _RW_INTERFACE_
  334. GetPerThreadEvent() ;
  335. #endif // _RWNEW_H_