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
static void
backtrace_and_maps (int do_abort, bool written, int fd)
{
  if (do_abort > 1 && written)
    {
      void *addrs[64];
#define naddrs (sizeof (addrs) / sizeof (addrs[0]))
      int n = __backtrace (addrs, naddrs);
      if (n > 2)
        {
#define strnsize(str) str, strlen (str)
#define writestr(str) write_not_cancel (fd, str)
          writestr (strnsize ("======= Backtrace: =========\n"));
          __backtrace_symbols_fd (addrs + 1, n - 1, fd);

          writestr (strnsize ("======= Memory map: ========\n"));
          int fd2 = open_not_cancel_2 ("/proc/self/maps", O_RDONLY);
          char buf[1024];
          ssize_t n2;
          while ((n2 = read_not_cancel (fd2, buf, sizeof (buf))) > 0)
            if (write_not_cancel (fd, buf, n2) != n2)
              break;
          close_not_cancel_no_status (fd2);
        }
    }
}
Beispiel #3
0
pthread_start_thread(void *arg)
{
  pthread_descr self = (pthread_descr) arg;
  struct pthread_request request;
  void * outcome;
#if HP_TIMING_AVAIL
  hp_timing_t tmpclock;
#endif
  /* Initialize special thread_self processing, if any.  */
#ifdef INIT_THREAD_SELF
  INIT_THREAD_SELF(self, self->p_nr);
#endif
#if HP_TIMING_AVAIL
  HP_TIMING_NOW (tmpclock);
  THREAD_SETMEM (self, p_cpuclock_offset, tmpclock);
#endif
  /* Make sure our pid field is initialized, just in case we get there
     before our father has initialized it. */
  THREAD_SETMEM(self, p_pid, __getpid());
  /* Initial signal mask is that of the creating thread. (Otherwise,
     we'd just inherit the mask of the thread manager.) */
  sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL);
  /* Set the scheduling policy and priority for the new thread, if needed */
  if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0)
    /* Explicit scheduling attributes were provided: apply them */
    __sched_setscheduler(THREAD_GETMEM(self, p_pid),
			 THREAD_GETMEM(self, p_start_args.schedpolicy),
                         &self->p_start_args.schedparam);
  else if (manager_thread->p_priority > 0)
    /* Default scheduling required, but thread manager runs in realtime
       scheduling: switch new thread to SCHED_OTHER policy */
    {
      struct sched_param default_params;
      default_params.sched_priority = 0;
      __sched_setscheduler(THREAD_GETMEM(self, p_pid),
                           SCHED_OTHER, &default_params);
    }
#if !(USE_TLS && HAVE___THREAD)
  /* Initialize thread-locale current locale to point to the global one.
     With __thread support, the variable's initializer takes care of this.  */
  __uselocale (LC_GLOBAL_LOCALE);
#else
  /* Initialize __resp.  */
  __resp = &self->p_res;
#endif
  /* Make gdb aware of new thread */
  if (__pthread_threads_debug && __pthread_sig_debug > 0) {
    request.req_thread = self;
    request.req_kind = REQ_DEBUG;
    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
					(char *) &request, sizeof(request)));
    suspend(self);
  }
  /* Run the thread code */
  outcome = self->p_start_args.start_routine(THREAD_GETMEM(self,
							   p_start_args.arg));
  /* Exit with the given return value */
  __pthread_do_exit(outcome, CURRENT_STACK_FRAME);
}
Beispiel #4
0
static void __updwtmp(const char *wtmp_file, const struct utmp *lutmp)
{
    int fd;

    fd = open_not_cancel_2(wtmp_file, O_APPEND | O_WRONLY);
    if (fd >= 0) {
	if (lockf(fd, F_LOCK, 0) == 0) {
	    write_not_cancel(fd, lutmp, sizeof(struct utmp));
	    lockf(fd, F_ULOCK, 0);
	    close_not_cancel_no_status(fd);
	}
    }
}
Beispiel #5
0
/* Delete a key */
int pthread_key_delete(pthread_key_t key)
{
  pthread_descr self = thread_self();

  pthread_mutex_lock(&pthread_keys_mutex);
  if (key >= PTHREAD_KEYS_MAX || !pthread_keys[key].in_use) {
    pthread_mutex_unlock(&pthread_keys_mutex);
    return EINVAL;
  }
  pthread_keys[key].in_use = 0;
  pthread_keys[key].destr = NULL;

  /* Set the value of the key to NULL in all running threads, so
     that if the key is reallocated later by pthread_key_create, its
     associated values will be NULL in all threads.

     If no threads have been created yet, or if we are exiting, clear
     it just in the current thread.  */

  struct pthread_key_delete_helper_args args;
  args.idx1st = key / PTHREAD_KEY_2NDLEVEL_SIZE;
  args.idx2nd = key % PTHREAD_KEY_2NDLEVEL_SIZE;
  if (!l4_is_invalid_cap(__pthread_manager_request)
      && !(__builtin_expect (__pthread_exit_requested, 0)))
    {
      struct pthread_request request;

      args.self = 0;

      request.req_thread = self;
      request.req_kind = REQ_FOR_EACH_THREAD;
      request.req_args.for_each.arg = &args;
      request.req_args.for_each.fn = pthread_key_delete_helper;
#if 1
      __pthread_send_manager_rq(&request, 1);
#else
      TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
					  (char *) &request, sizeof(request)));
