[PATCH] kernel32: add condition variables prototypes and tests
Marcus Meissner
meissner at suse.de
Sun Sep 2 07:51:06 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