diff --git a/test/initmain.c b/test/initmain.c index 8cb1f00c..95a38201 100644 --- a/test/initmain.c +++ b/test/initmain.c @@ -44,6 +44,7 @@ Test(InitAfterInitialized) struct testParams { uint32_t flag; + threadSysError err; }; /* @@ -148,8 +149,7 @@ static void queueThread(void *data) { struct testParams *p = (struct testParams *) data; - // TODO reintegrate the timer somehow -// p->err = timerSleep(1250 * timerMillisecond); + p->err = threadSleep(1250 * threadMillisecond); uiQueueMain(queued, p); } @@ -168,8 +168,8 @@ Test(QueueMain_DifferentThread) err = threadThreadWaitAndFree(thread); if (err != 0) TestFatalf("error waiting for thread to finish: " threadSysErrorFmt, threadSysErrorFmtArg(err)); -// if (p.err != 0) -// TestErrorf("error sleeping in thread to ensure a high likelihood the uiQueueMain() is run after uiMain() starts: " timerSysErrorFmt, timerSysErrorFmtArg(p.err)); + if (p.err != 0) + TestErrorf("error sleeping in thread to ensure a high likelihood the uiQueueMain() is run after uiMain() starts: " threadSysErrorFmt, threadSysErrorFmtArg(p.err)); if (p.flag != 1) TestErrorf("uiQueueMain() didn't set flag properly:" diff("%d"), p.flag, 1); @@ -179,7 +179,7 @@ static void queueOrderThread(void *data) { struct testParams *p = (struct testParams *) data; -// p->err = timerSleep(1250 * timerMillisecond); + p->err = threadSleep(1250 * threadMillisecond); queueOrder(p); } @@ -198,8 +198,8 @@ Test(QueueMain_DifferentThreadSequence) err = threadThreadWaitAndFree(thread); if (err != 0) TestFatalf("error waiting for thread to finish: " threadSysErrorFmt, threadSysErrorFmtArg(err)); -// if (p.err != 0) -// TestErrorf("error sleeping in thread to ensure a high likelihood the uiQueueMain() is run after uiMain() starts: " timerSysErrorFmt, timerSysErrorFmtArg(p.err)); + if (p.err != 0) + TestErrorf("error sleeping in thread to ensure a high likelihood the uiQueueMain() is run after uiMain() starts: " threadSysErrorFmt, threadSysErrorFmtArg(p.err)); checkOrder(p.flag); } diff --git a/test/thread.h b/test/thread.h index bb809edf..519251b0 100644 --- a/test/thread.h +++ b/test/thread.h @@ -23,6 +23,18 @@ typedef uint64_t threadSysError; extern threadSysError threadNewThread(void (*f)(void *data), void *data, threadThread **t); extern threadSysError threadThreadWaitAndFree(threadThread *t); +typedef int64_t threadDuration; + +#define threadDurationMin ((threadDuration) INT64_MIN) +#define threadDurationMax ((threadDuration) INT64_MAX) + +#define threadNanosecond ((threadDuration) 1) +#define threadMicrosecond ((threadDuration) 1000) +#define threadMillisecond ((threadDuration) 1000000) +#define threadSecond ((threadDuration) 1000000000) + +extern threadSysError threadSleep(threadDuration d); + #ifdef __cplusplus } #endif diff --git a/test/thread_notwindows.c b/test/thread_notwindows.c index 0991f9cb..8aa0277f 100644 --- a/test/thread_notwindows.c +++ b/test/thread_notwindows.c @@ -4,8 +4,10 @@ #define _POSIX_C_SOURCE 200112L #define _XOPEN_SOURCE 600 #include -#include #include +#include +#include +#include #include "thread.h" // Do not put any test cases in this file; they will not be run. @@ -63,3 +65,21 @@ threadSysError threadThreadWaitAndFree(threadThread *t) free(t); return 0; } + +threadSysError threadSleep(threadDuration d) +{ + struct timespec duration, remaining; + int err; + + duration.tv_sec = d / threadSecond; + duration.tv_nsec = d % threadSecond; + for (;;) { + errno = 0; + if (nanosleep(&duration, &remaining) == 0) + return 0; + err = errno; + if (err != EINTR) + return (threadSysError) err; + duration = remaining; + } +} diff --git a/test/thread_windows.c b/test/thread_windows.c index 2293c75a..d7babf86 100644 --- a/test/thread_windows.c +++ b/test/thread_windows.c @@ -52,6 +52,26 @@ static HRESULT WINAPI hrWaitForSingleObject(HANDLE handle, DWORD timeout) return S_OK; } +static HRESULT WINAPI hrCreateWaitableTimerW(LPSECURITY_ATTRIBUTES attributes, BOOL manualReset, LPCWSTR name, HANDLE *handle) +{ + SetLastError(0); + *handle = CreateWaitableTimerW(attributes, manualReset, name); + if (*handle == NULL) + return lastErrorToHRESULT(); + return S_OK; +} + +static HRESULT WINAPI hrSetWaitableTimer(HANDLE timer, const LARGE_INTEGER *duration, LONG period, PTIMERAPCROUTINE completionRoutine, LPVOID completionData, BOOL resume) +{ + BOOL ret; + + SetLastError(0); + ret = SetWaitableTimer(timer, duration, period, completionRoutine, completionData, resume); + if (ret == 0) + return lastErrorToHRESULT(); + return S_OK; +} + struct threadThread { uintptr_t handle; void (*f)(void *data); @@ -100,3 +120,24 @@ threadSysError threadThreadWaitAndFree(threadThread *t) free(t); return 0; } + +threadSysError timerSleep(threadDuration d) +{ + HANDLE timer; + LARGE_INTEGER duration; + HRESULT hr; + + duration.QuadPart = d / 100; + duration.QuadPart = -duration.QuadPart; + hr = hrCreateWaitableTimerW(NULL, TRUE, NULL, &timer); + if (hr != S_OK) + return (threadSysError) hr; + hr = hrSetWaitableTimer(timer, &duration, 0, NULL, NULL, FALSE); + if (hr != S_OK) { + CloseHandle(timer); + return (threadSysError) hr; + } + hr = hrWaitForSingleObject(timer, INFINITE); + CloseHandle(timer); + return (threadSysError) hr; +}