X-Git-Url: https://git.draconx.ca/gitweb/cdecl99.git/blobdiff_plain/beac10d6593fee948759c05d956b83db6803f2ec..1943156e7ba5c0318a54369a52297f74bad7b5b9:/t/errthread.c diff --git a/t/errthread.c b/t/errthread.c index 445fc83..3161cf4 100644 --- a/t/errthread.c +++ b/t/errthread.c @@ -23,14 +23,6 @@ #include "errmsg.h" #include "tap.h" -/* - * Function called from output.c but not needed for error messaging. - */ -const char *cdecl__token_name(unsigned token) -{ - tap_bail_out("stub cdecl__token_name called"); -} - /* * Prior returned value from cdecl_get_error in the main thread. */ @@ -60,65 +52,44 @@ static void check_simple_err(const struct cdecl_error *err, unsigned t, } } -static void thread2_func(void) -{ - const struct cdecl_error *err; - - cdecl__errmsg(CDECL__ENOTYPE); - err = cdecl_get_error(); - - /* - * Ensure that the error returned in this new thread is distinct from - * the error returned in the main thread. - */ - tap_diag("thread[2] err: %p", (void *)err); - tap_result(thread1_err != err, "thread[2] new state"); - - check_simple_err(err, 2, CDECL_ENOPARSE, CDECL__ENOTYPE); - - tap_diag("thread[2] exit"); -} - #if USE_POSIX_THREADS || USE_ISOC_AND_POSIX_THREADS #define THREAD_API "posix" #include -static void *thread2(void *p) -{ - thread2_func(); - return 0; -} +#define DEFINE_SIMPLE_THREAD_TEST(run_func, thread_entry_func) \ + static void *run_func##_(void *p) { thread_entry_func(); return 0; } \ + static void run_func(void) \ + { \ + pthread_t t; int err; \ + if (!(err = pthread_create(&t, 0, run_func##_, 0))) \ + if (!(err = pthread_join(t, 0))) \ + return; \ + tap_bail_out("%s failed: %s", #run_func, strerror(err)); \ + } -static void run_thread2(void) +static void check_init_once(void) { - pthread_t t; - int err; - - if (!(err = pthread_create(&t, 0, thread2, 0))) - if (!(err = pthread_join(t, 0))) - return; - - tap_bail_out("run_thread2 failed: %s", strerror(err)); + tap_result(1, "init_once # SKIP test not implemented"); } #elif USE_ISOC_THREADS #define THREAD_API "isoc" #include -static int thread2(void *p) -{ - thread2_func(); - return 0; -} +#define DEFINE_SIMPLE_THREAD_TEST(run_func, thread_entry_func) \ + static int run_func##_(void *p) { thread_entry_func(); return 0; } \ + static void run_func(void) \ + { \ + thrd_t t; \ + if (thrd_create(&t, run_func##_, 0) == thrd_success) \ + if (thrd_join(t, 0) == thrd_success) \ + return; \ + tap_bail_out("%s failed", #run_func); \ + } -static void run_thread2(void) +static void check_init_once(void) { - thrd_t t; - if (thrd_create(&t, thread2, 0) == thrd_success) - if (thrd_join(t, 0) == thrd_success) - return; - - tap_bail_out("run_thread2 failed"); + tap_result(1, "init_once # SKIP test not implemented"); } #elif USE_WINDOWS_THREADS @@ -126,28 +97,76 @@ static void run_thread2(void) #define WIN32_LEAN_AND_MEAN #include -static DWORD WINAPI thread2(LPVOID p) +#define DEFINE_SIMPLE_THREAD_TEST(run_func, thread_entry_func) \ + static DWORD WINAPI run_func##_(LPVOID p) \ + { thread_entry_func(); return 0; } \ + static void run_func(void) \ + { \ + HANDLE h; DWORD rc; \ + if ((h = CreateThread(0, 0, run_func##_, 0, 0, &rc))) do { \ + if (GetExitCodeThread(h, &rc) && rc != STILL_ACTIVE) { \ + CloseHandle(h); \ + return; \ + } \ + } while (WaitForSingleObject(h, INFINITE) != WAIT_FAILED); \ + tap_bail_out("%s failed (%lu)", #run_func, GetLastError()); \ + } + +/* Also include init_once sanity test on Windows */ +#define TEST_W32_NO_DLLMAIN 1 +#include "thread-w32.h" + +HANDLE init_semaphore; + +static void init_once_cb(void) +{ + tap_result(1, "init_once_cb start"); + + ReleaseSemaphore(init_semaphore, 2, NULL); + Sleep(1000); + + tap_diag("init_once_cb exit"); +} + +static DWORD WINAPI init_thread(LPVOID p) { - thread2_func(); + WaitForSingleObject(init_semaphore, INFINITE); + + tap_diag("init_thread start"); + init_once(); + tap_diag("init_thread exit"); + return 0; } -static void run_thread2(void) +static void check_init_once(void) { - HANDLE h; + HANDLE threads[3]; DWORD rc; + int i; - if ((h = CreateThread(NULL, 0, thread2, NULL, 0, &rc))) { - do { - if (GetExitCodeThread(h, &rc) && rc != STILL_ACTIVE) { - CloseHandle(h); - return; - } - } while (WaitForSingleObject(h, INFINITE) != WAIT_FAILED); - } + if (!(init_semaphore = CreateSemaphore(NULL, 0, 10, NULL))) + tap_bail_out("check_init_once failed (%lu)", GetLastError()); + + if (!(threads[0] = CreateThread(NULL, 0, init_thread, NULL, 0, &rc))) + tap_bail_out("check_init_once failed (%lu)", GetLastError()); + if (!(threads[1] = CreateThread(NULL, 0, init_thread, NULL, 0, &rc))) + tap_bail_out("check_init_once failed (%lu)", GetLastError()); + if (!(threads[2] = CreateThread(NULL, 0, init_thread, NULL, 0, &rc))) + tap_bail_out("check_init_once failed (%lu)", GetLastError()); + + ReleaseSemaphore(init_semaphore, 1, NULL); + WaitForMultipleObjects(3, threads, TRUE, INFINITE); + + for (i = 0; i < 3; i++) + CloseHandle(threads[i]); + CloseHandle(init_semaphore); - tap_bail_out("run_thread2 failed (%lu)", GetLastError()); + for (i = 0; i < 10000000; i++) + init_once(); } + + #else #undef THREAD_API int main(void) @@ -157,13 +176,43 @@ int main(void) #endif #ifdef THREAD_API + +static void thread_result(void) +{ + tap_result(1, "thread runs"); +} +DEFINE_SIMPLE_THREAD_TEST(check_thread_create, thread_result); + +static void err_in_thread(void) +{ + const struct cdecl_error *err; + + cdecl__errmsg(CDECL__ENOTYPE); + err = cdecl_get_error(); + + /* + * Ensure that the error returned in this new thread is distinct from + * the error returned in the main thread. + */ + tap_diag("thread[2] err: %p", (void *)err); + tap_result(thread1_err != err, "thread[2] new state"); + + check_simple_err(err, 2, CDECL_ENOPARSE, CDECL__ENOTYPE); + + tap_diag("thread[2] exit"); +} +DEFINE_SIMPLE_THREAD_TEST(check_err_in_thread, err_in_thread); + int main(void) { size_t test_live_allocations(void); const struct cdecl_error *err; tap_diag("using thread API: " THREAD_API); - tap_plan(9); + tap_plan(11); + + /* Create/join a thread to tickle DllMain on Windows. */ + check_thread_create(); /* Simulate an error in the main thread. */ cdecl__errmsg(CDECL__ENOMEM); @@ -171,7 +220,7 @@ int main(void) tap_diag("thread[1] err: %p", (void *)thread1_err); check_simple_err(thread1_err, 1, CDECL_ENOMEM, CDECL__ENOMEM); - run_thread2(); + check_err_in_thread(); /* * Back in the main thread, the error previously returned by @@ -195,6 +244,12 @@ int main(void) * Main thread allocation should be the only one left. */ tap_result(test_live_allocations() == 1, "thread cleanup"); + + /* + * Basic init_once sanity check for Windows. + */ + check_init_once(); + tap_done(); } #endif