Back to index

glibc  2.9
tlsdeschtab.h
Go to the documentation of this file.
00001 /* Hash table for TLS descriptors.
00002    Copyright (C) 2005, 2008 Free Software Foundation, Inc.
00003    This file is part of the GNU C Library.
00004    Contributed by Alexandre Oliva  <aoliva@redhat.com>
00005 
00006    The GNU C Library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Lesser General Public
00008    License as published by the Free Software Foundation; either
00009    version 2.1 of the License, or (at your option) any later version.
00010 
00011    The GNU C Library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Lesser General Public License for more details.
00015 
00016    You should have received a copy of the GNU Lesser General Public
00017    License along with the GNU C Library; if not, write to the Free
00018    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00019    02111-1307 USA.  */
00020 
00021 #ifndef TLSDESCHTAB_H
00022 # define TLSDESCHTAB_H 1
00023 
00024 # ifdef SHARED
00025 
00026 #  include <inline-hashtab.h>
00027 
00028 inline static int
00029 hash_tlsdesc (void *p)
00030 {
00031   struct tlsdesc_dynamic_arg *td = p;
00032 
00033   /* We know all entries are for the same module, so ti_offset is the
00034      only distinguishing entry.  */
00035   return td->tlsinfo.ti_offset;
00036 }
00037 
00038 inline static int
00039 eq_tlsdesc (void *p, void *q)
00040 {
00041   struct tlsdesc_dynamic_arg *tdp = p, *tdq = q;
00042 
00043   return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
00044 }
00045 
00046 inline static int
00047 map_generation (struct link_map *map)
00048 {
00049   size_t idx = map->l_tls_modid;
00050   struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
00051 
00052   /* Find the place in the dtv slotinfo list.  */
00053   do
00054     {
00055       /* Does it fit in the array of this list element?  */
00056       if (idx < listp->len)
00057        {
00058          /* We should never get here for a module in static TLS, so
00059             we can assume that, if the generation count is zero, we
00060             still haven't determined the generation count for this
00061             module.  */
00062          if (listp->slotinfo[idx].gen)
00063            return listp->slotinfo[idx].gen;
00064          else
00065            break;
00066        }
00067       idx -= listp->len;
00068       listp = listp->next;
00069     }
00070   while (listp != NULL);
00071 
00072   /* If we get to this point, the module still hasn't been assigned an
00073      entry in the dtv slotinfo data structures, and it will when we're
00074      done with relocations.  At that point, the module will get a
00075      generation number that is one past the current generation, so
00076      return exactly that.  */
00077   return GL(dl_tls_generation) + 1;
00078 }
00079 
00080 void *
00081 internal_function
00082 _dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
00083 {
00084   struct hashtab *ht;
00085   void **entry;
00086   struct tlsdesc_dynamic_arg *td, test;
00087 
00088   /* FIXME: We could use a per-map lock here, but is it worth it?  */
00089   __rtld_lock_lock_recursive (GL(dl_load_lock));
00090 
00091   ht = map->l_mach.tlsdesc_table;
00092   if (! ht)
00093     {
00094       ht = htab_create ();
00095       if (! ht)
00096        {
00097          __rtld_lock_unlock_recursive (GL(dl_load_lock));
00098          return 0;
00099        }
00100       map->l_mach.tlsdesc_table = ht;
00101     }
00102 
00103   test.tlsinfo.ti_module = map->l_tls_modid;
00104   test.tlsinfo.ti_offset = ti_offset;
00105   entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
00106   if (*entry)
00107     {
00108       td = *entry;
00109       __rtld_lock_unlock_recursive (GL(dl_load_lock));
00110       return td;
00111     }
00112 
00113   *entry = td = malloc (sizeof (struct tlsdesc_dynamic_arg));
00114   /* This may be higher than the map's generation, but it doesn't
00115      matter much.  Worst case, we'll have one extra DTV update per
00116      thread.  */
00117   td->gen_count = map_generation (map);
00118   td->tlsinfo = test.tlsinfo;
00119 
00120   __rtld_lock_unlock_recursive (GL(dl_load_lock));
00121   return td;
00122 }
00123 
00124 # endif /* SHARED */
00125 
00126 /* The idea of the following two functions is to stop multiple threads
00127    from attempting to resolve the same TLS descriptor without busy
00128    waiting.  Ideally, we should be able to release the lock right
00129    after changing td->entry, and then using say a condition variable
00130    or a futex wake to wake up any waiting threads, but let's try to
00131    avoid introducing such dependencies.  */
00132 
00133 inline static int
00134 _dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller)
00135 {
00136   if (caller != td->entry)
00137     return 1;
00138 
00139   __rtld_lock_lock_recursive (GL(dl_load_lock));
00140   if (caller != td->entry)
00141     {
00142       __rtld_lock_unlock_recursive (GL(dl_load_lock));
00143       return 1;
00144     }
00145 
00146   td->entry = _dl_tlsdesc_resolve_hold;
00147 
00148   return 0;
00149 }
00150 
00151 inline static void
00152 _dl_tlsdesc_wake_up_held_fixups (void)
00153 {
00154   __rtld_lock_unlock_recursive (GL(dl_load_lock));
00155 }
00156 
00157 #endif