From 26ab7a4424d075b8753d9a0689724cf7ddc97c15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 1 Aug 2018 00:05:23 +0300 Subject: [PATCH] Add a test app for thread local variables with destructors --- Dockerfile.dev | 3 +- run-tests.sh | 8 +++- test/tlstest-lib.cpp | 38 ++++++++++++++++ test/tlstest-main.cpp | 100 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 2 deletions(-) create mode 100644 test/tlstest-lib.cpp create mode 100644 test/tlstest-main.cpp diff --git a/Dockerfile.dev b/Dockerfile.dev index cdcc6d1..8743b99 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -60,9 +60,10 @@ RUN ./build-libcxx.sh $TOOLCHAIN_PREFIX COPY test/*.cpp ./test/ RUN cd test && \ for arch in $TOOLCHAIN_ARCHS; do \ - for test in hello-cpp hello-exception; do \ + for test in hello-cpp hello-exception tlstest-main; do \ $arch-w64-mingw32-clang++ $test.cpp -o $test-$arch.exe || exit 1; \ done; \ + $arch-w64-mingw32-clang++ tlstest-lib.cpp -shared -o tlstest-lib-$arch.dll || exit 1; \ done # Build libssp diff --git a/run-tests.sh b/run-tests.sh index d52ba4c..e970657 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -14,7 +14,7 @@ export PATH=$PREFIX/bin:$PATH cd test TESTS_C="hello hello-tls crt-test setjmp" TESTS_C_NO_BUILTIN="crt-test" -TESTS_CPP="hello-cpp hello-exception" +TESTS_CPP="hello-cpp hello-exception tlstest-main" for arch in $ARCHS; do for test in $TESTS_C; do $arch-w64-mingw32-clang $test.c -o $test-$arch.exe @@ -27,6 +27,7 @@ for arch in $ARCHS; do for test in $TESTS_CPP; do $arch-w64-mingw32-clang++ $test.cpp -o $test-$arch.exe done + $arch-w64-mingw32-clang++ tlstest-lib.cpp -shared -o tlstest-lib-$arch.dll case $arch in i686|x86_64) RUN=wine @@ -41,6 +42,10 @@ for arch in $ARCHS; do COPY="$COPY_AARCH64" ;; esac + cp tlstest-lib-$arch.dll tlstest-lib.dll + if [ -n "$COPY" ]; then + $COPY tlstest-lib.dll + fi for test in $TESTS_C $TESTS_CPP $TESTS_EXTRA; do file=$test-$arch.exe if [ -n "$COPY" ]; then @@ -50,4 +55,5 @@ for arch in $ARCHS; do $RUN $file fi done + rm -f tlstest-lib.dll done diff --git a/test/tlstest-lib.cpp b/test/tlstest-lib.cpp new file mode 100644 index 0000000..76a0e57 --- /dev/null +++ b/test/tlstest-lib.cpp @@ -0,0 +1,38 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include + +class Hello { +public: + Hello(const char* s) { + str = s; + thread = GetCurrentThreadId(); + fprintf(stderr, "%s ctor on thread %d\n", str, thread); + } + ~Hello() { + fprintf(stderr, "%s dtor from thread %d, now on %d\n", str, thread, (int) GetCurrentThreadId()); + } + const char* str; + int thread; +}; + +Hello lib_h("lib global"); +static thread_local Hello lib_tls_h("lib global tls"); + +static void lib_atexit(void) { + fprintf(stderr, "lib_atexit\n"); +} + +static class SetAtexit { +public: + SetAtexit() { + atexit(lib_atexit); + } +} sa; + +extern "C" void __declspec(dllexport) func(void) { + fprintf(stderr, "func\n"); + static thread_local Hello h2("lib local tls"); + fprintf(stderr, "func end, thread %d\n", lib_tls_h.thread); +} diff --git a/test/tlstest-main.cpp b/test/tlstest-main.cpp new file mode 100644 index 0000000..8061cc9 --- /dev/null +++ b/test/tlstest-main.cpp @@ -0,0 +1,100 @@ +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include + +HANDLE event1, event2, event3; +void (*func)(void); + +DWORD fls_key = FLS_OUT_OF_INDEXES; + +class Hello { +public: + Hello(const char* s) { + str = s; + thread = GetCurrentThreadId(); + fprintf(stderr, "%s ctor on thread %d\n", str, thread); + } + ~Hello() { + fprintf(stderr, "%s dtor from thread %d, now on %d\n", str, thread, (int) GetCurrentThreadId()); + } + const char* str; + int thread; +}; + +unsigned __stdcall threadfunc(void *arg) { + HANDLE event = (HANDLE) arg; + int threadId = GetCurrentThreadId(); + fprintf(stderr, "threadfunc thread %d\n", threadId); + static thread_local Hello main_h("main local tls"); + SetEvent(event3); + WaitForSingleObject(event, INFINITE); + fprintf(stderr, "thread %d calling func\n", threadId); + if (func) + func(); + SetEvent(event3); + WaitForSingleObject(event, INFINITE); + + fprintf(stderr, "thread %d finishing\n", threadId); + return 0; +} + +static Hello main_h("main global"); + +static void atexit_func(void) { + fprintf(stderr, "main atexit_func\n"); +} + +int main(int argc, char* argv[]) { + atexit(atexit_func); + fprintf(stderr, "main\n"); + event1 = CreateEvent(NULL, FALSE, FALSE, NULL); + event2 = CreateEvent(NULL, FALSE, FALSE, NULL); + event3 = CreateEvent(NULL, FALSE, FALSE, NULL); + fprintf(stderr, "main, starting thread1\n"); + HANDLE thread1 = (HANDLE)_beginthreadex(NULL, 0, threadfunc, event1, 0, NULL); + WaitForSingleObject(event3, INFINITE); + fprintf(stderr, "main, thread1 started\n"); + fprintf(stderr, "LoadLibrary tlstest-lib.dll\n"); + HMODULE h = LoadLibrary("tlstest-lib.dll"); + fprintf(stderr, "LoadLibrary tlstest-lib.dll ret %p\n", h); + if (!h) { + fprintf(stderr, "Unable to load tlstest-lib.dll\n"); + return 1; + } + func = (void (*)(void)) GetProcAddress(h, "func"); + fprintf(stderr, "main, got func address, calling it\n"); + if (func) + func(); + + fprintf(stderr, "main, starting thread2\n"); + HANDLE thread2 = (HANDLE)_beginthreadex(NULL, 0, threadfunc, event2, 0, NULL); + WaitForSingleObject(event3, INFINITE); + fprintf(stderr, "main, thread2 started\n"); + + SetEvent(event1); + WaitForSingleObject(event3, INFINITE); + fprintf(stderr, "main, thread1 work done\n"); + + SetEvent(event2); + WaitForSingleObject(event3, INFINITE); + fprintf(stderr, "main, thread2 work done\n"); + + SetEvent(event1); + WaitForSingleObject(thread1, INFINITE); + fprintf(stderr, "main, thread1 joined\n"); + + fprintf(stderr, "FreeLibrary\n"); + FreeLibrary(h); + fprintf(stderr, "FreeLibrary done\n"); + + SetEvent(event2); + WaitForSingleObject(thread2, INFINITE); + fprintf(stderr, "main, thread2 joined\n"); + static thread_local Hello main_h("main local tls"); + atexit(atexit_func); + fprintf(stderr, "main done\n"); + return 0; +}