mirror of
https://github.com/reactos/reactos.git
synced 2024-07-01 02:10:07 +00:00
[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 svn path=/trunk/; revision=74703
This commit is contained in:
parent
29177f71b6
commit
296d09b486
|
@ -134,6 +134,7 @@ add_subdirectory(netevent)
|
|||
add_subdirectory(netid)
|
||||
add_subdirectory(newdev)
|
||||
add_subdirectory(npptools)
|
||||
add_subdirectory(ntdll_vista)
|
||||
add_subdirectory(ntdsapi)
|
||||
add_subdirectory(ntlanman)
|
||||
add_subdirectory(ntmarta)
|
||||
|
|
17
reactos/dll/win32/ntdll_vista/CMakeLists.txt
Normal file
17
reactos/dll/win32/ntdll_vista/CMakeLists.txt
Normal file
|
@ -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)
|
36
reactos/dll/win32/ntdll_vista/DllMain.c
Normal file
36
reactos/dll/win32/ntdll_vista/DllMain.c
Normal file
|
@ -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;
|
||||
}
|
525
reactos/dll/win32/ntdll_vista/condvar.c
Normal file
525
reactos/dll/win32/ntdll_vista/condvar.c
Normal file
|
@ -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<EFBFBD>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 */
|
10
reactos/dll/win32/ntdll_vista/ntdll_vista.spec
Normal file
10
reactos/dll/win32/ntdll_vista/ntdll_vista.spec
Normal file
|
@ -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)
|
57
reactos/dll/win32/ntdll_vista/rtl_vista.h
Normal file
57
reactos/dll/win32/ntdll_vista/rtl_vista.h
Normal file
|
@ -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 */
|
|
@ -13,7 +13,7 @@
|
|||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <rtl.h>
|
||||
#include <rtl_vista.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <debug.h>
|
|
@ -16,7 +16,6 @@ list(APPEND SOURCE
|
|||
bitmap.c
|
||||
bootdata.c
|
||||
compress.c
|
||||
condvar.c
|
||||
crc32.c
|
||||
critical.c
|
||||
dbgbuffer.c
|
||||
|
@ -56,7 +55,6 @@ list(APPEND SOURCE
|
|||
security.c
|
||||
slist.c
|
||||
sid.c
|
||||
srw.c
|
||||
splaytree.c
|
||||
thread.c
|
||||
time.c
|
||||
|
|
Loading…
Reference in a new issue