#endif
      suspend(self);
    }
  else
    {
      if (self->p_specific[args.idx1st] != NULL)
	self->p_specific[args.idx1st][args.idx2nd] = NULL;
    }

  pthread_mutex_unlock(&pthread_keys_mutex);
  return 0;
}
Beispiel #6
0
int sem_post(sem_t * sem)
{
  pthread_descr self = thread_self();
  pthread_descr th;
#if 0 // AW11
  struct pthread_request request;
  if (THREAD_GETMEM(self, p_in_sighandler) == NULL)
#endif
  {
    __pthread_lock(&sem->__sem_lock, self);
    if (sem->__sem_waiting == NULL) {
      if (sem->__sem_value >= SEM_VALUE_MAX) {
        /* Overflow */
        __set_errno(ERANGE);
        __pthread_unlock(&sem->__sem_lock);
        return -1;
      }
      sem->__sem_value++;
      __pthread_unlock(&sem->__sem_lock);
    } else {
      th = dequeue(&sem->__sem_waiting);
      __pthread_unlock(&sem->__sem_lock);
      th->p_sem_avail = 1;
      WRITE_MEMORY_BARRIER();
      restart(th);
    }
  }
#if 0 // AW11
  else {
    /* If we're in signal handler, delegate post operation to
       the thread manager. */
    if (__pthread_manager_request < 0) {
      if (__pthread_initialize_manager() < 0) {
        __set_errno(EAGAIN);
        return -1;
      }
    }
    request.req_kind = REQ_POST;
    request.req_args.post = sem;
    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
					(char *) &request, sizeof(request)));
  }
#endif
  return 0;
}
Beispiel #7
0
void __pthread_manager_sighandler(int sig)
{
  int kick_manager = terminated_children == 0 && main_thread_exiting;
  terminated_children = 1;

  /* If the main thread is terminating, kick the thread manager loop
     each time some threads terminate. This eliminates a two second
     shutdown delay caused by the thread manager sleeping in the
     call to __poll(). Instead, the thread manager is kicked into
     action, reaps the outstanding threads and resumes the main thread
     so that it can complete the shutdown. */

  if (kick_manager) {
    struct pthread_request request;
    request.req_thread = 0;
    request.req_kind = REQ_KICK;
    TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request,
					(char *) &request, sizeof(request)));
  }
}
Beispiel #8
0
_IO_ssize_t
_IO_new_file_write (_IO_FILE *f, const void *data, _IO_ssize_t n)
{
  _IO_ssize_t to_do = n;
  while (to_do > 0)
    {
      _IO_ssize_t count = (__builtin_expect (f->_flags2
					     & _IO_FLAGS2_NOTCANCEL, 0)
			   ? write_not_cancel (f->_fileno, data, to_do)
			   : write (f->_fileno, data, to_do));
      if (count < 0)
	{
	  f->_flags |= _IO_ERR_SEEN;
	  break;
	}
      to_do -= count;
      data = (void *) ((char *) data + count);
    }
  n -= to_do;
  if (f->_offset >= 0)
    f->_offset += n;
  return n;
}
Beispiel #9
0
/* Function used in the clone call to setup the signals mask, posix_spawn
   attributes, and file actions.  It run on its own stack (provided by the
   posix_spawn call).  */
