OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-old/] [gcc-4.2.2/] [gcc/] [config/] [vxlib.c] - Blame information for rev 856

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 38 julius
/* Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
2
   Contributed by Zack Weinberg <zack@codesourcery.com>
3
 
4
This file is part of GCC.
5
 
6
GCC is free software; you can redistribute it and/or modify it under
7
the terms of the GNU General Public License as published by the Free
8
Software Foundation; either version 2, or (at your option) any later
9
version.
10
 
11
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12
WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with GCC; see the file COPYING.  If not, write to the Free
18
Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
19
02110-1301, USA.  */
20
 
21
/* As a special exception, if you link this library with other files,
22
   some of which are compiled with GCC, to produce an executable,
23
   this library does not by itself cause the resulting executable
24
   to be covered by the GNU General Public License.
25
   This exception does not however invalidate any other reasons why
26
   the executable file might be covered by the GNU General Public License.  */
27
 
28
/* Threads compatibility routines for libgcc2 for VxWorks.
29
   These are out-of-line routines called from gthr-vxworks.h.  */
30
 
31
#include "tconfig.h"
32
#include "tsystem.h"
33
#include "gthr.h"
34
 
35
#if defined(__GTHREADS)
36
#include <vxWorks.h>
37
#ifndef __RTP__
38
#include <vxLib.h>
39
#endif
40
#include <taskLib.h>
41
#ifndef __RTP__
42
#include <taskHookLib.h>
43
#else
44
# include <errno.h>
45
#endif
46
 
47
/* Init-once operation.
48
 
49
   This would be a clone of the implementation from gthr-solaris.h,
50
   except that we have a bootstrap problem - the whole point of this
51
   exercise is to prevent double initialization, but if two threads
52
   are racing with each other, once->mutex is liable to be initialized
53
   by both.  Then each thread will lock its own mutex, and proceed to
54
   call the initialization routine.
55
 
56
   So instead we use a bare atomic primitive (vxTas()) to handle
57
   mutual exclusion.  Threads losing the race then busy-wait, calling
58
   taskDelay() to yield the processor, until the initialization is
59
   completed.  Inefficient, but reliable.  */
60
 
61
int
62
__gthread_once (__gthread_once_t *guard, void (*func)(void))
63
{
64
  if (guard->done)
65
    return 0;
66
 
67
#ifdef __RTP__
68
  __gthread_lock_library ();
69
#else
70
  while (!vxTas ((void *)&guard->busy))
71
    taskDelay (1);
72
#endif
73
 
74
  /* Only one thread at a time gets here.  Check ->done again, then
75
     go ahead and call func() if no one has done it yet.  */
76
  if (!guard->done)
77
    {
78
      func ();
79
      guard->done = 1;
80
    }
81
 
82
#ifdef __RTP__
83
  __gthread_unlock_library ();
84
#else
85
  guard->busy = 0;
86
#endif
87
  return 0;
88
}
89
 
90
/* Thread-local storage.
91
 
92
   We reserve a field in the TCB to point to a dynamically allocated
93
   array which is used to store TLS values.  A TLS key is simply an
94
   offset in this array.  The exact location of the TCB field is not
95
   known to this code nor to vxlib.c -- all access to it indirects
96
   through the routines __gthread_get_tls_data and
97
   __gthread_set_tls_data, which are provided by the VxWorks kernel.
98
 
99
   There is also a global array which records which keys are valid and
100
   which have destructors.
101
 
102
   A task delete hook is installed to execute key destructors.  The
103
   routines __gthread_enter_tls_dtor_context and
104
   __gthread_leave_tls_dtor_context, which are also provided by the
105
   kernel, ensure that it is safe to call free() on memory allocated
106
   by the task being deleted.  (This is a no-op on VxWorks 5, but
107
   a major undertaking on AE.)
108
 
109
   The task delete hook is only installed when at least one thread
110
   has TLS data.  This is a necessary precaution, to allow this module
111
   to be unloaded - a module with a hook can not be removed.
112
 
113
   Since this interface is used to allocate only a small number of
114
   keys, the table size is small and static, which simplifies the
115
   code quite a bit.  Revisit this if and when it becomes necessary.  */
116
 
117
#define MAX_KEYS 4
118
 
119
/* This is the structure pointed to by the pointer returned
120
   by __gthread_get_tls_data.  */
121
struct tls_data
122
{
123
  int *owner;
124
  void *values[MAX_KEYS];
125
  unsigned int generation[MAX_KEYS];
126
};
127
 
