[PATCH] kernel32: add condition variables prototypes and tests

Marcus Meissner meissner at suse.de
Sun Sep 2 05:53:05 CDT 2012


Hi,

This patch adds the definitions for condition variables and a multi
threaded simple producer/consumer testcase.

No functionality is added yet.

The test currently runs for 0.5 second, which results in ca 100 roundtrips
currently on my Lenovo Thinkpad X61 with a slightly buggy condition
variable implementation.

Ciao, Marcus
---
 dlls/kernel32/tests/sync.c |  114 ++++++++++++++++++++++++++++++++++++++++++++
 include/winbase.h          |    8 ++++
 include/winnt.h            |    6 +++
 3 Dateien geändert, 128 Zeilen hinzugefügt(+)

diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c
index 5ce8f09..91d88d8 100644
--- a/dlls/kernel32/tests/sync.c
+++ b/dlls/kernel32/tests/sync.c
@@ -42,6 +42,11 @@ static BOOL   (WINAPI *pInitOnceExecuteOnce)(PINIT_ONCE,PINIT_ONCE_FN,PVOID,LPVO
 static BOOL   (WINAPI *pInitOnceBeginInitialize)(PINIT_ONCE,DWORD,BOOL*,LPVOID*);
 static BOOL   (WINAPI *pInitOnceComplete)(PINIT_ONCE,DWORD,LPVOID);
 
+static VOID   (WINAPI *pInitializeConditionVariable)(PCONDITION_VARIABLE);
+static BOOL   (WINAPI *pSleepConditionVariableCS)(PCONDITION_VARIABLE,PCRITICAL_SECTION,DWORD);
+static VOID   (WINAPI *pWakeAllConditionVariable)(PCONDITION_VARIABLE);
+static VOID   (WINAPI *pWakeConditionVariable)(PCONDITION_VARIABLE);
+
 static void test_signalandwait(void)
 {
     DWORD (WINAPI *pSignalObjectAndWait)(HANDLE, HANDLE, DWORD, BOOL);
@@ -1238,6 +1243,110 @@ static void test_initonce(void)
     ok(initonce.Ptr == (void*)0xdeadbee2, "got %p\n", initonce.Ptr);
 }
 
+static CONDITION_VARIABLE buffernotempty,buffernotfull;
+static CRITICAL_SECTION   buffercrit;
+static BOOL condvar_stop = FALSE, condvar_sleeperr = FALSE;
+static LONG bufferlen,totalproduced,totalconsumed;
+static LONG condvar_producer_sleepcnt,condvar_consumer_sleepcnt;
+
+#define BUFFER_SIZE 10
+
+static DWORD WINAPI condvar_producer(LPVOID x) {
+    while (1) {
+        Sleep(rand() % 10);
+
+        EnterCriticalSection(&buffercrit);
+        while ((bufferlen == BUFFER_SIZE) && !condvar_stop) {
+            condvar_producer_sleepcnt++;
+            if (!SleepConditionVariableCS(&buffernotfull, &buffercrit, 2000))
+                condvar_sleeperr = TRUE;
+        }
+        if (condvar_stop) {
+            LeaveCriticalSection(&buffercrit);
+            break;
+        }
+        bufferlen++;
+        totalproduced++;
+        LeaveCriticalSection(&buffercrit);
+        WakeConditionVariable(&buffernotempty);
+    }
+    return 0;
+}
+
+static DWORD WINAPI condvar_consumer(LPVOID x) {
+    DWORD *cnt = (DWORD*)x;
+
+    while (1) {
+        EnterCriticalSection(&buffercrit);
+        while ((bufferlen == 0) && !condvar_stop) {
+            condvar_consumer_sleepcnt++;
+            if (!SleepConditionVariableCS (&buffernotempty, &buffercrit, 2000))
+                condvar_sleeperr = TRUE;
+        }
+        if (condvar_stop && (bufferlen == 0)) {
+            LeaveCriticalSection(&buffercrit);
+            break;
+        }
+        bufferlen--;
+        totalconsumed++;
+        (*cnt)++;
+        LeaveCriticalSection(&buffercrit);
+        WakeConditionVariable(&buffernotfull);
+        Sleep(rand() % 10);
+    }
+    return 0;
+}
+
+static void test_condvars(void)
+{
+    HANDLE hp1,hp2,hc1,hc2;
+    DWORD dummy;
+    DWORD cnt1,cnt2;
+
+    if (!pInitializeConditionVariable) {
+        skip("no condition variable support.\n");
+        return;
+    }
+
+    /* Implement a producer / consumer scheme with non-full / non-empty triggers */
+    pInitializeConditionVariable(&buffernotfull);
+    pInitializeConditionVariable(&buffernotempty);
+    InitializeCriticalSection(&buffercrit);
+    bufferlen = totalproduced = totalconsumed = cnt1 = cnt2 = 0;
+
+    hp1 = CreateThread(NULL, 0, condvar_producer, NULL, 0, &dummy);
+    hp2 = CreateThread(NULL, 0, condvar_producer, NULL, 0, &dummy);
+    hc1 = CreateThread(NULL, 0, condvar_consumer, (PVOID)&cnt1, 0, &dummy);
+    hc2 = CreateThread(NULL, 0, condvar_consumer, (PVOID)&cnt2, 0, &dummy);
+
+    /* Limit run to 0.5 seconds. */
+    Sleep(500);
+
+    /* tear down start */
+    condvar_stop = TRUE;
+
+    /* final wake up call */
+    pWakeAllConditionVariable (&buffernotfull);
+    pWakeAllConditionVariable (&buffernotempty);
+
+    WaitForSingleObject(hp1, 1000);
+    WaitForSingleObject(hp2, 1000);
+    WaitForSingleObject(hc1, 1000);
+    WaitForSingleObject(hc2, 1000);
+
+    ok(totalconsumed == totalproduced,
+       "consumed %d != produced %d\n", totalconsumed, totalproduced);
+    ok (!condvar_sleeperr, "error occured during SleepConditionVariableCS\n");
+    /* Checking cnt1 - cnt2 for non-0 would be not good, the case where
+     * one consumer does not get anything to do is possible. */
+    /* fprintf(stderr,"produced %d, c1 %d, c2 %d\n", totalproduced, cnt1, cnt2); */
+
+    /* The sleeps of the producer or consumer should not go above 10000, otherwise
+     * the implementation does not sleep correctly. */
+
+    /* fprintf(stderr,"producer sleep %d, consumer sleep %d\n", condvar_producer_sleepcnt, condvar_consumer_sleepcnt); */
+}
+
 START_TEST(sync)
 {
     HMODULE hdll = GetModuleHandle("kernel32");
@@ -1254,6 +1363,10 @@ START_TEST(sync)
     pInitOnceExecuteOnce = (void *)GetProcAddress(hdll, "InitOnceExecuteOnce");
     pInitOnceBeginInitialize = (void *)GetProcAddress(hdll, "InitOnceBeginInitialize");
     pInitOnceComplete = (void *)GetProcAddress(hdll, "InitOnceComplete");
+    pInitializeConditionVariable = (void *)GetProcAddress(hdll, "InitializeConditionVariable");
+    pSleepConditionVariableCS = (void *)GetProcAddress(hdll, "SleepConditionVariableCS");
+    pWakeAllConditionVariable = (void *)GetProcAddress(hdll, "WakeAllConditionVariable");
+    pWakeConditionVariable = (void *)GetProcAddress(hdll, "WakeConditionVariable");
 
     test_signalandwait();
     test_mutex();
@@ -1266,4 +1379,5 @@ START_TEST(sync)
     test_WaitForSingleObject();
     test_WaitForMultipleObjects();
     test_initonce();
+    test_condvars();
 }
diff --git a/include/winbase.h b/include/winbase.h
index 619120e..c1e62a3 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -63,6 +63,10 @@ typedef PRTL_SRWLOCK PSRWLOCK;
 
 typedef WAITORTIMERCALLBACKFUNC WAITORTIMERCALLBACK;
 
+#define CONDITION_VARIABLE_INIT RTL_CONDITION_VARIABLE_INIT
+#define CONDITION_VARIABLE_LOCKMODE_SHARED RTL_CONDITION_VARIABLE_LOCKMODE_SHARED
+typedef RTL_CONDITION_VARIABLE CONDITION_VARIABLE, *PCONDITION_VARIABLE;
+
 #define EXCEPTION_DEBUG_EVENT       1
 #define CREATE_THREAD_DEBUG_EVENT   2
 #define CREATE_PROCESS_DEBUG_EVENT  3
@@ -1880,6 +1884,7 @@ WINBASEAPI BOOL        WINAPI HeapValidate(HANDLE,DWORD,LPCVOID);
 WINBASEAPI BOOL        WINAPI HeapWalk(HANDLE,LPPROCESS_HEAP_ENTRY);
 WINBASEAPI BOOL        WINAPI InitAtomTable(DWORD);
 WINADVAPI  BOOL        WINAPI InitializeAcl(PACL,DWORD,DWORD);
+WINBASEAPI VOID        WINAPI InitializeConditionVariable(PCONDITION_VARIABLE);
 WINBASEAPI void        WINAPI InitializeCriticalSection(CRITICAL_SECTION *lpCrit);
 WINBASEAPI BOOL        WINAPI InitializeCriticalSectionAndSpinCount(CRITICAL_SECTION *,DWORD);
 WINBASEAPI BOOL        WINAPI InitializeCriticalSectionEx(CRITICAL_SECTION *,DWORD,DWORD);
@@ -2172,6 +2177,7 @@ WINBASEAPI BOOL        WINAPI SetupComm(HANDLE,DWORD,DWORD);
 WINBASEAPI DWORD       WINAPI SignalObjectAndWait(HANDLE,HANDLE,DWORD,BOOL);
 WINBASEAPI DWORD       WINAPI SizeofResource(HMODULE,HRSRC);
 WINBASEAPI VOID        WINAPI Sleep(DWORD);
+WINBASEAPI BOOL        WINAPI SleepConditionVariableCS(PCONDITION_VARIABLE,PCRITICAL_SECTION,DWORD);
 WINBASEAPI DWORD       WINAPI SleepEx(DWORD,BOOL);
 WINBASEAPI DWORD       WINAPI SuspendThread(HANDLE);
 WINBASEAPI void        WINAPI SwitchToFiber(LPVOID);
@@ -2224,6 +2230,8 @@ WINBASEAPI DWORD       WINAPI WaitForSingleObjectEx(HANDLE,DWORD,BOOL);
 WINBASEAPI BOOL        WINAPI WaitNamedPipeA(LPCSTR,DWORD);
 WINBASEAPI BOOL        WINAPI WaitNamedPipeW(LPCWSTR,DWORD);
 #define                       WaitNamedPipe WINELIB_NAME_AW(WaitNamedPipe)
+WINBASEAPI VOID        WINAPI WakeAllConditionVariable(PCONDITION_VARIABLE);
+WINBASEAPI VOID        WINAPI WakeConditionVariable(PCONDITION_VARIABLE);
 WINBASEAPI UINT        WINAPI WinExec(LPCSTR,UINT);
 WINBASEAPI BOOL        WINAPI Wow64DisableWow64FsRedirection(PVOID*);
 WINBASEAPI BOOLEAN     WINAPI Wow64EnableWow64FsRedirection(BOOLEAN);
diff --git a/include/winnt.h b/include/winnt.h
index 5625e37..5106701 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -5082,6 +5082,12 @@ typedef struct _RTL_SRWLOCK {
 
 #define RTL_SRWLOCK_INIT {0}
 
+typedef struct _RTL_CONDITION_VARIABLE {
+    PVOID Ptr;
+} RTL_CONDITION_VARIABLE, *PRTL_CONDITION_VARIABLE;
+#define RTL_CONDITION_VARIABLE_INIT {0}
+#define RTL_CONDITION_VARIABLE_LOCKMODE_SHARED  0x1
+
 typedef VOID (NTAPI * WAITORTIMERCALLBACKFUNC) (PVOID, BOOLEAN );
 typedef VOID (NTAPI * PFLS_CALLBACK_FUNCTION) ( PVOID );
 
-- 
1.7.10.4




More information about the wine-patches mailing list