]> git.saurik.com Git - apple/dyld.git/blob - testing/test-cases/thread-local-atexit.dtest/main.cpp
d86dcabda8983f844907f009ef56a0302772b7ca
[apple/dyld.git] / testing / test-cases / thread-local-atexit.dtest / main.cpp
1
2 // BUILD: $CXX main.cpp -std=c++11 -o $BUILD_DIR/thread-local-atexit.exe
3
4 // RUN: ./thread-local-atexit.exe
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <pthread.h>
9
10 // We create an A and a B.
11 // While destroying B we create a C
12 // Given that tlv_finalize has "destroy in reverse order of construction", we
13 // must then immediately destroy C before we destroy A to maintain that invariant
14
15 enum State {
16 None,
17 ConstructedA,
18 ConstructedB,
19 ConstructedC,
20 DestroyingB,
21 DestroyedA,
22 DestroyedB,
23 DestroyedC,
24 };
25
26 struct A {
27 A();
28 ~A();
29 };
30
31 struct B {
32 B();
33 ~B();
34 };
35
36 struct C {
37 C();
38 ~C();
39 };
40
41 State state;
42
43 A::A() {
44 if ( state != None ) {
45 printf("[FAIL] thread-local-atexit: should be in the 'None' state\n");
46 }
47 state = ConstructedA;
48 }
49
50 B::B() {
51 if ( state != ConstructedA ) {
52 printf("[FAIL] thread-local-atexit: should be in the 'ConstructedA' state\n");
53 _Exit(0);
54 }
55 state = ConstructedB;
56 }
57
58 C::C() {
59 // We construct C during B's destructor
60 if ( state != DestroyingB ) {
61 printf("[FAIL] thread-local-atexit: should be in the 'DestroyingB' state\n");
62 _Exit(0);
63 }
64 state = ConstructedC;
65 }
66
67 // We destroy B first
68 B::~B() {
69 if ( state != ConstructedB ) {
70 printf("[FAIL] thread-local-atexit: should be in the 'ConstructedB' state\n");
71 _Exit(0);
72 }
73 state = DestroyingB;
74 static thread_local C c;
75 if ( state != ConstructedC ) {
76 printf("[FAIL] thread-local-atexit: should be in the 'ConstructedC' state\n");
77 _Exit(0);
78 }
79 state = DestroyedB;
80 }
81
82 // Then we destroy C
83 C::~C() {
84 if ( state != DestroyedB ) {
85 printf("[FAIL] thread-local-atexit: should be in the 'DestroyedB' state\n");
86 _Exit(0);
87 }
88 state = DestroyedC;
89 }
90
91 // And finally destroy A
92 A::~A() {
93 if ( state != DestroyedC ) {
94 printf("[FAIL] thread-local-atexit: should be in the 'DestroyedC' state\n");
95 _Exit(0);
96 }
97 state = DestroyedA;
98 printf("[PASS] thread-local-atexit\n");
99 }
100
101 static void* work(void* arg)
102 {
103 thread_local A a;
104 thread_local B b;
105
106 return NULL;
107 }
108
109 int main() {
110 printf("[BEGIN] thread-local-atexit\n");
111
112 pthread_t worker;
113 if ( pthread_create(&worker, NULL, work, NULL) != 0 ) {
114 printf("[FAIL] thread-local-atexit, pthread_create\n");
115 return 0;
116 }
117
118 void* dummy;
119 pthread_join(worker, &dummy);
120
121 return 0;
122 }
123