t_scantest_LDADD = src/scan.lo src/parse.lo src/keywords.lo $(TEST_LIBS)
$(t_scantest_OBJECTS): $(gnulib_headers) src/scan.h src/parse.h
-EXTRA_LIBRARIES += t/libmemwrap.a
-t_libmemwrap_a_SOURCES = t/memwrap.c
-$(t_libmemwrap_a_OBJECTS): $(gnulib_headers)
-
-EXTRA_LIBRARIES += t/liberrtest.a
-t_liberrtest_a_SOURCES = src/error.c
-t_liberrtest_a_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_MALLOC_HOOK
-t_liberrtest_a_SHORTNAME = t
-$(t_liberrtest_a_OBJECTS): $(gnulib_headers)
+EXTRA_LTLIBRARIES += t/liberrtest.la
+t_liberrtest_la_SOURCES = src/error.c t/errmemwrap.c
+t_liberrtest_la_CPPFLAGS = $(AM_CPPFLAGS) -DTEST_MALLOC_HOOK
+t_liberrtest_la_LDFLAGS = -no-undefined -avoid-version \
+ -bindir '$(bindir)' -rpath '$(libdir)'
+EXTRA_t_liberrtest_la_DEPENDENCIES = $(shared_gl_objects)
+t_liberrtest_la_LIBADD = src/output.lo $(EXTRA_t_liberrtest_la_DEPENDENCIES) \
+ $(LTLIBINTL) $(LIBTHREAD)
+t_liberrtest_la_SHORTNAME = t
+$(t_liberrtest_la_OBJECTS): $(gnulib_headers)
check_PROGRAMS += t/errthread
-EXTRA_t_errthread_DEPENDENCIES = $(t_liberrtest_a_OBJECTS) \
- $(t_libmemwrap_a_OBJECTS) \
- src/output.lo $(shared_gl_objects)
-t_errthread_LDADD = $(EXTRA_t_errthread_DEPENDENCIES) \
- libtest.a $(LTLIBINTL) $(LIBMULTITHREAD)
+t_errthread_LDADD = t/liberrtest.la libtest.a $(LIBMULTITHREAD)
$(t_errthread_OBJECTS): $(gnulib_headers) src/errmsg.h
src/error.lo: src/errmsg.h
#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.
*/
}
}
-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)
{
#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)
{
#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;
#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);
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