And split all the thread stuff into their own file. Almost done with all this test library cleanup!
This commit is contained in:
parent
89e882c4a8
commit
57abc83fe3
|
@ -2,6 +2,7 @@
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "test.h"
|
#include "test.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
// TODO fix up the formatting of testing.c so we can use newlines on the got/want stuff
|
// TODO fix up the formatting of testing.c so we can use newlines on the got/want stuff
|
||||||
|
|
||||||
|
@ -137,12 +138,13 @@ static void queueThread(void *data)
|
||||||
|
|
||||||
testingTest(QueueMain_DifferentThread)
|
testingTest(QueueMain_DifferentThread)
|
||||||
{
|
{
|
||||||
testingThread *thread;
|
threadThread *thread;
|
||||||
int flag = 0;
|
int flag = 0;
|
||||||
|
|
||||||
thread = testingNewThread(queueThread, &flag);
|
// TODO check errors
|
||||||
|
threadNewThread(queueThread, &flag, &thread);
|
||||||
timeout_uiMain(t, 5 * timerSecond);
|
timeout_uiMain(t, 5 * timerSecond);
|
||||||
testingThreadWaitAndFree(thread);
|
threadThreadWaitAndFree(thread);
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
@ -158,12 +160,13 @@ static void queueOrderThread(void *data)
|
||||||
|
|
||||||
testingTest(QueueMain_DifferentThreadSequence)
|
testingTest(QueueMain_DifferentThreadSequence)
|
||||||
{
|
{
|
||||||
testingThread *thread;
|
threadThread *thread;
|
||||||
uint32_t flag = 1; // make sure it's initialized just in case
|
uint32_t flag = 1; // make sure it's initialized just in case
|
||||||
|
|
||||||
thread = testingNewThread(queueOrderThread, &flag);
|
// TODO check errors
|
||||||
|
threadNewThread(queueOrderThread, &flag, &thread);
|
||||||
timeout_uiMain(t, 5 * timerSecond);
|
timeout_uiMain(t, 5 * timerSecond);
|
||||||
testingThreadWaitAndFree(thread);
|
threadThreadWaitAndFree(thread);
|
||||||
checkOrder(t, flag);
|
checkOrder(t, flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,12 +9,12 @@ libui_test_sources = [
|
||||||
|
|
||||||
if libui_OS == 'windows'
|
if libui_OS == 'windows'
|
||||||
libui_test_sources += [
|
libui_test_sources += [
|
||||||
'testing_windows.c',
|
'thread_windows.c',
|
||||||
'timer_windows.c',
|
'timer_windows.c',
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
libui_test_sources += [
|
libui_test_sources += [
|
||||||
'testing_darwinunix.c',
|
'thread_darwinunix.c',
|
||||||
'timer_darwinunix.c'
|
'timer_darwinunix.c'
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "testing.h"
|
#include "testing.h"
|
||||||
#include "testingpriv.h"
|
|
||||||
|
|
||||||
void testingprivInternalError(const char *fmt, ...)
|
void testingprivInternalError(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -30,6 +29,9 @@ void *testingprivMalloc(size_t n, const char *what)
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define testingprivNew(T) ((T *) testingprivMalloc(sizeof (T), #T))
|
||||||
|
#define testingprivNewArray(T, n) ((T *) testingprivMalloc(n * sizeof (T), #T "[" #n "]"))
|
||||||
|
|
||||||
void *testingprivRealloc(void *x, size_t n, const char *what)
|
void *testingprivRealloc(void *x, size_t n, const char *what)
|
||||||
{
|
{
|
||||||
void *y;
|
void *y;
|
||||||
|
@ -40,6 +42,8 @@ void *testingprivRealloc(void *x, size_t n, const char *what)
|
||||||
return y;
|
return y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define testingprivResizeArray(x, T, n) ((T *) testingprivRealloc(x, n * sizeof (T), #T "[" #n "]"))
|
||||||
|
|
||||||
void testingprivFree(void *x)
|
void testingprivFree(void *x)
|
||||||
{
|
{
|
||||||
free(x);
|
free(x);
|
||||||
|
|
|
@ -64,11 +64,6 @@ extern void testingTFailNow(testingT *t);
|
||||||
extern void testingTSkipNow(testingT *t);
|
extern void testingTSkipNow(testingT *t);
|
||||||
extern void testingTDefer(testingT *t, void (*f)(testingT *t, void *data), void *data);
|
extern void testingTDefer(testingT *t, void (*f)(testingT *t, void *data), void *data);
|
||||||
|
|
||||||
// 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);
|
||||||
|
|
|
@ -1,59 +0,0 @@
|
||||||
// 28 april 2019
|
|
||||||
// TODO pin down minimum POSIX versions (depends on what macOS 10.8 conforms to and what GLib/GTK+ require)
|
|
||||||
// TODO feature test macros for things like monotonic clocks?
|
|
||||||
// TODO is this needed in this file specifically, or just in testing_unix.c?
|
|
||||||
#define _POSIX_C_SOURCE 200112L
|
|
||||||
#include <errno.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <setjmp.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <time.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include "testing.h"
|
|
||||||
#include "testingpriv.h"
|
|
||||||
|
|
||||||
// TODO don't start the timer on any platform until after we call setjmp(); also decide whether to start the timer before or after resuming the thread on Windows
|
|
||||||
|
|
||||||
struct testingThread {
|
|
||||||
pthread_t thread;
|
|
||||||
void (*f)(void *data);
|
|
||||||
void *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *threadThreadProc(void *data)
|
|
||||||
{
|
|
||||||
testingThread *t = (testingThread *) data;
|
|
||||||
|
|
||||||
(*(t->f))(t->data);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
testingThread *testingNewThread(void (*f)(void *data), void *data)
|
|
||||||
{
|
|
||||||
testingThread *t;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
t = testingprivNew(testingThread);
|
|
||||||
t->f = f;
|
|
||||||
t->data = data;
|
|
||||||
|
|
||||||
err = pthread_create(&(t->thread), NULL, threadThreadProc, t);
|
|
||||||
if (err != 0)
|
|
||||||
testingprivInternalError("error creating thread: %s (%d)", strerror(err), err);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
void testingThreadWaitAndFree(testingThread *t)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = pthread_join(t->thread, NULL);
|
|
||||||
if (err != 0)
|
|
||||||
testingprivInternalError("error waiting for thread to finish: %s (%d)", strerror(err), err);
|
|
||||||
// TODO do we need to free t->thread somehow?
|
|
||||||
testingprivFree(t);
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
// 29 april 2019
|
|
||||||
|
|
||||||
extern void testingprivInternalError(const char *fmt, ...);
|
|
||||||
extern void *testingprivMalloc(size_t n, const char *what);
|
|
||||||
#define testingprivNew(T) ((T *) testingprivMalloc(sizeof (T), #T))
|
|
||||||
#define testingprivNewArray(T, n) ((T *) testingprivMalloc(n * sizeof (T), #T "[" #n "]"))
|
|
||||||
extern void *testingprivRealloc(void *x, size_t n, const char *what);
|
|
||||||
#define testingprivResizeArray(x, T, n) ((T *) testingprivRealloc(x, n * sizeof (T), #T "[" #n "]"))
|
|
||||||
extern void testingprivFree(void *x);
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
// 4 may 2019
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// I don't like this threading model, but let's use it for now so I can continue working
|
||||||
|
|
||||||
|
typedef struct threadThread threadThread;
|
||||||
|
|
||||||
|
typedef uint64_t threadSysError;
|
||||||
|
#ifdef _WIN32
|
||||||
|
#define threadSysErrorFmt "0x%08I32X"
|
||||||
|
#define threadSysErrorFmtArg(x) ((uint32_t) x)
|
||||||
|
#else
|
||||||
|
#include <string.h>
|
||||||
|
#define threadSysErrorFmt "%s (%d)"
|
||||||
|
#define threadSysErrorFmtArg(x) strerror((int) x), ((int) x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern threadSysError threadNewThread(void (*f)(void *data), void *data, threadThread **t);
|
||||||
|
extern threadSysError threadThreadWaitAndFree(threadThread *t);
|
|
@ -0,0 +1,61 @@
|
||||||
|
// 28 april 2019
|
||||||
|
// TODO pin down minimum POSIX versions (depends on what macOS 10.8 conforms to and what GLib/GTK+ require)
|
||||||
|
#define _POSIX_C_SOURCE 200112L
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
|
struct threadThread {
|
||||||
|
pthread_t thread;
|
||||||
|
void (*f)(void *data);
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *threadThreadProc(void *data)
|
||||||
|
{
|
||||||
|
threadThread *t = (threadThread *) data;
|
||||||
|
|
||||||
|
(*(t->f))(t->data);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
threadSysError threadNewThread(void (*f)(void *data), void *data, threadThread **t)
|
||||||
|
{
|
||||||
|
threadThread *tout;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
*t = NULL;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
tout = (threadThread *) malloc(sizeof (threadThread));
|
||||||
|
if (tout == NULL) {
|
||||||
|
err = errno;
|
||||||
|
if (err == 0)
|
||||||
|
err = ENOMEM;
|
||||||
|
return (threadSysError) err;
|
||||||
|
}
|
||||||
|
tout->f = f;
|
||||||
|
tout->data = data;
|
||||||
|
|
||||||
|
err = pthread_create(&(tout->thread), NULL, threadThreadProc, tout);
|
||||||
|
if (err != 0) {
|
||||||
|
free(tout);
|
||||||
|
return (threadSysError) err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = tout;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
threadSysError threadThreadWaitAndFree(threadThread *t)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = pthread_join(t->thread, NULL);
|
||||||
|
if (err != 0)
|
||||||
|
return (threadSysError) err;
|
||||||
|
// TODO do we have to release t->thread somehow?
|
||||||
|
free(t);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -10,13 +10,8 @@
|
||||||
#define NTDDI_VERSION 0x06000000
|
#define NTDDI_VERSION 0x06000000
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include <errno.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include "thread.h"
|
||||||
#include "timer.h"
|
|
||||||
#include "testing.h"
|
|
||||||
#include "testingpriv.h"
|
|
||||||
|
|
||||||
static HRESULT lastErrorCodeToHRESULT(DWORD lastError)
|
static HRESULT lastErrorCodeToHRESULT(DWORD lastError)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +50,7 @@ static HRESULT WINAPI hrWaitForSingleObject(HANDLE handle, DWORD timeout)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct testingThread {
|
struct threadThread {
|
||||||
uintptr_t handle;
|
uintptr_t handle;
|
||||||
void (*f)(void *data);
|
void (*f)(void *data);
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -63,34 +58,43 @@ struct testingThread {
|
||||||
|
|
||||||
static unsigned __stdcall threadThreadProc(void *data)
|
static unsigned __stdcall threadThreadProc(void *data)
|
||||||
{
|
{
|
||||||
testingThread *t = (testingThread *) data;
|
threadThread *t = (threadThread *) data;
|
||||||
|
|
||||||
(*(t->f))(t->data);
|
(*(t->f))(t->data);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
testingThread *testingNewThread(void (*f)(void *data), void *data)
|
threadSysError threadNewThread(void (*f)(void *data), void *data, threadThread **t)
|
||||||
{
|
{
|
||||||
testingThread *t;
|
threadThread *tout;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
t = testingprivNew(testingThread);
|
*t = NULL;
|
||||||
t->f = f;
|
|
||||||
t->data = data;
|
|
||||||
|
|
||||||
hr = hr_beginthreadex(NULL, 0, threadThreadProc, t, 0, NULL, &(t->handle));
|
tout = (threadThread *) malloc(sizeof (threadThread));
|
||||||
if (hr != S_OK)
|
if (tout == NULL)
|
||||||
testingprivInternalError("error creating thread: 0x%08I32X", hr);
|
return (threadSysError) E_OUTOFMEMORY;
|
||||||
return t;
|
tout->f = f;
|
||||||
|
tout->data = data;
|
||||||
|
|
||||||
|
hr = hr_beginthreadex(NULL, 0, threadThreadProc, tout, 0, NULL, &(tout->handle));
|
||||||
|
if (hr != S_OK) {
|
||||||
|
free(tout);
|
||||||
|
return (threadSysError) hr;
|
||||||
|
}
|
||||||
|
|
||||||
|
*t = tout;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testingThreadWaitAndFree(testingThread *t)
|
threadSysError threadThreadWaitAndFree(threadThread *t)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
hr = hrWaitForSingleObject((HANDLE) (t->handle), INFINITE);
|
hr = hrWaitForSingleObject((HANDLE) (t->handle), INFINITE);
|
||||||
if (hr != S_OK)
|
if (hr != S_OK)
|
||||||
testingprivInternalError("error waiting for thread to finish: 0x%08I32X", hr);
|
return (threadSysError) hr;
|
||||||
CloseHandle((HANDLE) (t->handle));
|
CloseHandle((HANDLE) (t->handle));
|
||||||
testingprivFree(t);
|
free(t);
|
||||||
|
return 0;
|
||||||
}
|
}
|
|
@ -206,6 +206,10 @@ struct timeoutParams {
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DWORD timeoutParamsSlot;
|
||||||
|
static HRESULT timeoutParamsHRESULT = S_OK;
|
||||||
|
static INIT_ONCE timeoutParamsOnce = INIT_ONCE_STATIC_INIT;
|
||||||
|
|
||||||
static void onTimeout(void)
|
static void onTimeout(void)
|
||||||
{
|
{
|
||||||
struct timeoutParams *p;
|
struct timeoutParams *p;
|
||||||
|
@ -214,10 +218,6 @@ static void onTimeout(void)
|
||||||
longjmp(p->retpos, 1);
|
longjmp(p->retpos, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD timeoutParamsSlot;
|
|
||||||
static HRESULT timeoutParamsHRESULT = S_OK;
|
|
||||||
static INIT_ONCE timeoutParamsOnce = INIT_ONCE_STATIC_INIT;
|
|
||||||
|
|
||||||
static BOOL CALLBACK timeoutParamsSlotInit(PINIT_ONCE once, PVOID param, PVOID *ctx)
|
static BOOL CALLBACK timeoutParamsSlotInit(PINIT_ONCE once, PVOID param, PVOID *ctx)
|
||||||
{
|
{
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
|
|
Loading…
Reference in New Issue