/* BeginSourceFile tls.c This file creates and deletes threads. It uses thread local storage variables too. */ #include #include #include #include #include #include #include #define N_THREADS 3 /* Uncomment to turn on debugging output */ /*#define START_DEBUG*/ /* Thread-local storage. */ __thread int a_thread_local; class K { public: static __thread int another_thread_local; }; __thread int K::another_thread_local; /* psymtabs->symtabs resolving check. */ extern __thread int file2_thread_local; /* Global variable just for info addr in gdb. */ int a_global; /* Print the results of thread-local storage. */ int thread_local_val[ N_THREADS ]; int another_thread_local_val[ N_THREADS ]; /* Semaphores to make sure the threads are alive when we print the TLS variables from gdb. */ sem_t tell_main, tell_thread; void print_error () { switch (errno) { case EAGAIN: fprintf (stderr, "EAGAIN\n"); break; case EINTR: fprintf (stderr, "EINTR\n"); break; case EINVAL: fprintf (stderr, "EINVAL\n"); break; case ENOSYS: fprintf (stderr, "ENOSYS\n"); break; case ENOENT: fprintf (stderr, "ENOENT\n"); break; case EDEADLK: fprintf (stderr, "EDEADLK\n"); break; default: fprintf (stderr, "Unknown error\n"); break; } } /* Routine for each thread to run, does nothing. */ void *spin( void *vp ) { int me = (long) vp; int i; /* Use a_global. */ a_global++; a_thread_local = 0; K::another_thread_local = me; for( i = 0; i <= me; i++ ) { a_thread_local += i; } another_thread_local_val[me] = K::another_thread_local; thread_local_val[ me ] = a_thread_local; /* here we know tls value */ if (sem_post (&tell_main) == -1) { fprintf (stderr, "th %d post on sem tell_main failed\n", me); print_error (); return NULL; } #ifdef START_DEBUG fprintf (stderr, "th %d post on tell main\n", me); #endif while (1) { #ifdef START_DEBUG fprintf (stderr, "th %d start wait on tell_thread\n", me); #endif if (sem_wait (&tell_thread) == 0) break; if (errno == EINTR) { #ifdef START_DEBUG fprintf (stderr, "th %d wait tell_thread got EINTR, rewaiting\n", me); #endif continue; } else { fprintf (stderr, "th %d wait on sem tell_thread failed\n", me); print_error (); return NULL; } } #ifdef START_DEBUG fprintf (stderr, "th %d Wait on tell_thread\n", me); #endif return NULL; } void function_referencing_file2_thread_local (void) { file2_thread_local = file2_thread_local; } void do_pass() { int i; pthread_t t[ N_THREADS ]; int err; for( i = 0; i < N_THREADS; i++) { thread_local_val[i] = 0; another_thread_local_val[i] = 0; } if (sem_init (&tell_main, 0, 0) == -1) { fprintf (stderr, "tell_main semaphore init failed\n"); return; } if (sem_init (&tell_thread, 0, 0) == -1) { fprintf (stderr, "tell_thread semaphore init failed\n"); return; } /* Start N_THREADS threads, then join them so that they are terminated. */ for( i = 0; i < N_THREADS; i++ ) { err = pthread_create( &t[i], NULL, spin, (void *) (long) i ); if( err != 0 ) { fprintf(stderr, "Error in thread %d create\n", i ); } } for( i = 0; i < N_THREADS; i++ ) { while (1) { #ifdef START_DEBUG fprintf (stderr, "main %d start wait on tell_main\n", i); #endif if (sem_wait (&tell_main) == 0) break; if (errno == EINTR) { #ifdef START_DEBUG fprintf (stderr, "main %d wait tell_main got EINTR, rewaiting\n", i); #endif continue; } else { fprintf (stderr, "main %d wait on sem tell_main failed\n", i); print_error (); return; } } } #ifdef START_DEBUG fprintf (stderr, "main done waiting on tell_main\n"); #endif i = 10; /* Here all threads should be still alive. */ for( i = 0; i < N_THREADS; i++ ) { if (sem_post (&tell_thread) == -1) { fprintf (stderr, "main %d post on sem tell_thread failed\n", i); print_error (); return; } #ifdef START_DEBUG fprintf (stderr, "main %d post on tell_thread\n", i); #endif } for( i = 0; i < N_THREADS; i++ ) { err = pthread_join(t[i], NULL ); if( err != 0 ) { fprintf (stderr, "error in thread %d join\n", i ); } } i = 10; /* Null line for setting bpts on. */ } int main() { do_pass (); return 0; /* Set breakpoint here before exit. */ } /* EndSourceFile */