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.

366 lines
8.8 KiB

  1. /*++
  2. rw.h
  3. This file defines some locks with the following performance characteristics :
  4. * A constant number of handles is used per lock instance
  5. * The lock entry/exit protocols use Interlocked operations and do not
  6. cause context switches in themselves.
  7. --*/
  8. #ifndef _CRW_H
  9. #define _CRW_H
  10. #include <limits.h>
  11. //
  12. // This class contains the meat - does actual locking etc...
  13. //
  14. class CShareLock {
  15. /*++
  16. Class Description :
  17. This class implements a reader writer lock.
  18. Multiple threads can successfully enter the lock by calling
  19. ShareLock(). Once any thread has entered the lock through
  20. ShareLock(), all threads calling ExclusiveLock() are blocked
  21. untill ShareUnlock() is called for each successfull ShareLock().
  22. This lock is fair - If multiple threads have passed through
  23. ShareLock(), and a thread calls ExclusiveLock(), all threads
  24. that arrive after the call to ExclusiveLock() will block untill
  25. the ExclusiveLock() thread has acquired and released the lock.
  26. This property is symetrical with ShareLock() and ExclusiveLock().
  27. --*/
  28. private :
  29. //
  30. // Number of Readers who have passed through the lock OR
  31. // the number of readers waiting for the lock (will be negative).
  32. // A value of 0 means nobody in the lock
  33. //
  34. volatile long cReadLock ;
  35. //
  36. // The number of readers remainin in the lock if
  37. // there is a writer waiting. This can become temporarily negative
  38. //
  39. volatile long cOutRdrs ;
  40. //
  41. // Critical section to allow only one writer into the lock at a time
  42. //
  43. CRITICAL_SECTION critWriters ;
  44. //
  45. // Semaphore for waiting writers to block on (Only 1 ever, others will
  46. // be queued on critWriters)
  47. //
  48. HANDLE hWaitingWriters ;
  49. //
  50. // Semaphore for waiting readers to block on
  51. //
  52. HANDLE hWaitingReaders ;
  53. //
  54. // You may not copy these objects - so this lock is private !
  55. //
  56. CShareLock( CShareLock& ) ;
  57. //
  58. // You may not copy through assignment - so this operator is private !
  59. //
  60. CShareLock& operator=( CShareLock& ) ;
  61. public :
  62. //
  63. // Construct and Destroy a CShareLock !
  64. //
  65. CShareLock( ) ;
  66. ~CShareLock( ) ;
  67. //
  68. // Check that the lock is correctly initialized - call only
  69. // after construction !
  70. //
  71. BOOL
  72. IsValid() ;
  73. //
  74. // Grab the lock for shared mode.
  75. // each call to ShareLock() must be paired with exactly 1 call
  76. // to ShareUnlock(). A thread that successfully calls ShareLock()
  77. // can only call ShareUnlock(), otherwise a deadlock can occur.
  78. // ( the sequence ShareLock(); ShareLock(); ShareUnlock(); ShareUnlock();
  79. // can also deadlock)
  80. //
  81. void
  82. ShareLock( ) ;
  83. //
  84. // Release the lock from shared mode !
  85. //
  86. void
  87. ShareUnlock( ) ;
  88. //
  89. // Grab the lock for Exclusive mode.
  90. // each call to ExclusiveLock() must be paired with exactly 1 call
  91. // to ExclusiveUnlock(). A thread that successfully calls ExclusiveLock()
  92. // can only call ExclusiveUnlock(), otherwise a deadlock can occur.
  93. // ( the sequence ExclusiveLock(); ExclusiveLock(); ExclusiveUnlock(); ExclusiveUnlock();
  94. // can also deadlock)
  95. //
  96. void
  97. ExclusiveLock( ) ;
  98. //
  99. // Release the lock from Exclusive mode !
  100. //
  101. void
  102. ExclusiveUnlock( ) ;
  103. //
  104. // Given that we've already acquired the lock Exclusively, convert to
  105. // Shared. This cannot fail. ShareUnlock() must be called after
  106. // we have done this.
  107. //
  108. void
  109. ExclusiveToShared() ;
  110. //
  111. // Given that we've acquired the lock in shared mode try to get
  112. // it exclusively.
  113. // This can fail for two reasons :
  114. // Another thread is trying to get the lock Exclusively
  115. // A bunch of other threads are also in the lock in shared mode.
  116. //
  117. // The function will return FALSE if it fails, in which case the
  118. // Shared lock is still held !
  119. //
  120. BOOL
  121. SharedToExclusive() ;
  122. //
  123. // Try to acquire the lock in shared mode.
  124. // This will only fail if an ExclusiveLock is held or being
  125. // waited for.
  126. // TRUE is returned if we get the lock Shared, FALSE otherwise !
  127. //
  128. BOOL
  129. TryShareLock() ;
  130. //
  131. // Try to acquire the lock in Exclusive mode.
  132. // This will fail if another thread is in the ExclusiveLock()
  133. // or ShareLock's are held.
  134. // TRUE is returned if we get the Exclusive Lock, FALSE otherwise !
  135. //
  136. BOOL
  137. TryExclusiveLock() ;
  138. //
  139. // PartialLocks -
  140. //
  141. // Partial Locks are similar to Exclusive Locks - only one thread
  142. // can successfully call PartialLock(), any other threads calling
  143. // PartialLock() or ExclusiveLock() will block.
  144. // HOWEVER - while a PartialLock() is held, Readers (threads calling
  145. // ShareLock()) may enter the lock.
  146. //
  147. void PartialLock() ;
  148. //
  149. // Release the PartialLock - Other Exclusive() or Partial lock acquirers
  150. // may now enter.
  151. //
  152. void PartialUnlock() ;
  153. //
  154. // Convert a Partial Lock to an Exclusive Lock. This function is
  155. // guaranteed to succeed, HOWEVER a lock can only be converted with
  156. // this function once, i.e. a thread doing
  157. // PartialLock() ;
  158. // FirstPartialToExclusive() ;
  159. // ExclusiveToPartial() ;
  160. // FirstPartialToExclusive() ;
  161. // will have problems - the second call to FirstPartialToExclusive()
  162. // may mess up the lock state and cause the lock to fail horribly.
  163. // If a user wishes to convert as above they must have a call sequence like :
  164. //
  165. // PartialLock() ;
  166. // FirstPartialToExclusive() or PartialToExclusive() ;
  167. // ExclusiveToPartial() ;
  168. // PartialToExclusive() ;
  169. //
  170. // If you change lock states more than once - you take your chances !
  171. //
  172. void FirstPartialToExclusive() ;
  173. //
  174. // Returns TRUE if we can get the lock Exclusively, otherwise
  175. // we return FALSE with the lock remaining in the Partially held state.
  176. //
  177. // NOTE : This function will fail in CShareLockNH, but will always
  178. // succeed for CShareLock() locks !
  179. //
  180. BOOL PartialToExclusive() ;
  181. //
  182. // We can always go from an ExclusiveLock() to a PartialLock() state.
  183. //
  184. void ExclusiveToPartial() ;
  185. //
  186. // We can always go from a PartialLock() state to a SharedLock() state
  187. //
  188. void PartialToShared() ;
  189. //
  190. // Returns TRUE if we can get the lock Partially !
  191. // If it returns FALSE we remain with the lock held Shared()
  192. //
  193. BOOL SharedToPartial() ;
  194. //
  195. // Returns TRUE only if no other threads are trying to get the lock
  196. // ExclusiveLy or Partially !
  197. //
  198. BOOL TryPartialLock() ;
  199. } ;
  200. class CSymLock {
  201. /*++
  202. Class Description :
  203. This class implements a symmetric lock, where multiple threads can simultaneously
  204. acquire the lock if they are all of the same group.
  205. For instance, multiple threads can call Group1Lock() and all enter the lock.
  206. Any thread successfully acquiring the lock through Group1Lock() blocks all threads
  207. trying to acquire the lock through Group2Lock(), and vice versa.
  208. --*/
  209. private :
  210. //
  211. // Main lock point where all acquiring threads determine who gets the lock !
  212. //
  213. volatile long m_lock ;
  214. //
  215. // Two variables for the lock exit procotol - used to determine the last thread
  216. // to leave the lock !
  217. //
  218. volatile long m_Departures ;
  219. volatile long m_left ;
  220. //
  221. // Handles for blocking threads !
  222. //
  223. HANDLE m_hSema4Group1 ;
  224. HANDLE m_hSema4Group2 ;
  225. //
  226. // Utility function - implements lock exit protocol when there
  227. // is no contention for the lock !
  228. //
  229. BOOL
  230. InterlockedDecWordAndMask( volatile long* plong,
  231. long mask,
  232. long decrement
  233. ) ;
  234. //
  235. // Utility functions - implement lock exit protocol for case where
  236. // InterlockedDecWordAndMask determines that there is contention for the lock !
  237. //
  238. //
  239. // How Group1 Leaves the lock under contention
  240. //
  241. BOOL
  242. Group1Departures( long bump ) ;
  243. //
  244. // How Group2 Leaves the lock under contention
  245. //
  246. BOOL
  247. Group2Departures( long bump ) ;
  248. //
  249. // You may not copy these objects - so the copy constructor is private !
  250. //
  251. CSymLock( CSymLock& ) ;
  252. //
  253. // You may not copy through assignment - so this operator is private !
  254. //
  255. CSymLock& operator=( CSymLock& ) ;
  256. public :
  257. //
  258. // Construct and Destruct the asymetric lock !
  259. //
  260. CSymLock() ;
  261. ~CSymLock() ;
  262. //
  263. // Check that the lock is correctly initialized - call only
  264. // after construction !
  265. //
  266. BOOL
  267. IsValid() ;
  268. //
  269. // Grab the lock for a group1 thread.
  270. // This function may not be called again on the same
  271. // thread until Group1Unlock() is called.
  272. // Group1Unlock() must be called exactly once for each
  273. // Group1Lock() !
  274. //
  275. void
  276. Group1Lock() ;
  277. //
  278. // Release the lock for a group1 thread.
  279. //
  280. void
  281. Group1Unlock() ;
  282. //
  283. // Grab the lock for a group2 thread.
  284. // This function may not be called again on the same
  285. // thread until Group2Unlock() is called.
  286. // Group2Unlock() must be called exactly once for each
  287. // Group2Lock() !
  288. //
  289. void
  290. Group2Lock() ;
  291. //
  292. // Release the lock for a Group2 thread !
  293. //
  294. void
  295. Group2Unlock() ;
  296. } ;
  297. #endif