ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

srw.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.