1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS system libraries 4 * PURPOSE: Slim Reader/Writer (SRW) Routines 5 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com> 6 * 7 * NOTES: The algorithms used in this implementation 8 * may be different from Vista's implementation. 9 * Since applications should treat the RTL_SRWLOCK 10 * structure as opaque data, it should not matter. 11 * The algorithms are probably not as optimized. 12 */ 13 14 /* INCLUDES *****************************************************************/ 15 16 #include <rtl_vista.h> 17 18 #define NDEBUG 19 #include <debug.h> 20 21 /* FUNCTIONS *****************************************************************/ 22 23 #ifdef _WIN64 24 #define InterlockedBitTestAndSetPointer(ptr,val) InterlockedBitTestAndSet64((PLONGLONG)ptr,(LONGLONG)val) 25 #define InterlockedAddPointer(ptr,val) InterlockedAdd64((PLONGLONG)ptr,(LONGLONG)val) 26 #define InterlockedAndPointer(ptr,val) InterlockedAnd64((PLONGLONG)ptr,(LONGLONG)val) 27 #define InterlockedOrPointer(ptr,val) InterlockedOr64((PLONGLONG)ptr,(LONGLONG)val) 28 #else 29 #define InterlockedBitTestAndSetPointer(ptr,val) InterlockedBitTestAndSet((PLONG)ptr,(LONG)val) 30 #define InterlockedAddPointer(ptr,val) InterlockedAdd((PLONG)ptr,(LONG)val) 31 #define InterlockedAndPointer(ptr,val) InterlockedAnd((PLONG)ptr,(LONG)val) 32 #define InterlockedOrPointer(ptr,val) InterlockedOr((PLONG)ptr,(LONG)val) 33 #endif 34 35 #define RTL_SRWLOCK_OWNED_BIT 0 36 #define RTL_SRWLOCK_CONTENDED_BIT 1 37 #define RTL_SRWLOCK_SHARED_BIT 2 38 #define RTL_SRWLOCK_CONTENTION_LOCK_BIT 3 39 #define RTL_SRWLOCK_OWNED (1 << RTL_SRWLOCK_OWNED_BIT) 40 #define RTL_SRWLOCK_CONTENDED (1 << RTL_SRWLOCK_CONTENDED_BIT) 41 #define RTL_SRWLOCK_SHARED (1 << RTL_SRWLOCK_SHARED_BIT) 42 #define RTL_SRWLOCK_CONTENTION_LOCK (1 << RTL_SRWLOCK_CONTENTION_LOCK_BIT) 43 #define RTL_SRWLOCK_MASK (RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED | \ 44 RTL_SRWLOCK_SHARED | RTL_SRWLOCK_CONTENTION_LOCK) 45 #define RTL_SRWLOCK_BITS 4 46 47 typedef struct _RTLP_SRWLOCK_SHARED_WAKE 48 { 49 LONG Wake; 50 volatile struct _RTLP_SRWLOCK_SHARED_WAKE *Next; 51 } volatile RTLP_SRWLOCK_SHARED_WAKE, *PRTLP_SRWLOCK_SHARED_WAKE; 52 53 typedef struct _RTLP_SRWLOCK_WAITBLOCK 54 { 55 /* SharedCount is the number of shared acquirers. */ 56 LONG SharedCount; 57 58 /* Last points to the last wait block in the chain. The value 59 is only valid when read from the first wait block. */ 60 volatile struct _RTLP_SRWLOCK_WAITBLOCK *Last; 61 62 /* Next points to the next wait block in the chain. */ 63 volatile struct _RTLP_SRWLOCK_WAITBLOCK *Next; 64 65 union 66 { 67 /* Wake is only valid for exclusive wait blocks */ 68 LONG Wake; 69 /* The wake chain is only valid for shared wait blocks */ 70 struct 71 { 72 PRTLP_SRWLOCK_SHARED_WAKE SharedWakeChain; 73 PRTLP_SRWLOCK_SHARED_WAKE LastSharedWake; 74 }; 75 }; 76 77 BOOLEAN Exclusive; 78 } volatile RTLP_SRWLOCK_WAITBLOCK, *PRTLP_SRWLOCK_WAITBLOCK; 79 80 81 static VOID 82 NTAPI 83 RtlpReleaseWaitBlockLockExclusive(IN OUT PRTL_SRWLOCK SRWLock, 84 IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock) 85 { 86 PRTLP_SRWLOCK_WAITBLOCK Next; 87 LONG_PTR NewValue; 88 89 /* NOTE: We're currently in an exclusive lock in contended mode. */ 90 91 Next = FirstWaitBlock->Next; 92 if (Next != NULL) 93 { 94 /* There's more blocks chained, we need to update the pointers 95 in the next wait block and update the wait block pointer. */ 96 NewValue = (LONG_PTR)Next | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 97 if (!FirstWaitBlock->Exclusive) 98 { 99 /* The next wait block has to be an exclusive lock! */ 100 ASSERT(Next->Exclusive); 101 102 /* Save the shared count */ 103 Next->SharedCount = FirstWaitBlock->SharedCount; 104 105 NewValue |= RTL_SRWLOCK_SHARED; 106 } 107 108 Next->Last = FirstWaitBlock->Last; 109 } 110 else 111 { 112 /* Convert the lock to a simple lock. */ 113 if (FirstWaitBlock->Exclusive) 114 NewValue = RTL_SRWLOCK_OWNED; 115 else 116 { 117 ASSERT(FirstWaitBlock->SharedCount > 0); 118 119 NewValue = ((LONG_PTR)FirstWaitBlock->SharedCount << RTL_SRWLOCK_BITS) | 120 RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED; 121 } 122 } 123 124 (void)InterlockedExchangePointer(&SRWLock->Ptr, (PVOID)NewValue); 125 126 if (FirstWaitBlock->Exclusive) 127 { 128 (void)InterlockedOr(&FirstWaitBlock->Wake, 129 TRUE); 130 } 131 else 132 { 133 PRTLP_SRWLOCK_SHARED_WAKE WakeChain, NextWake; 134 135 /* If we were the first one to acquire the shared 136 lock, we now need to wake all others... */ 137 WakeChain = FirstWaitBlock->SharedWakeChain; 138 do 139 { 140 NextWake = WakeChain->Next; 141 142 (void)InterlockedOr((PLONG)&WakeChain->Wake, 143 TRUE); 144 145 WakeChain = NextWake; 146 } while (WakeChain != NULL); 147 } 148 } 149 150 151 static VOID 152 NTAPI 153 RtlpReleaseWaitBlockLockLastShared(IN OUT PRTL_SRWLOCK SRWLock, 154 IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock) 155 { 156 PRTLP_SRWLOCK_WAITBLOCK Next; 157 LONG_PTR NewValue; 158 159 /* NOTE: We're currently in a shared lock in contended mode. */ 160 161 /* The next acquirer to be unwaited *must* be an exclusive lock! */ 162 ASSERT(FirstWaitBlock->Exclusive); 163 164 Next = FirstWaitBlock->Next; 165 if (Next != NULL) 166 { 167 /* There's more blocks chained, we need to update the pointers 168 in the next wait block and update the wait block pointer. */ 169 NewValue = (LONG_PTR)Next | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 170 171 Next->Last = FirstWaitBlock->Last; 172 } 173 else 174 { 175 /* Convert the lock to a simple exclusive lock. */ 176 NewValue = RTL_SRWLOCK_OWNED; 177 } 178 179 (void)InterlockedExchangePointer(&SRWLock->Ptr, (PVOID)NewValue); 180 181 (void)InterlockedOr(&FirstWaitBlock->Wake, 182 TRUE); 183 } 184 185 186 static VOID 187 NTAPI 188 RtlpReleaseWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock) 189 { 190 InterlockedAndPointer(&SRWLock->Ptr, 191 ~RTL_SRWLOCK_CONTENTION_LOCK); 192 } 193 194 195 static PRTLP_SRWLOCK_WAITBLOCK 196 NTAPI 197 RtlpAcquireWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock) 198 { 199 LONG_PTR PrevValue; 200 PRTLP_SRWLOCK_WAITBLOCK WaitBlock; 201 202 while (1) 203 { 204 PrevValue = InterlockedOrPointer(&SRWLock->Ptr, 205 RTL_SRWLOCK_CONTENTION_LOCK); 206 207 if (!(PrevValue & RTL_SRWLOCK_CONTENTION_LOCK)) 208 break; 209 210 YieldProcessor(); 211 } 212 213 if (!(PrevValue & RTL_SRWLOCK_CONTENDED) || 214 (PrevValue & ~RTL_SRWLOCK_MASK) == 0) 215 { 216 /* Too bad, looks like the wait block was removed in the 217 meanwhile, unlock again */ 218 RtlpReleaseWaitBlockLock(SRWLock); 219 return NULL; 220 } 221 222 WaitBlock = (PRTLP_SRWLOCK_WAITBLOCK)(PrevValue & ~RTL_SRWLOCK_MASK); 223 224 return WaitBlock; 225 } 226 227 228 static VOID 229 NTAPI 230 RtlpAcquireSRWLockExclusiveWait(IN OUT PRTL_SRWLOCK SRWLock, 231 IN PRTLP_SRWLOCK_WAITBLOCK WaitBlock) 232 { 233 LONG_PTR CurrentValue; 234 235 while (1) 236 { 237 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 238 if (!(CurrentValue & RTL_SRWLOCK_SHARED)) 239 { 240 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 241 { 242 if (WaitBlock->Wake != 0) 243 { 244 /* Our wait block became the first one 245 in the chain, we own the lock now! */ 246 break; 247 } 248 } 249 else 250 { 251 /* The last wait block was removed and/or we're 252 finally a simple exclusive lock. This means we 253 don't need to wait anymore, we acquired the lock! */ 254 break; 255 } 256 } 257 258 YieldProcessor(); 259 } 260 } 261 262 263 static VOID 264 NTAPI 265 RtlpAcquireSRWLockSharedWait(IN OUT PRTL_SRWLOCK SRWLock, 266 IN OUT PRTLP_SRWLOCK_WAITBLOCK FirstWait OPTIONAL, 267 IN OUT PRTLP_SRWLOCK_SHARED_WAKE WakeChain) 268 { 269 if (FirstWait != NULL) 270 { 271 while (WakeChain->Wake == 0) 272 { 273 YieldProcessor(); 274 } 275 } 276 else 277 { 278 LONG_PTR CurrentValue; 279 280 while (1) 281 { 282 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 283 if (CurrentValue & RTL_SRWLOCK_SHARED) 284 { 285 /* The RTL_SRWLOCK_OWNED bit always needs to be set when 286 RTL_SRWLOCK_SHARED is set! */ 287 ASSERT(CurrentValue & RTL_SRWLOCK_OWNED); 288 289 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 290 { 291 if (WakeChain->Wake != 0) 292 { 293 /* Our wait block became the first one 294 in the chain, we own the lock now! */ 295 break; 296 } 297 } 298 else 299 { 300 /* The last wait block was removed and/or we're 301 finally a simple shared lock. This means we 302 don't need to wait anymore, we acquired the lock! */ 303 break; 304 } 305 } 306 307 YieldProcessor(); 308 } 309 } 310 } 311 312 313 VOID 314 NTAPI 315 RtlInitializeSRWLock(OUT PRTL_SRWLOCK SRWLock) 316 { 317 SRWLock->Ptr = NULL; 318 } 319 320 321 VOID 322 NTAPI 323 RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock) 324 { 325 __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock; 326 RTLP_SRWLOCK_SHARED_WAKE SharedWake; 327 LONG_PTR CurrentValue, NewValue; 328 PRTLP_SRWLOCK_WAITBLOCK First, Shared, FirstWait; 329 330 while (1) 331 { 332 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 333 334 if (CurrentValue & RTL_SRWLOCK_SHARED) 335 { 336 /* NOTE: It is possible that the RTL_SRWLOCK_OWNED bit is set! */ 337 338 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 339 { 340 /* There's other waiters already, lock the wait blocks and 341 increment the shared count */ 342 First = RtlpAcquireWaitBlockLock(SRWLock); 343 if (First != NULL) 344 { 345 FirstWait = NULL; 346 347 if (First->Exclusive) 348 { 349 /* We need to setup a new wait block! Although 350 we're currently in a shared lock and we're acquiring 351 a shared lock, there are exclusive locks queued. We need 352 to wait until those are released. */ 353 Shared = First->Last; 354 355 if (Shared->Exclusive) 356 { 357 StackWaitBlock.Exclusive = FALSE; 358 StackWaitBlock.SharedCount = 1; 359 StackWaitBlock.Next = NULL; 360 StackWaitBlock.Last = &StackWaitBlock; 361 StackWaitBlock.SharedWakeChain = &SharedWake; 362 363 Shared->Next = &StackWaitBlock; 364 First->Last = &StackWaitBlock; 365 366 Shared = &StackWaitBlock; 367 FirstWait = &StackWaitBlock; 368 } 369 else 370 { 371 Shared->LastSharedWake->Next = &SharedWake; 372 Shared->SharedCount++; 373 } 374 } 375 else 376 { 377 Shared = First; 378 Shared->LastSharedWake->Next = &SharedWake; 379 Shared->SharedCount++; 380 } 381 382 SharedWake.Next = NULL; 383 SharedWake.Wake = 0; 384 385 Shared->LastSharedWake = &SharedWake; 386 387 RtlpReleaseWaitBlockLock(SRWLock); 388 389 RtlpAcquireSRWLockSharedWait(SRWLock, 390 FirstWait, 391 &SharedWake); 392 393 /* Successfully incremented the shared count, we acquired the lock */ 394 break; 395 } 396 } 397 else 398 { 399 /* This is a fastest path, just increment the number of 400 current shared locks */ 401 402 /* Since the RTL_SRWLOCK_SHARED bit is set, the RTL_SRWLOCK_OWNED bit also has 403 to be set! */ 404 405 ASSERT(CurrentValue & RTL_SRWLOCK_OWNED); 406 407 NewValue = (CurrentValue >> RTL_SRWLOCK_BITS) + 1; 408 NewValue = (NewValue << RTL_SRWLOCK_BITS) | (CurrentValue & RTL_SRWLOCK_MASK); 409 410 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 411 (PVOID)NewValue, 412 (PVOID)CurrentValue) == CurrentValue) 413 { 414 /* Successfully incremented the shared count, we acquired the lock */ 415 break; 416 } 417 } 418 } 419 else 420 { 421 if (CurrentValue & RTL_SRWLOCK_OWNED) 422 { 423 /* The resource is currently acquired exclusively */ 424 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 425 { 426 SharedWake.Next = NULL; 427 SharedWake.Wake = 0; 428 429 /* There's other waiters already, lock the wait blocks and 430 increment the shared count. If the last block in the chain 431 is an exclusive lock, add another block. */ 432 433 StackWaitBlock.Exclusive = FALSE; 434 StackWaitBlock.SharedCount = 0; 435 StackWaitBlock.Next = NULL; 436 StackWaitBlock.Last = &StackWaitBlock; 437 StackWaitBlock.SharedWakeChain = &SharedWake; 438 439 First = RtlpAcquireWaitBlockLock(SRWLock); 440 if (First != NULL) 441 { 442 Shared = First->Last; 443 if (Shared->Exclusive) 444 { 445 Shared->Next = &StackWaitBlock; 446 First->Last = &StackWaitBlock; 447 448 Shared = &StackWaitBlock; 449 FirstWait = &StackWaitBlock; 450 } 451 else 452 { 453 FirstWait = NULL; 454 Shared->LastSharedWake->Next = &SharedWake; 455 } 456 457 Shared->SharedCount++; 458 Shared->LastSharedWake = &SharedWake; 459 460 RtlpReleaseWaitBlockLock(SRWLock); 461 462 RtlpAcquireSRWLockSharedWait(SRWLock, 463 FirstWait, 464 &SharedWake); 465 466 /* Successfully incremented the shared count, we acquired the lock */ 467 break; 468 } 469 } 470 else 471 { 472 SharedWake.Next = NULL; 473 SharedWake.Wake = 0; 474 475 /* We need to setup the first wait block. Currently an exclusive lock is 476 held, change the lock to contended mode. */ 477 StackWaitBlock.Exclusive = FALSE; 478 StackWaitBlock.SharedCount = 1; 479 StackWaitBlock.Next = NULL; 480 StackWaitBlock.Last = &StackWaitBlock; 481 StackWaitBlock.SharedWakeChain = &SharedWake; 482 StackWaitBlock.LastSharedWake = &SharedWake; 483 484 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 485 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 486 (PVOID)NewValue, 487 (PVOID)CurrentValue) == CurrentValue) 488 { 489 RtlpAcquireSRWLockSharedWait(SRWLock, 490 &StackWaitBlock, 491 &SharedWake); 492 493 /* Successfully set the shared count, we acquired the lock */ 494 break; 495 } 496 } 497 } 498 else 499 { 500 /* This is a fast path, we can simply try to set the shared count to 1 */ 501 NewValue = (1 << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED; 502 503 /* The RTL_SRWLOCK_CONTENDED bit should never be set if neither the 504 RTL_SRWLOCK_SHARED nor the RTL_SRWLOCK_OWNED bit is set */ 505 ASSERT(!(CurrentValue & RTL_SRWLOCK_CONTENDED)); 506 507 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 508 (PVOID)NewValue, 509 (PVOID)CurrentValue) == CurrentValue) 510 { 511 /* Successfully set the shared count, we acquired the lock */ 512 break; 513 } 514 } 515 } 516 517 YieldProcessor(); 518 } 519 } 520 521 522 VOID 523 NTAPI 524 RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock) 525 { 526 LONG_PTR CurrentValue, NewValue; 527 PRTLP_SRWLOCK_WAITBLOCK WaitBlock; 528 BOOLEAN LastShared; 529 530 while (1) 531 { 532 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 533 534 if (CurrentValue & RTL_SRWLOCK_SHARED) 535 { 536 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 537 { 538 /* There's a wait block, we need to wake a pending 539 exclusive acquirer if this is the last shared release */ 540 WaitBlock = RtlpAcquireWaitBlockLock(SRWLock); 541 if (WaitBlock != NULL) 542 { 543 LastShared = (--WaitBlock->SharedCount == 0); 544 545 if (LastShared) 546 RtlpReleaseWaitBlockLockLastShared(SRWLock, 547 WaitBlock); 548 else 549 RtlpReleaseWaitBlockLock(SRWLock); 550 551 /* We released the lock */ 552 break; 553 } 554 } 555 else 556 { 557 /* This is a fast path, we can simply decrement the shared 558 count and store the pointer */ 559 NewValue = CurrentValue >> RTL_SRWLOCK_BITS; 560 561 if (--NewValue != 0) 562 { 563 NewValue = (NewValue << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED; 564 } 565 566 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 567 (PVOID)NewValue, 568 (PVOID)CurrentValue) == CurrentValue) 569 { 570 /* Successfully released the lock */ 571 break; 572 } 573 } 574 } 575 else 576 { 577 /* The RTL_SRWLOCK_SHARED bit has to be present now, 578 even in the contended case! */ 579 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 580 } 581 582 YieldProcessor(); 583 } 584 } 585 586 587 VOID 588 NTAPI 589 RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock) 590 { 591 __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock; 592 PRTLP_SRWLOCK_WAITBLOCK First, Last; 593 594 if (InterlockedBitTestAndSetPointer(&SRWLock->Ptr, 595 RTL_SRWLOCK_OWNED_BIT)) 596 { 597 LONG_PTR CurrentValue, NewValue; 598 599 while (1) 600 { 601 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 602 603 if (CurrentValue & RTL_SRWLOCK_SHARED) 604 { 605 /* A shared lock is being held right now. We need to add a wait block! */ 606 607 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 608 { 609 goto AddWaitBlock; 610 } 611 else 612 { 613 /* There are no wait blocks so far, we need to add ourselves as the first 614 wait block. We need to keep the shared count! */ 615 StackWaitBlock.Exclusive = TRUE; 616 StackWaitBlock.SharedCount = (LONG)(CurrentValue >> RTL_SRWLOCK_BITS); 617 StackWaitBlock.Next = NULL; 618 StackWaitBlock.Last = &StackWaitBlock; 619 StackWaitBlock.Wake = 0; 620 621 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_CONTENDED | RTL_SRWLOCK_OWNED; 622 623 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 624 (PVOID)NewValue, 625 (PVOID)CurrentValue) == CurrentValue) 626 { 627 RtlpAcquireSRWLockExclusiveWait(SRWLock, 628 &StackWaitBlock); 629 630 /* Successfully acquired the exclusive lock */ 631 break; 632 } 633 } 634 } 635 else 636 { 637 if (CurrentValue & RTL_SRWLOCK_OWNED) 638 { 639 /* An exclusive lock is being held right now. We need to add a wait block! */ 640 641 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 642 { 643 AddWaitBlock: 644 StackWaitBlock.Exclusive = TRUE; 645 StackWaitBlock.SharedCount = 0; 646 StackWaitBlock.Next = NULL; 647 StackWaitBlock.Last = &StackWaitBlock; 648 StackWaitBlock.Wake = 0; 649 650 First = RtlpAcquireWaitBlockLock(SRWLock); 651 if (First != NULL) 652 { 653 Last = First->Last; 654 Last->Next = &StackWaitBlock; 655 First->Last = &StackWaitBlock; 656 657 RtlpReleaseWaitBlockLock(SRWLock); 658 659 RtlpAcquireSRWLockExclusiveWait(SRWLock, 660 &StackWaitBlock); 661 662 /* Successfully acquired the exclusive lock */ 663 break; 664 } 665 } 666 else 667 { 668 /* There are no wait blocks so far, we need to add ourselves as the first 669 wait block. We need to keep the shared count! */ 670 StackWaitBlock.Exclusive = TRUE; 671 StackWaitBlock.SharedCount = 0; 672 StackWaitBlock.Next = NULL; 673 StackWaitBlock.Last = &StackWaitBlock; 674 StackWaitBlock.Wake = 0; 675 676 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 677 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 678 (PVOID)NewValue, 679 (PVOID)CurrentValue) == CurrentValue) 680 { 681 RtlpAcquireSRWLockExclusiveWait(SRWLock, 682 &StackWaitBlock); 683 684 /* Successfully acquired the exclusive lock */ 685 break; 686 } 687 } 688 } 689 else 690 { 691 if (!InterlockedBitTestAndSetPointer(&SRWLock->Ptr, 692 RTL_SRWLOCK_OWNED_BIT)) 693 { 694 /* We managed to get hold of a simple exclusive lock! */ 695 break; 696 } 697 } 698 } 699 700 YieldProcessor(); 701 } 702 } 703 } 704 705 706 VOID 707 NTAPI 708 RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock) 709 { 710 LONG_PTR CurrentValue, NewValue; 711 PRTLP_SRWLOCK_WAITBLOCK WaitBlock; 712 713 while (1) 714 { 715 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 716 717 if (!(CurrentValue & RTL_SRWLOCK_OWNED)) 718 { 719 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 720 } 721 722 if (!(CurrentValue & RTL_SRWLOCK_SHARED)) 723 { 724 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 725 { 726 /* There's a wait block, we need to wake the next pending 727 acquirer (exclusive or shared) */ 728 WaitBlock = RtlpAcquireWaitBlockLock(SRWLock); 729 if (WaitBlock != NULL) 730 { 731 RtlpReleaseWaitBlockLockExclusive(SRWLock, 732 WaitBlock); 733 734 /* We released the lock */ 735 break; 736 } 737 } 738 else 739 { 740 /* This is a fast path, we can simply clear the RTL_SRWLOCK_OWNED 741 bit. All other bits should be 0 now because this is a simple 742 exclusive lock and no one is waiting. */ 743 744 ASSERT(!(CurrentValue & ~RTL_SRWLOCK_OWNED)); 745 746 NewValue = 0; 747 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 748 (PVOID)NewValue, 749 (PVOID)CurrentValue) == CurrentValue) 750 { 751 /* We released the lock */ 752 break; 753 } 754 } 755 } 756 else 757 { 758 /* The RTL_SRWLOCK_SHARED bit must not be present now, 759 not even in the contended case! */ 760 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 761 } 762 763 YieldProcessor(); 764 } 765 } 766