static int
__spawni_child (void *arguments)
{
  struct posix_spawn_args *args = arguments;
  const posix_spawnattr_t *restrict attr = args->attr;
  const posix_spawn_file_actions_t *file_actions = args->fa;
  int p = args->pipe[1];
  int ret;

  close_not_cancel (args->pipe[0]);

  /* The child must ensure that no signal handler are enabled because it shared
     memory with parent, so the signal disposition must be either SIG_DFL or
     SIG_IGN.  It does by iterating over all signals and although it could
     possibly be more optimized (by tracking which signal potentially have a
     signal handler), it might requires system specific solutions (since the
     sigset_t data type can be very different on different architectures).  */
  struct sigaction sa;
  memset (&sa, '\0', sizeof (sa));

  sigset_t hset;
  __sigprocmask (SIG_BLOCK, 0, &hset);
  for (int sig = 1; sig < _NSIG; ++sig)
    {
      if ((attr->__flags & POSIX_SPAWN_SETSIGDEF)
	  && sigismember (&attr->__sd, sig))
	{
	  sa.sa_handler = SIG_DFL;
	}
      else if (sigismember (&hset, sig))
	{
	  if (__nptl_is_internal_signal (sig))
	    sa.sa_handler = SIG_IGN;
	  else
	    {
	      __libc_sigaction (sig, 0, &sa);
	      if (sa.sa_handler == SIG_IGN)
		continue;
	      sa.sa_handler = SIG_DFL;
	    }
	}
      else
	continue;

      __libc_sigaction (sig, &sa, 0);
    }

#ifdef _POSIX_PRIORITY_SCHEDULING
  /* Set the scheduling algorithm and parameters.  */
  if ((attr->__flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
      == POSIX_SPAWN_SETSCHEDPARAM)
    {
      if ((ret = __sched_setparam (0, &attr->__sp)) == -1)
	goto fail;
    }
  else if ((attr->__flags & POSIX_SPAWN_SETSCHEDULER) != 0)
    {
      if ((ret = __sched_setscheduler (0, attr->__policy, &attr->__sp)) == -1)
	goto fail;
    }
#endif

  /* Set the process group ID.  */
  if ((attr->__flags & POSIX_SPAWN_SETPGROUP) != 0
      && (ret = __setpgid (0, attr->__pgrp)) != 0)
    goto fail;

  /* Set the effective user and group IDs.  */
  if ((attr->__flags & POSIX_SPAWN_RESETIDS) != 0
      && ((ret = local_seteuid (__getuid ())) != 0
	  || (ret = local_setegid (__getgid ())) != 0))
    goto fail;

  /* Execute the file actions.  */
  if (file_actions != 0)
    {
      int cnt;
      struct rlimit64 fdlimit;
      bool have_fdlimit = false;

      for (cnt = 0; cnt < file_actions->__used; ++cnt)
	{
	  struct __spawn_action *action = &file_actions->__actions[cnt];

	  /* Dup the pipe fd onto an unoccupied one to avoid any file
	     operation to clobber it.  */
	  if ((action->action.close_action.fd == p)
	      || (action->action.open_action.fd == p)
	      || (action->action.dup2_action.fd == p))
	    {
	      if ((ret = __dup (p)) < 0)
		goto fail;
	      p = ret;
	    }

	  switch (action->tag)
	    {
	    case spawn_do_close:
	      if ((ret =
		   close_not_cancel (action->action.close_action.fd)) != 0)
		{
		  if (!have_fdlimit)
		    {
		      __getrlimit64 (RLIMIT_NOFILE, &fdlimit);
		      have_fdlimit = true;
		    }

		  /* Signal errors only for file descriptors out of range.  */
		  if (action->action.close_action.fd < 0
		      || action->action.close_action.fd >= fdlimit.rlim_cur)
		    goto fail;
		}
	      break;

	    case spawn_do_open:
	      {
		ret = open_not_cancel (action->action.open_action.path,
				       action->action.
				       open_action.oflag | O_LARGEFILE,
				       action->action.open_action.mode);

		if (ret == -1)
		  goto fail;

		int new_fd = ret;

		/* Make sure the desired file descriptor is used.  */
		if (ret != action->action.open_action.fd)
		  {
		    if ((ret = __dup2 (new_fd, action->action.open_action.fd))
			!= action->action.open_action.fd)
		      goto fail;

		    if ((ret = close_not_cancel (new_fd)) != 0)
		      goto fail;
		  }
	      }
	      break;

	    case spawn_do_dup2:
	      if ((ret = __dup2 (action->action.dup2_action.fd,
				 action->action.dup2_action.newfd))
		  != action->action.dup2_action.newfd)
		goto fail;
	      break;
	    }
	}
    }

  /* Set the initial signal mask of the child if POSIX_SPAWN_SETSIGMASK
     is set, otherwise restore the previous one.  */
  __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
		 ? &attr->__ss : &args->oldmask, 0);

  args->exec (args->file, args->argv, args->envp);

  /* This is compatibility function required to enable posix_spawn run
     script without shebang definition for older posix_spawn versions
     (2.15).  */
  maybe_script_execute (args);

  ret = -errno;

fail:
  /* Since sizeof errno < PIPE_BUF, the write is atomic. */
  ret = -ret;
  if (ret)
    while (write_not_cancel (p, &ret, sizeof ret) < 0)
      continue;
  exit (SPAWN_ERROR);
}