Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygensrw.c
Go to the documentation of this file.
00001 /* 00002 * COPYRIGHT: See COPYING in the top level directory 00003 * PROJECT: ReactOS system libraries 00004 * PURPOSE: Slim Reader/Writer (SRW) Routines 00005 * PROGRAMMER: Thomas Weidenmueller <w3seek@reactos.com> 00006 * 00007 * NOTES: The algorithms used in this implementation 00008 * may be different from Vista's implementation. 00009 * Since applications should treat the RTL_SRWLOCK 00010 * structure as opaque data, it should not matter. 00011 * The algorithms are probably not as optimized. 00012 */ 00013 00014 /* INCLUDES *****************************************************************/ 00015 00016 #include <rtl.h> 00017 00018 #define NDEBUG 00019 #include <debug.h> 00020 00021 /* FUNCTIONS *****************************************************************/ 00022 00023 #ifdef _WIN64 00024 #define InterlockedBitTestAndSetPointer(ptr,val) InterlockedBitTestAndSet64((PLONGLONG)ptr,(LONGLONG)val) 00025 #define InterlockedAddPointer(ptr,val) InterlockedAdd64((PLONGLONG)ptr,(LONGLONG)val) 00026 #define InterlockedAndPointer(ptr,val) InterlockedAnd64((PLONGLONG)ptr,(LONGLONG)val) 00027 #define InterlockedOrPointer(ptr,val) InterlockedOr64((PLONGLONG)ptr,(LONGLONG)val) 00028 #else 00029 #define InterlockedBitTestAndSetPointer(ptr,val) InterlockedBitTestAndSet((PLONG)ptr,(LONG)val) 00030 #define InterlockedAddPointer(ptr,val) InterlockedAdd((PLONG)ptr,(LONG)val) 00031 #define InterlockedAndPointer(ptr,val) InterlockedAnd((PLONG)ptr,(LONG)val) 00032 #define InterlockedOrPointer(ptr,val) InterlockedOr((PLONG)ptr,(LONG)val) 00033 #endif 00034 00035 #define RTL_SRWLOCK_OWNED_BIT 0 00036 #define RTL_SRWLOCK_CONTENDED_BIT 1 00037 #define RTL_SRWLOCK_SHARED_BIT 2 00038 #define RTL_SRWLOCK_CONTENTION_LOCK_BIT 3 00039 #define RTL_SRWLOCK_OWNED (1 << RTL_SRWLOCK_OWNED_BIT) 00040 #define RTL_SRWLOCK_CONTENDED (1 << RTL_SRWLOCK_CONTENDED_BIT) 00041 #define RTL_SRWLOCK_SHARED (1 << RTL_SRWLOCK_SHARED_BIT) 00042 #define RTL_SRWLOCK_CONTENTION_LOCK (1 << RTL_SRWLOCK_CONTENTION_LOCK_BIT) 00043 #define RTL_SRWLOCK_MASK (RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED | \ 00044 RTL_SRWLOCK_SHARED | RTL_SRWLOCK_CONTENTION_LOCK) 00045 #define RTL_SRWLOCK_BITS 4 00046 00047 #if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 40300) || \ 00048 (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ == 40303) 00049 /* This macro will cause the code to assert if compiled with a buggy 00050 version of GCC that doesn't align the wait blocks properly on the stack! */ 00051 #define ASSERT_SRW_WAITBLOCK(ptr) \ 00052 ASSERT(((ULONG_PTR)ptr & ((1 << RTL_SRWLOCK_BITS) - 1)) == 0) 00053 #else 00054 #define ASSERT_SRW_WAITBLOCK(ptr) ((void)0) 00055 #endif 00056 00057 typedef struct _RTLP_SRWLOCK_SHARED_WAKE 00058 { 00059 LONG Wake; 00060 volatile struct _RTLP_SRWLOCK_SHARED_WAKE *Next; 00061 } volatile RTLP_SRWLOCK_SHARED_WAKE, *PRTLP_SRWLOCK_SHARED_WAKE; 00062 00063 typedef struct _RTLP_SRWLOCK_WAITBLOCK 00064 { 00065 /* SharedCount is the number of shared acquirers. */ 00066 LONG SharedCount; 00067 00068 /* Last points to the last wait block in the chain. The value 00069 is only valid when read from the first wait block. */ 00070 volatile struct _RTLP_SRWLOCK_WAITBLOCK *Last; 00071 00072 /* Next points to the next wait block in the chain. */ 00073 volatile struct _RTLP_SRWLOCK_WAITBLOCK *Next; 00074 00075 union 00076 { 00077 /* Wake is only valid for exclusive wait blocks */ 00078 LONG Wake; 00079 /* The wake chain is only valid for shared wait blocks */ 00080 struct 00081 { 00082 PRTLP_SRWLOCK_SHARED_WAKE SharedWakeChain; 00083 PRTLP_SRWLOCK_SHARED_WAKE LastSharedWake; 00084 }; 00085 }; 00086 00087 BOOLEAN Exclusive; 00088 } volatile RTLP_SRWLOCK_WAITBLOCK, *PRTLP_SRWLOCK_WAITBLOCK; 00089 00090 00091 static VOID 00092 NTAPI 00093 RtlpReleaseWaitBlockLockExclusive(IN OUT PRTL_SRWLOCK SRWLock, 00094 IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock) 00095 { 00096 PRTLP_SRWLOCK_WAITBLOCK Next; 00097 LONG_PTR NewValue; 00098 00099 /* NOTE: We're currently in an exclusive lock in contended mode. */ 00100 00101 Next = FirstWaitBlock->Next; 00102 if (Next != NULL) 00103 { 00104 /* There's more blocks chained, we need to update the pointers 00105 in the next wait block and update the wait block pointer. */ 00106 NewValue = (LONG_PTR)Next | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 00107 if (!FirstWaitBlock->Exclusive) 00108 { 00109 /* The next wait block has to be an exclusive lock! */ 00110 ASSERT(Next->Exclusive); 00111 00112 /* Save the shared count */ 00113 Next->SharedCount = FirstWaitBlock->SharedCount; 00114 00115 NewValue |= RTL_SRWLOCK_SHARED; 00116 } 00117 00118 Next->Last = FirstWaitBlock->Last; 00119 } 00120 else 00121 { 00122 /* Convert the lock to a simple lock. */ 00123 if (FirstWaitBlock->Exclusive) 00124 NewValue = RTL_SRWLOCK_OWNED; 00125 else 00126 { 00127 ASSERT(FirstWaitBlock->SharedCount > 0); 00128 00129 NewValue = ((LONG_PTR)FirstWaitBlock->SharedCount << RTL_SRWLOCK_BITS) | 00130 RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED; 00131 } 00132 } 00133 00134 (void)InterlockedExchangePointer(&SRWLock->Ptr, (PVOID)NewValue); 00135 00136 if (FirstWaitBlock->Exclusive) 00137 { 00138 (void)InterlockedOr(&FirstWaitBlock->Wake, 00139 TRUE); 00140 } 00141 else 00142 { 00143 PRTLP_SRWLOCK_SHARED_WAKE WakeChain, Next; 00144 00145 /* If we were the first one to acquire the shared 00146 lock, we now need to wake all others... */ 00147 WakeChain = FirstWaitBlock->SharedWakeChain; 00148 do 00149 { 00150 Next = WakeChain->Next; 00151 00152 (void)InterlockedOr((PLONG)&WakeChain->Wake, 00153 TRUE); 00154 00155 WakeChain = Next; 00156 } while (WakeChain != NULL); 00157 } 00158 } 00159 00160 00161 static VOID 00162 NTAPI 00163 RtlpReleaseWaitBlockLockLastShared(IN OUT PRTL_SRWLOCK SRWLock, 00164 IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock) 00165 { 00166 PRTLP_SRWLOCK_WAITBLOCK Next; 00167 LONG_PTR NewValue; 00168 00169 /* NOTE: We're currently in a shared lock in contended mode. */ 00170 00171 /* The next acquirer to be unwaited *must* be an exclusive lock! */ 00172 ASSERT(FirstWaitBlock->Exclusive); 00173 00174 Next = FirstWaitBlock->Next; 00175 if (Next != NULL) 00176 { 00177 /* There's more blocks chained, we need to update the pointers 00178 in the next wait block and update the wait block pointer. */ 00179 NewValue = (LONG_PTR)Next | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 00180 00181 Next->Last = FirstWaitBlock->Last; 00182 } 00183 else 00184 { 00185 /* Convert the lock to a simple exclusive lock. */ 00186 NewValue = RTL_SRWLOCK_OWNED; 00187 } 00188 00189 (void)InterlockedExchangePointer(&SRWLock->Ptr, (PVOID)NewValue); 00190 00191 (void)InterlockedOr(&FirstWaitBlock->Wake, 00192 TRUE); 00193 } 00194 00195 00196 static VOID 00197 NTAPI 00198 RtlpReleaseWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock) 00199 { 00200 InterlockedAndPointer(&SRWLock->Ptr, 00201 ~RTL_SRWLOCK_CONTENTION_LOCK); 00202 } 00203 00204 00205 static PRTLP_SRWLOCK_WAITBLOCK 00206 NTAPI 00207 RtlpAcquireWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock) 00208 { 00209 LONG_PTR PrevValue; 00210 PRTLP_SRWLOCK_WAITBLOCK WaitBlock; 00211 00212 while (1) 00213 { 00214 PrevValue = InterlockedOrPointer(&SRWLock->Ptr, 00215 RTL_SRWLOCK_CONTENTION_LOCK); 00216 00217 if (!(PrevValue & RTL_SRWLOCK_CONTENTION_LOCK)) 00218 break; 00219 00220 YieldProcessor(); 00221 } 00222 00223 if (!(PrevValue & RTL_SRWLOCK_CONTENDED) || 00224 (PrevValue & ~RTL_SRWLOCK_MASK) == 0) 00225 { 00226 /* Too bad, looks like the wait block was removed in the 00227 meanwhile, unlock again */ 00228 RtlpReleaseWaitBlockLock(SRWLock); 00229 return NULL; 00230 } 00231 00232 WaitBlock = (PRTLP_SRWLOCK_WAITBLOCK)(PrevValue & ~RTL_SRWLOCK_MASK); 00233 00234 ASSERT_SRW_WAITBLOCK(WaitBlock); 00235 return WaitBlock; 00236 } 00237 00238 00239 static VOID 00240 NTAPI 00241 RtlpAcquireSRWLockExclusiveWait(IN OUT PRTL_SRWLOCK SRWLock, 00242 IN PRTLP_SRWLOCK_WAITBLOCK WaitBlock) 00243 { 00244 LONG_PTR CurrentValue; 00245 00246 while (1) 00247 { 00248 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 00249 if (!(CurrentValue & RTL_SRWLOCK_SHARED)) 00250 { 00251 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00252 { 00253 if (WaitBlock->Wake != 0) 00254 { 00255 /* Our wait block became the first one 00256 in the chain, we own the lock now! */ 00257 break; 00258 } 00259 } 00260 else 00261 { 00262 /* The last wait block was removed and/or we're 00263 finally a simple exclusive lock. This means we 00264 don't need to wait anymore, we acquired the lock! */ 00265 break; 00266 } 00267 } 00268 00269 YieldProcessor(); 00270 } 00271 } 00272 00273 00274 static VOID 00275 NTAPI 00276 RtlpAcquireSRWLockSharedWait(IN OUT PRTL_SRWLOCK SRWLock, 00277 IN OUT PRTLP_SRWLOCK_WAITBLOCK FirstWait OPTIONAL, 00278 IN OUT PRTLP_SRWLOCK_SHARED_WAKE WakeChain) 00279 { 00280 if (FirstWait != NULL) 00281 { 00282 while (WakeChain->Wake == 0) 00283 { 00284 YieldProcessor(); 00285 } 00286 } 00287 else 00288 { 00289 LONG_PTR CurrentValue; 00290 00291 while (1) 00292 { 00293 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 00294 if (CurrentValue & RTL_SRWLOCK_SHARED) 00295 { 00296 /* The RTL_SRWLOCK_OWNED bit always needs to be set when 00297 RTL_SRWLOCK_SHARED is set! */ 00298 ASSERT(CurrentValue & RTL_SRWLOCK_OWNED); 00299 00300 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00301 { 00302 if (WakeChain->Wake != 0) 00303 { 00304 /* Our wait block became the first one 00305 in the chain, we own the lock now! */ 00306 break; 00307 } 00308 } 00309 else 00310 { 00311 /* The last wait block was removed and/or we're 00312 finally a simple shared lock. This means we 00313 don't need to wait anymore, we acquired the lock! */ 00314 break; 00315 } 00316 } 00317 00318 YieldProcessor(); 00319 } 00320 } 00321 } 00322 00323 00324 VOID 00325 NTAPI 00326 RtlInitializeSRWLock(OUT PRTL_SRWLOCK SRWLock) 00327 { 00328 SRWLock->Ptr = NULL; 00329 } 00330 00331 00332 VOID 00333 NTAPI 00334 RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock) 00335 { 00336 __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock; 00337 RTLP_SRWLOCK_SHARED_WAKE SharedWake; 00338 LONG_PTR CurrentValue, NewValue; 00339 PRTLP_SRWLOCK_WAITBLOCK First, Shared, FirstWait; 00340 00341 while (1) 00342 { 00343 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 00344 00345 if (CurrentValue & RTL_SRWLOCK_SHARED) 00346 { 00347 /* NOTE: It is possible that the RTL_SRWLOCK_OWNED bit is set! */ 00348 00349 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00350 { 00351 /* There's other waiters already, lock the wait blocks and 00352 increment the shared count */ 00353 First = RtlpAcquireWaitBlockLock(SRWLock); 00354 if (First != NULL) 00355 { 00356 FirstWait = NULL; 00357 00358 if (First->Exclusive) 00359 { 00360 /* We need to setup a new wait block! Although 00361 we're currently in a shared lock and we're acquiring 00362 a shared lock, there are exclusive locks queued. We need 00363 to wait until those are released. */ 00364 Shared = First->Last; 00365 00366 if (Shared->Exclusive) 00367 { 00368 StackWaitBlock.Exclusive = FALSE; 00369 StackWaitBlock.SharedCount = 1; 00370 StackWaitBlock.Next = NULL; 00371 StackWaitBlock.Last = &StackWaitBlock; 00372 StackWaitBlock.SharedWakeChain = &SharedWake; 00373 00374 Shared->Next = &StackWaitBlock; 00375 First->Last = &StackWaitBlock; 00376 00377 Shared = &StackWaitBlock; 00378 FirstWait = &StackWaitBlock; 00379 } 00380 else 00381 { 00382 Shared->LastSharedWake->Next = &SharedWake; 00383 Shared->SharedCount++; 00384 } 00385 } 00386 else 00387 { 00388 Shared = First; 00389 Shared->LastSharedWake->Next = &SharedWake; 00390 Shared->SharedCount++; 00391 } 00392 00393 SharedWake.Next = NULL; 00394 SharedWake.Wake = 0; 00395 00396 Shared->LastSharedWake = &SharedWake; 00397 00398 ASSERT_SRW_WAITBLOCK(Shared); 00399 00400 RtlpReleaseWaitBlockLock(SRWLock); 00401 00402 RtlpAcquireSRWLockSharedWait(SRWLock, 00403 FirstWait, 00404 &SharedWake); 00405 00406 /* Successfully incremented the shared count, we acquired the lock */ 00407 break; 00408 } 00409 } 00410 else 00411 { 00412 /* This is a fastest path, just increment the number of 00413 current shared locks */ 00414 00415 /* Since the RTL_SRWLOCK_SHARED bit is set, the RTL_SRWLOCK_OWNED bit also has 00416 to be set! */ 00417 00418 ASSERT(CurrentValue & RTL_SRWLOCK_OWNED); 00419 00420 NewValue = (CurrentValue >> RTL_SRWLOCK_BITS) + 1; 00421 NewValue = (NewValue << RTL_SRWLOCK_BITS) | (CurrentValue & RTL_SRWLOCK_MASK); 00422 00423 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00424 (PVOID)NewValue, 00425 (PVOID)CurrentValue) == CurrentValue) 00426 { 00427 /* Successfully incremented the shared count, we acquired the lock */ 00428 break; 00429 } 00430 } 00431 } 00432 else 00433 { 00434 if (CurrentValue & RTL_SRWLOCK_OWNED) 00435 { 00436 /* The resource is currently acquired exclusively */ 00437 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00438 { 00439 SharedWake.Next = NULL; 00440 SharedWake.Wake = 0; 00441 00442 /* There's other waiters already, lock the wait blocks and 00443 increment the shared count. If the last block in the chain 00444 is an exclusive lock, add another block. */ 00445 00446 StackWaitBlock.Exclusive = FALSE; 00447 StackWaitBlock.SharedCount = 0; 00448 StackWaitBlock.Next = NULL; 00449 StackWaitBlock.Last = &StackWaitBlock; 00450 StackWaitBlock.SharedWakeChain = &SharedWake; 00451 00452 First = RtlpAcquireWaitBlockLock(SRWLock); 00453 if (First != NULL) 00454 { 00455 Shared = First->Last; 00456 if (Shared->Exclusive) 00457 { 00458 Shared->Next = &StackWaitBlock; 00459 First->Last = &StackWaitBlock; 00460 00461 Shared = &StackWaitBlock; 00462 FirstWait = &StackWaitBlock; 00463 } 00464 else 00465 { 00466 FirstWait = NULL; 00467 Shared->LastSharedWake->Next = &SharedWake; 00468 } 00469 00470 ASSERT_SRW_WAITBLOCK(Shared); 00471 00472 Shared->SharedCount++; 00473 Shared->LastSharedWake = &SharedWake; 00474 00475 RtlpReleaseWaitBlockLock(SRWLock); 00476 00477 RtlpAcquireSRWLockSharedWait(SRWLock, 00478 FirstWait, 00479 &SharedWake); 00480 00481 /* Successfully incremented the shared count, we acquired the lock */ 00482 break; 00483 } 00484 } 00485 else 00486 { 00487 SharedWake.Next = NULL; 00488 SharedWake.Wake = 0; 00489 00490 /* We need to setup the first wait block. Currently an exclusive lock is 00491 held, change the lock to contended mode. */ 00492 StackWaitBlock.Exclusive = FALSE; 00493 StackWaitBlock.SharedCount = 1; 00494 StackWaitBlock.Next = NULL; 00495 StackWaitBlock.Last = &StackWaitBlock; 00496 StackWaitBlock.SharedWakeChain = &SharedWake; 00497 StackWaitBlock.LastSharedWake = &SharedWake; 00498 00499 ASSERT_SRW_WAITBLOCK(&StackWaitBlock); 00500 00501 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 00502 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00503 (PVOID)NewValue, 00504 (PVOID)CurrentValue) == CurrentValue) 00505 { 00506 RtlpAcquireSRWLockSharedWait(SRWLock, 00507 &StackWaitBlock, 00508 &SharedWake); 00509 00510 /* Successfully set the shared count, we acquired the lock */ 00511 break; 00512 } 00513 } 00514 } 00515 else 00516 { 00517 /* This is a fast path, we can simply try to set the shared count to 1 */ 00518 NewValue = (1 << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED; 00519 00520 /* The RTL_SRWLOCK_CONTENDED bit should never be set if neither the 00521 RTL_SRWLOCK_SHARED nor the RTL_SRWLOCK_OWNED bit is set */ 00522 ASSERT(!(CurrentValue & RTL_SRWLOCK_CONTENDED)); 00523 00524 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00525 (PVOID)NewValue, 00526 (PVOID)CurrentValue) == CurrentValue) 00527 { 00528 /* Successfully set the shared count, we acquired the lock */ 00529 break; 00530 } 00531 } 00532 } 00533 00534 YieldProcessor(); 00535 } 00536 } 00537 00538 00539 VOID 00540 NTAPI 00541 RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock) 00542 { 00543 LONG_PTR CurrentValue, NewValue; 00544 PRTLP_SRWLOCK_WAITBLOCK WaitBlock; 00545 BOOLEAN LastShared; 00546 00547 while (1) 00548 { 00549 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 00550 00551 if (CurrentValue & RTL_SRWLOCK_SHARED) 00552 { 00553 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00554 { 00555 /* There's a wait block, we need to wake a pending 00556 exclusive acquirer if this is the last shared release */ 00557 WaitBlock = RtlpAcquireWaitBlockLock(SRWLock); 00558 if (WaitBlock != NULL) 00559 { 00560 LastShared = (--WaitBlock->SharedCount == 0); 00561 00562 if (LastShared) 00563 RtlpReleaseWaitBlockLockLastShared(SRWLock, 00564 WaitBlock); 00565 else 00566 RtlpReleaseWaitBlockLock(SRWLock); 00567 00568 /* We released the lock */ 00569 break; 00570 } 00571 } 00572 else 00573 { 00574 /* This is a fast path, we can simply decrement the shared 00575 count and store the pointer */ 00576 NewValue = CurrentValue >> RTL_SRWLOCK_BITS; 00577 00578 if (--NewValue != 0) 00579 { 00580 NewValue = (NewValue << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED; 00581 } 00582 00583 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00584 (PVOID)NewValue, 00585 (PVOID)CurrentValue) == CurrentValue) 00586 { 00587 /* Successfully released the lock */ 00588 break; 00589 } 00590 } 00591 } 00592 else 00593 { 00594 /* The RTL_SRWLOCK_SHARED bit has to be present now, 00595 even in the contended case! */ 00596 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 00597 } 00598 00599 YieldProcessor(); 00600 } 00601 } 00602 00603 00604 VOID 00605 NTAPI 00606 RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock) 00607 { 00608 __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock; 00609 PRTLP_SRWLOCK_WAITBLOCK First, Last; 00610 00611 if (InterlockedBitTestAndSetPointer(&SRWLock->Ptr, 00612 RTL_SRWLOCK_OWNED_BIT)) 00613 { 00614 LONG_PTR CurrentValue, NewValue; 00615 00616 while (1) 00617 { 00618 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 00619 00620 if (CurrentValue & RTL_SRWLOCK_SHARED) 00621 { 00622 /* A shared lock is being held right now. We need to add a wait block! */ 00623 00624 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00625 { 00626 goto AddWaitBlock; 00627 } 00628 else 00629 { 00630 /* There are no wait blocks so far, we need to add ourselves as the first 00631 wait block. We need to keep the shared count! */ 00632 StackWaitBlock.Exclusive = TRUE; 00633 StackWaitBlock.SharedCount = (LONG)(CurrentValue >> RTL_SRWLOCK_BITS); 00634 StackWaitBlock.Next = NULL; 00635 StackWaitBlock.Last = &StackWaitBlock; 00636 StackWaitBlock.Wake = 0; 00637 00638 ASSERT_SRW_WAITBLOCK(&StackWaitBlock); 00639 00640 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_CONTENDED | RTL_SRWLOCK_OWNED; 00641 00642 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00643 (PVOID)NewValue, 00644 (PVOID)CurrentValue) == CurrentValue) 00645 { 00646 RtlpAcquireSRWLockExclusiveWait(SRWLock, 00647 &StackWaitBlock); 00648 00649 /* Successfully acquired the exclusive lock */ 00650 break; 00651 } 00652 } 00653 } 00654 else 00655 { 00656 if (CurrentValue & RTL_SRWLOCK_OWNED) 00657 { 00658 /* An exclusive lock is being held right now. We need to add a wait block! */ 00659 00660 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00661 { 00662 AddWaitBlock: 00663 StackWaitBlock.Exclusive = TRUE; 00664 StackWaitBlock.SharedCount = 0; 00665 StackWaitBlock.Next = NULL; 00666 StackWaitBlock.Last = &StackWaitBlock; 00667 StackWaitBlock.Wake = 0; 00668 00669 ASSERT_SRW_WAITBLOCK(&StackWaitBlock); 00670 00671 First = RtlpAcquireWaitBlockLock(SRWLock); 00672 if (First != NULL) 00673 { 00674 Last = First->Last; 00675 Last->Next = &StackWaitBlock; 00676 First->Last = &StackWaitBlock; 00677 00678 RtlpReleaseWaitBlockLock(SRWLock); 00679 00680 RtlpAcquireSRWLockExclusiveWait(SRWLock, 00681 &StackWaitBlock); 00682 00683 /* Successfully acquired the exclusive lock */ 00684 break; 00685 } 00686 } 00687 else 00688 { 00689 /* There are no wait blocks so far, we need to add ourselves as the first 00690 wait block. We need to keep the shared count! */ 00691 StackWaitBlock.Exclusive = TRUE; 00692 StackWaitBlock.SharedCount = 0; 00693 StackWaitBlock.Next = NULL; 00694 StackWaitBlock.Last = &StackWaitBlock; 00695 StackWaitBlock.Wake = 0; 00696 00697 ASSERT_SRW_WAITBLOCK(&StackWaitBlock); 00698 00699 NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; 00700 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00701 (PVOID)NewValue, 00702 (PVOID)CurrentValue) == CurrentValue) 00703 { 00704 RtlpAcquireSRWLockExclusiveWait(SRWLock, 00705 &StackWaitBlock); 00706 00707 /* Successfully acquired the exclusive lock */ 00708 break; 00709 } 00710 } 00711 } 00712 else 00713 { 00714 if (!InterlockedBitTestAndSetPointer(&SRWLock->Ptr, 00715 RTL_SRWLOCK_OWNED_BIT)) 00716 { 00717 /* We managed to get hold of a simple exclusive lock! */ 00718 break; 00719 } 00720 } 00721 } 00722 00723 YieldProcessor(); 00724 } 00725 } 00726 } 00727 00728 00729 VOID 00730 NTAPI 00731 RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock) 00732 { 00733 LONG_PTR CurrentValue, NewValue; 00734 PRTLP_SRWLOCK_WAITBLOCK WaitBlock; 00735 00736 while (1) 00737 { 00738 CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr; 00739 00740 if (!(CurrentValue & RTL_SRWLOCK_OWNED)) 00741 { 00742 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 00743 } 00744 00745 if (!(CurrentValue & RTL_SRWLOCK_SHARED)) 00746 { 00747 if (CurrentValue & RTL_SRWLOCK_CONTENDED) 00748 { 00749 /* There's a wait block, we need to wake the next pending 00750 acquirer (exclusive or shared) */ 00751 WaitBlock = RtlpAcquireWaitBlockLock(SRWLock); 00752 if (WaitBlock != NULL) 00753 { 00754 RtlpReleaseWaitBlockLockExclusive(SRWLock, 00755 WaitBlock); 00756 00757 /* We released the lock */ 00758 break; 00759 } 00760 } 00761 else 00762 { 00763 /* This is a fast path, we can simply clear the RTL_SRWLOCK_OWNED 00764 bit. All other bits should be 0 now because this is a simple 00765 exclusive lock and no one is waiting. */ 00766 00767 ASSERT(!(CurrentValue & ~RTL_SRWLOCK_OWNED)); 00768 00769 NewValue = 0; 00770 if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, 00771 (PVOID)NewValue, 00772 (PVOID)CurrentValue) == CurrentValue) 00773 { 00774 /* We released the lock */ 00775 break; 00776 } 00777 } 00778 } 00779 else 00780 { 00781 /* The RTL_SRWLOCK_SHARED bit must not be present now, 00782 not even in the contended case! */ 00783 RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED); 00784 } 00785 00786 YieldProcessor(); 00787 } 00788 } Generated on Fri May 25 2012 04:34:52 for ReactOS by
1.7.6.1
|