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