]> git.draconx.ca Git - cdecl99.git/blobdiff - t/errthread.c
libcdecl: Fix TLS cleanup on Windows.
[cdecl99.git] / t / errthread.c
index 0f1fdf1de0bee3abc6db8d0a7c9cb962815eddce..3161cf4c482a4ff17f95408f3d599cc1ebef14f8 100644 (file)
 #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,46 +52,20 @@ 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 <pthread.h>
 
-static void *thread2(void *p)
-{
-       thread2_func();
-       return 0;
-}
-
-static void run_thread2(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));
-}
+#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 check_init_once(void)
 {
@@ -110,21 +76,16 @@ static void check_init_once(void)
 #define THREAD_API "isoc"
 #include <threads.h>
 
-static int thread2(void *p)
-{
-       thread2_func();
-       return 0;
-}
-
-static void run_thread2(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");
-}
+#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 check_init_once(void)
 {
@@ -136,30 +97,23 @@ static void check_init_once(void)
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 
-static DWORD WINAPI thread2(LPVOID p)
-{
-       thread2_func();
-       return 0;
-}
-
-static void run_thread2(void)
-{
-       HANDLE h;
-       DWORD rc;
-
-       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);
+#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()); \
        }
 
-       tap_bail_out("run_thread2 failed (%lu)", GetLastError());
-}
-
 /* Also include init_once sanity test on Windows */
+#define TEST_W32_NO_DLLMAIN 1
 #include "thread-w32.h"
 
 HANDLE init_semaphore;
@@ -222,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(10);
+       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);
@@ -236,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