/*++ Copyright (c) 1995 Microsoft Corporation Module Name: ntos\tdi\isn\fwd\rwlock.h Abstract: Reader-Writer lock macros Author: Vadim Eydelman Revision History: --*/ #ifndef _IPXFWD_RWLOCK_ #define _IPXFWD_RWLOCK_ typedef volatile LONG VOLCTR, *PVOLCTR; typedef PVOLCTR RWCOOKIE, *PRWCOOKIE; // Reader- writer lock. // Allows no-lock access to the tables for readers - they merely // increment the counter to record their presence upon entrance // and decrement the same counter as they leave. // Writers are supposed to be serialized (externally) and their // actions are limited to ATOMIC insertions of new elements and // ATOMIC removals/replacements. The removals/replacements MUST // be followed by a wait for all potential readers who might still // be using the element that was removed/replaced typedef struct _RW_LOCK { KEVENT Event; // Event to release waiting writer VOLCTR Ctr1; // Two alternating VOLCTR Ctr2; // reader counters volatile PVOLCTR CurCtr; // Counter currently in use } RW_LOCK, *PRW_LOCK; /*++ ******************************************************************* I n i t i a l i z e R W L o c k Routine Description: Initializes RW lock Arguments: lock - pointer to lock to initialize Return Value: None ******************************************************************* --*/ //VOID //InitializeRWLock ( // PRW_LOCK lock // ); #define InitializeRWLock(lock) { \ KeInitializeEvent (&(lock)->Event, \ SynchronizationEvent, \ FALSE); \ (lock)->Ctr1 = (lock)->Ctr2 = 0; \ (lock)->CurCtr = &(lock)->Ctr1; \ } /*++ ******************************************************************* A c q u i r e R e a d e r A c c e s s Routine Description: Acquires reader access to resource protected by the lock Arguments: lock - pointer to lock cookie - pointer to buffer to store lock state for subsequent release operation Return Value: None ******************************************************************* --*/ //VOID //AcquireReaderAccess ( // IN PRW_LOCK lock, // OUT RWCOOKIE cookie // ); #define AcquireReaderAccess(lock,cookie) \ do { \ register LONG local,local1; \ cookie = (lock)->CurCtr; /*Get current counter pointer*/ \ local = *(cookie); /*Copy counter value*/ \ local1 = local + 1; \ if ((local>=0) /*If counter is valid*/ \ /*and it hasn't changed while*/ \ /*we were checking and trying*/ \ /*to increment it,*/ \ && (InterlockedCompareExchange ( \ (PLONG)(cookie), \ local1, \ local) \ ==local)) \ break; /*then we obtained the access*/ \ } while (1) /*otherwise, we have to do it again (possibly with*/\ /*the other counter if writer switched it on us)*/ /*++ ******************************************************************* R e l e a s e R e a d e r A c c e s s Routine Description: Releases reader access to resource protected by the lock Arguments: lock - pointer to lock cookie - lock state for subsequent stored during acquire operation Return Value: None ******************************************************************* --*/ //VOID //ReleaseReaderAccess ( // IN PRW_LOCK lock, // IN RWCOOKIE cookie // ); #define ReleaseReaderAccess(lock,cookie) { \ /*If counter drops below 0, we have to signal the writer*/ \ if (InterlockedDecrement((PLONG)cookie)<0) { \ LONG res; \ ASSERT (*(cookie)==-1); \ res = KeSetEvent (&(lock)->Event, 0, FALSE); \ ASSERT (res==0); \ } \ } /*++ ******************************************************************* W a i t F o r A l l R e a d e r s Routine Description: Waits for all readers that were accessing the resource prior to the call to exit (New readers are not included) Arguments: lock - pointer to lock Return Value: None ******************************************************************* --*/ //VOID //WaitForAllReaders ( // PRW_LOCK lock // ); #define WaitForAllReaders(lock) { \ RWCOOKIE prevCtr = (lock)->CurCtr; \ /*Switch the counter first*/ \ if (prevCtr==&(lock)->Ctr1) { \ (lock)->Ctr2 = 0; \ (lock)->CurCtr = &(lock)->Ctr2; \ } \ else { \ ASSERT (prevCtr==&(lock)->Ctr2); \ (lock)->Ctr1 = 0; \ (lock)->CurCtr = &(lock)->Ctr1; \ } \ /* If not all readers are gone, we'll have to wait for them*/ \ if (InterlockedDecrement((PLONG)prevCtr)>=0) { \ NTSTATUS status \ = KeWaitForSingleObject ( \ &(lock)->Event, \ Executive, \ ExGetPreviousMode(),\ FALSE, \ 0); \ ASSERT (NT_SUCCESS(status)); \ ASSERT (*prevCtr==-1); \ } \ } #endif