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