128
/* To make sure we only delete TLS data associated with this object,
129
   include a pointer to a local variable in the TLS data object.  */
130
static int self_owner;
131
 
132
/* The number of threads for this module which have active TLS data.
133
   This is protected by tls_lock.  */
134
static int active_tls_threads;
135
 
136
/* kernel provided routines */
137
extern void *__gthread_get_tls_data (void);
138
extern void __gthread_set_tls_data (void *data);
139
 
140
extern void __gthread_enter_tls_dtor_context (void);
141
extern void __gthread_leave_tls_dtor_context (void);
142
 
143
 
144
/* This is a global structure which records all of the active keys.
145
 
146
   A key is potentially valid (i.e. has been handed out by
147
   __gthread_key_create) iff its generation count in this structure is
148
   even.  In that case, the matching entry in the dtors array is a
149
   routine to be called when a thread terminates with a valid,
150
   non-NULL specific value for that key.
151
 
152
   A key is actually valid in a thread T iff the generation count
153
   stored in this structure is equal to the generation count stored in
154
   T's specific-value structure.  */
155
 
156
typedef void (*tls_dtor) (void *);
157
 
158
struct tls_keys
159
{
160
  tls_dtor dtor[MAX_KEYS];
161
  unsigned int generation[MAX_KEYS];
162
};
163
 
164
#define KEY_VALID_P(key) !(tls_keys.generation[key] & 1)
165
 
166
/* Note: if MAX_KEYS is increased, this initializer must be updated
167
   to match.  All the generation counts begin at 1, which means no
168
   key is valid.  */
169
static struct tls_keys tls_keys =
170
{
171
  { 0, 0, 0, 0 },
172
  { 1, 1, 1, 1 }
173
};
174
 
175
/* This lock protects the tls_keys structure.  */
176
static __gthread_mutex_t tls_lock;
177
 
178
static __gthread_once_t tls_init_guard = __GTHREAD_ONCE_INIT;
179
 
180
/* Internal routines.  */
181
 
182
/* The task TCB has just been deleted.  Call the destructor
183
   function for each TLS key that has both a destructor and
184
   a non-NULL specific value in this thread.
185
 
186
   This routine does not need to take tls_lock; the generation
187
   count protects us from calling a stale destructor.  It does
188
   need to read tls_keys.dtor[key] atomically.  */
189
 
190
static void
191
tls_delete_hook (void *tcb ATTRIBUTE_UNUSED)
192
{
193
  struct tls_data *data = __gthread_get_tls_data ();
194
  __gthread_key_t key;
195
 
196
  if (data && data->owner == &self_owner)
197
    {
198
      __gthread_enter_tls_dtor_context ();
199
      for (key = 0; key < MAX_KEYS; key++)
200
        {
201
          if (data->generation[key] == tls_keys.generation[key])
202
            {
203
              tls_dtor dtor = tls_keys.dtor[key];
204
 
205
              if (dtor)
206
                dtor (data->values[key]);
207
            }
208
        }
209
      free (data);
210
 
211
      /* We can't handle an error here, so just leave the thread
212
         marked as loaded if one occurs.  */
213
      if (__gthread_mutex_lock (&tls_lock) != ERROR)
214
        {
215
          active_tls_threads--;
216
          if (active_tls_threads == 0)
217
            taskDeleteHookDelete ((FUNCPTR)tls_delete_hook);
218
          __gthread_mutex_unlock (&tls_lock);
219
        }
220
 
221
      __gthread_set_tls_data (0);
222
      __gthread_leave_tls_dtor_context ();
223
    }
224
}
225
 
226
/* Initialize global data used by the TLS system.  */
227
static void
228
tls_init (void)
229
{
230
  __GTHREAD_MUTEX_INIT_FUNCTION (&tls_lock);
231
}
232
 
233
static void tls_destructor (void) __attribute__ ((destructor));
234
static void
235
tls_destructor (void)
236
{
237
#ifdef __RTP__
238
  /* All threads but this one should have exited by now.  */
239
  tls_delete_hook (NULL);
240
#else
241
  /* Unregister the hook forcibly.  The counter of active threads may
242
     be incorrect, because constructors (like the C++ library's) and
243
     destructors (like this one) run in the context of the shell rather
244
     than in a task spawned from this module.  */
245
  taskDeleteHookDelete ((FUNCPTR)tls_delete_hook);
246
#endif
247
 
248
  if (tls_init_guard.done && __gthread_mutex_lock (&tls_lock) != ERROR)
249
    semDelete (tls_lock);
250
}
251
 
252
/* External interface */
253
 
