Author: pschweitzer Date: Tue May 30 21:35:05 2017 New Revision: 74703
URL: http://svn.reactos.org/svn/reactos?rev=74703&view=rev Log: [NTDLL_VISTA] Create a new NTDLL library that exports some of the NTDLL Vista+ functions. This new NTDLL includes at the time of commit: - SRW locks implementation that was originally built in RTL but never used ; - Condition variables implementation which is a new code in ReactOS trunk.
Condition variables is an implementation of Stephan Röger, with minor formatting changes by Timo Kreuzer and various changes by myself.
CORE-7546 CORE-8204
Added: trunk/reactos/dll/win32/ntdll_vista/ trunk/reactos/dll/win32/ntdll_vista/CMakeLists.txt (with props) trunk/reactos/dll/win32/ntdll_vista/DllMain.c (with props) trunk/reactos/dll/win32/ntdll_vista/condvar.c (with props) trunk/reactos/dll/win32/ntdll_vista/ntdll_vista.spec (with props) trunk/reactos/dll/win32/ntdll_vista/rtl_vista.h (with props) trunk/reactos/dll/win32/ntdll_vista/srw.c - copied, changed from r74702, trunk/reactos/sdk/lib/rtl/srw.c Removed: trunk/reactos/sdk/lib/rtl/srw.c Modified: trunk/reactos/dll/win32/CMakeLists.txt trunk/reactos/sdk/lib/rtl/CMakeLists.txt
Modified: trunk/reactos/dll/win32/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/CMakeLists.txt?re... ============================================================================== --- trunk/reactos/dll/win32/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/dll/win32/CMakeLists.txt [iso-8859-1] Tue May 30 21:35:05 2017 @@ -134,6 +134,7 @@ add_subdirectory(netid) add_subdirectory(newdev) add_subdirectory(npptools) +add_subdirectory(ntdll_vista) add_subdirectory(ntdsapi) add_subdirectory(ntlanman) add_subdirectory(ntmarta)
Added: trunk/reactos/dll/win32/ntdll_vista/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ntdll_vista/CMake... ============================================================================== --- trunk/reactos/dll/win32/ntdll_vista/CMakeLists.txt (added) +++ trunk/reactos/dll/win32/ntdll_vista/CMakeLists.txt [iso-8859-1] Tue May 30 21:35:05 2017 @@ -0,0 +1,17 @@ + +remove_definitions(-D_WIN32_WINNT=0x502 -DWINVER=0x502) +add_definitions(-D_WIN32_WINNT=0x600 -DWINVER=0x600) + +spec2def(ntdll_vista.dll ntdll_vista.spec ADD_IMPORTLIB) + +list(APPEND SOURCE + DllMain.c + condvar.c + srw.c + ${CMAKE_CURRENT_BINARY_DIR}/ntdll_vista.def) + +add_library(ntdll_vista SHARED ${SOURCE}) +set_module_type(ntdll_vista win32dll ENTRYPOINT DllMain 12) +add_importlibs(ntdll_vista ntdll kernel32) +add_dependencies(ntdll_vista psdk) +add_cd_file(TARGET ntdll_vista DESTINATION reactos/system32 FOR all)
Propchange: trunk/reactos/dll/win32/ntdll_vista/CMakeLists.txt ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/dll/win32/ntdll_vista/DllMain.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ntdll_vista/DllMa... ============================================================================== --- trunk/reactos/dll/win32/ntdll_vista/DllMain.c (added) +++ trunk/reactos/dll/win32/ntdll_vista/DllMain.c [iso-8859-1] Tue May 30 21:35:05 2017 @@ -0,0 +1,36 @@ +#include <stdarg.h> + +#define WIN32_NO_STATUS + +#include <windef.h> +#include <winbase.h> +#include <winreg.h> +#include <winuser.h> +#include <winwlx.h> + +#define NDEBUG +#include <debug.h> + +VOID +RtlpInitializeKeyedEvent(VOID); + +VOID +RtlpCloseKeyedEvent(VOID); + +BOOL +WINAPI +DllMain(HANDLE hDll, + DWORD dwReason, + LPVOID lpReserved) +{ + if (dwReason == DLL_PROCESS_ATTACH) + { + DisableThreadLibraryCalls(hDll); + RtlpInitializeKeyedEvent(); + } + else if (dwReason == DLL_PROCESS_DETACH) + { + RtlpCloseKeyedEvent(); + } + return TRUE; +}
Propchange: trunk/reactos/dll/win32/ntdll_vista/DllMain.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/dll/win32/ntdll_vista/condvar.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ntdll_vista/condv... ============================================================================== --- trunk/reactos/dll/win32/ntdll_vista/condvar.c (added) +++ trunk/reactos/dll/win32/ntdll_vista/condvar.c [iso-8859-1] Tue May 30 21:35:05 2017 @@ -0,0 +1,525 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * PURPOSE: Condition Variable Routines + * PROGRAMMERS: Thomas Weidenmueller w3seek@reactos.com + * Stephan A. R�ger + */ + +/* NOTE: This functionality can be optimized for releasing single + threads or for releasing all waiting threads at once. This + implementation is optimized for releasing a single thread at a time. + It wakes up sleeping threads in FIFO order. */ + +/* INCLUDES ******************************************************************/ + +#include <rtl_vista.h> + +#define NDEBUG +#include <debug.h> + +/* INTERNAL TYPES ************************************************************/ + +#define COND_VAR_UNUSED_FLAG ((ULONG_PTR)1) +#define COND_VAR_LOCKED_FLAG ((ULONG_PTR)2) +#define COND_VAR_FLAGS_MASK ((ULONG_PTR)3) +#define COND_VAR_ADDRESS_MASK (~COND_VAR_FLAGS_MASK) + +typedef struct _COND_VAR_WAIT_ENTRY +{ + /* ListEntry must have an alignment of at least 32-bits, since we + want COND_VAR_ADDRESS_MASK to cover all of the address. */ + LIST_ENTRY ListEntry; + PVOID WaitKey; + BOOLEAN ListRemovalHandled; +} COND_VAR_WAIT_ENTRY, * PCOND_VAR_WAIT_ENTRY; + +#define CONTAINING_COND_VAR_WAIT_ENTRY(address, field) \ + CONTAINING_RECORD(address, COND_VAR_WAIT_ENTRY, field) + +/* GLOBALS *******************************************************************/ + +static HANDLE CondVarKeyedEventHandle = NULL; + +/* INTERNAL FUNCTIONS ********************************************************/ + +FORCEINLINE +ULONG_PTR +InternalCmpXChgCondVarAcq(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN ULONG_PTR Exchange, + IN ULONG_PTR Comperand) +{ + return (ULONG_PTR)InterlockedCompareExchangePointerAcquire(&ConditionVariable->Ptr, + (PVOID)Exchange, + (PVOID)Comperand); +} + +FORCEINLINE +ULONG_PTR +InternalCmpXChgCondVarRel(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN ULONG_PTR Exchange, + IN ULONG_PTR Comperand) +{ + return (ULONG_PTR)InterlockedCompareExchangePointerRelease(&ConditionVariable->Ptr, + (PVOID)Exchange, + (PVOID)Comperand); +} + +FORCEINLINE +BOOLEAN * +InternalGetListRemovalHandledFlag(IN PCOND_VAR_WAIT_ENTRY Entry) +{ + return (BOOLEAN *)&Entry->ListRemovalHandled; +} + +static +PCOND_VAR_WAIT_ENTRY +InternalLockCondVar(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN PCOND_VAR_WAIT_ENTRY InsertEntry OPTIONAL, + IN BOOLEAN * AbortIfLocked OPTIONAL) +{ + /* InsertEntry and AbortIfLocked may be NULL on entry. This routine + will return NULL if the lock was not acquired. Otherwise it has + successfully acquired the lock and the return value is a valid + reference to the list head associated with ConditionVariable. + The caller must in this case call InternalUnlockCondVar later + in order to unlock the condition variable. + + If InsertEntry is NULL and there are no entries on the list, this + routine will not acquire the lock and return NULL. If InsertEntry + is not NULL this routine ensures that InsertEntry will be on the + list when it returns successfully. + + If the lock is owned by another thread and AbortIfLocked is NULL, + this routine will block until it acquires the lock. If AbortIfLocked + is not NULL and the lock is owned by another thread, this routine + will periodically check if *AbortIfLocked is nonzero and if so, will + return NULL instead of continuing the wait. */ + + ULONG_PTR OldVal = (ULONG_PTR)ConditionVariable->Ptr; + + for (;;) + { + ULONG_PTR NewVal, LockRes; + PLIST_ENTRY OldListHead; + + if (OldVal & COND_VAR_LOCKED_FLAG) + { + /* The locked flag is set, indicating someone else currently + holds the lock. We'll spin until this flag becomes + clear or we're asked to abort. */ + YieldProcessor(); + + if ((AbortIfLocked != NULL) && *AbortIfLocked) + { + /* The caller wants us to abort in this case. */ + return NULL; + } + + /* Refresh OldVal and try again. */ + OldVal = *(ULONG_PTR *)&ConditionVariable->Ptr; + continue; + } + + /* Retrieve the list head currently associated with the + condition variable. */ + OldListHead = (PLIST_ENTRY)(OldVal & COND_VAR_ADDRESS_MASK); + if (InsertEntry == NULL) + { + /* The caller doesn't want to put any entry on the list. */ + if (OldListHead == NULL) + { + /* The list is empty, so there is nothing to lock. */ + return NULL; + } + + /* The list isn't empty. In this case we need to preserve + all of OldVal. */ + NewVal = OldVal; + } + else + { + /* Let InsertEntry be the new list head. Preserve only the + bits inside the COND_VAR_FLAGS_MASK range. */ + NewVal = ((OldVal & COND_VAR_FLAGS_MASK) | + (ULONG_PTR)&InsertEntry->ListEntry); + } + + /* Set the flag that indicates someone is holding the lock and + try to update the condition variable thread-safe. */ + NewVal |= COND_VAR_LOCKED_FLAG; + LockRes = InternalCmpXChgCondVarAcq(ConditionVariable, NewVal, OldVal); + if (LockRes == OldVal) + { + /* We successfully updated ConditionVariable the way we + wanted and now hold the lock. */ + if (InsertEntry == NULL) + { + /* We know that OldVal contains a valid address in + this case. */ + ASSERT(OldListHead != NULL); + return CONTAINING_COND_VAR_WAIT_ENTRY(OldListHead, ListEntry); + } + + /* InsertEntry is not on the list yet, so add it. In any + case InsertEntry will be the new list head. */ + if (OldListHead == NULL) + { + /* List was empty before. */ + InitializeListHead(&InsertEntry->ListEntry); + } + else + { + /* Make InsertEntry the last entry of the old list. + As InsertEntry will take the role as new list head, + OldListHead will become the second entry (InsertEntry->Flink) + on the new list. */ + InsertTailList(OldListHead, &InsertEntry->ListEntry); + } + + return InsertEntry; + } + + /* We didn't manage to update ConditionVariable, so try again. */ + OldVal = LockRes; + } +} + +static +VOID +InternalUnlockCondVar(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN PCOND_VAR_WAIT_ENTRY RemoveEntry OPTIONAL) +{ + /* This routine assumes that the lock is being held on entry. + RemoveEntry may be NULL. If it is not NULL, this routine + assumes that RemoveEntry is on the list and will remove it + before releasing the lock. */ + ULONG_PTR OldVal = (ULONG_PTR)ConditionVariable->Ptr; + PLIST_ENTRY NewHeadEntry; + + ASSERT((OldVal & COND_VAR_LOCKED_FLAG) && + (OldVal & COND_VAR_ADDRESS_MASK)); + + NewHeadEntry = (PLIST_ENTRY)(OldVal & COND_VAR_ADDRESS_MASK); + if (RemoveEntry != NULL) + { + /* We have to drop RemoveEntry from the list. */ + if (&RemoveEntry->ListEntry == NewHeadEntry) + { + /* RemoveEntry is the list head. */ + if (!IsListEmpty(NewHeadEntry)) + { + /* The second entry in the list will become the new + list head. It's from the thread that arrived + right before the owner of RemoveEntry. */ + NewHeadEntry = NewHeadEntry->Flink; + RemoveEntryList(&RemoveEntry->ListEntry); + } + else + { + /* The list will be empty, so discard the list. */ + NewHeadEntry = NULL; + } + } + else + { + /* RemoveEntry is not the list head. The current list head + will remain. */ + RemoveEntryList(&RemoveEntry->ListEntry); + } + + /* Indicate to the owner of RemoveEntry that the entry + was removed from the list. RemoveEntry may not be touched + from here on. We don't use volatile semantics here since + the cache will anyway be flushed soon when we update + ConditionVariable. */ + RemoveEntry->ListRemovalHandled = TRUE; + } + + /* Now unlock thread-safe, while preserving any flags within the + COND_VAR_FLAGS_MASK range except for COND_VAR_LOCKED_FLAG. */ + for (;;) + { + ULONG_PTR NewVal = ((OldVal & (COND_VAR_FLAGS_MASK ^ COND_VAR_LOCKED_FLAG)) | + (ULONG_PTR)NewHeadEntry); + ULONG_PTR LockRes = InternalCmpXChgCondVarRel(ConditionVariable, NewVal, OldVal); + if (LockRes == OldVal) + { + /* We unlocked. */ + break; + } + + /* Try again. */ + OldVal = LockRes; + } +} + +static +VOID +InternalWake(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN BOOLEAN ReleaseAll) +{ + /* If ReleaseAll is zero on entry, one thread at most will be woken. + Otherwise all waiting threads are woken. Wakeups happen in FIFO + order. */ + PCOND_VAR_WAIT_ENTRY CONST HeadEntry = InternalLockCondVar(ConditionVariable, NULL, NULL); + PCOND_VAR_WAIT_ENTRY Entry; + PCOND_VAR_WAIT_ENTRY NextEntry; + LARGE_INTEGER Timeout; + PCOND_VAR_WAIT_ENTRY RemoveOnUnlockEntry; + + ASSERT(CondVarKeyedEventHandle != NULL); + + if (HeadEntry == NULL) + { + /* There is noone there to wake up. In this case do nothing + and return immediately. We don't stockpile releases. */ + return; + } + + Timeout.QuadPart = 0; + RemoveOnUnlockEntry = NULL; + + /* Release sleeping threads. We will iterate from the last entry on + the list to the first. Note that the loop condition is always + true for the initial test. */ + for (Entry = CONTAINING_COND_VAR_WAIT_ENTRY(HeadEntry->ListEntry.Blink, ListEntry); + Entry != NULL; + Entry = NextEntry) + { + NTSTATUS Status; + + if (HeadEntry == Entry) + { + /* After the current entry we've iterated through the + entire list in backward direction. Then exit.*/ + NextEntry = NULL; + } + else + { + /* Store away the next reference right now, since we may + not touch Entry anymore at the end of the block. */ + NextEntry = CONTAINING_COND_VAR_WAIT_ENTRY(Entry->ListEntry.Blink, ListEntry); + } + + /* Wake the thread associated with this event. We will + immediately return if we failed (zero timeout). */ + Status = NtReleaseKeyedEvent(CondVarKeyedEventHandle, + &Entry->WaitKey, + FALSE, + &Timeout); + + if (!NT_SUCCESS(Status)) + { + /* We failed to wake a thread. We'll keep trying. */ + ASSERT(STATUS_INVALID_HANDLE != Status); + continue; + } + + /* We've woken a thread and will make sure this thread + is removed from the list. */ + if (HeadEntry == Entry) + { + /* This is the list head. We can't remove it as easily as + other entries and will pass it to the unlock routine + later (we will exit the loop after this round anyway). */ + RemoveOnUnlockEntry = HeadEntry; + } + else + { + /* We can remove the entry right away. */ + RemoveEntryList(&Entry->ListEntry); + + /* Now tell the woken thread that removal from the list was + already taken care of here so that this thread can resume + its normal operation more quickly. We may not touch + Entry after signaling this, since it may lie in invalid + memory from there on. */ + *InternalGetListRemovalHandledFlag(Entry) = TRUE; + } + + if (!ReleaseAll) + { + /* We've successfully woken one thread as the caller + demanded. */ + break; + } + } + + InternalUnlockCondVar(ConditionVariable, RemoveOnUnlockEntry); +} + +VOID +NTAPI +RtlAcquireSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock); +VOID +NTAPI +RtlAcquireSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock); +VOID +NTAPI +RtlReleaseSRWLockExclusive(IN OUT PRTL_SRWLOCK SRWLock); +VOID +NTAPI +RtlReleaseSRWLockShared(IN OUT PRTL_SRWLOCK SRWLock); + +static +NTSTATUS +InternalSleep(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN OUT PRTL_CRITICAL_SECTION CriticalSection OPTIONAL, + IN OUT PRTL_SRWLOCK SRWLock OPTIONAL, + IN ULONG SRWFlags, + IN const LARGE_INTEGER * TimeOut OPTIONAL) +{ + /* Either CriticalSection or SRWLock must be NULL, but not both. + These caller provided lock must be held on entry and will be + held again on return. */ + + COND_VAR_WAIT_ENTRY OwnEntry; + NTSTATUS Status; + + ASSERT(CondVarKeyedEventHandle != NULL); + ASSERT((CriticalSection == NULL) != (SRWLock == NULL)); + + RtlZeroMemory(&OwnEntry, sizeof(OwnEntry)); + + /* Put OwnEntry on the list. */ + InternalLockCondVar(ConditionVariable, &OwnEntry, NULL); + InternalUnlockCondVar(ConditionVariable, NULL); + + /* We can now drop the caller provided lock as a preparation for + going to sleep. */ + if (CriticalSection == NULL) + { + if (0 == (RTL_CONDITION_VARIABLE_LOCKMODE_SHARED & SRWFlags)) + { + RtlReleaseSRWLockExclusive(SRWLock); + } + else + { + RtlReleaseSRWLockShared(SRWLock); + } + } + else + { + RtlLeaveCriticalSection(CriticalSection); + } + + /* Now sleep using the caller provided timeout. */ + Status = NtWaitForKeyedEvent(CondVarKeyedEventHandle, + &OwnEntry.WaitKey, + FALSE, + (PLARGE_INTEGER)TimeOut); + + ASSERT(STATUS_INVALID_HANDLE != Status); + + if (!*InternalGetListRemovalHandledFlag(&OwnEntry)) + { + /* Remove OwnEntry from the list again, since it still seems to + be on the list. We will know for sure once we've acquired + the lock. */ + if (InternalLockCondVar(ConditionVariable, + NULL, + InternalGetListRemovalHandledFlag(&OwnEntry))) + { + /* Unlock and potentially remove OwnEntry. Self-removal is + usually only necessary when a timeout occurred. */ + InternalUnlockCondVar(ConditionVariable, + !OwnEntry.ListRemovalHandled ? + &OwnEntry : NULL); + } + } + +#if _DEBUG + /* Clear OwnEntry to aid in detecting bugs. */ + RtlZeroMemory(&OwnEntry, sizeof(OwnEntry)); +#endif + + /* Reacquire the caller provided lock, as we are about to return. */ + if (CriticalSection == NULL) + { + if (0 == (RTL_CONDITION_VARIABLE_LOCKMODE_SHARED & SRWFlags)) + { + RtlAcquireSRWLockExclusive(SRWLock); + } + else + { + RtlAcquireSRWLockShared(SRWLock); + } + } + else + { + RtlEnterCriticalSection(CriticalSection); + } + + /* Return whatever NtWaitForKeyedEvent returned. */ + return Status; +} + +VOID +RtlpInitializeKeyedEvent(VOID) +{ + ASSERT(CondVarKeyedEventHandle == NULL); + NtCreateKeyedEvent(&CondVarKeyedEventHandle, EVENT_ALL_ACCESS, NULL, 0); +} + +VOID +RtlpCloseKeyedEvent(VOID) +{ + ASSERT(CondVarKeyedEventHandle != NULL); + NtClose(CondVarKeyedEventHandle); + CondVarKeyedEventHandle = NULL; +} + +/* EXPORTED FUNCTIONS ********************************************************/ + +VOID +NTAPI +RtlInitializeConditionVariable(OUT PRTL_CONDITION_VARIABLE ConditionVariable) +{ + ConditionVariable->Ptr = NULL; +} + +VOID +NTAPI +RtlWakeConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable) +{ + InternalWake(ConditionVariable, FALSE); +} + +VOID +NTAPI +RtlWakeAllConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable) +{ + InternalWake(ConditionVariable, TRUE); +} + +NTSYSAPI +NTSTATUS +NTAPI +RtlSleepConditionVariableCS(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN OUT PRTL_CRITICAL_SECTION CriticalSection, + IN const LARGE_INTEGER * TimeOut OPTIONAL) +{ + return InternalSleep(ConditionVariable, + CriticalSection, + (PRTL_SRWLOCK)NULL, + 0, + TimeOut); +} + +NTSYSAPI +NTSTATUS +NTAPI +RtlSleepConditionVariableSRW(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, + IN OUT PRTL_SRWLOCK SRWLock, + IN const LARGE_INTEGER * TimeOut OPTIONAL, + IN ULONG Flags) +{ + return InternalSleep(ConditionVariable, + (PRTL_CRITICAL_SECTION)NULL, + SRWLock, + Flags, + TimeOut); +} + +/* EOF */
Propchange: trunk/reactos/dll/win32/ntdll_vista/condvar.c ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/dll/win32/ntdll_vista/ntdll_vista.spec URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ntdll_vista/ntdll... ============================================================================== --- trunk/reactos/dll/win32/ntdll_vista/ntdll_vista.spec (added) +++ trunk/reactos/dll/win32/ntdll_vista/ntdll_vista.spec [iso-8859-1] Tue May 30 21:35:05 2017 @@ -0,0 +1,10 @@ +@ stdcall RtlInitializeConditionVariable(ptr) +@ stdcall RtlWakeConditionVariable(ptr) +@ stdcall RtlWakeAllConditionVariable(ptr) +@ stdcall RtlSleepConditionVariableCS(ptr ptr ptr) +@ stdcall RtlSleepConditionVariableSRW(ptr ptr ptr long) +@ stdcall RtlInitializeSRWLock(ptr) +@ stdcall RtlAcquireSRWLockShared(ptr) +@ stdcall RtlReleaseSRWLockShared(ptr) +@ stdcall RtlAcquireSRWLockExclusive(ptr) +@ stdcall RtlReleaseSRWLockExclusive(ptr)
Propchange: trunk/reactos/dll/win32/ntdll_vista/ntdll_vista.spec ------------------------------------------------------------------------------ svn:eol-style = native
Added: trunk/reactos/dll/win32/ntdll_vista/rtl_vista.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ntdll_vista/rtl_v... ============================================================================== --- trunk/reactos/dll/win32/ntdll_vista/rtl_vista.h (added) +++ trunk/reactos/dll/win32/ntdll_vista/rtl_vista.h [iso-8859-1] Tue May 30 21:35:05 2017 @@ -0,0 +1,57 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS System Libraries + * FILE: lib/rtl/rtl.h + * PURPOSE: Run-Time Libary Header + * PROGRAMMER: Alex Ionescu + */ + +#ifndef RTL_H +#define RTL_H + +/* We're a core NT DLL, we don't import syscalls */ +#define _INC_SWPRINTF_INL_ +#undef __MSVCRT__ + +/* C Headers */ +#include <stdlib.h> +#include <stdio.h> + +/* PSDK/NDK Headers */ +#define WIN32_NO_STATUS +#define _INC_WINDOWS +#define COM_NO_WINDOWS_H +#define COBJMACROS +#define CONST_VTABLE +#include <windef.h> +#include <winbase.h> +#include <winreg.h> +#include <objbase.h> +#include <ntintsafe.h> +#include <ndk/exfuncs.h> +#include <ndk/iofuncs.h> +#include <ndk/kefuncs.h> +#include <ndk/ldrfuncs.h> +#include <ndk/mmfuncs.h> +#include <ndk/obfuncs.h> +#include <ndk/psfuncs.h> +#include <ndk/rtlfuncs.h> +#include <ndk/setypes.h> +#include <ndk/sefuncs.h> +#include <ndk/umfuncs.h> + +/* SEH support with PSEH */ +#include <pseh/pseh2.h> + +/* Use intrinsics for x86 and x64 */ +#if defined(_M_IX86) || defined(_M_AMD64) +#define InterlockedCompareExchange _InterlockedCompareExchange +#define InterlockedIncrement _InterlockedIncrement +#define InterlockedDecrement _InterlockedDecrement +#define InterlockedExchangeAdd _InterlockedExchangeAdd +#define InterlockedExchange _InterlockedExchange +#define InterlockedBitTestAndSet _interlockedbittestandset +#define InterlockedBitTestAndSet64 _interlockedbittestandset64 +#endif + +#endif /* RTL_H */
Propchange: trunk/reactos/dll/win32/ntdll_vista/rtl_vista.h ------------------------------------------------------------------------------ svn:eol-style = native
Copied: trunk/reactos/dll/win32/ntdll_vista/srw.c (from r74702, trunk/reactos/sdk/lib/rtl/srw.c) URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/ntdll_vista/srw.c... ============================================================================== --- trunk/reactos/sdk/lib/rtl/srw.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/ntdll_vista/srw.c [iso-8859-1] Tue May 30 21:35:05 2017 @@ -13,7 +13,7 @@
/* INCLUDES *****************************************************************/
-#include <rtl.h> +#include <rtl_vista.h>
#define NDEBUG #include <debug.h>
Modified: trunk/reactos/sdk/lib/rtl/CMakeLists.txt URL: http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/rtl/CMakeLists.txt?... ============================================================================== --- trunk/reactos/sdk/lib/rtl/CMakeLists.txt [iso-8859-1] (original) +++ trunk/reactos/sdk/lib/rtl/CMakeLists.txt [iso-8859-1] Tue May 30 21:35:05 2017 @@ -16,7 +16,6 @@ bitmap.c bootdata.c compress.c - condvar.c crc32.c critical.c dbgbuffer.c @@ -56,7 +55,6 @@ security.c slist.c sid.c - srw.c splaytree.c thread.c time.c
Removed: trunk/reactos/sdk/lib/rtl/srw.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/sdk/lib/rtl/srw.c?rev=74702 ============================================================================== --- trunk/reactos/sdk/lib/rtl/srw.c [iso-8859-1] (original) +++ trunk/reactos/sdk/lib/rtl/srw.c (removed) @@ -1,765 +0,0 @@ -/* - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS system libraries - * PURPOSE: Slim Reader/Writer (SRW) Routines - * PROGRAMMER: Thomas Weidenmueller w3seek@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> - -/* 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 - -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, NextWake; - - /* If we were the first one to acquire the shared - lock, we now need to wake all others... */ - WakeChain = FirstWaitBlock->SharedWakeChain; - do - { - NextWake = WakeChain->Next; - - (void)InterlockedOr((PLONG)&WakeChain->Wake, - TRUE); - - WakeChain = NextWake; - } 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); - - 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; - - 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 ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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; - } - - 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; - - NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; - if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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 ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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 ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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 = (LONG)(CurrentValue >> RTL_SRWLOCK_BITS); - StackWaitBlock.Next = NULL; - StackWaitBlock.Last = &StackWaitBlock; - StackWaitBlock.Wake = 0; - - NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_SHARED | RTL_SRWLOCK_CONTENDED | RTL_SRWLOCK_OWNED; - - if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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; - - 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; - - NewValue = (ULONG_PTR)&StackWaitBlock | RTL_SRWLOCK_OWNED | RTL_SRWLOCK_CONTENDED; - if ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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 ((LONG_PTR)InterlockedCompareExchangePointer(&SRWLock->Ptr, - (PVOID)NewValue, - (PVOID)CurrentValue) == 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(); - } -}