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. */ 24int a_global; 25 26/* Print the results of thread-local storage. */ 27int thread_local_val[ N_THREADS ]; 28int 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. */ 32sem_t tell_main, tell_thread; 33 34 35void 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. */ 64void *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 121void 122do_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 213int 214main() 215{ 216 do_pass (); 217 218 return 0; /* Set breakpoint here before exit. */ 219} 220 221/* EndSourceFile */ 222