Blame elf/tlsdeschtab.h

Packit Service 82fcde
/* Hash table for TLS descriptors.
Packit Service 82fcde
   Copyright (C) 2005-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Alexandre Oliva  <aoliva@redhat.com>
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#ifndef TLSDESCHTAB_H
Packit Service 82fcde
# define TLSDESCHTAB_H 1
Packit Service 82fcde
Packit Service 82fcde
#include <atomic.h>
Packit Service 82fcde
Packit Service 82fcde
# ifdef SHARED
Packit Service 82fcde
Packit Service 82fcde
#  include <inline-hashtab.h>
Packit Service 82fcde
Packit Service 82fcde
inline static int
Packit Service 82fcde
hash_tlsdesc (void *p)
Packit Service 82fcde
{
Packit Service 82fcde
  struct tlsdesc_dynamic_arg *td = p;
Packit Service 82fcde
Packit Service 82fcde
  /* We know all entries are for the same module, so ti_offset is the
Packit Service 82fcde
     only distinguishing entry.  */
Packit Service 82fcde
  return td->tlsinfo.ti_offset;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
inline static int
Packit Service 82fcde
eq_tlsdesc (void *p, void *q)
Packit Service 82fcde
{
Packit Service 82fcde
  struct tlsdesc_dynamic_arg *tdp = p, *tdq = q;
Packit Service 82fcde
Packit Service 82fcde
  return tdp->tlsinfo.ti_offset == tdq->tlsinfo.ti_offset;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
inline static size_t
Packit Service 82fcde
map_generation (struct link_map *map)
Packit Service 82fcde
{
Packit Service 82fcde
  size_t idx = map->l_tls_modid;
Packit Service 82fcde
  struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
Packit Service 82fcde
Packit Service 82fcde
  /* Find the place in the dtv slotinfo list.  */
Packit Service 82fcde
  do
Packit Service 82fcde
    {
Packit Service 82fcde
      /* Does it fit in the array of this list element?  */
Packit Service 82fcde
      if (idx < listp->len)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We should never get here for a module in static TLS, so
Packit Service 82fcde
	     we can assume that, if the generation count is zero, we
Packit Service 82fcde
	     still haven't determined the generation count for this
Packit Service 82fcde
	     module.  */
Packit Service 82fcde
	  if (listp->slotinfo[idx].map == map && listp->slotinfo[idx].gen)
Packit Service 82fcde
	    return listp->slotinfo[idx].gen;
Packit Service 82fcde
	  else
Packit Service 82fcde
	    break;
Packit Service 82fcde
	}
Packit Service 82fcde
      idx -= listp->len;
Packit Service 82fcde
      listp = listp->next;
Packit Service 82fcde
    }
Packit Service 82fcde
  while (listp != NULL);
Packit Service 82fcde
Packit Service 82fcde
  /* If we get to this point, the module still hasn't been assigned an
Packit Service 82fcde
     entry in the dtv slotinfo data structures, and it will when we're
Packit Service 82fcde
     done with relocations.  At that point, the module will get a
Packit Service 82fcde
     generation number that is one past the current generation, so
Packit Service 82fcde
     return exactly that.  */
Packit Service 82fcde
  return GL(dl_tls_generation) + 1;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
void *
Packit Service 82fcde
_dl_make_tlsdesc_dynamic (struct link_map *map, size_t ti_offset)
Packit Service 82fcde
{
Packit Service 82fcde
  struct hashtab *ht;
Packit Service 82fcde
  void **entry;
Packit Service 82fcde
  struct tlsdesc_dynamic_arg *td, test;
Packit Service 82fcde
Packit Service 82fcde
  /* FIXME: We could use a per-map lock here, but is it worth it?  */
Packit Service 82fcde
  __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit Service 82fcde
Packit Service 82fcde
  ht = map->l_mach.tlsdesc_table;
Packit Service 82fcde
  if (! ht)
Packit Service 82fcde
    {
Packit Service 82fcde
      ht = htab_create ();
Packit Service 82fcde
      if (! ht)
Packit Service 82fcde
	{
Packit Service 82fcde
	  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
	  return 0;
Packit Service 82fcde
	}
Packit Service 82fcde
      map->l_mach.tlsdesc_table = ht;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  test.tlsinfo.ti_module = map->l_tls_modid;
Packit Service 82fcde
  test.tlsinfo.ti_offset = ti_offset;
Packit Service 82fcde
  entry = htab_find_slot (ht, &test, 1, hash_tlsdesc, eq_tlsdesc);
Packit Service 82fcde
  if (! entry)
Packit Service 82fcde
    {
Packit Service 82fcde
      __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (*entry)
Packit Service 82fcde
    {
Packit Service 82fcde
      td = *entry;
Packit Service 82fcde
      __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
      return td;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  *entry = td = malloc (sizeof (struct tlsdesc_dynamic_arg));
Packit Service 82fcde
  /* This may be higher than the map's generation, but it doesn't
Packit Service 82fcde
     matter much.  Worst case, we'll have one extra DTV update per
Packit Service 82fcde
     thread.  */
Packit Service 82fcde
  td->gen_count = map_generation (map);
Packit Service 82fcde
  td->tlsinfo = test.tlsinfo;
Packit Service 82fcde
Packit Service 82fcde
  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
  return td;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
# endif /* SHARED */
Packit Service 82fcde
Packit Service 82fcde
/* The idea of the following two functions is to stop multiple threads
Packit Service 82fcde
   from attempting to resolve the same TLS descriptor without busy
Packit Service 82fcde
   waiting.  Ideally, we should be able to release the lock right
Packit Service 82fcde
   after changing td->entry, and then using say a condition variable
Packit Service 82fcde
   or a futex wake to wake up any waiting threads, but let's try to
Packit Service 82fcde
   avoid introducing such dependencies.  */
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
__attribute__ ((unused))
Packit Service 82fcde
_dl_tlsdesc_resolve_early_return_p (struct tlsdesc volatile *td, void *caller)
Packit Service 82fcde
{
Packit Service 82fcde
  if (caller != atomic_load_relaxed (&td->entry))
Packit Service 82fcde
    return 1;
Packit Service 82fcde
Packit Service 82fcde
  __rtld_lock_lock_recursive (GL(dl_load_lock));
Packit Service 82fcde
  if (caller != atomic_load_relaxed (&td->entry))
Packit Service 82fcde
    {
Packit Service 82fcde
      __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  atomic_store_relaxed (&td->entry, _dl_tlsdesc_resolve_hold);
Packit Service 82fcde
Packit Service 82fcde
  return 0;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static void
Packit Service 82fcde
__attribute__ ((unused))
Packit Service 82fcde
_dl_tlsdesc_wake_up_held_fixups (void)
Packit Service 82fcde
{
Packit Service 82fcde
  __rtld_lock_unlock_recursive (GL(dl_load_lock));
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#endif