lock.c 23 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211
  1. /*++
  2. Copyright (c) 2012 Minoca Corp.
  3. This file is licensed under the terms of the GNU General Public License
  4. version 3. Alternative licensing terms are available. Contact
  5. info@minocacorp.com for details. See the LICENSE file at the root of this
  6. project for complete licensing information.
  7. Module Name:
  8. lock.c
  9. Abstract:
  10. This module implements common synchronization primitives in the kernel.
  11. Author:
  12. Evan Green 6-Aug-2012
  13. Environment:
  14. Kernel
  15. --*/
  16. //
  17. // ------------------------------------------------------------------- Includes
  18. //
  19. #include <minoca/kernel/kernel.h>
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. #define QUEUED_LOCK_TAG 0x6C51654B // 'lQeK'
  24. #define SHARED_EXCLUSIVE_LOCK_TAG 0x6553654B // 'eSeK'
  25. //
  26. // Define shared exclusive lock states.
  27. //
  28. #define SHARED_EXCLUSIVE_LOCK_FREE 0
  29. #define SHARED_EXCLUSIVE_LOCK_EXCLUSIVE ((ULONG)-1)
  30. #define SHARED_EXCLUSIVE_LOCK_MAX_WAITERS ((ULONG)-2)
  31. //
  32. // ----------------------------------------------- Internal Function Prototypes
  33. //
  34. //
  35. // ------------------------------------------------------ Data Type Definitions
  36. //
  37. //
  38. // -------------------------------------------------------------------- Globals
  39. //
  40. //
  41. // Queued lock directory where all queued locks are stored. This is primarily
  42. // done to keep the root directory tidy.
  43. //
  44. POBJECT_HEADER KeQueuedLockDirectory = NULL;
  45. //
  46. // ------------------------------------------------------------------ Functions
  47. //
  48. KERNEL_API
  49. PQUEUED_LOCK
  50. KeCreateQueuedLock (
  51. VOID
  52. )
  53. /*++
  54. Routine Description:
  55. This routine creates a new queued lock under the current thread. These locks
  56. can be used at up to dispatch level if non-paged memory is used.
  57. Arguments:
  58. None.
  59. Return Value:
  60. Returns a pointer to the new lock on success.
  61. NULL on failure.
  62. --*/
  63. {
  64. PQUEUED_LOCK NewLock;
  65. POBJECT_HEADER NewObject;
  66. NewObject = ObCreateObject(ObjectQueuedLock,
  67. KeQueuedLockDirectory,
  68. NULL,
  69. 0,
  70. sizeof(QUEUED_LOCK),
  71. NULL,
  72. 0,
  73. QUEUED_LOCK_TAG);
  74. NewLock = (PQUEUED_LOCK)NewObject;
  75. if (NewLock != NULL) {
  76. //
  77. // Initialize the lock to signal one thread so the first wait acquires
  78. // it.
  79. //
  80. ObSignalObject(NewObject, SignalOptionSignalOne);
  81. }
  82. return NewLock;
  83. }
  84. KERNEL_API
  85. VOID
  86. KeDestroyQueuedLock (
  87. PQUEUED_LOCK Lock
  88. )
  89. /*++
  90. Routine Description:
  91. This routine destroys a queued lock by decrementing its reference count.
  92. Arguments:
  93. Lock - Supplies a pointer to the queued lock to destroy.
  94. Return Value:
  95. None. When the function returns, the lock must not be used again.
  96. --*/
  97. {
  98. ObReleaseReference(&(Lock->Header));
  99. return;
  100. }
  101. KERNEL_API
  102. VOID
  103. KeAcquireQueuedLock (
  104. PQUEUED_LOCK Lock
  105. )
  106. /*++
  107. Routine Description:
  108. This routine acquires the queued lock. If the lock is held, the thread
  109. blocks until it becomes available.
  110. Arguments:
  111. Lock - Supplies a pointer to the queued lock to acquire.
  112. Return Value:
  113. None. When the function returns, the lock will be held.
  114. --*/
  115. {
  116. KSTATUS Status;
  117. Status = KeAcquireQueuedLockTimed(Lock, WAIT_TIME_INDEFINITE);
  118. ASSERT(KSUCCESS(Status));
  119. return;
  120. }
  121. KERNEL_API
  122. KSTATUS
  123. KeAcquireQueuedLockTimed (
  124. PQUEUED_LOCK Lock,
  125. ULONG TimeoutInMilliseconds
  126. )
  127. /*++
  128. Routine Description:
  129. This routine acquires the queued lock. If the lock is held, the thread
  130. blocks until it becomes available or the specified timeout expires.
  131. Arguments:
  132. Lock - Supplies a pointer to the queued lock to acquire.
  133. TimeoutInMilliseconds - Supplies the number of milliseconds that the given
  134. object should be waited on before timing out. Use WAIT_TIME_INDEFINITE
  135. to wait forever on the object.
  136. Return Value:
  137. STATUS_SUCCESS on success.
  138. STATUS_TIMEOUT if the specified amount of time expired and the lock could
  139. not be acquired.
  140. --*/
  141. {
  142. KSTATUS Status;
  143. PKTHREAD Thread;
  144. Thread = KeGetCurrentThread();
  145. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  146. ASSERT((Lock->OwningThread != Thread) || (Thread == NULL));
  147. Status = ObWaitOnObject(&(Lock->Header), 0, TimeoutInMilliseconds);
  148. if (KSUCCESS(Status)) {
  149. Lock->OwningThread = Thread;
  150. }
  151. return Status;
  152. }
  153. KERNEL_API
  154. VOID
  155. KeReleaseQueuedLock (
  156. PQUEUED_LOCK Lock
  157. )
  158. /*++
  159. Routine Description:
  160. This routine releases a queued lock that has been previously acquired.
  161. Arguments:
  162. Lock - Supplies a pointer to the queued lock to release.
  163. Return Value:
  164. None.
  165. --*/
  166. {
  167. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  168. Lock->OwningThread = NULL;
  169. ObSignalObject(&(Lock->Header), SignalOptionSignalOne);
  170. return;
  171. }
  172. KERNEL_API
  173. BOOL
  174. KeTryToAcquireQueuedLock (
  175. PQUEUED_LOCK Lock
  176. )
  177. /*++
  178. Routine Description:
  179. This routine attempts to acquire the queued lock. If the lock is busy, it
  180. does not add this thread to the queue of waiters.
  181. Arguments:
  182. Lock - Supplies a pointer to a queued lock.
  183. Return Value:
  184. Returns TRUE if the lock was acquired, or FALSE otherwise.
  185. --*/
  186. {
  187. KSTATUS Status;
  188. ASSERT(KeGetRunLevel() <= RunLevelDispatch);
  189. Status = ObWaitOnObject(&(Lock->Header), 0, 0);
  190. if (!KSUCCESS(Status)) {
  191. return FALSE;
  192. }
  193. Lock->OwningThread = KeGetCurrentThread();
  194. return TRUE;
  195. }
  196. KERNEL_API
  197. BOOL
  198. KeIsQueuedLockHeld (
  199. PQUEUED_LOCK Lock
  200. )
  201. /*++
  202. Routine Description:
  203. This routine determines whether a queued lock is acquired or free.
  204. Arguments:
  205. Lock - Supplies a pointer to the queued lock.
  206. Return Value:
  207. TRUE if the queued lock is held.
  208. FALSE if the queued lock is free.
  209. --*/
  210. {
  211. if (Lock->Header.WaitQueue.State == SignaledForOne) {
  212. return FALSE;
  213. }
  214. return TRUE;
  215. }
  216. KERNEL_API
  217. VOID
  218. KeInitializeSpinLock (
  219. PKSPIN_LOCK Lock
  220. )
  221. /*++
  222. Routine Description:
  223. This routine initializes a spinlock.
  224. Arguments:
  225. Lock - Supplies a pointer to the lock to initialize.
  226. Return Value:
  227. None.
  228. --*/
  229. {
  230. Lock->LockHeld = 0;
  231. Lock->OwningThread = NULL;
  232. //
  233. // This atomic exchange serves as a memory barrier and serializing
  234. // instruction.
  235. //
  236. RtlAtomicExchange32(&(Lock->LockHeld), 0);
  237. return;
  238. }
  239. KERNEL_API
  240. VOID
  241. KeAcquireSpinLock (
  242. PKSPIN_LOCK Lock
  243. )
  244. /*++
  245. Routine Description:
  246. This routine acquires a kernel spinlock. It must be acquired at or below
  247. dispatch level. This routine may yield the processor.
  248. Arguments:
  249. Lock - Supplies a pointer to the lock to acquire.
  250. Return Value:
  251. None.
  252. --*/
  253. {
  254. ULONG LockValue;
  255. while (TRUE) {
  256. LockValue = RtlAtomicCompareExchange32(&(Lock->LockHeld), 1, 0);
  257. if (LockValue == 0) {
  258. break;
  259. }
  260. ArProcessorYield();
  261. }
  262. Lock->OwningThread = KeGetCurrentThread();
  263. return;
  264. }
  265. KERNEL_API
  266. VOID
  267. KeReleaseSpinLock (
  268. PKSPIN_LOCK Lock
  269. )
  270. /*++
  271. Routine Description:
  272. This routine releases a kernel spinlock.
  273. Arguments:
  274. Lock - Supplies a pointer to the lock to release.
  275. Return Value:
  276. None.
  277. --*/
  278. {
  279. ULONG LockValue;
  280. //
  281. // The interlocked version is a serializing instruction, so this avoids
  282. // unsafe processor and compiler reordering. Simply setting the lock to
  283. // FALSE is not safe.
  284. //
  285. LockValue = RtlAtomicExchange32(&(Lock->LockHeld), 0);
  286. //
  287. // Assert if the lock was not held.
  288. //
  289. ASSERT(LockValue != 0);
  290. return;
  291. }
  292. KERNEL_API
  293. BOOL
  294. KeTryToAcquireSpinLock (
  295. PKSPIN_LOCK Lock
  296. )
  297. /*++
  298. Routine Description:
  299. This routine makes one attempt to acquire a spinlock.
  300. Arguments:
  301. Lock - Supplies a pointer to the lock to attempt to acquire.
  302. Return Value:
  303. TRUE if the lock was acquired.
  304. FALSE if the lock was not acquired.
  305. --*/
  306. {
  307. ULONG LockValue;
  308. LockValue = RtlAtomicCompareExchange32(&(Lock->LockHeld), 1, 0);
  309. if (LockValue == 0) {
  310. Lock->OwningThread = KeGetCurrentThread();
  311. return TRUE;
  312. }
  313. return FALSE;
  314. }
  315. KERNEL_API
  316. BOOL
  317. KeIsSpinLockHeld (
  318. PKSPIN_LOCK Lock
  319. )
  320. /*++
  321. Routine Description:
  322. This routine determines whether a spin lock is held or free.
  323. Arguments:
  324. Lock - Supplies a pointer to the lock to check.
  325. Return Value:
  326. TRUE if the lock has been acquired.
  327. FALSE if the lock is free.
  328. --*/
  329. {
  330. ULONG Held;
  331. Held = RtlAtomicOr32(&(Lock->LockHeld), 0);
  332. if (Held != 0) {
  333. return TRUE;
  334. }
  335. return FALSE;
  336. }
  337. KERNEL_API
  338. PSHARED_EXCLUSIVE_LOCK
  339. KeCreateSharedExclusiveLock (
  340. VOID
  341. )
  342. /*++
  343. Routine Description:
  344. This routine creates a shared-exclusive lock.
  345. Arguments:
  346. None.
  347. Return Value:
  348. Returns a pointer to a shared-exclusive lock on success, or NULL on failure.
  349. --*/
  350. {
  351. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock;
  352. KSTATUS Status;
  353. SharedExclusiveLock = MmAllocateNonPagedPool(sizeof(SHARED_EXCLUSIVE_LOCK),
  354. SHARED_EXCLUSIVE_LOCK_TAG);
  355. if (SharedExclusiveLock == NULL) {
  356. Status = STATUS_INSUFFICIENT_RESOURCES;
  357. goto CreateSharedExclusiveLockEnd;
  358. }
  359. RtlZeroMemory(SharedExclusiveLock, sizeof(SHARED_EXCLUSIVE_LOCK));
  360. SharedExclusiveLock->Event = KeCreateEvent(NULL);
  361. if (SharedExclusiveLock->Event == NULL) {
  362. Status = STATUS_INSUFFICIENT_RESOURCES;
  363. goto CreateSharedExclusiveLockEnd;
  364. }
  365. KeSignalEvent(SharedExclusiveLock->Event, SignalOptionSignalOne);
  366. Status = STATUS_SUCCESS;
  367. CreateSharedExclusiveLockEnd:
  368. if (!KSUCCESS(Status)) {
  369. if (SharedExclusiveLock != NULL) {
  370. KeDestroySharedExclusiveLock(SharedExclusiveLock);
  371. SharedExclusiveLock = NULL;
  372. }
  373. }
  374. return SharedExclusiveLock;
  375. }
  376. KERNEL_API
  377. VOID
  378. KeDestroySharedExclusiveLock (
  379. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  380. )
  381. /*++
  382. Routine Description:
  383. This routine destroys a shared-exclusive lock.
  384. Arguments:
  385. SharedExclusiveLock - Supplies a pointer to a shared-exclusive lock.
  386. Return Value:
  387. None.
  388. --*/
  389. {
  390. if (SharedExclusiveLock->Event != NULL) {
  391. KeDestroyEvent(SharedExclusiveLock->Event);
  392. }
  393. MmFreeNonPagedPool(SharedExclusiveLock);
  394. return;
  395. }
  396. KERNEL_API
  397. VOID
  398. KeAcquireSharedExclusiveLockShared (
  399. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  400. )
  401. /*++
  402. Routine Description:
  403. This routine acquired the given shared-exclusive lock in shared mode.
  404. Arguments:
  405. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  406. Return Value:
  407. None.
  408. --*/
  409. {
  410. ULONG ExclusiveWaiters;
  411. BOOL IsWaiter;
  412. ULONG PreviousState;
  413. ULONG PreviousWaiters;
  414. ULONG SharedWaiters;
  415. ULONG State;
  416. IsWaiter = FALSE;
  417. while (TRUE) {
  418. State = SharedExclusiveLock->State;
  419. ExclusiveWaiters = SharedExclusiveLock->ExclusiveWaiters;
  420. //
  421. // If no one is trying to acquire exclusive, or this is not the first
  422. // time around, try to acquire the lock. The reason subsequent attempts
  423. // are allowed to try to acquire even with exclusive waiters is that
  424. // without this, shared acquires may go down indefinitely on a free
  425. // lock (since they soaked up the "signal for one" and got woken up
  426. // ahead of the exclusive waiter).
  427. //
  428. if (((ExclusiveWaiters == 0) || (IsWaiter != FALSE)) &&
  429. (State < SHARED_EXCLUSIVE_LOCK_EXCLUSIVE - 1)) {
  430. PreviousState = State;
  431. State = RtlAtomicCompareExchange32(&(SharedExclusiveLock->State),
  432. PreviousState + 1,
  433. PreviousState);
  434. if (State == PreviousState) {
  435. //
  436. // Let all the blocked reader brethren go if this thread was
  437. // also blocked.
  438. //
  439. if (SharedExclusiveLock->SharedWaiters != 0) {
  440. KeSignalEvent(SharedExclusiveLock->Event,
  441. SignalOptionPulse);
  442. }
  443. break;
  444. //
  445. // The addition got foiled, go try again.
  446. //
  447. } else {
  448. continue;
  449. }
  450. }
  451. //
  452. // Either someone is trying to get it exclusive, or the attempt to
  453. // get it shared failed. Become a waiter so that the event will be
  454. // signaled when the lock is released. Use compare-exchange to avoid
  455. // overflowing.
  456. //
  457. if (IsWaiter == FALSE) {
  458. SharedWaiters = SharedExclusiveLock->SharedWaiters;
  459. if (SharedWaiters >= SHARED_EXCLUSIVE_LOCK_MAX_WAITERS) {
  460. continue;
  461. }
  462. PreviousWaiters = RtlAtomicCompareExchange32(
  463. &(SharedExclusiveLock->SharedWaiters),
  464. SharedWaiters + 1,
  465. SharedWaiters);
  466. if (PreviousWaiters != SharedWaiters) {
  467. continue;
  468. }
  469. IsWaiter = TRUE;
  470. }
  471. //
  472. // Recheck the condition now that the waiter count is incremented, as a
  473. // release may not have seen any waiters and therefore never signaled
  474. // the event.
  475. //
  476. if ((SharedExclusiveLock->ExclusiveWaiters == 0) &&
  477. (SharedExclusiveLock->State != SHARED_EXCLUSIVE_LOCK_EXCLUSIVE)) {
  478. continue;
  479. }
  480. KeWaitForEvent(SharedExclusiveLock->Event, FALSE, WAIT_TIME_INDEFINITE);
  481. }
  482. //
  483. // This thread is no longer waiting, away it goes.
  484. //
  485. if (IsWaiter != FALSE) {
  486. PreviousWaiters =
  487. RtlAtomicAdd32(&(SharedExclusiveLock->SharedWaiters), -1);
  488. ASSERT(PreviousWaiters != 0);
  489. }
  490. return;
  491. }
  492. KERNEL_API
  493. BOOL
  494. KeTryToAcquireSharedExclusiveLockShared (
  495. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  496. )
  497. /*++
  498. Routine Description:
  499. This routine makes a single attempt to acquire the given shared-exclusive
  500. lock in shared mode.
  501. Arguments:
  502. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  503. Return Value:
  504. TRUE if the lock was successfully acquired shared.
  505. FALSE if the lock was not successfully acquired shared.
  506. --*/
  507. {
  508. ULONG ExclusiveWaiters;
  509. ULONG PreviousState;
  510. ULONG State;
  511. State = SharedExclusiveLock->State;
  512. ExclusiveWaiters = SharedExclusiveLock->ExclusiveWaiters;
  513. if ((ExclusiveWaiters == 0) &&
  514. (State < SHARED_EXCLUSIVE_LOCK_EXCLUSIVE - 1)) {
  515. PreviousState = State;
  516. State = RtlAtomicCompareExchange32(&(SharedExclusiveLock->State),
  517. PreviousState + 1,
  518. PreviousState);
  519. if (State == PreviousState) {
  520. //
  521. // Let all the blocked reader brethren go if this thread was
  522. // also blocked.
  523. //
  524. if (SharedExclusiveLock->SharedWaiters != 0) {
  525. KeSignalEvent(SharedExclusiveLock->Event,
  526. SignalOptionPulse);
  527. }
  528. return TRUE;
  529. }
  530. }
  531. return FALSE;
  532. }
  533. KERNEL_API
  534. VOID
  535. KeReleaseSharedExclusiveLockShared (
  536. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  537. )
  538. /*++
  539. Routine Description:
  540. This routine releases the given shared-exclusive lock from shared mode.
  541. Arguments:
  542. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  543. Return Value:
  544. None.
  545. --*/
  546. {
  547. ULONG PreviousState;
  548. PreviousState = RtlAtomicAdd32(&(SharedExclusiveLock->State), -1);
  549. ASSERT((PreviousState < SHARED_EXCLUSIVE_LOCK_EXCLUSIVE) &&
  550. (PreviousState != SHARED_EXCLUSIVE_LOCK_FREE));
  551. //
  552. // If this was the last reader and there are writers waiting, signal the
  553. // event.
  554. //
  555. if ((PreviousState - 1 == SHARED_EXCLUSIVE_LOCK_FREE) &&
  556. (SharedExclusiveLock->ExclusiveWaiters != 0)) {
  557. KeSignalEvent(SharedExclusiveLock->Event, SignalOptionSignalOne);
  558. }
  559. return;
  560. }
  561. KERNEL_API
  562. VOID
  563. KeAcquireSharedExclusiveLockExclusive (
  564. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  565. )
  566. /*++
  567. Routine Description:
  568. This routine acquired the given shared-exclusive lock in exclusive mode.
  569. Arguments:
  570. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  571. Return Value:
  572. None.
  573. --*/
  574. {
  575. ULONG CurrentState;
  576. ULONG ExclusiveWaiters;
  577. BOOL IsWaiting;
  578. ULONG PreviousWaiters;
  579. ULONG State;
  580. IsWaiting = FALSE;
  581. while (TRUE) {
  582. State = RtlAtomicCompareExchange32(&(SharedExclusiveLock->State),
  583. SHARED_EXCLUSIVE_LOCK_EXCLUSIVE,
  584. SHARED_EXCLUSIVE_LOCK_FREE);
  585. if (State == SHARED_EXCLUSIVE_LOCK_FREE) {
  586. break;
  587. }
  588. //
  589. // Increment the exclusive waiters count to indicate to readers that
  590. // the event needs to be signaled. Use compare-exchange to avoid
  591. // overflowing.
  592. //
  593. if (IsWaiting == FALSE) {
  594. ExclusiveWaiters = SharedExclusiveLock->ExclusiveWaiters;
  595. if (ExclusiveWaiters >= SHARED_EXCLUSIVE_LOCK_MAX_WAITERS) {
  596. continue;
  597. }
  598. PreviousWaiters = RtlAtomicCompareExchange32(
  599. &(SharedExclusiveLock->ExclusiveWaiters),
  600. ExclusiveWaiters + 1,
  601. ExclusiveWaiters);
  602. if (PreviousWaiters != ExclusiveWaiters) {
  603. continue;
  604. }
  605. IsWaiting = TRUE;
  606. }
  607. //
  608. // Recheck the state now that the exclusive waiters count has been
  609. // incremented, in case the release didn't see the increment and never
  610. // signaled the event.
  611. //
  612. CurrentState = SharedExclusiveLock->State;
  613. if (CurrentState == SHARED_EXCLUSIVE_LOCK_FREE) {
  614. continue;
  615. }
  616. KeWaitForEvent(SharedExclusiveLock->Event, FALSE, WAIT_TIME_INDEFINITE);
  617. }
  618. //
  619. // This lucky writer is no longer waiting.
  620. //
  621. if (IsWaiting != FALSE) {
  622. PreviousWaiters =
  623. RtlAtomicAdd32(&(SharedExclusiveLock->ExclusiveWaiters), -1);
  624. ASSERT(PreviousWaiters != 0);
  625. }
  626. return;
  627. }
  628. KERNEL_API
  629. BOOL
  630. KeTryToAcquireSharedExclusiveLockExclusive (
  631. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  632. )
  633. /*++
  634. Routine Description:
  635. This routine makes a single attempt to acquire the given shared-exclusive
  636. lock exclusively.
  637. Arguments:
  638. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  639. Return Value:
  640. TRUE if the lock was successfully acquired exclusively.
  641. FALSE if the lock was not successfully acquired.
  642. --*/
  643. {
  644. ULONG State;
  645. State = RtlAtomicCompareExchange32(&(SharedExclusiveLock->State),
  646. SHARED_EXCLUSIVE_LOCK_EXCLUSIVE,
  647. SHARED_EXCLUSIVE_LOCK_FREE);
  648. if (State == SHARED_EXCLUSIVE_LOCK_FREE) {
  649. return TRUE;
  650. }
  651. return FALSE;
  652. }
  653. KERNEL_API
  654. VOID
  655. KeReleaseSharedExclusiveLockExclusive (
  656. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  657. )
  658. /*++
  659. Routine Description:
  660. This routine releases the given shared-exclusive lock from exclusive mode.
  661. Arguments:
  662. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  663. Return Value:
  664. None.
  665. --*/
  666. {
  667. ASSERT(SharedExclusiveLock->State == SHARED_EXCLUSIVE_LOCK_EXCLUSIVE);
  668. RtlAtomicExchange32(&(SharedExclusiveLock->State),
  669. SHARED_EXCLUSIVE_LOCK_FREE);
  670. if ((SharedExclusiveLock->SharedWaiters != 0) ||
  671. (SharedExclusiveLock->ExclusiveWaiters != 0)) {
  672. KeSignalEvent(SharedExclusiveLock->Event, SignalOptionSignalOne);
  673. }
  674. return;
  675. }
  676. KERNEL_API
  677. VOID
  678. KeSharedExclusiveLockConvertToExclusive (
  679. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  680. )
  681. /*++
  682. Routine Description:
  683. This routine converts a lock that the caller holds shared into one that
  684. the caller holds exclusive. This routine will most likely fully release
  685. and reacquire the lock.
  686. Arguments:
  687. SharedExclusiveLock - Supplies a pointer to the shared-exclusive lock.
  688. Return Value:
  689. None.
  690. --*/
  691. {
  692. ULONG State;
  693. //
  694. // Try a shortcut in the case that this caller is the only one that has it
  695. // shared.
  696. //
  697. State = RtlAtomicCompareExchange32(&(SharedExclusiveLock->State),
  698. SHARED_EXCLUSIVE_LOCK_EXCLUSIVE,
  699. 1);
  700. ASSERT((State >= 1) && (State < SHARED_EXCLUSIVE_LOCK_EXCLUSIVE));
  701. //
  702. // If the fast conversion failed, get in line like everybody else.
  703. //
  704. if (State != 1) {
  705. KeReleaseSharedExclusiveLockShared(SharedExclusiveLock);
  706. KeAcquireSharedExclusiveLockExclusive(SharedExclusiveLock);
  707. }
  708. return;
  709. }
  710. KERNEL_API
  711. BOOL
  712. KeIsSharedExclusiveLockHeld (
  713. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  714. )
  715. /*++
  716. Routine Description:
  717. This routine determines whether a shared-exclusive lock is held or free.
  718. Arguments:
  719. SharedExclusiveLock - Supplies a pointer to a shared-exclusive lock.
  720. Return Value:
  721. Returns TRUE if the shared-exclusive lock is held, or FALSE if not.
  722. --*/
  723. {
  724. if (SharedExclusiveLock->State != SHARED_EXCLUSIVE_LOCK_FREE) {
  725. return TRUE;
  726. }
  727. return FALSE;
  728. }
  729. KERNEL_API
  730. BOOL
  731. KeIsSharedExclusiveLockHeldExclusive (
  732. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  733. )
  734. /*++
  735. Routine Description:
  736. This routine determines whether a shared-exclusive lock is held exclusively
  737. or not.
  738. Arguments:
  739. SharedExclusiveLock - Supplies a pointer to a shared-exclusive lock.
  740. Return Value:
  741. Returns TRUE if the shared-exclusive lock is held exclusively, or FALSE
  742. otherwise.
  743. --*/
  744. {
  745. if (SharedExclusiveLock->State == SHARED_EXCLUSIVE_LOCK_EXCLUSIVE) {
  746. return TRUE;
  747. }
  748. return FALSE;
  749. }
  750. KERNEL_API
  751. BOOL
  752. KeIsSharedExclusiveLockHeldShared (
  753. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  754. )
  755. /*++
  756. Routine Description:
  757. This routine determines whether a shared-exclusive lock is held shared or
  758. not.
  759. Arguments:
  760. SharedExclusiveLock - Supplies a pointer to a shared-exclusive lock.
  761. Return Value:
  762. Returns TRUE if the shared-exclusive lock is held shared, or FALSE
  763. otherwise.
  764. --*/
  765. {
  766. if ((SharedExclusiveLock->State != SHARED_EXCLUSIVE_LOCK_FREE) &&
  767. (SharedExclusiveLock->State < SHARED_EXCLUSIVE_LOCK_EXCLUSIVE)) {
  768. return TRUE;
  769. }
  770. return FALSE;
  771. }
  772. KERNEL_API
  773. BOOL
  774. KeIsSharedExclusiveLockContended (
  775. PSHARED_EXCLUSIVE_LOCK SharedExclusiveLock
  776. )
  777. /*++
  778. Routine Description:
  779. This routine determines whether a shared-exclusive lock is being waited on
  780. for shared or exclusive access.
  781. Arguments:
  782. SharedExclusiveLock - Supplies a pointer to a shared-exclusive lock.
  783. Return Value:
  784. Returns TRUE if other threads are waiting to acquire the lock, or FALSE
  785. if the lock is uncontented.
  786. --*/
  787. {
  788. if ((SharedExclusiveLock->SharedWaiters != 0) ||
  789. (SharedExclusiveLock->ExclusiveWaiters != 0)) {
  790. return TRUE;
  791. }
  792. return FALSE;
  793. }
  794. //
  795. // --------------------------------------------------------- Internal Functions
  796. //