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.

481 lines
15 KiB

  1. #ifndef _SHARELOCK_HPP_
  2. #define _SHARELOCK_HPP_
  3. // Ruler
  4. // 1 2 3 4 5 6 7 8
  5. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  6. /********************************************************************/
  7. /* */
  8. /* The standard layout. */
  9. /* */
  10. /* The standard layout for 'hpp' files for this code is as */
  11. /* follows: */
  12. /* */
  13. /* 1. Include files. */
  14. /* 2. Constants exported from the class. */
  15. /* 3. Data structures exported from the class. */
  16. /* 4. Forward references to other data structures. */
  17. /* 5. Class specifications (including inline functions). */
  18. /* 6. Additional large inline functions. */
  19. /* */
  20. /* Any portion that is not required is simply omitted. */
  21. /* */
  22. /********************************************************************/
  23. #include "Global.hpp"
  24. #include "Environment.hpp"
  25. /********************************************************************/
  26. /* */
  27. /* Sharelock and Semaphore locking. */
  28. /* */
  29. /* This class provides a very conservative locking scheme. */
  30. /* The assumption behind the code is that locks will be */
  31. /* held for a very short time. A lock can be obtained in */
  32. /* either exclusive mode or shared mode. If the lock is not */
  33. /* available the caller waits by spinning or if that fails */
  34. /* by sleeping. */
  35. /* */
  36. /********************************************************************/
  37. class SHARELOCK : public ENVIRONMENT
  38. {
  39. //
  40. // Private data.
  41. //
  42. SBIT32 MaxSpins;
  43. SBIT32 MaxUsers;
  44. VOLATILE SBIT32 Exclusive;
  45. VOLATILE SBIT32 TotalUsers;
  46. #ifdef ENABLE_RECURSIVE_LOCKS
  47. SBIT32 Owner;
  48. SBIT32 Recursive;
  49. #endif
  50. HANDLE Semaphore;
  51. VOLATILE SBIT32 Waiting;
  52. #ifdef ENABLE_LOCK_STATISTICS
  53. //
  54. // Counters for debugging builds.
  55. //
  56. VOLATILE SBIT32 TotalExclusiveLocks;
  57. VOLATILE SBIT32 TotalShareLocks;
  58. VOLATILE SBIT32 TotalSleeps;
  59. VOLATILE SBIT32 TotalSpins;
  60. VOLATILE SBIT32 TotalTimeouts;
  61. VOLATILE SBIT32 TotalWaits;
  62. #endif
  63. public:
  64. //
  65. // Public functions.
  66. //
  67. SHARELOCK( SBIT32 NewMaxSpins = 4096, SBIT32 NewMaxUsers = 256 );
  68. INLINE VOID ChangeExclusiveLockToSharedLock( VOID );
  69. INLINE BOOLEAN ChangeSharedLockToExclusiveLock( SBIT32 Sleep = INFINITE );
  70. INLINE BOOLEAN ClaimExclusiveLock( SBIT32 Sleep = INFINITE );
  71. INLINE BOOLEAN ClaimShareLock( SBIT32 Sleep = INFINITE );
  72. INLINE VOID ReleaseExclusiveLock( VOID );
  73. INLINE VOID ReleaseShareLock( VOID );
  74. BOOLEAN UpdateMaxSpins( SBIT32 NewMaxSpins );
  75. BOOLEAN UpdateMaxUsers( SBIT32 NewMaxUsers );
  76. ~SHARELOCK( VOID );
  77. //
  78. // Public inline functions.
  79. //
  80. INLINE SBIT32 ActiveUsers( VOID )
  81. { return (SBIT32) TotalUsers; }
  82. private:
  83. //
  84. // Private functions.
  85. //
  86. INLINE VOID DeleteExclusiveOwner( VOID );
  87. INLINE VOID NewExclusiveOwner( SBIT32 NewOwner );
  88. BOOLEAN SleepWaitingForLock( SBIT32 Sleep );
  89. VOID UpdateSemaphore( VOID );
  90. BOOLEAN WaitForExclusiveLock( SBIT32 Sleep );
  91. BOOLEAN WaitForShareLock( SBIT32 Sleep );
  92. VOID WakeAllSleepers( VOID );
  93. //
  94. // Disabled operations.
  95. //
  96. SHARELOCK( CONST SHARELOCK & Copy );
  97. VOID operator=( CONST SHARELOCK & Copy );
  98. };
  99. /********************************************************************/
  100. /* */
  101. /* Change an exclusive lock to a shared lock. */
  102. /* */
  103. /* Downgrade the existing exclusive lock to a shared lock. */
  104. /* */
  105. /********************************************************************/
  106. INLINE VOID SHARELOCK::ChangeExclusiveLockToSharedLock( VOID )
  107. {
  108. #ifdef ENABLE_RECURSIVE_LOCKS
  109. //
  110. // When we have recursive lock calls we do not
  111. // release the lock until we have exited to the
  112. // top level.
  113. //
  114. if ( Recursive <= 0 )
  115. {
  116. //
  117. // Delete the exclusive owner information.
  118. //
  119. DeleteExclusiveOwner();
  120. #endif
  121. //
  122. // Simply decrement the exclusive count.
  123. // This allows the lock to be shared.
  124. //
  125. (VOID) AtomicDecrement( & Exclusive );
  126. #ifdef ENABLE_RECURSIVE_LOCKS
  127. }
  128. #endif
  129. #ifdef ENABLE_LOCK_STATISTICS
  130. //
  131. // Update the statistics.
  132. //
  133. (VOID) AtomicIncrement( & TotalShareLocks );
  134. #endif
  135. }
  136. /********************************************************************/
  137. /* */
  138. /* Change a shared lock to an exclusive lock. */
  139. /* */
  140. /* Upgrade the existing shared lock to an exclusive lock. */
  141. /* */
  142. /********************************************************************/
  143. INLINE BOOLEAN SHARELOCK::ChangeSharedLockToExclusiveLock( SBIT32 Sleep )
  144. {
  145. #ifdef ENABLE_RECURSIVE_LOCKS
  146. REGISTER SBIT32 ThreadId = GetThreadId();
  147. //
  148. // We may already own an exclusive lock. If so
  149. // we increment the recursive count otherwise
  150. // we have to wait.
  151. //
  152. if ( Owner != ThreadId )
  153. {
  154. #endif
  155. //
  156. // We need to increment the exclusive count
  157. // to prevent the lock from being shared.
  158. //
  159. (VOID) AtomicIncrement( & Exclusive );
  160. //
  161. // If the total number of users is one then
  162. // we have the lock exclusively otherwise we
  163. // may need to wait.
  164. //
  165. if ( TotalUsers != 1 )
  166. {
  167. //
  168. // We have to wait. If we are not allowed
  169. // to sleep or we have timed out then exit.
  170. //
  171. if ( ! WaitForExclusiveLock( Sleep ) )
  172. { return False; }
  173. }
  174. #ifdef ENABLE_RECURSIVE_LOCKS
  175. //
  176. // Register the new exclusive owner
  177. // of the lock.
  178. //
  179. NewExclusiveOwner( ThreadId );
  180. }
  181. #endif
  182. #ifdef ENABLE_LOCK_STATISTICS
  183. //
  184. // Update the statistics.
  185. //
  186. (VOID) AtomicIncrement( & TotalExclusiveLocks );
  187. #endif
  188. return True;
  189. }
  190. /********************************************************************/
  191. /* */
  192. /* Claim an exclusive lock. */
  193. /* */
  194. /* Claim an exclusive lock if available else wait or exit. */
  195. /* */
  196. /********************************************************************/
  197. INLINE BOOLEAN SHARELOCK::ClaimExclusiveLock( SBIT32 Sleep )
  198. {
  199. #ifdef ENABLE_RECURSIVE_LOCKS
  200. REGISTER SBIT32 ThreadId = GetThreadId();
  201. //
  202. // We may already own an exclusive lock. If so
  203. // we increment the recursive count otherwise
  204. // we have to wait.
  205. //
  206. if ( Owner != ThreadId )
  207. {
  208. #endif
  209. //
  210. // We need to increment the exclusive count
  211. // to prevent the lock from being shared and
  212. // the total number of users count.
  213. //
  214. (VOID) AtomicIncrement( & Exclusive );
  215. (VOID) AtomicIncrement( & TotalUsers );
  216. if ( TotalUsers != 1 )
  217. {
  218. //
  219. // We have to wait. If we are not allowed
  220. // to sleep or we have timed out then exit.
  221. //
  222. if ( ! WaitForExclusiveLock( Sleep ) )
  223. { return False; }
  224. }
  225. #ifdef ENABLE_RECURSIVE_LOCKS
  226. //
  227. // Register the new exclusive owner
  228. // of the lock.
  229. //
  230. NewExclusiveOwner( ThreadId );
  231. }
  232. else
  233. { Recursive ++; }
  234. #endif
  235. #ifdef ENABLE_LOCK_STATISTICS
  236. //
  237. // Update the statistics.
  238. //
  239. (VOID) AtomicIncrement( & TotalExclusiveLocks );
  240. #endif
  241. return True;
  242. }
  243. /********************************************************************/
  244. /* */
  245. /* Claim a shared lock. */
  246. /* */
  247. /* Claim a shared lock if available else wait or exit. */
  248. /* */
  249. /********************************************************************/
  250. INLINE BOOLEAN SHARELOCK::ClaimShareLock( SBIT32 Sleep )
  251. {
  252. #ifdef ENABLE_RECURSIVE_LOCKS
  253. REGISTER SBIT32 ThreadId = GetThreadId();
  254. //
  255. // We may already own an exclusive lock. If so
  256. // we increment the recursive count otherwise
  257. // we have to wait.
  258. //
  259. if ( Owner != ThreadId )
  260. {
  261. #endif
  262. //
  263. // We need to increment the total number of
  264. // users count to prevent the lock from being
  265. // claimed for exclusive use.
  266. //
  267. (VOID) AtomicIncrement( & TotalUsers );
  268. if ( (Exclusive > 0) || (TotalUsers > MaxUsers) )
  269. {
  270. //
  271. // We have to wait. If we are not allowed
  272. // to sleep or we have timed out then exit.
  273. //
  274. if ( ! WaitForShareLock( Sleep ) )
  275. { return False; }
  276. }
  277. #ifdef ENABLE_RECURSIVE_LOCKS
  278. }
  279. else
  280. { Recursive ++; }
  281. #endif
  282. #ifdef ENABLE_LOCK_STATISTICS
  283. //
  284. // Update the statistics.
  285. //
  286. (VOID) AtomicIncrement( & TotalShareLocks );
  287. #endif
  288. return True;
  289. }
  290. #ifdef ENABLE_RECURSIVE_LOCKS
  291. /********************************************************************/
  292. /* */
  293. /* New exclusive owner. */
  294. /* */
  295. /* Delete the exclusive lock owner information. */
  296. /* */
  297. /********************************************************************/
  298. INLINE VOID SHARELOCK::DeleteExclusiveOwner( VOID )
  299. {
  300. #ifdef DEBUGGING
  301. if ( Owner != NULL )
  302. {
  303. #endif
  304. Owner = NULL;
  305. #ifdef DEBUGGING
  306. }
  307. else
  308. { Failure( "Sharelock has no owner in DeleteExclusiveOwner" ); }
  309. #endif
  310. }
  311. /********************************************************************/
  312. /* */
  313. /* New exclusive owner. */
  314. /* */
  315. /* Register new exclusive lock owner information. */
  316. /* */
  317. /********************************************************************/
  318. INLINE VOID SHARELOCK::NewExclusiveOwner( SBIT32 NewOwner )
  319. {
  320. #ifdef DEBUGGING
  321. if ( Owner == NULL )
  322. {
  323. #endif
  324. Owner = NewOwner;
  325. #ifdef DEBUGGING
  326. }
  327. else
  328. { Failure( "Already exclusive in NewExclusiveOwner" ); }
  329. #endif
  330. }
  331. #endif
  332. /********************************************************************/
  333. /* */
  334. /* Release an exclusive lock. */
  335. /* */
  336. /* Release an exclusive lock and if needed wakeup any sleepers. */
  337. /* */
  338. /********************************************************************/
  339. INLINE VOID SHARELOCK::ReleaseExclusiveLock( VOID )
  340. {
  341. #ifdef ENABLE_RECURSIVE_LOCKS
  342. //
  343. // When we have recursive lock calls we do not
  344. // release the lock until we have exited to the
  345. // top level.
  346. //
  347. if ( Recursive <= 0 )
  348. {
  349. //
  350. // Delete the exclusive owner information.
  351. //
  352. DeleteExclusiveOwner();
  353. #endif
  354. //
  355. // Release an exclusive lock.
  356. //
  357. #ifdef DEBUGGING
  358. if
  359. (
  360. (AtomicDecrement( & TotalUsers ) < 0)
  361. ||
  362. (AtomicDecrement( & Exclusive ) < 0)
  363. )
  364. { Failure( "Negative lock count in ReleaseExclusiveLock" ); }
  365. #else
  366. AtomicDecrement( & TotalUsers );
  367. AtomicDecrement( & Exclusive );
  368. #endif
  369. //
  370. // Wakeup anyone who is asleep waiting.
  371. //
  372. if ( Waiting > 0 )
  373. { WakeAllSleepers(); }
  374. #ifdef ENABLE_RECURSIVE_LOCKS
  375. }
  376. else
  377. { Recursive --; }
  378. #endif
  379. }
  380. /********************************************************************/
  381. /* */
  382. /* Release a shared lock. */
  383. /* */
  384. /* Release a shared lock and if needed wakeup any sleepers. */
  385. /* */
  386. /********************************************************************/
  387. INLINE VOID SHARELOCK::ReleaseShareLock( VOID )
  388. {
  389. #ifdef ENABLE_RECURSIVE_LOCKS
  390. //
  391. // When we have recursive lock calls we do not
  392. // release the lock until we have exited to the
  393. // top level.
  394. //
  395. if ( Recursive <= 0 )
  396. {
  397. #endif
  398. #ifdef DEBUGGING
  399. //
  400. // Release a shared lock.
  401. //
  402. if ( AtomicDecrement( & TotalUsers ) < 0 )
  403. { Failure( "Negative lock count in ReleaseShareLock" ); }
  404. #else
  405. AtomicDecrement( & TotalUsers );
  406. #endif
  407. //
  408. // Wakeup anyone who is asleep waiting.
  409. //
  410. if ( Waiting > 0 )
  411. { WakeAllSleepers(); }
  412. #ifdef ENABLE_RECURSIVE_LOCKS
  413. }
  414. else
  415. { Recursive --; }
  416. #endif
  417. }
  418. #endif