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