Beispiel #1
0
/* Do some minimal initialization which has to be done during the
   startup of the C library.  */
void
__pthread_initialize_minimal(void)
{
#ifdef USE_TLS
  pthread_descr self;

  /* First of all init __pthread_handles[0] and [1] if needed.  */
# if __LT_SPINLOCK_INIT != 0
  __pthread_handles[0].h_lock = __LOCK_INITIALIZER;
  __pthread_handles[1].h_lock = __LOCK_INITIALIZER;
# endif
# ifndef SHARED
  /* Unlike in the dynamically linked case the dynamic linker has not
     taken care of initializing the TLS data structures.  */
  __libc_setup_tls (TLS_TCB_SIZE, TLS_TCB_ALIGN);
# elif !USE___THREAD
  if (__builtin_expect (GL(dl_tls_dtv_slotinfo_list) == NULL, 0))
    {
      tcbhead_t *tcbp;

      /* There is no actual TLS being used, so the thread register
	 was not initialized in the dynamic linker.  */

      /* We need to install special hooks so that the malloc and memalign
	 calls in _dl_tls_setup and _dl_allocate_tls won't cause full
	 malloc initialization that will try to set up its thread state.  */

      extern void __libc_malloc_pthread_startup (bool first_time);
      __libc_malloc_pthread_startup (true);

      if (__builtin_expect (_dl_tls_setup (), 0)
	  || __builtin_expect ((tcbp = _dl_allocate_tls (NULL)) == NULL, 0))
	{
	  static const char msg[] = "\
cannot allocate TLS data structures for initial thread\n";
	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO,
						msg, sizeof msg - 1));
	  abort ();
	}
      const char *lossage = TLS_INIT_TP (tcbp, 0);
      if (__builtin_expect (lossage != NULL, 0))
	{
	  static const char msg[] = "cannot set up thread-local storage: ";
	  const char nl = '\n';
	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO,
						msg, sizeof msg - 1));
	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO,
						lossage, strlen (lossage)));
	  TEMP_FAILURE_RETRY (write_not_cancel (STDERR_FILENO, &nl, 1));
	}

      /* Though it was allocated with libc's malloc, that was done without
	 the user's __malloc_hook installed.  A later realloc that uses
	 the hooks might not work with that block from the plain malloc.
	 So we record this block as unfreeable just as the dynamic linker
	 does when it allocates the DTV before the libc malloc exists.  */
      GL(dl_initial_dtv) = GET_DTV (tcbp);

      __libc_malloc_pthread_startup (false);
    }
