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 #include "test_support.h"
21 static pthread_t sMainThread
;
22 static pthread_t sWorker1
;
23 static pthread_t sWorker2
;
25 static bool sMainThreadInitialized
= false;
26 static bool sWorker1Initialized
= false;
27 static bool sWorker2Initialized
= false;
28 static bool sMainThreadFinalized
= false;
29 static bool sWorker1Finalized
= false;
30 static bool sWorker2Finalized
= false;
33 Struct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
40 bool& getInitializer() {
41 if (pthread_equal(pthread_self(), sMainThread
)) {
42 return sMainThreadInitialized
;
44 if (pthread_equal(pthread_self(), sWorker1
)) {
45 return sWorker1Initialized
;
47 if (pthread_equal(pthread_self(), sWorker2
)) {
48 return sWorker2Initialized
;
53 bool& getFinalizer() {
54 if (pthread_equal(pthread_self(), sMainThread
)) {
55 return sMainThreadFinalized
;
57 if (pthread_equal(pthread_self(), sWorker1
)) {
58 return sWorker1Finalized
;
60 if (pthread_equal(pthread_self(), sWorker2
)) {
61 return sWorker2Finalized
;
66 // TLVs are laxily initialized so have something to do to trigger init
74 static thread_local Struct s
;
76 // Add another thread local so that we test dyld's ability to grow the vector of tlv atexits to run
78 static bool sMainThreadInitialized_Another
= false;
79 static bool sWorker1Initialized_Another
= false;
80 static bool sWorker2Initialized_Another
= false;
81 static bool sMainThreadFinalized_Another
= false;
82 static bool sWorker1Finalized_Another
= false;
83 static bool sWorker2Finalized_Another
= false;
85 struct AnotherStruct
{
86 AnotherStruct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
93 bool& getInitializer() {
94 if (pthread_equal(pthread_self(), sMainThread
)) {
95 return sMainThreadInitialized_Another
;
97 if (pthread_equal(pthread_self(), sWorker1
)) {
98 return sWorker1Initialized_Another
;
100 if (pthread_equal(pthread_self(), sWorker2
)) {
101 return sWorker2Initialized_Another
;
106 bool& getFinalizer() {
107 if (pthread_equal(pthread_self(), sMainThread
)) {
108 return sMainThreadFinalized_Another
;
110 if (pthread_equal(pthread_self(), sWorker1
)) {
111 return sWorker1Finalized_Another
;
113 if (pthread_equal(pthread_self(), sWorker2
)) {
114 return sWorker2Finalized_Another
;
119 // TLVs are laxily initialized so have something to do to trigger init
127 static thread_local AnotherStruct sAnotherStruct
;
129 static void* work2(void* arg
)
136 static void* work1(void* arg
)
140 if ( pthread_create(&sWorker2
, NULL
, work2
, NULL
) != 0 ) {
141 FAIL("pthread_create");
144 pthread_join(sWorker2
, &dummy
);
149 bool passedChecksInMain
= false;
151 void checkMainThreadFinalizer() {
152 if ( !passedChecksInMain
)
154 // _tlv_exit is only called on x86 mac
156 bool shouldFinalize
= true;
158 bool shouldFinalize
= false;
160 if ( sMainThreadFinalized
!= shouldFinalize
)
161 FAIL("Main thread finalisation not as expected");
162 else if ( sMainThreadFinalized_Another
!= shouldFinalize
)
163 FAIL("Main thread other struct finalisation not as expected");
168 int main(int argc
, const char* argv
[], const char* envp
[], const char* apple
[]) {
169 sMainThread
= pthread_self();
172 sAnotherStruct
.doWork();
174 // Note, as of writing this is being run after the tlv finalizer for this thread
175 // so this should check that this order continues to be used.
176 atexit(&checkMainThreadFinalizer
);
178 if ( pthread_create(&sWorker1
, NULL
, work1
, NULL
) != 0 ) {
179 FAIL("pthread_create");
183 pthread_join(sWorker1
, &dummy
);
185 // validate each thread had different addresses for all TLVs
186 if ( !sMainThreadInitialized
)
187 FAIL("Main thread was not initialized");
188 else if ( !sWorker1Initialized
)
189 FAIL("Thread 1 was not initialized");
190 else if ( !sWorker2Initialized
)
191 FAIL("Thread 2 was not initialized");
192 else if ( !sWorker1Finalized
)
193 FAIL("Thread 1 was not finalised");
194 else if ( !sWorker2Finalized
)
195 FAIL("Thread 2 was not finalised");
196 else if ( !sMainThreadInitialized_Another
)
197 FAIL("Main thread other variable was not initialized");
198 else if ( !sWorker1Initialized_Another
)
199 FAIL("Thread 1 other variable was not initialized");
200 else if ( !sWorker2Initialized_Another
)
201 FAIL("Thread 2 other variable was not initialized");
202 else if ( !sWorker1Finalized_Another
)
203 FAIL("Thread 1 other variable was not finalised");
204 else if ( !sWorker2Finalized_Another
)
205 FAIL("Thread 2 other variable was not finalised");
207 passedChecksInMain
= true;