From: Sebastian Lackner Subject: [1/2] ntdll: Implement condition variable functions using keyed events Message-Id: <52C9BE9A.40707@fds-team.de> Date: Sun, 05 Jan 2014 21:20:42 +0100 Fixes 30164 and 30173. After all the clean up (thanks to Marcus Meissner for some suggestions) this patch should be pretty much self-explaining. This implementation uses variable->Ptr to store the number of sleeping threads, and uses keyed events to wait for wakeup calls. --- dlls/ntdll/ntdll.spec | 4 +++ dlls/ntdll/sync.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 4 +++ 3 files changed, 100 insertions(+) From d4ec2d09f2c33773f069b5893838fcd94203a87a Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sun, 5 Jan 2014 03:48:34 +0100 Subject: ntdll: Implement condition variable functions using keyed events --- dlls/ntdll/ntdll.spec | 4 +++ dlls/ntdll/sync.c | 92 +++++++++++++++++++++++++++++++++++++++++++++++++ include/winternl.h | 4 +++ 3 files changed, 100 insertions(+) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 6418671..2e507bb 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -672,6 +672,7 @@ @ stdcall RtlInitUnicodeStringEx(ptr wstr) # @ stub RtlInitializeAtomPackage @ stdcall RtlInitializeBitMap(ptr long long) +@ stdcall RtlInitializeConditionVariable(ptr) @ stub RtlInitializeContext @ stdcall RtlInitializeCriticalSection(ptr) @ stdcall RtlInitializeCriticalSectionAndSpinCount(ptr long) @@ -867,6 +868,7 @@ @ stub RtlSetUserFlagsHeap @ stub RtlSetUserValueHeap @ stdcall RtlSizeHeap(long long ptr) +@ stdcall RtlSleepConditionVariableCS(ptr ptr ptr) @ stub RtlSplay @ stub RtlStartRXact # @ stub RtlStatMemoryStream @@ -932,6 +934,8 @@ # @ stub RtlValidateUnicodeString @ stdcall RtlVerifyVersionInfo(ptr long int64) @ stdcall -arch=x86_64 RtlVirtualUnwind(long long long ptr ptr ptr ptr ptr) +@ stdcall RtlWakeAllConditionVariable(ptr) +@ stdcall RtlWakeConditionVariable(ptr) @ stub RtlWalkFrameChain @ stdcall RtlWalkHeap(long ptr) @ stdcall RtlWow64EnableFsRedirection(long) diff --git a/dlls/ntdll/sync.c b/dlls/ntdll/sync.c index b05bd19..45b92ac 100644 --- a/dlls/ntdll/sync.c +++ b/dlls/ntdll/sync.c @@ -63,6 +63,17 @@ WINE_DEFAULT_DEBUG_CHANNEL(ntdll); HANDLE keyed_event = NULL; +static inline int interlocked_dec_if_nonzero( int *dest ) +{ + int val, tmp; + for (val = *dest;; val = tmp) + { + if (!val || (tmp = interlocked_cmpxchg( dest, val - 1, val )) == val) + break; + } + return val; +} + /* creates a struct security_descriptor and contained information in one contiguous piece of memory */ NTSTATUS NTDLL_create_struct_sd(PSECURITY_DESCRIPTOR nt_sd, struct security_descriptor **server_sd, data_size_t *server_sd_len) @@ -1410,3 +1421,84 @@ void WINAPI RtlReleaseSRWLockShared( RTL_SRWLOCK *lock ) { FIXME( "%p stub\n", lock ); } + +/*********************************************************************** + * RtlInitializeConditionVariable (NTDLL.@) + * + * Initializes the condition variable with NULL. + * + * PARAMS + * variable [O] condition variable + * + * RETURNS + * Nothing. + */ +VOID WINAPI RtlInitializeConditionVariable( RTL_CONDITION_VARIABLE *variable ) +{ + variable->Ptr = NULL; +} + +/*********************************************************************** + * RtlWakeConditionVariable (NTDLL.@) + * + * Wakes up one thread waiting on the condition variable. + * + * PARAMS + * variable [I/O] condition variable to wake up. + * + * RETURNS + * Nothing. + * + * NOTES + * The calling thread does not have to own any lock in order to call + * this function. + */ +VOID WINAPI RtlWakeConditionVariable( RTL_CONDITION_VARIABLE *variable ) +{ + if (interlocked_dec_if_nonzero( (int *)&variable->Ptr )) + NtReleaseKeyedEvent( keyed_event, (void *)&variable->Ptr, FALSE, NULL ); +} + +/*********************************************************************** + * RtlWakeAllConditionVariable (NTDLL.@) + * + * See WakeConditionVariable, wakes up all waiting threads. + */ +VOID WINAPI RtlWakeAllConditionVariable( RTL_CONDITION_VARIABLE *variable ) +{ + int val = interlocked_xchg( (int *)&variable->Ptr, 0 ); + while (val-- > 0) + NtReleaseKeyedEvent( keyed_event, (void *)&variable->Ptr, FALSE, NULL ); +} + +/*********************************************************************** + * RtlSleepConditionVariableCS (NTDLL.@) + * + * Atomically releases the critical section and suspends the thread, + * waiting for a Wake(All)ConditionVariable event. Afterwards it enters + * the critical section again and returns. + * + * PARAMS + * variable [I/O] condition variable + * crit [I/O] critical section to leave temporarily + * timeout [I] timeout + * + * RETURNS + * see NtWaitForKeyedEvent for all possible return values. + */ +NTSTATUS WINAPI RtlSleepConditionVariableCS( RTL_CONDITION_VARIABLE *variable, RTL_CRITICAL_SECTION *crit, LARGE_INTEGER *timeout) +{ + NTSTATUS status; + interlocked_xchg_add( (int *)&variable->Ptr, 1 ); + RtlLeaveCriticalSection( crit ); + + status = NtWaitForKeyedEvent( keyed_event, (void *)&variable->Ptr, FALSE, timeout ); + if (status != STATUS_SUCCESS) + { + if (!interlocked_dec_if_nonzero( (int *)&variable->Ptr )) + status = NtWaitForKeyedEvent( keyed_event, (void *)&variable->Ptr, FALSE, NULL ); + } + + RtlEnterCriticalSection( crit ); + return status; +} diff --git a/include/winternl.h b/include/winternl.h index d93b37a..18235d7 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -2418,6 +2418,7 @@ NTSYSAPI void WINAPI RtlInitAnsiString(PANSI_STRING,PCSZ); NTSYSAPI NTSTATUS WINAPI RtlInitAnsiStringEx(PANSI_STRING,PCSZ); NTSYSAPI void WINAPI RtlInitUnicodeString(PUNICODE_STRING,PCWSTR); NTSYSAPI NTSTATUS WINAPI RtlInitUnicodeStringEx(PUNICODE_STRING,PCWSTR); +NTSYSAPI void WINAPI RtlInitializeConditionVariable(RTL_CONDITION_VARIABLE *); NTSYSAPI NTSTATUS WINAPI RtlInitializeCriticalSection(RTL_CRITICAL_SECTION *); NTSYSAPI NTSTATUS WINAPI RtlInitializeCriticalSectionAndSpinCount(RTL_CRITICAL_SECTION *,ULONG); NTSYSAPI NTSTATUS WINAPI RtlInitializeCriticalSectionEx(RTL_CRITICAL_SECTION *,ULONG,ULONG); @@ -2501,6 +2502,7 @@ NTSYSAPI NTSTATUS WINAPI RtlSetSaclSecurityDescriptor(PSECURITY_DESCRIPTOR,BOOL NTSYSAPI NTSTATUS WINAPI RtlSetThreadErrorMode(DWORD,LPDWORD); NTSYSAPI NTSTATUS WINAPI RtlSetTimeZoneInformation(const RTL_TIME_ZONE_INFORMATION*); NTSYSAPI SIZE_T WINAPI RtlSizeHeap(HANDLE,ULONG,const void*); +NTSYSAPI NTSTATUS WINAPI RtlSleepConditionVariableCS(RTL_CONDITION_VARIABLE *,RTL_CRITICAL_SECTION *,LARGE_INTEGER *); NTSYSAPI NTSTATUS WINAPI RtlStringFromGUID(REFGUID,PUNICODE_STRING); NTSYSAPI LPDWORD WINAPI RtlSubAuthoritySid(PSID,DWORD); NTSYSAPI LPBYTE WINAPI RtlSubAuthorityCountSid(PSID); @@ -2544,6 +2546,8 @@ NTSYSAPI BOOLEAN WINAPI RtlValidAcl(PACL); NTSYSAPI BOOLEAN WINAPI RtlValidSid(PSID); NTSYSAPI BOOLEAN WINAPI RtlValidateHeap(HANDLE,ULONG,LPCVOID); NTSYSAPI NTSTATUS WINAPI RtlVerifyVersionInfo(const RTL_OSVERSIONINFOEXW*,DWORD,DWORDLONG); +NTSYSAPI void WINAPI RtlWakeAllConditionVariable(RTL_CONDITION_VARIABLE *); +NTSYSAPI void WINAPI RtlWakeConditionVariable(RTL_CONDITION_VARIABLE *); NTSYSAPI NTSTATUS WINAPI RtlWalkHeap(HANDLE,PVOID); NTSYSAPI NTSTATUS WINAPI RtlWow64EnableFsRedirection(BOOLEAN); NTSYSAPI NTSTATUS WINAPI RtlWow64EnableFsRedirectionEx(ULONG,ULONG*); -- 1.7.9.5