Beispiel #2
0
void
internal_function
_dl_deallocate_tls (void *tcb, bool dealloc_tcb)
{
  dtv_t *dtv = GET_DTV (tcb);
  size_t cnt;

  /* We need to free the memory allocated for non-static TLS.  */
  for (cnt = 0; cnt < dtv[-1].counter; ++cnt)
    if (! dtv[1 + cnt].pointer.is_static
	&& dtv[1 + cnt].pointer.val != TLS_DTV_UNALLOCATED)
      _dl_free (dtv[1 + cnt].pointer.val);

  /* The array starts with dtv[-1].  */
  if (dtv != _dl_initial_dtv)
    _dl_free (dtv - 1);

  if (dealloc_tcb)
    {
# ifdef TLS_TCB_AT_TP
      /* The TCB follows the TLS blocks.  Back up to free the whole block.  */
      tcb -= _dl_tls_static_size - TLS_TCB_SIZE;
# elif defined(TLS_DTV_AT_TP)
      /* Back up the TLS_PRE_TCB_SIZE bytes.  */
      tcb -= (TLS_PRE_TCB_SIZE + _dl_tls_static_align - 1)
	     & ~(_dl_tls_static_align - 1);
# endif
      _dl_free (tcb);
    }
}
Beispiel #3
0
internal_function
init_tls (void)
{
	/* Number of elements in the static TLS block.  */
	_dl_tls_static_nelem = _dl_tls_max_dtv_idx;

	/* Do not do this twice.  The audit interface might have required
	   the DTV interfaces to be set up early.  */
	if (_dl_initial_dtv != NULL)
		return NULL;

	/* Allocate the array which contains the information about the
	   dtv slots.  We allocate a few entries more than needed to
	   avoid the need for reallocation.  */
	size_t nelem = _dl_tls_max_dtv_idx + 1 + TLS_SLOTINFO_SURPLUS;

	/* Allocate.  */
	_dl_assert (_dl_tls_dtv_slotinfo_list == NULL);
	_dl_tls_dtv_slotinfo_list = (struct dtv_slotinfo_list *)
		_dl_calloc (sizeof (struct dtv_slotinfo_list)
			+ nelem * sizeof (struct dtv_slotinfo), 1);
	/* No need to check the return value.  If memory allocation failed
	   the program would have been terminated.  */

	struct dtv_slotinfo *slotinfo = _dl_tls_dtv_slotinfo_list->slotinfo;
	_dl_tls_dtv_slotinfo_list->len = nelem;
	_dl_tls_dtv_slotinfo_list->next = NULL;

	/* Fill in the information from the loaded modules.  No namespace
	   but the base one can be filled at this time.  */
	int i = 0;
	struct link_map *l;
	for (l =  (struct link_map *) _dl_loaded_modules; l != NULL; l = l->l_next)
		if (l->l_tls_blocksize != 0)
		{
			/* This is a module with TLS data.  Store the map reference.
			   The generation counter is zero.  */

			/* Skeep slot[0]: it will be never used */
			slotinfo[++i].map = l;
		}
	_dl_assert (i == _dl_tls_max_dtv_idx);

	/* Compute the TLS offsets for the various blocks.  */
	_dl_determine_tlsoffset ();

	/* Construct the static TLS block and the dtv for the initial
	   thread.  For some platforms this will include allocating memory
	   for the thread descriptor.  The memory for the TLS block will
	   never be freed.  It should be allocated accordingly.  The dtv
	   array can be changed if dynamic loading requires it.  */
	void *tcbp = _dl_allocate_tls_storage ();
	if (tcbp == NULL) {
		_dl_debug_early("\ncannot allocate TLS data structures for initial thread");
		_dl_exit(30);
	}

	/* Store for detection of the special case by __tls_get_addr
	   so it knows not to pass this dtv to the normal realloc.  */
	_dl_initial_dtv = GET_DTV (tcbp);

	/* And finally install it for the main thread.  If ld.so itself uses
	   TLS we know the thread pointer was initialized earlier.  */
	const char *lossage = TLS_INIT_TP (tcbp, USE___THREAD);
	if(__builtin_expect (lossage != NULL, 0)) {
		_dl_debug_early("cannot set up thread-local storage: %s\n", lossage);
		_dl_exit(30);
	}
	tls_init_tp_called = true;

	return tcbp;
}
Beispiel #4
0
internal_function
_dl_allocate_tls_init (void *result)
{
  if (result == NULL)
    /* The memory allocation failed.  */
    return NULL;

  dtv_t *dtv = GET_DTV (result);
  struct dtv_slotinfo_list *listp;
  size_t total = 0;
  size_t maxgen = 0;

  /* We have to prepare the dtv for all currently loaded modules using
     TLS.  For those which are dynamically loaded we add the values
     indicating deferred allocation.  */
  listp = _dl_tls_dtv_slotinfo_list;
  while (1)
    {
      size_t cnt;

      for (cnt = total == 0 ? 1 : 0; cnt < listp->len; ++cnt)
	{
	  struct link_map *map;
	  void *dest;

	  /* Check for the total number of used slots.  */
	  if (total + cnt > _dl_tls_max_dtv_idx)
	    break;

	  map = listp->slotinfo[cnt].map;
	  if (map == NULL)
	    /* Unused entry.  */
	    continue;

	  /* Keep track of the maximum generation number.  This might
	     not be the generation counter.  */
	  maxgen = MAX (maxgen, listp->slotinfo[cnt].gen);

	  if (map->l_tls_offset == NO_TLS_OFFSET)
	    {
	      /* For dynamically loaded modules we simply store
		 the value indicating deferred allocation.  */
	      dtv[map->l_tls_modid].pointer.val = TLS_DTV_UNALLOCATED;
	      dtv[map->l_tls_modid].pointer.is_static = false;
	      continue;
	    }

	  _dl_assert (map->l_tls_modid == cnt);
	  _dl_assert (map->l_tls_blocksize >= map->l_tls_initimage_size);
# ifdef TLS_TCB_AT_TP
	  _dl_assert ((size_t) map->l_tls_offset >= map->l_tls_blocksize);
	  dest = (char *) result - map->l_tls_offset;
# elif defined(TLS_DTV_AT_TP)
	  dest = (char *) result + map->l_tls_offset;
# else
#  error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined"
# endif

	  /* Copy the initialization image and clear the BSS part.  */
	  dtv[map->l_tls_modid].pointer.val = dest;
	  dtv[map->l_tls_modid].pointer.is_static = true;
	  _dl_memcpy(dest, map->l_tls_initimage, map->l_tls_initimage_size);
	  _dl_memset((dest + map->l_tls_initimage_size), '\0',
		  map->l_tls_blocksize - map->l_tls_initimage_size);

	}

      total += cnt;
      if (total >= _dl_tls_max_dtv_idx)
	break;

      listp = listp->next;
      _dl_assert (listp != NULL);
    }

  /* The DTV version is up-to-date now.  */
  dtv[0].counter = maxgen;

  return result;
}
Beispiel #5
0
/*
 * Get the TD address  - this function needs to be called
 * when the DTV value has not been restored yet.
 */
void* get_td_addr(void)
{
    dtv_t* dtv = GET_DTV();
    return read_dtv_val(dtv);
}