Exemplo n.º 1
0
static int pthread_allocate_stack(const pthread_attr_t *attr,
                                  pthread_descr default_new_thread,
                                  int pagesize,
                                  pthread_descr * out_new_thread,
                                  char ** out_new_thread_bottom,
                                  char ** out_guardaddr,
                                  size_t * out_guardsize)
{
  pthread_descr new_thread;
  char * new_thread_bottom;
  char * guardaddr;
  size_t stacksize, guardsize;

  if (attr != NULL && attr->__stackaddr_set)
    {
      /* The user provided a stack. */
      new_thread = (pthread_descr) ((long)(attr->__stackaddr) & -sizeof(void *)) - 1;
      new_thread_bottom = (char *) attr->__stackaddr - attr->__stacksize;
      guardaddr = NULL;
      guardsize = 0;
      __pthread_nonstandard_stacks = 1;
#ifndef __ARCH_USE_MMU__
      /* check the initial thread stack boundaries so they don't overlap */
      NOMMU_INITIAL_THREAD_BOUNDS((char *) new_thread, (char *) new_thread_bottom);

      PDEBUG("initial stack: bos=%p, tos=%p\n", __pthread_initial_thread_bos,
            __pthread_initial_thread_tos);
#endif
    }
  else
    {
#ifdef __ARCH_USE_MMU__
      stacksize = STACK_SIZE - pagesize;
      if (attr != NULL)
        stacksize = MIN(stacksize, roundup(attr->__stacksize, pagesize));
      /* Allocate space for stack and thread descriptor at default address */
      new_thread = default_new_thread;
      new_thread_bottom = (char *) (new_thread + 1) - stacksize;
      if (mmap((caddr_t)((char *)(new_thread + 1) - INITIAL_STACK_SIZE),
               INITIAL_STACK_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
               MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_GROWSDOWN,
               -1, 0) == MAP_FAILED)
        /* Bad luck, this segment is already mapped. */
        return -1;
      /* We manage to get a stack.  Now see whether we need a guard
         and allocate it if necessary.  Notice that the default
         attributes (stack_size = STACK_SIZE - pagesize) do not need
	 a guard page, since the RLIMIT_STACK soft limit prevents stacks
	 from running into one another. */
      if (stacksize == (size_t) (STACK_SIZE - pagesize))
        {
          /* We don't need a guard page. */
          guardaddr = NULL;
          guardsize = 0;
        }
      else
        {
          /* Put a bad page at the bottom of the stack */
          guardsize = attr->__guardsize;
          guardaddr = (void *)new_thread_bottom - guardsize;
          if (mmap((caddr_t) guardaddr, guardsize, 0, MAP_FIXED, -1, 0)
              == MAP_FAILED)
            {
              /* We don't make this an error.  */
              guardaddr = NULL;
              guardsize = 0;
            }
        }
#else
      /* We cannot mmap to this huge chunk of stack space when we don't have
       * an MMU. Pretend we are using a user provided stack even if there was
       * none provided by the user. Thus, we get around the mmap and reservation
       * of a huge stack segment. -StS */

      stacksize = INITIAL_STACK_SIZE;
      /* The user may want to use a non-default stacksize */
      if (attr != NULL)
	{
	  stacksize = attr->__stacksize;
	}

      /* malloc a stack - memory from the bottom up */
      if ((new_thread_bottom = malloc(stacksize)) == NULL)
	{
	  /* bad luck, we cannot malloc any more */
	  return -1 ;
	}
      PDEBUG("malloced chunk: base=%p, size=0x%04x\n", new_thread_bottom, stacksize);

      /* Set up the pointers. new_thread marks the TOP of the stack frame and
       * the address of the pthread_descr struct at the same time. Therefore we
       * must account for its size and fit it in the malloc()'ed block. The
       * value of `new_thread' is then passed to clone() as the stack argument.
       *
       *               ^ +------------------------+
       *               | |  pthread_descr struct  |
       *               | +------------------------+  <- new_thread
       * malloc block  | |                        |
       *               | |  thread stack          |
       *               | |                        |
       *               v +------------------------+  <- new_thread_bottom
       *
       * Note: The calculated value of new_thread must be word aligned otherwise
       * the kernel chokes on a non-aligned stack frame. Choose the lower
       * available word boundary.
       */
      new_thread = ((pthread_descr) ((int)(new_thread_bottom + stacksize) & -sizeof(void*))) - 1;
      guardaddr = NULL;
      guardsize = 0;

      PDEBUG("thread stack: bos=%p, tos=%p\n", new_thread_bottom, new_thread);

      /* check the initial thread stack boundaries so they don't overlap */
      NOMMU_INITIAL_THREAD_BOUNDS((char *) new_thread, (char *) new_thread_bottom);

      PDEBUG("initial stack: bos=%p, tos=%p\n", __pthread_initial_thread_bos,
	     __pthread_initial_thread_tos);

      /* on non-MMU systems we always have non-standard stack frames */
      __pthread_nonstandard_stacks = 1;

#endif /* __ARCH_USE_MMU__ */
    }

  /* Clear the thread data structure.  */
  memset (new_thread, '\0', sizeof (*new_thread));
  *out_new_thread = new_thread;
  *out_new_thread_bottom = new_thread_bottom;
  *out_guardaddr = guardaddr;
  *out_guardsize = guardsize;
  return 0;
}
Exemplo n.º 2
0
int __pthread_initialize_manager(void)
{
  int manager_pipe[2];
  int pid;
  int report_events;
  struct pthread_request request;

  *__libc_multiple_threads_ptr = 1;

  /* If basic initialization not done yet (e.g. we're called from a
     constructor run before our constructor), do it now */
  if (__pthread_initial_thread_bos == NULL) pthread_initialize();
  /* Setup stack for thread manager */
  __pthread_manager_thread_bos = malloc(THREAD_MANAGER_STACK_SIZE);
  if (__pthread_manager_thread_bos == NULL) return -1;
  __pthread_manager_thread_tos =
    __pthread_manager_thread_bos + THREAD_MANAGER_STACK_SIZE;

  /* On non-MMU systems we make sure that the initial thread bounds don't overlap
   * with the manager stack frame */
  NOMMU_INITIAL_THREAD_BOUNDS(__pthread_manager_thread_tos,__pthread_manager_thread_bos);
  PDEBUG("manager stack: size=%d, bos=%p, tos=%p\n", THREAD_MANAGER_STACK_SIZE,
	 __pthread_manager_thread_bos, __pthread_manager_thread_tos);
#if 0
  PDEBUG("initial stack: estimate bos=%p, tos=%p\n",
	 __pthread_initial_thread_bos, __pthread_initial_thread_tos);
#endif

  /* Setup pipe to communicate with thread manager */
  if (pipe(manager_pipe) == -1) {
    free(__pthread_manager_thread_bos);
    return -1;
  }
  /* Start the thread manager */
  pid = 0;
#if defined(USE_TLS) && USE_TLS
  if (__linuxthreads_initial_report_events != 0)
    THREAD_SETMEM (((pthread_descr) NULL), p_report_events,
		   __linuxthreads_initial_report_events);
  report_events = THREAD_GETMEM (((pthread_descr) NULL), p_report_events);
#else
  if (__linuxthreads_initial_report_events != 0)
    __pthread_initial_thread.p_report_events
      = __linuxthreads_initial_report_events;
  report_events = __pthread_initial_thread.p_report_events;
#endif
  if (__builtin_expect (report_events, 0))
    {
      /* It's a bit more complicated.  We have to report the creation of
	 the manager thread.  */
      int idx = __td_eventword (TD_CREATE);
      uint32_t mask = __td_eventmask (TD_CREATE);

      if ((mask & (__pthread_threads_events.event_bits[idx]
		   | __pthread_initial_thread.p_eventbuf.eventmask.event_bits[idx]))
	  != 0)
	{

	 __pthread_lock(__pthread_manager_thread.p_lock, NULL);

#ifdef __ia64__
	  pid = __clone2(__pthread_manager_event,
			(void **) __pthread_manager_thread_tos,
			THREAD_MANAGER_STACK_SIZE,
			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
			(void *)(long)manager_pipe[0]);
#else
	  pid = clone(__pthread_manager_event,
			(void **) __pthread_manager_thread_tos,
			CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
			(void *)(long)manager_pipe[0]);
#endif

	  if (pid != -1)
	    {
	      /* Now fill in the information about the new thread in
	         the newly created thread's data structure.  We cannot let
	         the new thread do this since we don't know whether it was
	         already scheduled when we send the event.  */
	      __pthread_manager_thread.p_eventbuf.eventdata =
		  &__pthread_manager_thread;
	      __pthread_manager_thread.p_eventbuf.eventnum = TD_CREATE;
	      __pthread_last_event = &__pthread_manager_thread;
	      __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
	      __pthread_manager_thread.p_pid = pid;

	      /* Now call the function which signals the event.  */
	      __linuxthreads_create_event ();
	    }
	  /* Now restart the thread.  */
	  __pthread_unlock(__pthread_manager_thread.p_lock);
	}
    }

  if (pid == 0) {
#ifdef __ia64__
    pid = __clone2(__pthread_manager, (void **) __pthread_manager_thread_tos,
		  THREAD_MANAGER_STACK_SIZE,
		  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
		  (void *)(long)manager_pipe[0]);
#else
    pid = clone(__pthread_manager, (void **) __pthread_manager_thread_tos,
		  CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,
		  (void *)(long)manager_pipe[0]);
#endif
  }
  if (pid == -1) {
    free(__pthread_manager_thread_bos);
    close(manager_pipe[0]);
    close(manager_pipe[1]);
    return -1;
  }
  __pthread_manager_request = manager_pipe[1]; /* writing end */
  __pthread_manager_reader = manager_pipe[0]; /* reading end */
  __pthread_manager_thread.p_tid = 2* PTHREAD_THREADS_MAX + 1;
  __pthread_manager_thread.p_pid = pid;

  /* Make gdb aware of new thread manager */
  if (__pthread_threads_debug && __pthread_sig_debug > 0)
    {
      raise(__pthread_sig_debug);
      /* We suspend ourself and gdb will wake us up when it is
	 ready to handle us. */
      __pthread_wait_for_restart_signal(thread_self());
    }
  /* Synchronize debugging of the thread manager */
  PDEBUG("send REQ_DEBUG to manager thread\n");
  request.req_kind = REQ_DEBUG;
  TEMP_FAILURE_RETRY(write(__pthread_manager_request,
	      (char *) &request, sizeof(request)));
  return 0;
}