summaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.threads/tls.c
blob: 9a87e91baa2ca9ba09c33397eb519d23bd977e62 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/* BeginSourceFile tls.c

  This file creates and deletes threads. It uses thread local storage
  variables too. */

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <semaphore.h>
#include <errno.h>

#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 */