dyld-732.8.tar.gz
[apple/dyld.git] / testing / test-cases / thread-local-destructors.dtest / main.cpp
1
2
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
5
6
7 // RUN: ./thread-local-destructors.exe
8
9
10 #include <stdbool.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <pthread.h>
14 #include <assert.h>
15 #include <unistd.h>
16
17 #include <TargetConditionals.h>
18
19 static pthread_t sMainThread;
20 static pthread_t sWorker1;
21 static pthread_t sWorker2;
22
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;
29
30 struct Struct {
31 Struct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
32 sInitializer = true;
33 }
34 ~Struct() {
35 sFinalizer = true;
36 }
37
38 bool& getInitializer() {
39 if (pthread_equal(pthread_self(), sMainThread)) {
40 return sMainThreadInitialized;
41 }
42 if (pthread_equal(pthread_self(), sWorker1)) {
43 return sWorker1Initialized;
44 }
45 if (pthread_equal(pthread_self(), sWorker2)) {
46 return sWorker2Initialized;
47 }
48 assert(false);
49 }
50
51 bool& getFinalizer() {
52 if (pthread_equal(pthread_self(), sMainThread)) {
53 return sMainThreadFinalized;
54 }
55 if (pthread_equal(pthread_self(), sWorker1)) {
56 return sWorker1Finalized;
57 }
58 if (pthread_equal(pthread_self(), sWorker2)) {
59 return sWorker2Finalized;
60 }
61 assert(false);
62 }
63
64 // TLVs are laxily initialized so have something to do to trigger init
65 void doWork() {
66 }
67
68 bool& sInitializer;
69 bool& sFinalizer;
70 };
71
72 static thread_local Struct s;
73
74 // Add another thread local so that we test dyld's ability to grow the vector of tlv atexits to run
75
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;
82
83 struct AnotherStruct {
84 AnotherStruct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
85 sInitializer = true;
86 }
87 ~AnotherStruct() {
88 sFinalizer = true;
89 }
90
91 bool& getInitializer() {
92 if (pthread_equal(pthread_self(), sMainThread)) {
93 return sMainThreadInitialized_Another;
94 }
95 if (pthread_equal(pthread_self(), sWorker1)) {
96 return sWorker1Initialized_Another;
97 }
98 if (pthread_equal(pthread_self(), sWorker2)) {
99 return sWorker2Initialized_Another;
100 }
101 assert(false);
102 }
103
104 bool& getFinalizer() {
105 if (pthread_equal(pthread_self(), sMainThread)) {
106 return sMainThreadFinalized_Another;
107 }
108 if (pthread_equal(pthread_self(), sWorker1)) {
109 return sWorker1Finalized_Another;
110 }
111 if (pthread_equal(pthread_self(), sWorker2)) {
112 return sWorker2Finalized_Another;
113 }
114 assert(false);
115 }
116
117 // TLVs are laxily initialized so have something to do to trigger init
118 void doWork() {
119 }
120
121 bool& sInitializer;
122 bool& sFinalizer;
123 };
124
125 static thread_local AnotherStruct sAnotherStruct;
126
127 static void* work2(void* arg)
128 {
129 s.doWork();
130
131 return NULL;
132 }
133
134 static void* work1(void* arg)
135 {
136 s.doWork();
137
138 if ( pthread_create(&sWorker2, NULL, work2, NULL) != 0 ) {
139 printf("[FAIL] thread-local-destructors, pthread_create\n");
140 exit(0);
141 }
142 void* dummy;
143 pthread_join(sWorker2, &dummy);
144
145 return NULL;
146 }
147
148 bool passedChecksInMain = false;
149
150 void checkMainThreadFinalizer() {
151 if ( !passedChecksInMain )
152 return;
153 // _tlv_exit is only called on x86 mac
154 #if TARGET_OS_OSX
155 bool shouldFinalize = true;
156 #else
157 bool shouldFinalize = false;
158 #endif
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");
163 else
164 printf("[PASS] thread-local-destructors\n");
165 }
166
167 int main()
168 {
169 printf("[BEGIN] thread-local-destructors\n");
170
171 sMainThread = pthread_self();
172 s.doWork();
173
174 sAnotherStruct.doWork();
175
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);
179
180 if ( pthread_create(&sWorker1, NULL, work1, NULL) != 0 ) {
181 printf("[FAIL] thread-local-destructors, pthread_create\n");
182 return 0;
183 }
184
185 void* dummy;
186 pthread_join(sWorker1, &dummy);
187
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");
209 else
210 passedChecksInMain = true;
211
212 return 0;
213 }
214