Cider Isn't Darwin Emulation, Really
Something went wrong. Try again.
6.4 kB · 214 lines
C++
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
// BUILD: $CC foo.c -dynamiclib -o $BUILD_DIR/libfoo.dylib -install_name $RUN_DIR/libfoo.dylib// BUILD: $CXX main.cpp -std=c++11 $BUILD_DIR/libfoo.dylib -o $BUILD_DIR/thread-local-destructors.exe
// RUN: ./thread-local-destructors.exe
#include <stdbool.h>#include <stdio.h>#include <stdlib.h>#include <pthread.h>#include <assert.h>#include <unistd.h>
#include <TargetConditionals.h>
static pthread_t sMainThread;static pthread_t sWorker1;static pthread_t sWorker2;
static bool sMainThreadInitialized = false;static bool sWorker1Initialized = false;static bool sWorker2Initialized = false;static bool sMainThreadFinalized = false;static bool sWorker1Finalized = false;static bool sWorker2Finalized = false;
struct Struct { Struct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) { sInitializer = true; } ~Struct() { sFinalizer = true; }
bool& getInitializer() { if (pthread_equal(pthread_self(), sMainThread)) { return sMainThreadInitialized; } if (pthread_equal(pthread_self(), sWorker1)) { return sWorker1Initialized; } if (pthread_equal(pthread_self(), sWorker2)) { return sWorker2Initialized; } assert(false); }
bool& getFinalizer() { if (pthread_equal(pthread_self(), sMainThread)) { return sMainThreadFinalized; } if (pthread_equal(pthread_self(), sWorker1)) { return sWorker1Finalized; } if (pthread_equal(pthread_self(), sWorker2)) { return sWorker2Finalized; } assert(false); }
// TLVs are laxily initialized so have something to do to trigger init void doWork() { }
bool& sInitializer; bool& sFinalizer;};
static thread_local Struct s;
// Add another thread local so that we test dyld's ability to grow the vector of tlv atexits to run
static bool sMainThreadInitialized_Another = false;static bool sWorker1Initialized_Another = false;static bool sWorker2Initialized_Another = false;static bool sMainThreadFinalized_Another = false;static bool sWorker1Finalized_Another = false;static bool sWorker2Finalized_Another = false;
struct AnotherStruct { AnotherStruct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) { sInitializer = true; } ~AnotherStruct() { sFinalizer = true; }
bool& getInitializer() { if (pthread_equal(pthread_self(), sMainThread)) { return sMainThreadInitialized_Another; } if (pthread_equal(pthread_self(), sWorker1)) { return sWorker1Initialized_Another; } if (pthread_equal(pthread_self(), sWorker2)) { return sWorker2Initialized_Another; } assert(false); }
bool& getFinalizer() { if (pthread_equal(pthread_self(), sMainThread)) { return sMainThreadFinalized_Another; } if (pthread_equal(pthread_self(), sWorker1)) { return sWorker1Finalized_Another; } if (pthread_equal(pthread_self(), sWorker2)) { return sWorker2Finalized_Another; } assert(false); }
// TLVs are laxily initialized so have something to do to trigger init void doWork() { }
bool& sInitializer; bool& sFinalizer;};
static thread_local AnotherStruct sAnotherStruct;
static void* work2(void* arg){ s.doWork();
return NULL;}
static void* work1(void* arg){ s.doWork();
if ( pthread_create(&sWorker2, NULL, work2, NULL) != 0 ) { printf("[FAIL] thread-local-destructors, pthread_create\n"); exit(0); } void* dummy; pthread_join(sWorker2, &dummy);
return NULL;}
bool passedChecksInMain = false;
void checkMainThreadFinalizer() { if ( !passedChecksInMain ) return; // _tlv_exit is only called on x86 mac#if TARGET_OS_OSX bool shouldFinalize = true;#else bool shouldFinalize = false;#endif if ( sMainThreadFinalized != shouldFinalize ) printf("[FAIL] thread-local-destructors, main thread finalisation not as expected\n"); else if ( sMainThreadFinalized_Another != shouldFinalize ) printf("[FAIL] thread-local-destructors, main thread other struct finalisation not as expected\n"); else printf("[PASS] thread-local-destructors\n");}
int main(){ printf("[BEGIN] thread-local-destructors\n");
sMainThread = pthread_self(); s.doWork();
sAnotherStruct.doWork();
// Note, as of writing this is being run after the tlv finalizer for this thread // so this should check that this order continues to be used. atexit(&checkMainThreadFinalizer);
if ( pthread_create(&sWorker1, NULL, work1, NULL) != 0 ) { printf("[FAIL] thread-local-destructors, pthread_create\n"); return 0; }
void* dummy; pthread_join(sWorker1, &dummy);
// validate each thread had different addresses for all TLVs if ( !sMainThreadInitialized ) printf("[FAIL] thread-local-destructors, main thread was not initialized\n"); else if ( !sWorker1Initialized ) printf("[FAIL] thread-local-destructors, thread 1 was not initialized\n"); else if ( !sWorker2Initialized ) printf("[FAIL] thread-local-destructors, thread 2 was not initialized\n"); else if ( !sWorker1Finalized ) printf("[FAIL] thread-local-destructors, thread 1 was not finalised\n"); else if ( !sWorker2Finalized ) printf("[FAIL] thread-local-destructors, thread 2 was not finalised\n"); else if ( !sMainThreadInitialized_Another ) printf("[FAIL] thread-local-destructors, main thread other variable was not initialized\n"); else if ( !sWorker1Initialized_Another ) printf("[FAIL] thread-local-destructors, thread 1 other variable was not initialized\n"); else if ( !sWorker2Initialized_Another ) printf("[FAIL] thread-local-destructors, thread 2 other variable was not initialized\n"); else if ( !sWorker1Finalized_Another ) printf("[FAIL] thread-local-destructors, thread 1 other variable was not finalised\n"); else if ( !sWorker2Finalized_Another ) printf("[FAIL] thread-local-destructors, thread 2 other variable was not finalised\n"); else passedChecksInMain = true;
return 0;}