update copyright year range in GDB files
[external/binutils.git] / gdb / testsuite / gdb.threads / tls.c
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
22 class 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.  */
30 extern __thread int file2_thread_local;
31
32 /* Global variable just for info addr in gdb.  */
33 int a_global;
34
35 /* Print the results of thread-local storage.  */
36 int thread_local_val[ N_THREADS ];
37 int 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.  */
41 sem_t tell_main, tell_thread;
42
43
44 void 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.  */
73 void *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
130 void
131 function_referencing_file2_thread_local (void)
132 {
133   file2_thread_local = file2_thread_local;
134 }
135
136 void
137 do_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
228 int
229 main()
230 {
231    do_pass ();
232
233    return 0;  /* Set breakpoint here before exit. */
234 }
235
236 /* EndSourceFile */