3 // BUILD: $CC foo.c -dynamiclib -o $BUILD_DIR/libfoo.dylib -install_name $RUN_DIR/libfoo.dylib
4 // BUILD: $CXX main.cpp -std=c++11 $BUILD_DIR/libfoo.dylib -o $BUILD_DIR/thread-local-destructors.exe
7 // RUN: ./thread-local-destructors.exe
17 #include <TargetConditionals.h>
19 static pthread_t sMainThread
;
20 static pthread_t sWorker1
;
21 static pthread_t sWorker2
;
23 static bool sMainThreadInitialized
= false;
24 static bool sWorker1Initialized
= false;
25 static bool sWorker2Initialized
= false;
26 static bool sMainThreadFinalized
= false;
27 static bool sWorker1Finalized
= false;
28 static bool sWorker2Finalized
= false;
31 Struct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
38 bool& getInitializer() {
39 if (pthread_equal(pthread_self(), sMainThread
)) {
40 return sMainThreadInitialized
;
42 if (pthread_equal(pthread_self(), sWorker1
)) {
43 return sWorker1Initialized
;
45 if (pthread_equal(pthread_self(), sWorker2
)) {
46 return sWorker2Initialized
;
51 bool& getFinalizer() {
52 if (pthread_equal(pthread_self(), sMainThread
)) {
53 return sMainThreadFinalized
;
55 if (pthread_equal(pthread_self(), sWorker1
)) {
56 return sWorker1Finalized
;
58 if (pthread_equal(pthread_self(), sWorker2
)) {
59 return sWorker2Finalized
;
64 // TLVs are laxily initialized so have something to do to trigger init
72 static thread_local Struct s
;
74 // Add another thread local so that we test dyld's ability to grow the vector of tlv atexits to run
76 static bool sMainThreadInitialized_Another
= false;
77 static bool sWorker1Initialized_Another
= false;
78 static bool sWorker2Initialized_Another
= false;
79 static bool sMainThreadFinalized_Another
= false;
80 static bool sWorker1Finalized_Another
= false;
81 static bool sWorker2Finalized_Another
= false;
83 struct AnotherStruct
{
84 AnotherStruct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
91 bool& getInitializer() {
92 if (pthread_equal(pthread_self(), sMainThread
)) {
93 return sMainThreadInitialized_Another
;
95 if (pthread_equal(pthread_self(), sWorker1
)) {
96 return sWorker1Initialized_Another
;
98 if (pthread_equal(pthread_self(), sWorker2
)) {
99 return sWorker2Initialized_Another
;
104 bool& getFinalizer() {
105 if (pthread_equal(pthread_self(), sMainThread
)) {
106 return sMainThreadFinalized_Another
;
108 if (pthread_equal(pthread_self(), sWorker1
)) {
109 return sWorker1Finalized_Another
;
111 if (pthread_equal(pthread_self(), sWorker2
)) {
112 return sWorker2Finalized_Another
;
117 // TLVs are laxily initialized so have something to do to trigger init
125 static thread_local AnotherStruct sAnotherStruct
;
127 static void* work2(void* arg
)
134 static void* work1(void* arg
)
138 if ( pthread_create(&sWorker2
, NULL
, work2
, NULL
) != 0 ) {
139 printf("[FAIL] thread-local-destructors, pthread_create\n");
143 pthread_join(sWorker2
, &dummy
);
148 bool passedChecksInMain
= false;
150 void checkMainThreadFinalizer() {
151 if ( !passedChecksInMain
)
153 // _tlv_exit is only called on x86 mac
155 bool shouldFinalize
= true;
157 bool shouldFinalize
= false;
159 if ( sMainThreadFinalized
!= shouldFinalize
)
160 printf("[FAIL] thread-local-destructors, main thread finalisation not as expected\n");
161 else if ( sMainThreadFinalized_Another
!= shouldFinalize
)
162 printf("[FAIL] thread-local-destructors, main thread other struct finalisation not as expected\n");
164 printf("[PASS] thread-local-destructors\n");
169 printf("[BEGIN] thread-local-destructors\n");
171 sMainThread
= pthread_self();
174 sAnotherStruct
.doWork();
176 // Note, as of writing this is being run after the tlv finalizer for this thread
177 // so this should check that this order continues to be used.
178 atexit(&checkMainThreadFinalizer
);
180 if ( pthread_create(&sWorker1
, NULL
, work1
, NULL
) != 0 ) {
181 printf("[FAIL] thread-local-destructors, pthread_create\n");
186 pthread_join(sWorker1
, &dummy
);
188 // validate each thread had different addresses for all TLVs
189 if ( !sMainThreadInitialized
)
190 printf("[FAIL] thread-local-destructors, main thread was not initialized\n");
191 else if ( !sWorker1Initialized
)
192 printf("[FAIL] thread-local-destructors, thread 1 was not initialized\n");
193 else if ( !sWorker2Initialized
)
194 printf("[FAIL] thread-local-destructors, thread 2 was not initialized\n");
195 else if ( !sWorker1Finalized
)
196 printf("[FAIL] thread-local-destructors, thread 1 was not finalised\n");
197 else if ( !sWorker2Finalized
)
198 printf("[FAIL] thread-local-destructors, thread 2 was not finalised\n");
199 else if ( !sMainThreadInitialized_Another
)
200 printf("[FAIL] thread-local-destructors, main thread other variable was not initialized\n");
201 else if ( !sWorker1Initialized_Another
)
202 printf("[FAIL] thread-local-destructors, thread 1 other variable was not initialized\n");
203 else if ( !sWorker2Initialized_Another
)
204 printf("[FAIL] thread-local-destructors, thread 2 other variable was not initialized\n");
205 else if ( !sWorker1Finalized_Another
)
206 printf("[FAIL] thread-local-destructors, thread 1 other variable was not finalised\n");
207 else if ( !sWorker2Finalized_Another
)
208 printf("[FAIL] thread-local-destructors, thread 2 other variable was not finalised\n");
210 passedChecksInMain
= true;