windows-nt/Source/XPSP1/NT/net/nwlink/fwd/rwlock.h

180 lines
7.7 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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