And added the multithreaded uiQueueMain() tests.
This commit is contained in:
parent
6c41fb712e
commit
df8eadb980
|
@ -63,7 +63,7 @@ testingTest(QueueMain)
|
||||||
uiQueueMain(queued, &flag);
|
uiQueueMain(queued, &flag);
|
||||||
timeout_uiMain(t, 5 * testingNsecPerSec, 0);
|
timeout_uiMain(t, 5 * testingNsecPerSec, 0);
|
||||||
if (flag != 1)
|
if (flag != 1)
|
||||||
testingTErrorf(t, "uiQueueMain didn't set flag properly: got %d, want 1", flag);
|
testingTErrorf(t, "uiQueueMain() didn't set flag properly: got %d, want 1", flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define queueOp(name, expr) \
|
#define queueOp(name, expr) \
|
||||||
|
@ -93,30 +93,77 @@ static const struct {
|
||||||
{ 16, "mul8 -> div3 -> sub2" },
|
{ 16, "mul8 -> div3 -> sub2" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void queueOrder(uint32_t *flag)
|
||||||
|
{
|
||||||
|
*flag = 7;
|
||||||
|
uiQueueMain(sub2, flag);
|
||||||
|
uiQueueMain(div3, flag);
|
||||||
|
uiQueueMain(mul8, flag);
|
||||||
|
uiQueueMain(done, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO somehow funnel the caller's file/line through
|
||||||
|
static void checkOrder(testingT *t, uint32_t flag)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (flag == orders[0].result)
|
||||||
|
return;
|
||||||
|
for (i = 1; i < 6; i++)
|
||||||
|
if (flag == orders[i].result) {
|
||||||
|
testingTErrorf(t, "got %" PRIu32 " (%s), want %" PRIu32 " (%s)", flag, orders[i].order, orders[0].result, orders[0].order);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
testingTErrorf(t, "got %" PRIu32 " (unknown order), want %" PRIu32 " (%s)", flag, orders[0].result, orders[0].order);
|
||||||
|
}
|
||||||
|
|
||||||
testingTest(QueueMain_Sequence)
|
testingTest(QueueMain_Sequence)
|
||||||
{
|
{
|
||||||
uint32_t flag;
|
uint32_t flag;
|
||||||
int i;
|
|
||||||
|
|
||||||
flag = 7;
|
queueOrder(&flag);
|
||||||
uiQueueMain(sub2, &flag);
|
|
||||||
uiQueueMain(div3, &flag);
|
|
||||||
uiQueueMain(mul8, &flag);
|
|
||||||
uiQueueMain(done, NULL);
|
|
||||||
timeout_uiMain(t, 5 * testingNsecPerSec, 0);
|
timeout_uiMain(t, 5 * testingNsecPerSec, 0);
|
||||||
if (flag != orders[0].result) {
|
checkOrder(t, flag);
|
||||||
for (i = 1; i < 6; i++)
|
|
||||||
if (flag == orders[i].result) {
|
|
||||||
testingTErrorf(t, "got %" PRIu32 " (%s), want %" PRIu32 " (%s)", flag, orders[i].order, orders[0].result, orders[0].order);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (i >= 6)
|
|
||||||
testingTErrorf(t, "got %" PRIu32 " (unknown order), want %" PRIu32 " (%s)", flag, orders[0].result, orders[0].order);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO testingTest(QueueMain_DifferentThread)
|
static void queueThread(void *data)
|
||||||
// TODO testingTest(QueueMain_DifferentThreadSequence)
|
{
|
||||||
|
int *flag = (int *) data;
|
||||||
|
|
||||||
|
testingSleep(1250 * testingNsecPerMsec);
|
||||||
|
uiQueueMain(queued, flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
testingTest(QueueMain_DifferentThread)
|
||||||
|
{
|
||||||
|
testingThread *thread;
|
||||||
|
int flag = 0;
|
||||||
|
|
||||||
|
thread = testingNewThread(queueThread, &flag);
|
||||||
|
timeout_uiMain(t, 5 * testingNsecPerSec, 0);
|
||||||
|
testingThreadWaitAndFree(thread);
|
||||||
|
if (flag != 1)
|
||||||
|
testingTErrorf(t, "uiQueueMain() didn't set flag properly: got %d, want 1", flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void queueOrderThread(void *data)
|
||||||
|
{
|
||||||
|
uint32_t *flag = (uint32_t *) data;
|
||||||
|
|
||||||
|
testingSleep(1250 * testingNsecPerMsec);
|
||||||
|
queueOrder(flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
testingTest(QueueMain_DifferentThreadSequence)
|
||||||
|
{
|
||||||
|
testingThread *thread;
|
||||||
|
uint32_t flag;
|
||||||
|
|
||||||
|
thread = testingNewThread(queueOrderThread, &flag);
|
||||||
|
timeout_uiMain(t, 5 * testingNsecPerSec, 0);
|
||||||
|
testingThreadWaitAndFree(thread);
|
||||||
|
checkOrder(t, flag);
|
||||||
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
static void timer(void *data)
|
static void timer(void *data)
|
||||||
|
|
|
@ -67,6 +67,7 @@ extern void testingTDefer(testingT *t, void (*f)(testingT *t, void *data), void
|
||||||
typedef struct testingTimer testingTimer;
|
typedef struct testingTimer testingTimer;
|
||||||
|
|
||||||
#define testingNsecPerUsec ((int64_t) 1000)
|
#define testingNsecPerUsec ((int64_t) 1000)
|
||||||
|
#define testingNsecPerMsec ((int64_t) 1000000)
|
||||||
#define testingNsecPerSec ((int64_t) 1000000000)
|
#define testingNsecPerSec ((int64_t) 1000000000)
|
||||||
|
|
||||||
extern testingTimer *testingNewTimer(void);
|
extern testingTimer *testingNewTimer(void);
|
||||||
|
@ -81,6 +82,13 @@ extern void testingFreeNsecString(char *s);
|
||||||
#define testingRunWithTimeout(t, timeout, f, data, comment, failNowOnError) \
|
#define testingRunWithTimeout(t, timeout, f, data, comment, failNowOnError) \
|
||||||
testingprivRunWithTimeout(t, __FILE__, __LINE__, timeout, f, data, comment, failNowOnError)
|
testingprivRunWithTimeout(t, __FILE__, __LINE__, timeout, f, data, comment, failNowOnError)
|
||||||
|
|
||||||
|
extern void testingSleep(int64_t nsec);
|
||||||
|
|
||||||
|
// TODO I don't like this threading model, but let's use it for now so I can continue working
|
||||||
|
typedef struct testingThread testingThread;
|
||||||
|
extern testingThread *testingNewThread(void (*f)(void *data), void *data);
|
||||||
|
extern void testingThreadWaitAndFree(testingThread *t);
|
||||||
|
|
||||||
extern void testingprivRegisterTest(const char *, void (*)(testingT *), const char *, long);
|
extern void testingprivRegisterTest(const char *, void (*)(testingT *), const char *, long);
|
||||||
extern void testingprivRegisterTestBefore(const char *, void (*)(testingT *), const char *, long);
|
extern void testingprivRegisterTestBefore(const char *, void (*)(testingT *), const char *, long);
|
||||||
extern void testingprivRegisterTestAfter(const char *, void (*)(testingT *), const char *, long);
|
extern void testingprivRegisterTestAfter(const char *, void (*)(testingT *), const char *, long);
|
||||||
|
|
|
@ -259,3 +259,56 @@ out:
|
||||||
if (failNowOnError)
|
if (failNowOnError)
|
||||||
testingTFailNow(t);
|
testingTFailNow(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testingSleep(int64_t nsec)
|
||||||
|
{
|
||||||
|
HANDLE timer;
|
||||||
|
LARGE_INTEGER duration;
|
||||||
|
|
||||||
|
// TODO check errors, possibly falling back to Sleep() (although it has lower resolution)
|
||||||
|
// TODO rename all the other durations that are timeout or timer to duration or nsec, both here and in the Unix/Darwin code
|
||||||
|
duration.QuadPart = nsec / 100;
|
||||||
|
duration.QuadPart = -duration.QuadPart;
|
||||||
|
timer = CreateWaitableTimerW(NULL, TRUE, NULL);
|
||||||
|
SetWaitableTimer(timer, &duration, 0, NULL, NULL, FALSE);
|
||||||
|
WaitForSingleObject(timer, INFINITE);
|
||||||
|
CloseHandle(timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct testingThread {
|
||||||
|
uintptr_t handle;
|
||||||
|
void (*f)(void *data);
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static unsigned __stdcall threadThreadProc(void *data)
|
||||||
|
{
|
||||||
|
testingThread *t = (testingThread *) data;
|
||||||
|
|
||||||
|
(*(t->f))(t->data);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
testingThread *testingNewThread(void (*f)(void *data), void *data)
|
||||||
|
{
|
||||||
|
testingThread *t;
|
||||||
|
|
||||||
|
t = malloc(sizeof (testingThread));
|
||||||
|
// TODO check error
|
||||||
|
ZeroMemory(t, sizeof (testingThread));
|
||||||
|
t->f = f;
|
||||||
|
t->data = data;
|
||||||
|
|
||||||
|
t->handle = _beginthreadex(NULL, 0, threadThreadProc, t, 0, NULL);
|
||||||
|
// TODO check error
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void testingThreadWaitAndFree(testingThread *t)
|
||||||
|
{
|
||||||
|
// TODO check errors
|
||||||
|
WaitForSingleObject((HANDLE) (t->handle), INFINITE);
|
||||||
|
// TODO end check errors
|
||||||
|
CloseHandle((HANDLE) (t->handle));
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue