Exemplo n.º 1
0
Arquivo: tls.c Projeto: GanShun/akaros
/* Free a previously allocated TLS region */
void free_tls(void *tcb)
{
	_dl_deallocate_tls(tcb, TRUE);
}
Exemplo n.º 2
0
/* Internal version of pthread_create.  See comment in
   pt-internal.h.  */
int
__pthread_create_internal (struct __pthread **thread,
			   const pthread_attr_t *attr,
			   void *(*start_routine)(void *), void *arg)
{
  int err;
  struct __pthread *pthread;
  const struct __pthread_attr *setup;
  sigset_t sigset;

  /* Allocate a new thread structure.  */
  err = __pthread_alloc (&pthread);
  if (err)
    goto failed;

  /* Use the default attributes if ATTR is NULL.  */
  setup = attr ? attr : &__pthread_default_attr;

  /* Initialize the thread state.  */
  pthread->state = (setup->detachstate == PTHREAD_CREATE_DETACHED
		    ? PTHREAD_DETACHED : PTHREAD_JOINABLE);

  /* If the user supplied a stack, it is not our responsibility to
     setup a stack guard.  */
  if (setup->stackaddr)
    pthread->guardsize = 0;
  else
    pthread->guardsize = (setup->guardsize <= setup->stacksize
			  ? setup->guardsize : setup->stacksize);

  /* Find a stack.  There are several scenarios: if a detached thread
     kills itself, it has no way to deallocate its stack, thus it
     leaves PTHREAD->stack set to true.  We try to reuse it here,
     however, if the user supplied a stack, we cannot use the old one.
     Right now, we simply deallocate it.  */
  if (pthread->stack)
    {
      if (setup->stackaddr != __pthread_default_attr.stackaddr)
	{
	  __pthread_stack_dealloc (pthread->stackaddr,
				   pthread->stacksize);
	  pthread->stackaddr = setup->stackaddr;
	  pthread->stacksize = setup->stacksize;
	}
    }
  else
    {
      err = __pthread_stack_alloc (&pthread->stackaddr,
				   setup->stacksize);
      if (err)
	goto failed_stack_alloc;

      pthread->stacksize = setup->stacksize;
      pthread->stack = 1;
    }

  /* Allocate the kernel thread and other required resources.  */
  err = __pthread_thread_alloc (pthread);
  if (err)
    goto failed_thread_alloc;

#ifdef ENABLE_TLS
  pthread->tcb = _dl_allocate_tls (NULL);
  if (!pthread->tcb)
    goto failed_thread_tls_alloc;
  pthread->tcb->tcb = pthread->tcb;
#endif /* ENABLE_TLS */

  /* And initialize the rest of the machine context.  This may include
     additional machine- and system-specific initializations that
     prove convenient.  */
  err = __pthread_setup (pthread, entry_point, start_routine, arg);
  if (err)
    goto failed_setup;

  /* Initialize the system-specific signal state for the new
     thread.  */
  err = __pthread_sigstate_init (pthread);
  if (err)
    goto failed_sigstate;

  /* Set the new thread's signal mask and set the pending signals to
     empty.  POSIX says: "The signal mask shall be inherited from the
     creating thread.  The set of signals pending for the new thread
     shall be empty."  If the currnet thread is not a pthread then we
     just inherit the process' sigmask.  */
  if (__pthread_num_threads == 1)
    err = sigprocmask (0, 0, &sigset);
  else
    err = __pthread_sigstate (_pthread_self (), 0, 0, &sigset, 0);
  assert_perror (err);

  err = __pthread_sigstate (pthread, SIG_SETMASK, &sigset, 0, 1);
  assert_perror (err);

  /* Increase the total number of threads.  We do this before actually
     starting the new thread, since the new thread might immediately
     call `pthread_exit' which decreases the number of threads and
     calls `exit' if the number of threads reaches zero.  Increasing
     the number of threads from within the new thread isn't an option
     since this thread might return and call `pthread_exit' before the
     new thread runs.  */
  __atomic_inc (&__pthread_total);

  /* Store a pointer to this thread in the thread ID lookup table.  We
     could use __thread_setid, however, we only lock for reading as no
     other thread should be using this entry (we also assume that the
     store is atomic).  */
  pthread_rwlock_rdlock (&__pthread_threads_lock);
  __pthread_threads[pthread->thread - 1] = pthread;
  pthread_rwlock_unlock (&__pthread_threads_lock);

  /* At this point it is possible to guess our pthread ID.  We have to
     make sure that all functions taking a pthread_t argument can
     handle the fact that this thread isn't really running yet.  */

  /* Schedule the new thread.  */
  err = __pthread_thread_start (pthread);
  if (err)
    goto failed_starting;

  /* At this point the new thread is up and running.  */

  *thread = pthread;

  return 0;

 failed_starting:
  __pthread_setid (pthread->thread, NULL);
  __atomic_dec (&__pthread_total);
 failed_sigstate:
  __pthread_sigstate_destroy (pthread);
 failed_setup:
#ifdef ENABLE_TLS
  _dl_deallocate_tls (pthread->tcb, 1);
 failed_thread_tls_alloc:
#endif /* ENABLE_TLS */
  __pthread_thread_dealloc (pthread);
  __pthread_thread_halt (pthread);
 failed_thread_alloc:
  __pthread_stack_dealloc (pthread->stackaddr, pthread->stacksize);
  pthread->stack = 0;
 failed_stack_alloc:
  __pthread_dealloc (pthread);
 failed:
  return err;
}