254
/* Store in KEYP a value which can be passed to __gthread_setspecific/
255
   __gthread_getspecific to store and retrieve a value which is
256
   specific to each calling thread.  If DTOR is not NULL, it will be
257
   called when a thread terminates with a non-NULL specific value for
258
   this key, with the value as its sole argument.  */
259
 
260
int
261
__gthread_key_create (__gthread_key_t *keyp, tls_dtor dtor)
262
{
263
  __gthread_key_t key;
264
 
265
  __gthread_once (&tls_init_guard, tls_init);
266
 
267
  if (__gthread_mutex_lock (&tls_lock) == ERROR)
268
    return errno;
269
 
270
  for (key = 0; key < MAX_KEYS; key++)
271
    if (!KEY_VALID_P (key))
272
      goto found_slot;
273
 
274
  /* no room */
275
  __gthread_mutex_unlock (&tls_lock);
276
  return EAGAIN;
277
 
278
 found_slot:
279
  tls_keys.generation[key]++;  /* making it even */
280
  tls_keys.dtor[key] = dtor;
281
  *keyp = key;
282
  __gthread_mutex_unlock (&tls_lock);
283
  return 0;
284
}
285
 
286
/* Invalidate KEY; it can no longer be used as an argument to
287
   setspecific/getspecific.  Note that this does NOT call destructor
288
   functions for any live values for this key.  */
289
int
290
__gthread_key_delete (__gthread_key_t key)
291
{
292
  if (key >= MAX_KEYS)
293
    return EINVAL;
294
 
295
  __gthread_once (&tls_init_guard, tls_init);
296
 
297
  if (__gthread_mutex_lock (&tls_lock) == ERROR)
298
    return errno;
299
 
300
  if (!KEY_VALID_P (key))
301
    {
302
      __gthread_mutex_unlock (&tls_lock);
303
      return EINVAL;
304
    }
305
 
306
  tls_keys.generation[key]++;  /* making it odd */
307
  tls_keys.dtor[key] = 0;
308
 
309
  __gthread_mutex_unlock (&tls_lock);
310
  return 0;
311
}
312
 
313
/* Retrieve the thread-specific value for KEY.  If it has never been
314
   set in this thread, or KEY is invalid, returns NULL.
315
 
316
   It does not matter if this function races with key_create or
317
   key_delete; the worst that can happen is you get a value other than
318
   the one that a serialized implementation would have provided.  */
319
 
320
void *
321
__gthread_getspecific (__gthread_key_t key)
322
{
323
  struct tls_data *data;
324
 
325
  if (key >= MAX_KEYS)
326
    return 0;
327
 
328
  data = __gthread_get_tls_data ();
329
 
330
  if (!data)
331
    return 0;
332
 
333
  if (data->generation[key] != tls_keys.generation[key])
334
    return 0;
335
 
336
  return data->values[key];
337
}
338
 
339
/* Set the thread-specific value for KEY.  If KEY is invalid, or
340
   memory allocation fails, returns -1, otherwise 0.
341
 
342
   The generation count protects this function against races with
343
   key_create/key_delete; the worst thing that can happen is that a
344
   value is successfully stored into a dead generation (and then
345
   immediately becomes invalid).  However, we do have to make sure
346
   to read tls_keys.generation[key] atomically.  */
347
 
348
int
349
__gthread_setspecific (__gthread_key_t key, void *value)
350
{
351
  struct tls_data *data;
352
  unsigned int generation;
353
 
354
  if (key >= MAX_KEYS)
355
    return EINVAL;
356
 
357
  data = __gthread_get_tls_data ();
358
  if (!data)
359
    {
360
      if (__gthread_mutex_lock (&tls_lock) == ERROR)
361
        return ENOMEM;
362
      if (active_tls_threads == 0)
363
        taskDeleteHookAdd ((FUNCPTR)tls_delete_hook);
364
      active_tls_threads++;
365
      __gthread_mutex_unlock (&tls_lock);
366
 
367
      data = malloc (sizeof (struct tls_data));
368
      if (!data)
369
        return ENOMEM;
370
 
371
      memset (data, 0, sizeof (struct tls_data));
372
      data->owner = &self_owner;
373
      __gthread_set_tls_data (data);
374
    }
375
 
376
  generation = tls_keys.generation[key];
377
 
378
  if (generation & 1)
379
    return EINVAL;
380
 
381
  data->generation[key] = generation;
382
  data->values[key] = value;
383
 
384
  return 0;
385
}
386
#endif /* __GTHREADS */

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.