Module: wine Branch: master Commit: 7a529328dbb2da8333e565f40503be4e871fc744 URL: http://source.winehq.org/git/wine.git/?a=commit;h=7a529328dbb2da8333e565f405...
Author: Marcus Meissner meissner@suse.de Date: Mon Sep 3 13:54:46 2012 +0200
kernel32: Add condition variables prototypes and tests.
---
dlls/kernel32/tests/sync.c | 116 ++++++++++++++++++++++++++++++++++++++++++++ include/winbase.h | 8 +++ include/winnt.h | 6 ++ 3 files changed, 130 insertions(+), 0 deletions(-)
diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c index 5ce8f09..02c023a 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,112 @@ 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 (!pSleepConditionVariableCS(&buffernotfull, &buffercrit, 2000)) + condvar_sleeperr = TRUE; + } + if (condvar_stop) { + LeaveCriticalSection(&buffercrit); + break; + } + bufferlen++; + totalproduced++; + LeaveCriticalSection(&buffercrit); + pWakeConditionVariable(&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 (!pSleepConditionVariableCS (&buffernotempty, &buffercrit, 2000)) + condvar_sleeperr = TRUE; + } + if (condvar_stop && (bufferlen == 0)) { + LeaveCriticalSection(&buffercrit); + break; + } + bufferlen--; + totalconsumed++; + (*cnt)++; + LeaveCriticalSection(&buffercrit); + pWakeConditionVariable(&buffernotfull); + Sleep(rand() % 10); + } + return 0; +} + +static void test_condvars(void) +{ + HANDLE hp1,hp2,hc1,hc2; + DWORD dummy; + DWORD cnt1,cnt2; + + if (!pInitializeConditionVariable) { + /* function is not yet in XP, only in newer Windows */ + /* and not yet implemented in Wine for some days/weeks */ + todo_wine win_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. */ + trace("produced %d, c1 %d, c2 %d\n", totalproduced, cnt1, cnt2); + /* The sleeps of the producer or consumer should not go above 100* produced count, + * otherwise the implementation does not sleep correctly. But yet again, this is + * not hard defined. */ + trace("producer sleep %d, consumer sleep %d\n", condvar_producer_sleepcnt, condvar_consumer_sleepcnt); +} + START_TEST(sync) { HMODULE hdll = GetModuleHandle("kernel32"); @@ -1254,6 +1365,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 +1381,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 );