Home | History | Annotate | Line # | Download | only in config
vxlib-tls.c revision 1.3.4.1
      1  1.3.4.1  christos /* Copyright (C) 2002-2016 Free Software Foundation, Inc.
      2      1.1       mrg    Contributed by Zack Weinberg <zack (at) codesourcery.com>
      3      1.1       mrg 
      4      1.1       mrg This file is part of GCC.
      5      1.1       mrg 
      6      1.1       mrg GCC is free software; you can redistribute it and/or modify it under
      7      1.1       mrg the terms of the GNU General Public License as published by the Free
      8      1.1       mrg Software Foundation; either version 3, or (at your option) any later
      9      1.1       mrg version.
     10      1.1       mrg 
     11      1.1       mrg GCC is distributed in the hope that it will be useful, but WITHOUT ANY
     12      1.1       mrg WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13      1.1       mrg FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
     14      1.1       mrg for more details.
     15      1.1       mrg 
     16      1.1       mrg Under Section 7 of GPL version 3, you are granted additional
     17      1.1       mrg permissions described in the GCC Runtime Library Exception, version
     18      1.1       mrg 3.1, as published by the Free Software Foundation.
     19      1.1       mrg 
     20      1.1       mrg You should have received a copy of the GNU General Public License and
     21      1.1       mrg a copy of the GCC Runtime Library Exception along with this program;
     22      1.1       mrg see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
     23      1.1       mrg <http://www.gnu.org/licenses/>.  */
     24      1.1       mrg 
     25      1.1       mrg /* Threads compatibility routines for libgcc2 for VxWorks.
     26      1.1       mrg    These are out-of-line routines called from gthr-vxworks.h.
     27      1.1       mrg 
     28      1.1       mrg    This file provides the TLS related support routines, calling specific
     29      1.1       mrg    VxWorks kernel entry points for this purpose.  The base VxWorks 5.x kernels
     30      1.1       mrg    don't feature these entry points, and we provide gthr_supp_vxw_5x.c as an
     31      1.1       mrg    option to fill this gap.  Asking users to rebuild a kernel is not to be
     32      1.1       mrg    taken lightly, still, so we have isolated these routines from the rest of
     33      1.1       mrg    vxlib to ensure that the kernel dependencies are only dragged when really
     34      1.1       mrg    necessary.  */
     35      1.1       mrg 
     36      1.1       mrg #include "tconfig.h"
     37      1.1       mrg #include "tsystem.h"
     38      1.1       mrg #include "gthr.h"
     39      1.1       mrg 
     40      1.1       mrg #if defined(__GTHREADS)
     41      1.1       mrg #include <vxWorks.h>
     42      1.1       mrg #ifndef __RTP__
     43      1.1       mrg #include <vxLib.h>
     44      1.1       mrg #endif
     45      1.1       mrg #include <taskLib.h>
     46      1.1       mrg #ifndef __RTP__
     47      1.1       mrg #include <taskHookLib.h>
     48      1.1       mrg #else
     49      1.1       mrg # include <errno.h>
     50      1.1       mrg #endif
     51      1.1       mrg 
     52      1.1       mrg /* Thread-local storage.
     53      1.1       mrg 
     54      1.1       mrg    We reserve a field in the TCB to point to a dynamically allocated
     55      1.1       mrg    array which is used to store TLS values.  A TLS key is simply an
     56      1.1       mrg    offset in this array.  The exact location of the TCB field is not
     57      1.1       mrg    known to this code nor to vxlib.c -- all access to it indirects
     58      1.1       mrg    through the routines __gthread_get_tls_data and
     59      1.1       mrg    __gthread_set_tls_data, which are provided by the VxWorks kernel.
     60      1.1       mrg 
     61      1.1       mrg    There is also a global array which records which keys are valid and
     62      1.1       mrg    which have destructors.
     63      1.1       mrg 
     64      1.1       mrg    A task delete hook is installed to execute key destructors.  The
     65      1.1       mrg    routines __gthread_enter_tls_dtor_context and
     66      1.1       mrg    __gthread_leave_tls_dtor_context, which are also provided by the
     67      1.1       mrg    kernel, ensure that it is safe to call free() on memory allocated
     68      1.1       mrg    by the task being deleted.  (This is a no-op on VxWorks 5, but
     69      1.1       mrg    a major undertaking on AE.)
     70      1.1       mrg 
     71      1.1       mrg    The task delete hook is only installed when at least one thread
     72      1.1       mrg    has TLS data.  This is a necessary precaution, to allow this module
     73      1.1       mrg    to be unloaded - a module with a hook can not be removed.
     74      1.1       mrg 
     75      1.1       mrg    Since this interface is used to allocate only a small number of
     76      1.1       mrg    keys, the table size is small and static, which simplifies the
     77      1.1       mrg    code quite a bit.  Revisit this if and when it becomes necessary.  */
     78      1.1       mrg 
     79      1.1       mrg #define MAX_KEYS 4
     80      1.1       mrg 
     81      1.1       mrg /* This is the structure pointed to by the pointer returned
     82      1.1       mrg    by __gthread_get_tls_data.  */
     83      1.1       mrg struct tls_data
     84      1.1       mrg {
     85      1.1       mrg   int *owner;
     86      1.1       mrg   void *values[MAX_KEYS];
     87      1.1       mrg   unsigned int generation[MAX_KEYS];
     88      1.1       mrg };
     89      1.1       mrg 
     90      1.1       mrg /* To make sure we only delete TLS data associated with this object,
     91      1.1       mrg    include a pointer to a local variable in the TLS data object.  */
     92      1.1       mrg static int self_owner;
     93      1.1       mrg 
     94      1.1       mrg /* Flag to check whether the delete hook is installed.  Once installed
     95      1.1       mrg    it is only removed when unloading this module.  */
     96      1.1       mrg static volatile int delete_hook_installed;
     97      1.1       mrg 
     98      1.1       mrg /* kernel provided routines */
     99      1.1       mrg extern void *__gthread_get_tls_data (void);
    100      1.1       mrg extern void __gthread_set_tls_data (void *data);
    101      1.1       mrg 
    102      1.1       mrg extern void __gthread_enter_tls_dtor_context (void);
    103      1.1       mrg extern void __gthread_leave_tls_dtor_context (void);
    104      1.1       mrg 
    105      1.1       mrg #ifndef __RTP__
    106      1.1       mrg 
    107      1.1       mrg extern void *__gthread_get_tsd_data (WIND_TCB *tcb);
    108      1.1       mrg extern void __gthread_set_tsd_data (WIND_TCB *tcb, void *data);
    109      1.1       mrg extern void __gthread_enter_tsd_dtor_context (WIND_TCB *tcb);
    110      1.1       mrg extern void __gthread_leave_tsd_dtor_context (WIND_TCB *tcb);
    111      1.1       mrg 
    112      1.1       mrg #endif /* __RTP__ */
    113      1.1       mrg 
    114      1.1       mrg /* This is a global structure which records all of the active keys.
    115      1.1       mrg 
    116      1.1       mrg    A key is potentially valid (i.e. has been handed out by
    117      1.1       mrg    __gthread_key_create) iff its generation count in this structure is
    118      1.1       mrg    even.  In that case, the matching entry in the dtors array is a
    119      1.1       mrg    routine to be called when a thread terminates with a valid,
    120      1.1       mrg    non-NULL specific value for that key.
    121      1.1       mrg 
    122      1.1       mrg    A key is actually valid in a thread T iff the generation count
    123      1.1       mrg    stored in this structure is equal to the generation count stored in
    124      1.1       mrg    T's specific-value structure.  */
    125      1.1       mrg 
    126      1.1       mrg typedef void (*tls_dtor) (void *);
    127      1.1       mrg 
    128      1.1       mrg struct tls_keys
    129      1.1       mrg {
    130      1.1       mrg   tls_dtor dtor[MAX_KEYS];
    131      1.1       mrg   unsigned int generation[MAX_KEYS];
    132      1.1       mrg };
    133      1.1       mrg 
    134      1.1       mrg #define KEY_VALID_P(key) !(tls_keys.generation[key] & 1)
    135      1.1       mrg 
    136      1.1       mrg /* Note: if MAX_KEYS is increased, this initializer must be updated
    137      1.1       mrg    to match.  All the generation counts begin at 1, which means no
    138      1.1       mrg    key is valid.  */
    139      1.1       mrg static struct tls_keys tls_keys =
    140      1.1       mrg {
    141      1.1       mrg   { 0, 0, 0, 0 },
    142      1.1       mrg   { 1, 1, 1, 1 }
    143      1.1       mrg };
    144      1.1       mrg 
    145      1.1       mrg /* This lock protects the tls_keys structure.  */
    146      1.1       mrg static __gthread_mutex_t tls_lock;
    147      1.1       mrg 
    148      1.1       mrg static __gthread_once_t tls_init_guard = __GTHREAD_ONCE_INIT;
    149      1.1       mrg 
    150      1.1       mrg /* Internal routines.  */
    151      1.1       mrg 
    152      1.1       mrg /* The task TCB has just been deleted.  Call the destructor
    153      1.1       mrg    function for each TLS key that has both a destructor and
    154      1.1       mrg    a non-NULL specific value in this thread.
    155      1.1       mrg 
    156      1.1       mrg    This routine does not need to take tls_lock; the generation
    157      1.1       mrg    count protects us from calling a stale destructor.  It does
    158      1.1       mrg    need to read tls_keys.dtor[key] atomically.  */
    159      1.1       mrg 
    160      1.1       mrg static void
    161      1.1       mrg tls_delete_hook (void *tcb ATTRIBUTE_UNUSED)
    162      1.1       mrg {
    163      1.1       mrg   struct tls_data *data;
    164      1.1       mrg   __gthread_key_t key;
    165      1.1       mrg 
    166      1.1       mrg #ifdef __RTP__
    167      1.1       mrg   data = __gthread_get_tls_data ();
    168      1.1       mrg #else
    169      1.1       mrg   /* In kernel mode, we can be called in the context of the thread
    170      1.1       mrg      doing the killing, so must use the TCB to determine the data of
    171      1.1       mrg      the thread being killed.  */
    172      1.1       mrg   data = __gthread_get_tsd_data (tcb);
    173      1.1       mrg #endif
    174      1.1       mrg 
    175      1.1       mrg   if (data && data->owner == &self_owner)
    176      1.1       mrg     {
    177      1.1       mrg #ifdef __RTP__
    178      1.1       mrg       __gthread_enter_tls_dtor_context ();
    179      1.1       mrg #else
    180      1.1       mrg       __gthread_enter_tsd_dtor_context (tcb);
    181      1.1       mrg #endif
    182      1.1       mrg       for (key = 0; key < MAX_KEYS; key++)
    183      1.1       mrg 	{
    184      1.1       mrg 	  if (data->generation[key] == tls_keys.generation[key])
    185      1.1       mrg 	    {
    186      1.1       mrg 	      tls_dtor dtor = tls_keys.dtor[key];
    187      1.1       mrg 
    188      1.1       mrg 	      if (dtor)
    189      1.1       mrg 		dtor (data->values[key]);
    190      1.1       mrg 	    }
    191      1.1       mrg 	}
    192      1.1       mrg       free (data);
    193      1.1       mrg #ifdef __RTP__
    194      1.1       mrg       __gthread_leave_tls_dtor_context ();
    195      1.1       mrg #else
    196      1.1       mrg       __gthread_leave_tsd_dtor_context (tcb);
    197      1.1       mrg #endif
    198      1.1       mrg 
    199      1.1       mrg #ifdef __RTP__
    200      1.1       mrg       __gthread_set_tls_data (0);
    201      1.1       mrg #else
    202      1.1       mrg       __gthread_set_tsd_data (tcb, 0);
    203      1.1       mrg #endif
    204      1.1       mrg     }
    205      1.1       mrg }
    206      1.1       mrg 
    207      1.1       mrg /* Initialize global data used by the TLS system.  */
    208      1.1       mrg static void
    209      1.1       mrg tls_init (void)
    210      1.1       mrg {
    211      1.1       mrg   __GTHREAD_MUTEX_INIT_FUNCTION (&tls_lock);
    212      1.1       mrg }
    213      1.1       mrg 
    214      1.1       mrg static void tls_destructor (void) __attribute__ ((destructor));
    215      1.1       mrg static void
    216      1.1       mrg tls_destructor (void)
    217      1.1       mrg {
    218      1.1       mrg #ifdef __RTP__
    219      1.1       mrg   /* All threads but this one should have exited by now.  */
    220      1.1       mrg   tls_delete_hook (NULL);
    221      1.1       mrg #endif
    222      1.1       mrg   /* Unregister the hook.  */
    223      1.1       mrg   if (delete_hook_installed)
    224      1.1       mrg     taskDeleteHookDelete ((FUNCPTR)tls_delete_hook);
    225      1.1       mrg 
    226      1.1       mrg   if (tls_init_guard.done && __gthread_mutex_lock (&tls_lock) != ERROR)
    227      1.1       mrg     semDelete (tls_lock);
    228      1.1       mrg }
    229      1.1       mrg 
    230      1.1       mrg /* External interface */
    231      1.1       mrg 
    232      1.1       mrg /* Store in KEYP a value which can be passed to __gthread_setspecific/
    233      1.1       mrg    __gthread_getspecific to store and retrieve a value which is
    234      1.1       mrg    specific to each calling thread.  If DTOR is not NULL, it will be
    235      1.1       mrg    called when a thread terminates with a non-NULL specific value for
    236      1.1       mrg    this key, with the value as its sole argument.  */
    237      1.1       mrg 
    238      1.1       mrg int
    239      1.1       mrg __gthread_key_create (__gthread_key_t *keyp, tls_dtor dtor)
    240      1.1       mrg {
    241      1.1       mrg   __gthread_key_t key;
    242      1.1       mrg 
    243      1.1       mrg   __gthread_once (&tls_init_guard, tls_init);
    244      1.1       mrg 
    245      1.1       mrg   if (__gthread_mutex_lock (&tls_lock) == ERROR)
    246      1.1       mrg     return errno;
    247      1.1       mrg 
    248      1.1       mrg   for (key = 0; key < MAX_KEYS; key++)
    249      1.1       mrg     if (!KEY_VALID_P (key))
    250      1.1       mrg       goto found_slot;
    251      1.1       mrg 
    252      1.1       mrg   /* no room */
    253      1.1       mrg   __gthread_mutex_unlock (&tls_lock);
    254      1.1       mrg   return EAGAIN;
    255      1.1       mrg 
    256      1.1       mrg  found_slot:
    257      1.1       mrg   tls_keys.generation[key]++;  /* making it even */
    258      1.1       mrg   tls_keys.dtor[key] = dtor;
    259      1.1       mrg   *keyp = key;
    260      1.1       mrg   __gthread_mutex_unlock (&tls_lock);
    261      1.1       mrg   return 0;
    262      1.1       mrg }
    263      1.1       mrg 
    264      1.1       mrg /* Invalidate KEY; it can no longer be used as an argument to
    265      1.1       mrg    setspecific/getspecific.  Note that this does NOT call destructor
    266      1.1       mrg    functions for any live values for this key.  */
    267      1.1       mrg int
    268      1.1       mrg __gthread_key_delete (__gthread_key_t key)
    269      1.1       mrg {
    270      1.1       mrg   if (key >= MAX_KEYS)
    271      1.1       mrg     return EINVAL;
    272      1.1       mrg 
    273      1.1       mrg   __gthread_once (&tls_init_guard, tls_init);
    274      1.1       mrg 
    275      1.1       mrg   if (__gthread_mutex_lock (&tls_lock) == ERROR)
    276      1.1       mrg     return errno;
    277      1.1       mrg 
    278      1.1       mrg   if (!KEY_VALID_P (key))
    279      1.1       mrg     {
    280      1.1       mrg       __gthread_mutex_unlock (&tls_lock);
    281      1.1       mrg       return EINVAL;
    282      1.1       mrg     }
    283      1.1       mrg 
    284      1.1       mrg   tls_keys.generation[key]++;  /* making it odd */
    285      1.1       mrg   tls_keys.dtor[key] = 0;
    286      1.1       mrg 
    287      1.1       mrg   __gthread_mutex_unlock (&tls_lock);
    288      1.1       mrg   return 0;
    289      1.1       mrg }
    290      1.1       mrg 
    291      1.1       mrg /* Retrieve the thread-specific value for KEY.  If it has never been
    292      1.1       mrg    set in this thread, or KEY is invalid, returns NULL.
    293      1.1       mrg 
    294      1.1       mrg    It does not matter if this function races with key_create or
    295      1.1       mrg    key_delete; the worst that can happen is you get a value other than
    296      1.1       mrg    the one that a serialized implementation would have provided.  */
    297      1.1       mrg 
    298      1.1       mrg void *
    299      1.1       mrg __gthread_getspecific (__gthread_key_t key)
    300      1.1       mrg {
    301      1.1       mrg   struct tls_data *data;
    302      1.1       mrg 
    303      1.1       mrg   if (key >= MAX_KEYS)
    304      1.1       mrg     return 0;
    305      1.1       mrg 
    306      1.1       mrg   data = __gthread_get_tls_data ();
    307      1.1       mrg 
    308      1.1       mrg   if (!data)
    309      1.1       mrg     return 0;
    310      1.1       mrg 
    311      1.1       mrg   if (data->generation[key] != tls_keys.generation[key])
    312      1.1       mrg     return 0;
    313      1.1       mrg 
    314      1.1       mrg   return data->values[key];
    315      1.1       mrg }
    316      1.1       mrg 
    317      1.1       mrg /* Set the thread-specific value for KEY.  If KEY is invalid, or
    318      1.1       mrg    memory allocation fails, returns -1, otherwise 0.
    319      1.1       mrg 
    320      1.1       mrg    The generation count protects this function against races with
    321      1.1       mrg    key_create/key_delete; the worst thing that can happen is that a
    322      1.1       mrg    value is successfully stored into a dead generation (and then
    323      1.1       mrg    immediately becomes invalid).  However, we do have to make sure
    324      1.1       mrg    to read tls_keys.generation[key] atomically.  */
    325      1.1       mrg 
    326      1.1       mrg int
    327      1.1       mrg __gthread_setspecific (__gthread_key_t key, void *value)
    328      1.1       mrg {
    329      1.1       mrg   struct tls_data *data;
    330      1.1       mrg   unsigned int generation;
    331      1.1       mrg 
    332      1.1       mrg   if (key >= MAX_KEYS)
    333      1.1       mrg     return EINVAL;
    334      1.1       mrg 
    335      1.1       mrg   data = __gthread_get_tls_data ();
    336      1.1       mrg   if (!data)
    337      1.1       mrg     {
    338      1.1       mrg       if (!delete_hook_installed)
    339      1.1       mrg 	{
    340      1.1       mrg 	  /* Install the delete hook.  */
    341      1.1       mrg 	  if (__gthread_mutex_lock (&tls_lock) == ERROR)
    342      1.1       mrg 	    return ENOMEM;
    343      1.1       mrg 	  if (!delete_hook_installed)
    344      1.1       mrg 	    {
    345      1.1       mrg 	      taskDeleteHookAdd ((FUNCPTR)tls_delete_hook);
    346      1.1       mrg 	      delete_hook_installed = 1;
    347      1.1       mrg 	    }
    348      1.1       mrg 	  __gthread_mutex_unlock (&tls_lock);
    349      1.1       mrg 	}
    350      1.1       mrg 
    351      1.1       mrg       data = malloc (sizeof (struct tls_data));
    352      1.1       mrg       if (!data)
    353      1.1       mrg 	return ENOMEM;
    354      1.1       mrg 
    355      1.1       mrg       memset (data, 0, sizeof (struct tls_data));
    356      1.1       mrg       data->owner = &self_owner;
    357      1.1       mrg       __gthread_set_tls_data (data);
    358      1.1       mrg     }
    359      1.1       mrg 
    360      1.1       mrg   generation = tls_keys.generation[key];
    361      1.1       mrg 
    362      1.1       mrg   if (generation & 1)
    363      1.1       mrg     return EINVAL;
    364      1.1       mrg 
    365      1.1       mrg   data->generation[key] = generation;
    366      1.1       mrg   data->values[key] = value;
    367      1.1       mrg 
    368      1.1       mrg   return 0;
    369      1.1       mrg }
    370      1.1       mrg #endif /* __GTHREADS */
    371