Author: weiden
Date: Wed Aug 30 23:02:42 2006
New Revision: 23806
URL:
http://svn.reactos.org/svn/reactos?rev=23806&view=rev
Log:
Implement Slim Reader/Writer (SRW) locks:
- Implement AcquireSRWLockExclusive(), AcquireSRWLockShared(), InitializeSRWLock(),
ReleaseSRWLockExclusive(), ReleaseSRWLockShared()
- NOTE: Some versions of GCC have a code generation bug with specially aligned structures
on the stack. If compiled with such a compiler, the code might trigger special assertions.
Pushlocks are also affected by this compiler bug.
- NOTE: The algorithms are most likely not the same as in Windows. Applications are
supposed to treat the lock variables as opaque data, therefore it shouldn't matter.
Added:
trunk/reactos/lib/rtl/srw.c (with props)
Modified:
trunk/reactos/dll/ntdll/def/ntdll.def
trunk/reactos/dll/win32/kernel32/kernel32.def
trunk/reactos/include/psdk/winbase.h
trunk/reactos/include/psdk/winnt.h
trunk/reactos/lib/rtl/rtl.rbuild
Modified: trunk/reactos/dll/ntdll/def/ntdll.def
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/ntdll/def/ntdll.def?re…
==============================================================================
--- trunk/reactos/dll/ntdll/def/ntdll.def (original)
+++ trunk/reactos/dll/ntdll/def/ntdll.def Wed Aug 30 23:02:42 2006
@@ -295,6 +295,8 @@
RtlAcquirePebLock@0
RtlAcquireResourceExclusive@8
RtlAcquireResourceShared@8
+RtlAcquireSRWLockExclusive@4
+RtlAcquireSRWLockShared@4
RtlAddAccessAllowedAce@16
RtlAddAccessAllowedAceEx@20
RtlAddAccessAllowedObjectAce@28
@@ -513,6 +515,7 @@
RtlInitializeResource@4
;RtlInitializeRXact
RtlInitializeSid@12
+RtlInitializeSRWLock@4
RtlInsertElementGenericTable@16
RtlInsertElementGenericTableAvl@16
RtlInsertElementGenericTableFull@24
@@ -612,6 +615,8 @@
RtlReleasePebLock@0
RtlReleaseRelativeName@4
RtlReleaseResource@4
+RtlReleaseSRWLockExclusive@4
+RtlReleaseSRWLockShared@4
;RtlRemoteCall
RtlRemoveVectoredExceptionHandler@4
RtlResetRtlTranslations@4
Modified: trunk/reactos/dll/win32/kernel32/kernel32.def
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/kernel32/kernel3…
==============================================================================
--- trunk/reactos/dll/win32/kernel32/kernel32.def (original)
+++ trunk/reactos/dll/win32/kernel32/kernel32.def Wed Aug 30 23:02:42 2006
@@ -30,6 +30,8 @@
;
LIBRARY KERNEL32.DLL
EXPORTS
+AcquireSRWLockExclusive(a)4=NTDLL.RtlAcquireSRWLockExclusive
+AcquireSRWLockShared(a)4=NTDLL.RtlAcquireSRWLockShared
ActivateActCtx@8
AddAtomA@4
AddAtomW@4
@@ -587,6 +589,7 @@
InitializeCriticalSection@4
InitializeCriticalSectionAndSpinCount@8
InitializeSListHead(a)4=NTDLL.RtlInitializeSListHead
+InitializeSRWLock(a)4=NTDLL.RtlInitializeSRWLock
InterlockedCompareExchange@12
InterlockedDecrement@4
InterlockedExchange@8
@@ -749,6 +752,8 @@
ReleaseActCtx@4
ReleaseMutex@4
ReleaseSemaphore@12
+ReleaseSRWLockExclusive(a)4=NTDLL.RtlReleaseSRWLockExclusive
+ReleaseSRWLockShared(a)4=NTDLL.RtlReleaseSRWLockShared
RemoveDirectoryA@4
RemoveDirectoryW@4
;RemoveLocalAlternateComputerNameA
Modified: trunk/reactos/include/psdk/winbase.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/psdk/winbase.h?rev…
==============================================================================
--- trunk/reactos/include/psdk/winbase.h (original)
+++ trunk/reactos/include/psdk/winbase.h Wed Aug 30 23:02:42 2006
@@ -540,6 +540,9 @@
#define CREATE_EVENT_INITIAL_SET 0x2
#define CREATE_MUTEX_INITIAL_OWNER 0x1
#define CREATE_WAITABLE_TIMER_MANUAL_RESET 0x1
+#define SRWLOCK_INIT RTL_SRWLOCK_INIT
+#define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
+#define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
#endif
#ifndef RC_INVOKED
@@ -1053,6 +1056,9 @@
DWORD MemberLevel;
DWORD Flags;
} JOB_SET_ARRAY, *PJOB_SET_ARRAY;
+#if (_WIN32_WINNT >= 0x0600)
+typedef RTL_SRWLOCK SRWLOCK, *PSRWLOCK;
+#endif
typedef DWORD(WINAPI
*LPPROGRESS_ROUTINE)(LARGE_INTEGER,LARGE_INTEGER,LARGE_INTEGER,LARGE_INTEGER,DWORD,DWORD,HANDLE,HANDLE,LPVOID);
typedef void(WINAPI *LPFIBER_START_ROUTINE)(PVOID);
typedef VOID (WINAPI *PFLS_CALLBACK_FUNCTION)(PVOID);
@@ -1093,6 +1099,10 @@
BOOL WINAPI
AccessCheck(PSECURITY_DESCRIPTOR,HANDLE,DWORD,PGENERIC_MAPPING,PPRIVILEGE_SET,PDWORD,PDWORD,PBOOL);
BOOL WINAPI
AccessCheckAndAuditAlarmA(LPCSTR,LPVOID,LPSTR,LPSTR,PSECURITY_DESCRIPTOR,DWORD,PGENERIC_MAPPING,BOOL,PDWORD,PBOOL,PBOOL);
BOOL WINAPI
AccessCheckAndAuditAlarmW(LPCWSTR,LPVOID,LPWSTR,LPWSTR,PSECURITY_DESCRIPTOR,DWORD,PGENERIC_MAPPING,BOOL,PDWORD,PBOOL,PBOOL);
+#if (_WIN32_WINNT >= 0x0600)
+VOID WINAPI AcquireSRWLockExclusive(PSRWLOCK);
+VOID WINAPI AcquireSRWLockShared(PSRWLOCK);
+#endif
#if (_WIN32_WINNT >= 0x0501)
BOOL WINAPI ActivateActCtx(HANDLE,ULONG_PTR*);
#endif
@@ -1659,6 +1669,9 @@
BOOL WINAPI InitializeSid (PSID,PSID_IDENTIFIER_AUTHORITY,BYTE);
#if !defined(__WINDDK_H) && _WIN32_WINNT >= 0x0501
VOID WINAPI InitializeSListHead(PSLIST_HEADER);
+#endif
+#if (_WIN32_WINNT >= 0x0600)
+VOID WINAPI InitializeSRWLock(PSRWLOCK);
#endif
#ifndef __INTERLOCKED_DECLARED
#define __INTERLOCKED_DECLARED
@@ -1842,6 +1855,10 @@
#endif
BOOL WINAPI ReleaseMutex(HANDLE);
BOOL WINAPI ReleaseSemaphore(HANDLE,LONG,LPLONG);
+#if (_WIN32_WINNT >= 0x0600)
+VOID WINAPI ReleaseSRWLockExclusive(PSRWLOCK);
+VOID WINAPI ReleaseSRWLockShared(PSRWLOCK);
+#endif
BOOL WINAPI RemoveDirectoryA(LPCSTR);
BOOL WINAPI RemoveDirectoryW(LPCWSTR);
#if (_WIN32_WINNT >= 0x0500)
Modified: trunk/reactos/include/psdk/winnt.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/psdk/winnt.h?rev=2…
==============================================================================
--- trunk/reactos/include/psdk/winnt.h (original)
+++ trunk/reactos/include/psdk/winnt.h Wed Aug 30 23:02:42 2006
@@ -2626,6 +2626,19 @@
} RTL_CRITICAL_SECTION,*PRTL_CRITICAL_SECTION;
#endif
+#define RTL_SRWLOCK_INIT {0}
+typedef struct _RTL_SRWLOCK
+{
+ PVOID Ptr;
+} RTL_SRWLOCK, *PRTL_SRWLOCK;
+
+#define RTL_CONDITION_VARIABLE_INIT {0}
+#define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED 0x1
+typedef struct _RTL_CONDITION_VARIABLE
+{
+ PVOID Ptr;
+} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
+
typedef LONG
(NTAPI *PVECTORED_EXCEPTION_HANDLER)(
struct _EXCEPTION_POINTERS *ExceptionInfo
Modified: trunk/reactos/lib/rtl/rtl.rbuild
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/rtl.rbuild?rev=238…
==============================================================================
--- trunk/reactos/lib/rtl/rtl.rbuild (original)
+++ trunk/reactos/lib/rtl/rtl.rbuild Wed Aug 30 23:02:42 2006
@@ -84,6 +84,7 @@
<file>security.c</file>
<file>sid.c</file>
<file>sprintf.c</file>
+ <file>srw.c</file>
<file>swprintf.c</file>
<file>splaytree.c</file>
<file>thread.c</file>
Added: trunk/reactos/lib/rtl/srw.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/lib/rtl/srw.c?rev=23806&am…
==============================================================================
--- trunk/reactos/lib/rtl/srw.c (added)
+++ trunk/reactos/lib/rtl/srw.c Wed Aug 30 23:02:42 2006
@@ -1,0 +1,832 @@
+/*
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS system libraries
+ * PURPOSE: Slim Reader/Writer (SRW) Routines
+ * PROGRAMMER: Thomas Weidenmueller <w3seek(a)reactos.com>
+ *
+ * NOTES: The algorithms used in this implementation
+ * may be different from Vista's implementation.
+ * Since applications should treat the RTL_SRWLOCK
+ * structure as opaque data, it should not matter.
+ * The algorithms are probably not as optimized.
+ */
+
+/* INCLUDES *****************************************************************/
+
+#include <rtl.h>
+
+#define NDEBUG
+#include <debug.h>
+
+/* FIXME *********************************************************************/
+
+/* FIXME: Interlocked functions that need to be made into a public header */
+FORCEINLINE
+LONG
+InterlockedAnd(IN OUT volatile LONG *Target,
+ IN LONG Set)
+{
+ LONG i;
+ LONG j;
+
+ j = *Target;
+ do {
+ i = j;
+ j = InterlockedCompareExchange((PLONG)Target,
+ i & Set,
+ i);
+
+ } while (i != j);
+
+ return j;
+}
+
+FORCEINLINE
+LONG
+InterlockedOr(IN OUT volatile LONG *Target,
+ IN LONG Set)
+{
+ LONG i;
+ LONG j;
+
+ j = *Target;
+ do {
+ i = j;
+ j = InterlockedCompareExchange((PLONG)Target,
+ i | Set,
+ i);
+
+ } while (i != j);
+
+ return j;
+}
+
+/* FUNCTIONS *****************************************************************/
+
+#ifdef _WIN64
+#define InterlockedBitTestAndSetPointer(ptr,val)
InterlockedBitTestAndSet64((PLONGLONG)ptr,(LONGLONG)val)
+#define InterlockedAddPointer(ptr,val) InterlockedAdd64((PLONGLONG)ptr,(LONGLONG)val)
+#define InterlockedAndPointer(ptr,val) InterlockedAnd64((PLONGLONG)ptr,(LONGLONG)val)
+#define InterlockedOrPointer(ptr,val) InterlockedOr64((PLONGLONG)ptr,(LONGLONG)val)
+#else
+#define InterlockedBitTestAndSetPointer(ptr,val)
InterlockedBitTestAndSet((PLONG)ptr,(LONG)val)
+#define InterlockedAddPointer(ptr,val) InterlockedAdd((PLONG)ptr,(LONG)val)
+#define InterlockedAndPointer(ptr,val) InterlockedAnd((PLONG)ptr,(LONG)val)
+#define InterlockedOrPointer(ptr,val) InterlockedOr((PLONG)ptr,(LONG)val)
+#endif
+
+#define RTL_SRWLOCK_OWNED_BIT 0
+#define RTL_SRWLOCK_CONTENDED_BIT 1
+#define RTL_SRWLOCK_SHARED_BIT 2
+#define RTL_SRWLOCK_CONTENTION_LOCK_BIT 3
+#define RTL_SRWLOCK_OWNED (1 << RTL_SRWLOCK_OWNED_BIT)
+#define RTL_SRWLOCK_CONTENDED (1 << RTL_SRWLOCK_CONTENDED_BIT)
+#define RTL_SRWLOCK_SHARED (1 << RTL_SRWLOCK_SHARED_BIT)
+#define RTL_SRWLOCK_CONTENTION_LOCK (1 << RTL_SRWLOCK_CONTENTION_LOCK_BIT)
+#define RTL_SRWLOCK_MASK (RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED | \
+ RTL_SRWLOCK_SHARED | RTL_SRWLOCK_CONTENTION_LOCK)
+#define RTL_SRWLOCK_BITS 4
+
+#if defined(__GNUC__)
+/* This macro will cause the code to assert if compiled with a buggy
+ version of GCC that doesn't align the wait blocks properly on the stack! */
+#define ASSERT_SRW_WAITBLOCK(ptr) \
+ ASSERT(((ULONG_PTR)ptr & ((1 << RTL_SRWLOCK_BITS) - 1)) == 0)
+#else
+#define ASSERT_SRW_WAITBLOCK(ptr)
+#endif
+
+typedef struct _RTLP_SRWLOCK_SHARED_WAKE
+{
+ LONG Wake;
+ volatile struct _RTLP_SRWLOCK_SHARED_WAKE *Next;
+} volatile RTLP_SRWLOCK_SHARED_WAKE, *PRTLP_SRWLOCK_SHARED_WAKE;
+
+typedef struct _RTLP_SRWLOCK_WAITBLOCK
+{
+ /* SharedCount is the number of shared acquirers. */
+ LONG SharedCount;
+
+ /* Last points to the last wait block in the chain. The value
+ is only valid when read from the first wait block. */
+ volatile struct _RTLP_SRWLOCK_WAITBLOCK *Last;
+
+ /* Next points to the next wait block in the chain. */
+ volatile struct _RTLP_SRWLOCK_WAITBLOCK *Next;
+
+ union
+ {
+ /* Wake is only valid for exclusive wait blocks */
+ LONG Wake;
+ /* The wake chain is only valid for shared wait blocks */
+ struct
+ {
+ PRTLP_SRWLOCK_SHARED_WAKE SharedWakeChain;
+ PRTLP_SRWLOCK_SHARED_WAKE LastSharedWake;
+ };
+ };
+
+ BOOLEAN Exclusive;
+} volatile RTLP_SRWLOCK_WAITBLOCK, *PRTLP_SRWLOCK_WAITBLOCK;
+
+
+static VOID
+NTAPI
+RtlpReleaseWaitBlockLockExclusive(IN OUT PRTL_SRWLOCK SRWLock,
+ IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock)
+{
+ PRTLP_SRWLOCK_WAITBLOCK Next;
+ LONG_PTR NewValue;
+
+ /* NOTE: We're currently in an exclusive lock in contended mode. */
+
+ Next = FirstWaitBlock->Next;
+ if (Next != NULL)
+ {
+ /* There's more blocks chained, we need to update the pointers
+ in the next wait block and update the wait block pointer. */
+ NewValue = (LONG_PTR)Next | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED;
+ if (!FirstWaitBlock->Exclusive)
+ {
+ /* The next wait block has to be an exclusive lock! */
+ ASSERT(Next->Exclusive);
+
+ /* Save the shared count */
+ Next->SharedCount = FirstWaitBlock->SharedCount;
+
+ NewValue |= RTL_SRWLOCK_SHARED;
+ }
+
+ Next->Last = FirstWaitBlock->Last;
+ }
+ else
+ {
+ /* Convert the lock to a simple lock. */
+ if (FirstWaitBlock->Exclusive)
+ NewValue = RTL_SRWLOCK_OWNED;
+ else
+ {
+ ASSERT(FirstWaitBlock->SharedCount > 0);
+
+ NewValue = ((LONG_PTR)FirstWaitBlock->SharedCount <<
RTL_SRWLOCK_BITS) |
+ RTL_SRWLOCK_SHARED | RTL_SRWLOCK_OWNED;
+ }
+ }
+
+ (void)InterlockedExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue);
+
+ if (FirstWaitBlock->Exclusive)
+ {
+ (void)InterlockedOr(&FirstWaitBlock->Wake,
+ TRUE);
+ }
+ else
+ {
+ PRTLP_SRWLOCK_SHARED_WAKE WakeChain, Next;
+
+ /* If we were the first one to acquire the shared
+ lock, we now need to wake all others... */
+ WakeChain = FirstWaitBlock->SharedWakeChain;
+ do
+ {
+ Next = WakeChain->Next;
+
+ (void)InterlockedOr((PLONG)&WakeChain->Wake,
+ TRUE);
+
+ WakeChain = Next;
+ } while (WakeChain != NULL);
+ }
+}
+
+
+static VOID
+NTAPI
+RtlpReleaseWaitBlockLockLastShared(IN OUT PRTL_SRWLOCK SRWLock,
+ IN PRTLP_SRWLOCK_WAITBLOCK FirstWaitBlock)
+{
+ PRTLP_SRWLOCK_WAITBLOCK Next;
+ LONG_PTR NewValue;
+
+ /* NOTE: We're currently in a shared lock in contended mode. */
+
+ /* The next acquirer to be unwaited *must* be an exclusive lock! */
+ ASSERT(FirstWaitBlock->Exclusive);
+
+ Next = FirstWaitBlock->Next;
+ if (Next != NULL)
+ {
+ /* There's more blocks chained, we need to update the pointers
+ in the next wait block and update the wait block pointer. */
+ NewValue = (LONG_PTR)Next | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED;
+
+ Next->Last = FirstWaitBlock->Last;
+ }
+ else
+ {
+ /* Convert the lock to a simple exclusive lock. */
+ NewValue = RTL_SRWLOCK_OWNED;
+ }
+
+ (void)InterlockedExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue);
+
+ (void)InterlockedOr(&FirstWaitBlock->Wake,
+ TRUE);
+}
+
+
+static VOID
+NTAPI
+RtlpReleaseWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock)
+{
+ InterlockedAndPointer(&SRWLock->Ptr,
+ ~RTL_SRWLOCK_CONTENTION_LOCK);
+}
+
+
+static PRTLP_SRWLOCK_WAITBLOCK
+NTAPI
+RtlpAcquireWaitBlockLock(IN OUT PRTL_SRWLOCK SRWLock)
+{
+ LONG_PTR PrevValue;
+ PRTLP_SRWLOCK_WAITBLOCK WaitBlock;
+
+ while (1)
+ {
+ PrevValue = InterlockedOrPointer(&SRWLock->Ptr,
+ RTL_SRWLOCK_CONTENTION_LOCK);
+
+ if (!(PrevValue & RTL_SRWLOCK_CONTENTION_LOCK))
+ break;
+
+ YieldProcessor();
+ }
+
+ if (!(PrevValue & RTL_SRWLOCK_CONTENDED) ||
+ (PrevValue & ~RTL_SRWLOCK_MASK) == 0)
+ {
+ /* Too bad, looks like the wait block was removed in the
+ meanwhile, unlock again */
+ RtlpReleaseWaitBlockLock(SRWLock);
+ return NULL;
+ }
+
+ WaitBlock = (PRTLP_SRWLOCK_WAITBLOCK)(PrevValue & ~RTL_SRWLOCK_MASK);
+
+ ASSERT_SRW_WAITBLOCK(WaitBlock);
+ return WaitBlock;
+}
+
+
+static VOID
+NTAPI
+RtlpAcquireSRWLockExclusiveWait(IN OUT PRTL_SRWLOCK SRWLock,
+ IN PRTLP_SRWLOCK_WAITBLOCK WaitBlock)
+{
+ LONG_PTR CurrentValue;
+
+ while (1)
+ {
+ CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
+ if (!(CurrentValue & RTL_SRWLOCK_SHARED))
+ {
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ if (WaitBlock->Wake != 0)
+ {
+ /* Our wait block became the first one
+ in the chain, we own the lock now! */
+ break;
+ }
+ }
+ else
+ {
+ /* The last wait block was removed and/or we're
+ finally a simple exclusive lock. This means we
+ don't need to wait anymore, we acquired the lock! */
+ break;
+ }
+ }
+
+ YieldProcessor();
+ }
+}
+
+
+static VOID
+NTAPI
+RtlpAcquireSRWLockSharedWait(IN OUT PRTL_SRWLOCK SRWLock,
+ IN OUT PRTLP_SRWLOCK_WAITBLOCK FirstWait OPTIONAL,
+ IN OUT PRTLP_SRWLOCK_SHARED_WAKE WakeChain)
+{
+ if (FirstWait != NULL)
+ {
+ while (WakeChain->Wake == 0)
+ {
+ YieldProcessor();
+ }
+ }
+ else
+ {
+ LONG_PTR CurrentValue;
+
+ while (1)
+ {
+ CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
+ if (CurrentValue & RTL_SRWLOCK_SHARED)
+ {
+ /* The RTL_SRWLOCK_OWNED bit always needs to be set when
+ RTL_SRWLOCK_SHARED is set! */
+ ASSERT(CurrentValue & RTL_SRWLOCK_OWNED);
+
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ if (WakeChain->Wake != 0)
+ {
+ /* Our wait block became the first one
+ in the chain, we own the lock now! */
+ break;
+ }
+ }
+ else
+ {
+ /* The last wait block was removed and/or we're
+ finally a simple shared lock. This means we
+ don't need to wait anymore, we acquired the lock! */
+ break;
+ }
+ }
+
+ YieldProcessor();
+ }
+ }
+}
+
+
+VOID
+NTAPI
+RtlInitializeSRWLock(OUT PRTL_SRWLOCK SRWLock)
+{
+ SRWLock->Ptr = NULL;
+}
+
+
+VOID
+NTAPI
+RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
+{
+ __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock;
+ RTLP_SRWLOCK_SHARED_WAKE SharedWake;
+ LONG_PTR CurrentValue, NewValue;
+ PRTLP_SRWLOCK_WAITBLOCK First, Shared, FirstWait;
+
+ while (1)
+ {
+ CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
+
+ if (CurrentValue & RTL_SRWLOCK_SHARED)
+ {
+ /* NOTE: It is possible that the RTL_SRWLOCK_OWNED bit is set! */
+
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ /* There's other waiters already, lock the wait blocks and
+ increment the shared count */
+ First = RtlpAcquireWaitBlockLock(SRWLock);
+ if (First != NULL)
+ {
+ FirstWait = NULL;
+
+ if (First->Exclusive)
+ {
+ /* We need to setup a new wait block! Although
+ we're currently in a shared lock and we're acquiring
+ a shared lock, there are exclusive locks queued. We need
+ to wait until those are released. */
+ Shared = First->Last;
+
+ if (Shared->Exclusive)
+ {
+ StackWaitBlock.Exclusive = FALSE;
+ StackWaitBlock.SharedCount = 1;
+ StackWaitBlock.Next = NULL;
+ StackWaitBlock.Last = &StackWaitBlock;
+ StackWaitBlock.SharedWakeChain = &SharedWake;
+
+ Shared->Next = &StackWaitBlock;
+ First->Last = &StackWaitBlock;
+
+ Shared = &StackWaitBlock;
+ FirstWait = &StackWaitBlock;
+ }
+ else
+ {
+ Shared->LastSharedWake->Next = &SharedWake;
+ Shared->SharedCount++;
+ }
+ }
+ else
+ {
+ Shared = First;
+ Shared->LastSharedWake->Next = &SharedWake;
+ Shared->SharedCount++;
+ }
+
+ SharedWake.Next = NULL;
+ SharedWake.Wake = 0;
+
+ Shared->LastSharedWake = &SharedWake;
+
+ ASSERT_SRW_WAITBLOCK(Shared);
+
+ RtlpReleaseWaitBlockLock(SRWLock);
+
+ RtlpAcquireSRWLockSharedWait(SRWLock,
+ FirstWait,
+ &SharedWake);
+
+ /* Successfully incremented the shared count, we acquired the lock
*/
+ break;
+ }
+ }
+ else
+ {
+ /* This is a fastest path, just increment the number of
+ current shared locks */
+
+ /* Since the RTL_SRWLOCK_SHARED bit is set, the RTL_SRWLOCK_OWNED bit
also has
+ to be set! */
+
+ ASSERT(CurrentValue & RTL_SRWLOCK_OWNED);
+
+ NewValue = (CurrentValue >> RTL_SRWLOCK_BITS) + 1;
+ NewValue = (NewValue << RTL_SRWLOCK_BITS) | (CurrentValue &
RTL_SRWLOCK_MASK);
+
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ /* Successfully incremented the shared count, we acquired the lock
*/
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (CurrentValue & RTL_SRWLOCK_OWNED)
+ {
+ /* The resource is currently acquired exclusively */
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ SharedWake.Next = NULL;
+ SharedWake.Wake = 0;
+
+ /* There's other waiters already, lock the wait blocks and
+ increment the shared count. If the last block in the chain
+ is an exclusive lock, add another block. */
+
+ StackWaitBlock.Exclusive = FALSE;
+ StackWaitBlock.SharedCount = 0;
+ StackWaitBlock.Next = NULL;
+ StackWaitBlock.Last = &StackWaitBlock;
+ StackWaitBlock.SharedWakeChain = &SharedWake;
+
+ First = RtlpAcquireWaitBlockLock(SRWLock);
+ if (First != NULL)
+ {
+ Shared = First->Last;
+ if (Shared->Exclusive)
+ {
+ Shared->Next = &StackWaitBlock;
+ First->Last = &StackWaitBlock;
+
+ Shared = &StackWaitBlock;
+ FirstWait = &StackWaitBlock;
+ }
+ else
+ {
+ FirstWait = NULL;
+ Shared->LastSharedWake->Next = &SharedWake;
+ }
+
+ ASSERT_SRW_WAITBLOCK(Shared);
+
+ Shared->SharedCount++;
+ Shared->LastSharedWake = &SharedWake;
+
+ RtlpReleaseWaitBlockLock(SRWLock);
+
+ RtlpAcquireSRWLockSharedWait(SRWLock,
+ FirstWait,
+ &SharedWake);
+
+ /* Successfully incremented the shared count, we acquired the
lock */
+ break;
+ }
+ }
+ else
+ {
+ SharedWake.Next = NULL;
+ SharedWake.Wake = 0;
+
+ /* We need to setup the first wait block. Currently an exclusive lock
is
+ held, change the lock to contended mode. */
+ StackWaitBlock.Exclusive = FALSE;
+ StackWaitBlock.SharedCount = 1;
+ StackWaitBlock.Next = NULL;
+ StackWaitBlock.Last = &StackWaitBlock;
+ StackWaitBlock.SharedWakeChain = &SharedWake;
+ StackWaitBlock.LastSharedWake = &SharedWake;
+
+ ASSERT_SRW_WAITBLOCK(&StackWaitBlock);
+
+ NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED |
RTL_SRWLOCK_CONTENDED;
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ RtlpAcquireSRWLockSharedWait(SRWLock,
+ &StackWaitBlock,
+ &SharedWake);
+
+ /* Successfully set the shared count, we acquired the lock */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* This is a fast path, we can simply try to set the shared count to 1
*/
+ NewValue = (1 << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED |
RTL_SRWLOCK_OWNED;
+
+ /* The RTL_SRWLOCK_CONTENDED bit should never be set if neither the
+ RTL_SRWLOCK_SHARED nor the RTL_SRWLOCK_OWNED bit is set */
+ ASSERT(!(CurrentValue & RTL_SRWLOCK_CONTENDED));
+
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ /* Successfully set the shared count, we acquired the lock */
+ break;
+ }
+ }
+ }
+
+ YieldProcessor();
+ }
+}
+
+
+VOID
+NTAPI
+RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock)
+{
+ LONG_PTR CurrentValue, NewValue;
+ PRTLP_SRWLOCK_WAITBLOCK WaitBlock;
+ BOOLEAN LastShared;
+
+ while (1)
+ {
+ CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
+
+ if (CurrentValue & RTL_SRWLOCK_SHARED)
+ {
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ /* There's a wait block, we need to wake a pending
+ exclusive acquirer if this is the last shared release */
+ WaitBlock = RtlpAcquireWaitBlockLock(SRWLock);
+ if (WaitBlock != NULL)
+ {
+ LastShared = (--WaitBlock->SharedCount == 0);
+
+ if (LastShared)
+ RtlpReleaseWaitBlockLockLastShared(SRWLock,
+ WaitBlock);
+ else
+ RtlpReleaseWaitBlockLock(SRWLock);
+
+ /* We released the lock */
+ break;
+ }
+ }
+ else
+ {
+ /* This is a fast path, we can simply decrement the shared
+ count and store the pointer */
+ NewValue = CurrentValue >> RTL_SRWLOCK_BITS;
+
+ if (--NewValue != 0)
+ {
+ NewValue = (NewValue << RTL_SRWLOCK_BITS) | RTL_SRWLOCK_SHARED
| RTL_SRWLOCK_OWNED;
+ }
+
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ /* Successfully released the lock */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* The RTL_SRWLOCK_SHARED bit has to be present now,
+ even in the contended case! */
+ RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
+ }
+
+ YieldProcessor();
+ }
+}
+
+
+VOID
+NTAPI
+RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
+{
+ __ALIGNED(16) RTLP_SRWLOCK_WAITBLOCK StackWaitBlock;
+ PRTLP_SRWLOCK_WAITBLOCK First, Last;
+
+ if (InterlockedBitTestAndSetPointer(&SRWLock->Ptr,
+ RTL_SRWLOCK_OWNED_BIT))
+ {
+ LONG_PTR CurrentValue, NewValue;
+
+ while (1)
+ {
+ CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
+
+ if (CurrentValue & RTL_SRWLOCK_SHARED)
+ {
+ /* A shared lock is being held right now. We need to add a wait block!
*/
+
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ goto AddWaitBlock;
+ }
+ else
+ {
+ /* There are no wait blocks so far, we need to add ourselves as the
first
+ wait block. We need to keep the shared count! */
+ StackWaitBlock.Exclusive = TRUE;
+ StackWaitBlock.SharedCount = CurrentValue >> RTL_SRWLOCK_BITS;
+ StackWaitBlock.Next = NULL;
+ StackWaitBlock.Last = &StackWaitBlock;
+ StackWaitBlock.Wake = 0;
+
+ ASSERT_SRW_WAITBLOCK(&StackWaitBlock);
+
+ NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_SHARED |
RTL_SRWLOCK_CONTENDED | RTL_SRWLOCK_OWNED;
+
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ RtlpAcquireSRWLockExclusiveWait(SRWLock,
+ &StackWaitBlock);
+
+ /* Successfully acquired the exclusive lock */
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (CurrentValue & RTL_SRWLOCK_OWNED)
+ {
+ /* An exclusive lock is being held right now. We need to add a wait
block! */
+
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+AddWaitBlock:
+ StackWaitBlock.Exclusive = TRUE;
+ StackWaitBlock.SharedCount = 0;
+ StackWaitBlock.Next = NULL;
+ StackWaitBlock.Last = &StackWaitBlock;
+ StackWaitBlock.Wake = 0;
+
+ ASSERT_SRW_WAITBLOCK(&StackWaitBlock);
+
+ First = RtlpAcquireWaitBlockLock(SRWLock);
+ if (First != NULL)
+ {
+ Last = First->Last;
+ Last->Next = &StackWaitBlock;
+ First->Last = &StackWaitBlock;
+
+ RtlpReleaseWaitBlockLock(SRWLock);
+
+ RtlpAcquireSRWLockExclusiveWait(SRWLock,
+ &StackWaitBlock);
+
+ /* Successfully acquired the exclusive lock */
+ break;
+ }
+ }
+ else
+ {
+ /* There are no wait blocks so far, we need to add ourselves as
the first
+ wait block. We need to keep the shared count! */
+ StackWaitBlock.Exclusive = TRUE;
+ StackWaitBlock.SharedCount = 0;
+ StackWaitBlock.Next = NULL;
+ StackWaitBlock.Last = &StackWaitBlock;
+ StackWaitBlock.Wake = 0;
+
+ ASSERT_SRW_WAITBLOCK(&StackWaitBlock);
+
+ NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED |
RTL_SRWLOCK_CONTENDED;
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ RtlpAcquireSRWLockExclusiveWait(SRWLock,
+ &StackWaitBlock);
+
+ /* Successfully acquired the exclusive lock */
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (!InterlockedBitTestAndSetPointer(&SRWLock->Ptr,
+ RTL_SRWLOCK_OWNED_BIT))
+ {
+ /* We managed to get hold of a simple exclusive lock! */
+ break;
+ }
+ }
+ }
+
+ YieldProcessor();
+ }
+ }
+}
+
+
+VOID
+NTAPI
+RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock)
+{
+ LONG_PTR CurrentValue, NewValue;
+ PRTLP_SRWLOCK_WAITBLOCK WaitBlock;
+
+ while (1)
+ {
+ CurrentValue = *(volatile LONG_PTR *)&SRWLock->Ptr;
+
+ if (!(CurrentValue & RTL_SRWLOCK_OWNED))
+ {
+ RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
+ }
+
+ if (!(CurrentValue & RTL_SRWLOCK_SHARED))
+ {
+ if (CurrentValue & RTL_SRWLOCK_CONTENDED)
+ {
+ /* There's a wait block, we need to wake the next pending
+ acquirer (exclusive or shared) */
+ WaitBlock = RtlpAcquireWaitBlockLock(SRWLock);
+ if (WaitBlock != NULL)
+ {
+ RtlpReleaseWaitBlockLockExclusive(SRWLock,
+ WaitBlock);
+
+ /* We released the lock */
+ break;
+ }
+ }
+ else
+ {
+ /* This is a fast path, we can simply clear the RTL_SRWLOCK_OWNED
+ bit. All other bits should be 0 now because this is a simple
+ exclusive lock and no one is waiting. */
+
+ ASSERT(!(CurrentValue & ~RTL_SRWLOCK_OWNED));
+
+ NewValue = 0;
+ if (InterlockedCompareExchangePointer(&SRWLock->Ptr,
+ (PVOID)NewValue,
+ (PVOID)CurrentValue) ==
(PVOID)CurrentValue)
+ {
+ /* We released the lock */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* The RTL_SRWLOCK_SHARED bit must not be present now,
+ not even in the contended case! */
+ RtlRaiseStatus(STATUS_RESOURCE_NOT_OWNED);
+ }
+
+ YieldProcessor();
+ }
+}
Propchange: trunk/reactos/lib/rtl/srw.c
------------------------------------------------------------------------------
svn:eol-style = native