1 /* BeginSourceFile tls.c 2 3 This file creates and deletes threads. It uses thread local storage 4 variables too. */ 5 6 #include <unistd.h> 7 #include <stdlib.h> 8 #include <stdio.h> 9 #include <assert.h> 10 #include <pthread.h> 11 #include <semaphore.h> 12 #include <errno.h> 13 14 #define N_THREADS 3 15 16 /* Uncomment to turn on debugging output */ 17 /*#define START_DEBUG*/ 18 19 /* Thread-local storage. */ 20 __thread int a_thread_local; 21 __thread int another_thread_local; 22 23 /* Global variable just for info addr in gdb. */ 24 int a_global; 25 26 /* Print the results of thread-local storage. */ 27 int thread_local_val[ N_THREADS ]; 28 int another_thread_local_val[ N_THREADS ]; 29 30 /* Semaphores to make sure the threads are alive when we print the TLS 31 variables from gdb. */ 32 sem_t tell_main, tell_thread; 33 34 35 void print_error () 36 { 37 switch (errno) 38 { 39 case EAGAIN: 40 fprintf (stderr, "EAGAIN\n"); 41 break; 42 case EINTR: 43 fprintf (stderr, "EINTR\n"); 44 break; 45 case EINVAL: 46 fprintf (stderr, "EINVAL\n"); 47 break; 48 case ENOSYS: 49 fprintf (stderr, "ENOSYS\n"); 50 break; 51 case ENOENT: 52 fprintf (stderr, "ENOENT\n"); 53 break; 54 case EDEADLK: 55 fprintf (stderr, "EDEADLK\n"); 56 break; 57 default: 58 fprintf (stderr, "Unknown error\n"); 59 break; 60 } 61 } 62 63 /* Routine for each thread to run, does nothing. */ 64 void *spin( vp ) 65 void * vp; 66 { 67 int me = (long) vp; 68 int i; 69 70 /* Use a_global. */ 71 a_global++; 72 73 a_thread_local = 0; 74 another_thread_local = me; 75 for( i = 0; i <= me; i++ ) { 76 a_thread_local += i; 77 } 78 79 another_thread_local_val[me] = another_thread_local; 80 thread_local_val[ me ] = a_thread_local; /* here we know tls value */ 81 82 if (sem_post (&tell_main) == -1) 83 { 84 fprintf (stderr, "th %d post on sem tell_main failed\n", me); 85 print_error (); 86 return; 87 } 88 #ifdef START_DEBUG 89 fprintf (stderr, "th %d post on tell main\n", me); 90 #endif 91 92 while (1) 93 { 94 #ifdef START_DEBUG 95 fprintf (stderr, "th %d start wait on tell_thread\n", me); 96 #endif 97 if (sem_wait (&tell_thread) == 0) 98 break; 99 100 if (errno == EINTR) 101 { 102 #ifdef START_DEBUG 103 fprintf (stderr, "th %d wait tell_thread got EINTR, rewaiting\n", me); 104 #endif 105 continue; 106 } 107 else 108 { 109 fprintf (stderr, "th %d wait on sem tell_thread failed\n", me); 110 print_error (); 111 return; 112 } 113 } 114 115 #ifdef START_DEBUG 116 fprintf (stderr, "th %d Wait on tell_thread\n", me); 117 #endif 118 119 } 120 121 void 122 do_pass() 123 { 124 int i; 125 pthread_t t[ N_THREADS ]; 126 int err; 127 128 for( i = 0; i < N_THREADS; i++) 129 { 130 thread_local_val[i] = 0; 131 another_thread_local_val[i] = 0; 132 } 133 134 if (sem_init (&tell_main, 0, 0) == -1) 135 { 136 fprintf (stderr, "tell_main semaphore init failed\n"); 137 return; 138 } 139 140 if (sem_init (&tell_thread, 0, 0) == -1) 141 { 142 fprintf (stderr, "tell_thread semaphore init failed\n"); 143 return; 144 } 145 146 /* Start N_THREADS threads, then join them so that they are terminated. */ 147 for( i = 0; i < N_THREADS; i++ ) 148 { 149 err = pthread_create( &t[i], NULL, spin, (void *) (long) i ); 150 if( err != 0 ) { 151 fprintf(stderr, "Error in thread %d create\n", i ); 152 } 153 } 154 155 for( i = 0; i < N_THREADS; i++ ) 156 { 157 while (1) 158 { 159 #ifdef START_DEBUG 160 fprintf (stderr, "main %d start wait on tell_main\n", i); 161 #endif 162 if (sem_wait (&tell_main) == 0) 163 break; 164 165 if (errno == EINTR) 166 { 167 #ifdef START_DEBUG 168 fprintf (stderr, "main %d wait tell_main got EINTR, rewaiting\n", i); 169 #endif 170 continue; 171 } 172 else 173 { 174 fprintf (stderr, "main %d wait on sem tell_main failed\n", i); 175 print_error (); 176 return; 177 } 178 } 179 } 180 181 #ifdef START_DEBUG 182 fprintf (stderr, "main done waiting on tell_main\n"); 183 #endif 184 185 i = 10; /* Here all threads should be still alive. */ 186 187 for( i = 0; i < N_THREADS; i++ ) 188 { 189 if (sem_post (&tell_thread) == -1) 190 { 191 fprintf (stderr, "main %d post on sem tell_thread failed\n", i); 192 print_error (); 193 return; 194 } 195 #ifdef START_DEBUG 196 fprintf (stderr, "main %d post on tell_thread\n", i); 197 #endif 198 } 199 200 for( i = 0; i < N_THREADS; i++ ) 201 { 202 err = pthread_join(t[i], NULL ); 203 if( err != 0 ) 204 { 205 fprintf (stderr, "error in thread %d join\n", i ); 206 } 207 } 208 209 i = 10; /* Null line for setting bpts on. */ 210 211 } 212 213 int 214 main() 215 { 216 do_pass (); 217 218 return 0; /* Set breakpoint here before exit. */ 219 } 220 221 /* EndSourceFile */ 222