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 31struct 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 40struct thread_var_info threadmain; 41struct thread_var_info thread1; 42struct thread_var_info thread2; 43 44 45__thread int a; // statically, initially 0 46__thread int b = 5; // statically, initially 5 47 48extern void _tlv_atexit(void (*termfunc)(void* objAddr), void* objAddr); 49 50void myinit() 51{ 52 a = 11; // dynamically initialized to 11 53 b = 42; // dynamically initialized to 42 54} 55 56void 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 74static 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 98int 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} 155