lock.c 20 KB

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