/* Condvar testing. */ #include #include #include #define ASSERT(x) assert(x) #if 1 #define TEST_RtlSleepConditionVariableCS RtlSleepConditionVariableCS #define TEST_RtlWakeConditionVariable RtlWakeConditionVariable #define TEST_RtlWakeAllConditionVariable RtlWakeAllConditionVariable VOID NTAPI RtlWakeConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable); VOID NTAPI RtlWakeAllConditionVariable(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable); NTSTATUS NTAPI RtlSleepConditionVariableCS(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN OUT PRTL_CRITICAL_SECTION CriticalSection, IN PLARGE_INTEGER TimeOut OPTIONAL); #else #define TEST_RtlSleepConditionVariableCS SleepFuncPtr #define TEST_RtlWakeConditionVariable WakeOneFuncPtr #define TEST_RtlWakeAllConditionVariable WakeAllFuncPtr #endif typedef void NTAPI WakeFunc(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable); typedef NTSTATUS NTAPI SleepFunc(IN OUT PRTL_CONDITION_VARIABLE ConditionVariable, IN OUT PRTL_CRITICAL_SECTION CriticalSection, IN PLARGE_INTEGER TimeOut OPTIONAL); WakeFunc * WakeOneFuncPtr; WakeFunc * WakeAllFuncPtr; SleepFunc * SleepFuncPtr; RTL_CRITICAL_SECTION g_Section; RTL_CONDITION_VARIABLE g_CondVar; BOOLEAN RunWorkers = FALSE; VOID DebugInit(IN HANDLE NtDll) { SleepFuncPtr = (SleepFunc *)GetProcAddress(NtDll, "RtlSleepConditionVariableCS"); WakeOneFuncPtr = (WakeFunc *)GetProcAddress(NtDll, "RtlWakeConditionVariable"); WakeAllFuncPtr = (WakeFunc *)GetProcAddress(NtDll, "RtlWakeAllConditionVariable"); ASSERT(NULL != SleepFuncPtr && NULL != WakeOneFuncPtr && NULL != WakeAllFuncPtr); return; } DWORD WINAPI TestWorker(IN PVOID p) { DWORD DefaultWaitSecs = 20; ULONG ThreadNum = (ULONG)p; LARGE_INTEGER Timeout; printf("Thread %d running\n", ThreadNum); Timeout.QuadPart = DefaultWaitSecs * -10000000LL; EnterCriticalSection(&g_Section); while (FALSE != RunWorkers) { NTSTATUS Status = TEST_RtlSleepConditionVariableCS(&g_CondVar, &g_Section, &Timeout); Status; printf("Thread %d spinning\n", ThreadNum); } LeaveCriticalSection(&g_Section); printf("Thread %d died\n", ThreadNum); return 0; } void Test() { DWORD ThreadCount = 4; UINT k; HANDLE NtDllHandle = LoadLibrary(L"Ntdll.dll"); ASSERT(NULL != NtDllHandle); DebugInit(NtDllHandle); InitializeCriticalSection(&g_Section); InitializeConditionVariable(&g_CondVar); *(BOOLEAN VOLATILE *)&RunWorkers = TRUE; for (k = 0; k != ThreadCount; k++) { DWORD Id; HANDLE Handle = CreateThread (NULL, 0, TestWorker, (PVOID)(k + 1), 0, &Id); CloseHandle(Handle); /* This will make it more likely that threads start running in creation order. */ Sleep(20); } /* Now wake some threads. */ Sleep(1000); printf("Releasing one thread...\n"); TEST_RtlWakeConditionVariable(&g_CondVar); Sleep(5000); printf("Releasing another thread...\n"); TEST_RtlWakeConditionVariable(&g_CondVar); Sleep(5000); printf("Releasing ALL threads...\n"); TEST_RtlWakeAllConditionVariable(&g_CondVar); Sleep(5000); *(BOOLEAN VOLATILE *)&RunWorkers = FALSE; printf("Exiting main\n"); /* FIXME: We're leaking NtDllHandle (this is just a test). */ Sleep(100000); return; } int _tmain() { Test(); return 0; }