dyld-750.5.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 #include "test_support.h"
20
21 static pthread_t sMainThread;
22 static pthread_t sWorker1;
23 static pthread_t sWorker2;
24
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;
31
32 struct Struct {
33 Struct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
34 sInitializer = true;
35 }
36 ~Struct() {
37 sFinalizer = true;
38 }
39
40 bool& getInitializer() {
41 if (pthread_equal(pthread_self(), sMainThread)) {
42 return sMainThreadInitialized;
43 }
44 if (pthread_equal(pthread_self(), sWorker1)) {
45 return sWorker1Initialized;
46 }
47 if (pthread_equal(pthread_self(), sWorker2)) {
48 return sWorker2Initialized;
49 }
50 assert(false);
51 }
52
53 bool& getFinalizer() {
54 if (pthread_equal(pthread_self(), sMainThread)) {
55 return sMainThreadFinalized;
56 }
57 if (pthread_equal(pthread_self(), sWorker1)) {
58 return sWorker1Finalized;
59 }
60 if (pthread_equal(pthread_self(), sWorker2)) {
61 return sWorker2Finalized;
62 }
63 assert(false);
64 }
65
66 // TLVs are laxily initialized so have something to do to trigger init
67 void doWork() {
68 }
69
70 bool& sInitializer;
71 bool& sFinalizer;
72 };
73
74 static thread_local Struct s;
75
76 // Add another thread local so that we test dyld's ability to grow the vector of tlv atexits to run
77
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;
84
85 struct AnotherStruct {
86 AnotherStruct() : sInitializer(getInitializer()), sFinalizer(getFinalizer()) {
87 sInitializer = true;
88 }
89 ~AnotherStruct() {
90 sFinalizer = true;
91 }
92
93 bool& getInitializer() {
94 if (pthread_equal(pthread_self(), sMainThread)) {
95 return sMainThreadInitialized_Another;
96 }
97 if (pthread_equal(pthread_self(), sWorker1)) {
98 return sWorker1Initialized_Another;
99 }
100 if (pthread_equal(pthread_self(), sWorker2)) {
101 return sWorker2Initialized_Another;
102 }
103 assert(false);
104 }
105
106 bool& getFinalizer() {
107 if (pthread_equal(pthread_self(), sMainThread)) {
108 return sMainThreadFinalized_Another;
109 }
110 if (pthread_equal(pthread_self(), sWorker1)) {
111 return sWorker1Finalized_Another;
112 }
113 if (pthread_equal(pthread_self(), sWorker2)) {
114 return sWorker2Finalized_Another;
115 }
116 assert(false);
117 }
118
119 // TLVs are laxily initialized so have something to do to trigger init
120 void doWork() {
121 }
122
123 bool& sInitializer;
124 bool& sFinalizer;
125 };
126
127 static thread_local AnotherStruct sAnotherStruct;
128
129 static void* work2(void* arg)
130 {
131 s.doWork();
132
133 return NULL;
134 }
135
136 static void* work1(void* arg)
137 {
138 s.doWork();
139
140 if ( pthread_create(&sWorker2, NULL, work2, NULL) != 0 ) {
141 FAIL("pthread_create");
142 }
143 void* dummy;
144 pthread_join(sWorker2, &dummy);
145
146 return NULL;
147 }
148
149 bool passedChecksInMain = false;
150
151 void checkMainThreadFinalizer() {
152 if ( !passedChecksInMain )
153 return;
154 // _tlv_exit is only called on x86 mac
155 #if TARGET_OS_OSX
156 bool shouldFinalize = true;
157 #else
158 bool shouldFinalize = false;
159 #endif
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");
164 else
165 PASS("Success");
166 }
167
168 int main(int argc, const char* argv[], const char* envp[], const char* apple[]) {
169 sMainThread = pthread_self();
170 s.doWork();
171
172 sAnotherStruct.doWork();
173
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);
177
178 if ( pthread_create(&sWorker1, NULL, work1, NULL) != 0 ) {
179 FAIL("pthread_create");
180 }
181
182 void* dummy;
183 pthread_join(sWorker1, &dummy);
184
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");
206 else
207 passedChecksInMain = true;
208
209 return 0;
210 }
211