[1/2] ntdll: Implement condition variable functions using keyed events

Sebastian Lackner sebastian at fds-team.de
Sun Jan 5 14:20:42 CST 2014


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(+)
-------------- next part --------------
>From d4ec2d09f2c33773f069b5893838fcd94203a87a Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian at fds-team.de>
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



More information about the wine-patches mailing list