]>
Commit | Line | Data |
---|---|---|
412ebb8e A |
1 | /* |
2 | * Copyright (c) 2010 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | */ | |
23 | #include <stdio.h> // fprintf(), NULL | |
24 | #include <stdlib.h> // exit(), EXIT_SUCCESS | |
25 | #include <pthread.h> | |
26 | #include <stdbool.h> | |
27 | ||
28 | #include "test.h" // PASS(), FAIL(), XPASS(), XFAIL() | |
29 | ||
30 | ||
31 | struct thread_var_info | |
32 | { | |
33 | pthread_t th; | |
34 | int* a_addr; | |
35 | int* b_addr; | |
36 | bool a_terminated; | |
37 | bool b_terminated; | |
38 | }; | |
39 | ||
40 | struct thread_var_info threadmain; | |
41 | struct thread_var_info thread1; | |
42 | struct thread_var_info thread2; | |
43 | ||
44 | ||
45 | __thread int a; // statically, initially 0 | |
46 | __thread int b = 5; // statically, initially 5 | |
47 | ||
48 | extern void _tlv_atexit(void (*termfunc)(void* objAddr), void* objAddr); | |
49 | ||
50 | void myinit() | |
51 | { | |
52 | a = 11; // dynamically initialized to 11 | |
53 | b = 42; // dynamically initialized to 42 | |
54 | } | |
55 | ||
56 | void myterm(void* objAddr) | |
57 | { | |
58 | pthread_t self = pthread_self(); | |
59 | //fprintf(stderr, "myterm(%p), self=%p\n", objAddr, self); | |
60 | if ( thread1.th == self && thread1.a_addr == objAddr ) | |
61 | thread1.a_terminated = true; | |
62 | else if ( thread1.th == self && thread1.b_addr == objAddr ) | |
63 | thread1.b_terminated = true; | |
64 | else if ( thread2.th == self && thread2.a_addr == objAddr ) | |
65 | thread2.a_terminated = true; | |
66 | else if ( thread2.th == self && thread2.b_addr == objAddr ) | |
67 | thread2.b_terminated = true; | |
68 | else if ( threadmain.th == self && threadmain.a_addr == objAddr ) | |
69 | threadmain.a_terminated = true; | |
70 | else if ( threadmain.th == self && threadmain.b_addr == objAddr ) | |
71 | threadmain.b_terminated = true; | |
72 | } | |
73 | ||
74 | static void* work(void* arg) | |
75 | { | |
76 | if ( a != 11 ) { | |
77 | FAIL("tlv-terminators: a not initialized to 11"); | |
78 | exit(0); | |
79 | } | |
80 | if ( b != 42 ) { | |
81 | FAIL("tlv-terminators: b not initialized to 42"); | |
82 | exit(0); | |
83 | } | |
84 | struct thread_var_info* s = (struct thread_var_info*)arg; | |
85 | s->th = pthread_self(); | |
86 | s->a_addr = &a; | |
87 | s->b_addr = &b; | |
88 | s->a_terminated = false; | |
89 | s->b_terminated = false; | |
90 | //fprintf(stderr, "self=%p, arg=%p, &a=%p, &b=%p\n", s->th, arg, s->a_addr , s->b_addr); | |
91 | ||
92 | _tlv_atexit(myterm, &a); | |
93 | _tlv_atexit(myterm, &b); | |
94 | ||
95 | return NULL; | |
96 | } | |
97 | ||
98 | int main() | |
99 | { | |
100 | pthread_t worker1; | |
101 | if ( pthread_create(&worker1, NULL, work, &thread1) != 0 ) { | |
102 | FAIL("pthread_create failed"); | |
103 | exit(0); | |
104 | } | |
105 | ||
106 | pthread_t worker2; | |
107 | if ( pthread_create(&worker2, NULL, work, &thread2) != 0 ) { | |
108 | FAIL("pthread_create failed"); | |
109 | exit(0); | |
110 | } | |
111 | ||
112 | void* result; | |
113 | //fprintf(stderr, "waiting for worker 1\n"); | |
114 | pthread_join(worker1, &result); | |
115 | //fprintf(stderr, "waiting for worker 2\n"); | |
116 | pthread_join(worker2, &result); | |
117 | ||
118 | work(&threadmain); | |
119 | ||
120 | //fprintf(stderr, "thread1: &a=%p, &b=%p\n", thread1.a_addr, thread1.b_addr); | |
121 | //fprintf(stderr, "thread2: &a=%p, &b=%p\n", thread2.a_addr, thread2.b_addr); | |
122 | //fprintf(stderr, "threadm: &a=%p, &b=%p\n", threadmain.a_addr, threadmain.b_addr); | |
123 | ||
124 | if ( ! thread1.a_terminated ) { | |
125 | FAIL("tlv-terminators: terminator for a on thread 1 not run"); | |
126 | exit(0); | |
127 | } | |
128 | if ( ! thread1.b_terminated ) { | |
129 | FAIL("tlv-terminators: terminator for b on thread 1 not run"); | |
130 | exit(0); | |
131 | } | |
132 | ||
133 | if ( ! thread2.a_terminated ) { | |
134 | FAIL("tlv-terminators: terminator for a on thread 2 not run"); | |
135 | exit(0); | |
136 | } | |
137 | if ( ! thread2.b_terminated ) { | |
138 | FAIL("tlv-terminators: terminator for b on thread 2 not run"); | |
139 | exit(0); | |
140 | } | |
141 | ||
142 | if ( threadmain.a_terminated ) { | |
143 | FAIL("tlv-terminators: terminator for a on main thread run early"); | |
144 | exit(0); | |
145 | } | |
146 | if ( threadmain.b_terminated ) { | |
147 | FAIL("tlv-terminators: terminator for b on main thread run early"); | |
148 | exit(0); | |
149 | } | |
150 | ||
151 | ||
152 | PASS("tlv-terminators"); | |
153 | return EXIT_SUCCESS; | |
154 | } |