Ejemplo n.º 1
0
int
__libc_system(const char *command)
{
	pid_t pid, savedpid;
	int pstat;
	struct sigaction ign, intact, quitact;
	sigset_t newsigblock, oldsigblock;

	if (!command)		/* just checking... */
		return(1);

	(void)sigemptyset(&newsigblock);
	(void)sigaddset(&newsigblock, SIGCHLD);
	(void)sigaddset(&newsigblock, SIGINT);
	(void)sigaddset(&newsigblock, SIGQUIT);
	(void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
	switch(pid = vfork()) {
	/*
	 * In the child, use unwrapped syscalls.  libthr is in
	 * undefined state after vfork().
	 */
	case -1:			/* error */
		(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
		return (-1);
	case 0:				/* child */
		/*
		 * Restore original signal dispositions and exec the command.
		 */
		(void)__sys_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
		execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
		_exit(127);
	}
	/* 
	 * If we are running means that the child has either completed
	 * its execve, or has failed.
	 * Block SIGINT/QUIT because sh -c handles it and wait for
	 * it to clean up.
	 */
	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	(void)sigemptyset(&ign.sa_mask);
	(void)__libc_sigaction(SIGINT, &ign, &intact);
	(void)__libc_sigaction(SIGQUIT, &ign, &quitact);
	savedpid = pid;
	do {
		pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
	} while (pid == -1 && errno == EINTR);
	(void)__libc_sigaction(SIGINT, &intact, NULL);
	(void)__libc_sigaction(SIGQUIT,  &quitact, NULL);
	(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
	return (pid == -1 ? -1 : pstat);
}
Ejemplo n.º 2
0
int
daemon(int nochdir, int noclose)
{
	struct sigaction osa, sa;
	int fd;
	pid_t newgrp;
	int oerrno;
	int osa_ok;

	/* A SIGHUP may be thrown when the parent exits below. */
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = SIG_IGN;
	sa.sa_flags = 0;
	osa_ok = __libc_sigaction(SIGHUP, &sa, &osa);

	switch (fork()) {
	case -1:
		return (-1);
	case 0:
		break;
	default:
		/*
		 * A fine point:  _exit(0), not exit(0), to avoid triggering
		 * atexit(3) processing
		 */
		_exit(0);
	}

	newgrp = setsid();
	oerrno = errno;
	if (osa_ok != -1)
		__libc_sigaction(SIGHUP, &osa, NULL);

	if (newgrp == -1) {
		errno = oerrno;
		return (-1);
	}

	if (!nochdir)
		(void)chdir("/");

	if (!noclose && (fd = _open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
		(void)_dup2(fd, STDIN_FILENO);
		(void)_dup2(fd, STDOUT_FILENO);
		(void)_dup2(fd, STDERR_FILENO);
		if (fd > 2)
			(void)_close(fd);
	}
	return (0);
}
Ejemplo n.º 3
0
void
abort(void)
{
	struct sigaction act;

	/*
	 * POSIX requires we flush stdio buffers on abort.
	 * XXX ISO C requires that abort() be async-signal-safe.
	 */
	if (__cleanup)
		(*__cleanup)();

	sigfillset(&act.sa_mask);
	/*
	 * Don't block SIGABRT to give any handler a chance; we ignore
	 * any errors -- ISO C doesn't allow abort to return anyway.
	 */
	sigdelset(&act.sa_mask, SIGABRT);
	(void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
	(void)raise(SIGABRT);

	/*
	 * If SIGABRT was ignored, or caught and the handler returns, do
	 * it again, only harder.
	 */
	act.sa_handler = SIG_DFL;
	act.sa_flags = 0;
	sigfillset(&act.sa_mask);
	(void)__libc_sigaction(SIGABRT, &act, NULL);
	sigdelset(&act.sa_mask, SIGABRT);
	(void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
	(void)raise(SIGABRT);
	exit(1);
}
Ejemplo n.º 4
0
int __sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
{
	if (sig-32U < 3) {
		errno = EINVAL;
		return -1;
	}
	return __libc_sigaction(sig, sa, old);
}
Ejemplo n.º 5
0
int __sigaction(int sig, const struct sigaction *sa, struct sigaction *old)
{
	if (sig == SIGCANCEL || sig == SIGSYSCALL) {
		errno = EINVAL;
		return -1;
	}
	return __libc_sigaction(sig, sa, old);
}
void __pthread_kill_other_threads_np(void)
{
  struct sigaction sa;
  /* Terminate all other threads and thread manager */
  pthread_onexit_process(0, NULL);
  /* Make current thread the main thread in case the calling thread
     changes its mind, does not exec(), and creates new threads instead. */
  __pthread_reset_main_thread();
  /* Reset the signal handlers behaviour for the signals the
     implementation uses since this would be passed to the new
     process.  */
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  sa.sa_handler = SIG_DFL;
  __libc_sigaction(__pthread_sig_restart, &sa, NULL);
  __libc_sigaction(__pthread_sig_cancel, &sa, NULL);
  if (__pthread_sig_debug > 0)
    __libc_sigaction(__pthread_sig_debug, &sa, NULL);
}
Ejemplo n.º 7
0
int
__sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
{
  if (sig <= 0 || sig >= NSIG || __is_internal_signal (sig))
    {
      __set_errno (EINVAL);
      return -1;
    }

  return __libc_sigaction (sig, act, oact);
}
Ejemplo n.º 8
0
/* The wrapper around sigaction.  Install our own signal handler
   around the signal. */
int __pthread_sigaction(int sig, const struct sigaction * act,
			struct sigaction * oact)
{
  struct sigaction newact;
  struct sigaction *newactp;
  __sighandler_t old = SIG_DFL;

  if (sig == __pthread_sig_restart ||
      sig == __pthread_sig_cancel ||
      (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
    {
      __set_errno (EINVAL);
      return -1;
    }
  if (sig > 0 && sig < NSIG)
    old = (__sighandler_t) __sighandler[sig].old;
  if (act)
    {
      newact = *act;
      if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
	  && sig > 0 && sig < NSIG)
	{
	  if (act->sa_flags & SA_SIGINFO)
	    newact.sa_handler = (__sighandler_t) __pthread_sighandler_rt;
	  else
	    newact.sa_handler = (__sighandler_t) __pthread_sighandler;
	  if (old == SIG_IGN || old == SIG_DFL || old == SIG_ERR)
	    __sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
	}
      newactp = &newact;
    }
  else
    newactp = NULL;
  if (__libc_sigaction(sig, newactp, oact) == -1)
    {
      if (act && (sig > 0 && sig < NSIG))
	__sighandler[sig].old = (arch_sighandler_t) old;
      return -1;
    }
  if (sig > 0 && sig < NSIG)
    {
      if (oact != NULL
	  /* We may have inherited SIG_IGN from the parent, so return the
	     kernel's idea of the signal handler the first time
	     through.  */
	  && old != SIG_ERR)
	oact->sa_handler = old;
      if (act)
	/* For the assignment it does not matter whether it's a normal
	   or real-time signal.  */
	__sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
    }
  return 0;
}
Ejemplo n.º 9
0
sig_t
signal(int s, sig_t a)
{
	struct sigaction sa, osa;

	sa.sa_handler = a;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if (!sigismember(&_sigintr, s))
		sa.sa_flags |= SA_RESTART;
	if (__libc_sigaction(s, &sa, &osa) < 0)
		return (SIG_ERR);
	return (osa.sa_handler);
}
Ejemplo n.º 10
0
/* The wrapper around sigaction.  Install our own signal handler
   around the signal. */
int __sigaction(int sig, const struct sigaction * act,
              struct sigaction * oact)
{
  struct sigaction newact;
  struct sigaction *newactp;

#ifdef DEBUG_PT
printf(__FUNCTION__": pthreads wrapper!\n");
#endif
  if (sig == __pthread_sig_restart ||
      sig == __pthread_sig_cancel ||
      (sig == __pthread_sig_debug && __pthread_sig_debug > 0))
    return EINVAL;
  if (act)
    {
      newact = *act;
      if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL
	  && sig > 0 && sig < NSIG)
	{
	  if (act->sa_flags & SA_SIGINFO)
	    newact.sa_handler = (__sighandler_t) pthread_sighandler_rt;
	  else
	    newact.sa_handler = (__sighandler_t) pthread_sighandler;
	}
      newactp = &newact;
    }
  else
    newactp = NULL;
  if (__libc_sigaction(sig, newactp, oact) == -1)
    return -1;
#ifdef DEBUG_PT
printf(__FUNCTION__": signahdler installed, __sigaction successful\n");
#endif
  if (sig > 0 && sig < NSIG)
    {
      if (oact != NULL)
	oact->sa_handler = (__sighandler_t) sighandler[sig].old;
      if (act)
	/* For the assignment is does not matter whether it's a normal
	   or real-time signal.  */
	sighandler[sig].old = (arch_sighandler_t) act->sa_handler;
    }
  return 0;
}
Ejemplo n.º 11
0
static void init_cancellation()
{
    struct sigaction sa = {
        .sa_flags = SA_SIGINFO | SA_RESTART,
        .sa_sigaction = cancel_handler
    };
    sigfillset(&sa.sa_mask);
    __libc_sigaction(SIGCANCEL, &sa, 0);
}

int pthread_cancel(pthread_t t)
{
    static int init;
    if (!init) {
        init_cancellation();
        init = 1;
    }
    a_store(&t->cancel, 1);
    return pthread_kill(t, SIGCANCEL);
}
Ejemplo n.º 12
0
void
__pthread_initialize_minimal_internal (void)
{
#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);

  /* We must prevent gcc from being clever and move any of the
     following code ahead of the __libc_setup_tls call.  This function
     will initialize the thread register which is subsequently
     used.  */
  __asm __volatile ("");
#endif

  /* Minimal initialization of the thread descriptor.  */
  struct pthread *pd = THREAD_SELF;
  __pthread_initialize_pids (pd);
  THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
  THREAD_SETMEM (pd, user_stack, true);
  if (LLL_LOCK_INITIALIZER != 0)
    THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
#if HP_TIMING_AVAIL
  THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
#endif

  /* Initialize the robust mutex data.  */
  {
#ifdef __PTHREAD_MUTEX_HAVE_PREV
    pd->robust_prev = &pd->robust_head;
#endif
    pd->robust_head.list = &pd->robust_head;
#ifdef __NR_set_robust_list
    pd->robust_head.futex_offset = (offsetof (pthread_mutex_t, __data.__lock)
				    - offsetof (pthread_mutex_t,
						__data.__list.__next));
    INTERNAL_SYSCALL_DECL (err);
    int res = INTERNAL_SYSCALL (set_robust_list, err, 2, &pd->robust_head,
				sizeof (struct robust_list_head));
    if (INTERNAL_SYSCALL_ERROR_P (res, err))
#endif
      set_robust_list_not_avail ();
  }

#ifdef __NR_futex
# ifndef __ASSUME_PRIVATE_FUTEX
  /* Private futexes are always used (at least internally) so that
     doing the test once this early is beneficial.  */
  {
    int word = 0;
    INTERNAL_SYSCALL_DECL (err);
    word = INTERNAL_SYSCALL (futex, err, 3, &word,
			    FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1);
    if (!INTERNAL_SYSCALL_ERROR_P (word, err))
      THREAD_SETMEM (pd, header.private_futex, FUTEX_PRIVATE_FLAG);
  }

  /* Private futexes have been introduced earlier than the
     FUTEX_CLOCK_REALTIME flag.  We don't have to run the test if we
     know the former are not supported.  This also means we know the
     kernel will return ENOSYS for unknown operations.  */
  if (THREAD_GETMEM (pd, header.private_futex) != 0)
# endif
# ifndef __ASSUME_FUTEX_CLOCK_REALTIME
    {
      int word = 0;
      /* NB: the syscall actually takes six parameters.  The last is the
	 bit mask.  But since we will not actually wait at all the value
	 is irrelevant.  Given that passing six parameters is difficult
	 on some architectures we just pass whatever random value the
	 calling convention calls for to the kernel.  It causes no harm.  */
      INTERNAL_SYSCALL_DECL (err);
      word = INTERNAL_SYSCALL (futex, err, 5, &word,
			       FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME
			       | FUTEX_PRIVATE_FLAG, 1, NULL, 0);
      assert (INTERNAL_SYSCALL_ERROR_P (word, err));
      if (INTERNAL_SYSCALL_ERRNO (word, err) != ENOSYS)
	__set_futex_clock_realtime ();
    }
# endif
#endif

  /* Set initial thread's stack block from 0 up to __libc_stack_end.
     It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
     purposes this is good enough.  */
  THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);

  /* Initialize the list of all running threads with the main thread.  */
  INIT_LIST_HEAD (&__stack_user);
  list_add (&pd->list, &__stack_user);

  /* Before initializing __stack_user, the debugger could not find us and
     had to set __nptl_initial_report_events.  Propagate its setting.  */
  THREAD_SETMEM (pd, report_events, __nptl_initial_report_events);

#if defined SIGCANCEL || defined SIGSETXID
  struct sigaction sa;
  __sigemptyset (&sa.sa_mask);

# ifdef SIGCANCEL
  /* Install the cancellation signal handler.  If for some reason we
     cannot install the handler we do not abort.  Maybe we should, but
     it is only asynchronous cancellation which is affected.  */
  sa.sa_sigaction = sigcancel_handler;
  sa.sa_flags = SA_SIGINFO;
  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);
# endif

# ifdef SIGSETXID
  /* Install the handle to change the threads' uid/gid.  */
  sa.sa_sigaction = sighandler_setxid;
  sa.sa_flags = SA_SIGINFO | SA_RESTART;
  (void) __libc_sigaction (SIGSETXID, &sa, NULL);
# endif

  /* The parent process might have left the signals blocked.  Just in
     case, unblock it.  We reuse the signal mask in the sigaction
     structure.  It is already cleared.  */
# ifdef SIGCANCEL
  __sigaddset (&sa.sa_mask, SIGCANCEL);
# endif
# ifdef SIGSETXID
  __sigaddset (&sa.sa_mask, SIGSETXID);
# endif
  {
    INTERNAL_SYSCALL_DECL (err);
    (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
			     NULL, _NSIG / 8);
  }
#endif

  /* Get the size of the static and alignment requirements for the TLS
     block.  */
  size_t static_tls_align;
  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);

  /* Make sure the size takes all the alignments into account.  */
  if (STACK_ALIGN > static_tls_align)
    static_tls_align = STACK_ALIGN;
  __static_tls_align_m1 = static_tls_align - 1;

  __static_tls_size = roundup (__static_tls_size, static_tls_align);

  /* Determine the default allowed stack size.  This is the size used
     in case the user does not specify one.  */
  struct rlimit limit;
  if (__getrlimit (RLIMIT_STACK, &limit) != 0
      || limit.rlim_cur == RLIM_INFINITY)
    /* The system limit is not usable.  Use an architecture-specific
       default.  */
    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
    /* The system limit is unusably small.
       Use the minimal size acceptable.  */
    limit.rlim_cur = PTHREAD_STACK_MIN;

  /* Make sure it meets the minimum size that allocate_stack
     (allocatestack.c) will demand, which depends on the page size.  */
  const uintptr_t pagesz = GLRO(dl_pagesize);
  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
  if (limit.rlim_cur < minstack)
    limit.rlim_cur = minstack;

  /* Round the resource limit up to page size.  */
  limit.rlim_cur = ALIGN_UP (limit.rlim_cur, pagesz);
  lll_lock (__default_pthread_attr_lock, LLL_PRIVATE);
  __default_pthread_attr.stacksize = limit.rlim_cur;
  __default_pthread_attr.guardsize = GLRO (dl_pagesize);
  lll_unlock (__default_pthread_attr_lock, LLL_PRIVATE);

#ifdef SHARED
  /* Transfer the old value from the dynamic linker's internal location.  */
  *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
  GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;

  /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock,
     keep the lock count from the ld.so implementation.  */
  GL(dl_rtld_lock_recursive) = (void *) __pthread_mutex_lock;
  GL(dl_rtld_unlock_recursive) = (void *) __pthread_mutex_unlock;
  unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
  GL(dl_load_lock).mutex.__data.__count = 0;
  while (rtld_lock_count-- > 0)
    __pthread_mutex_lock (&GL(dl_load_lock).mutex);

  GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
#endif

  GL(dl_init_static_tls) = &__pthread_init_static_tls;

  GL(dl_wait_lookup_done) = &__wait_lookup_done;

  /* Register the fork generation counter with the libc.  */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
  __libc_multiple_threads_ptr =
#endif
    __libc_pthread_init (&__fork_generation, __reclaim_stacks,
			 ptr_pthread_functions);

  /* Determine whether the machine is SMP or not.  */
  __is_smp = is_smp_system ();
}
Ejemplo n.º 13
0
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
	ssize_t nr;
	int input, output, save_errno, i, need_restart, input_is_tty;
	char ch, *p, *end;
	struct termios term, oterm;
	struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
	struct sigaction savetstp, savettin, savettou, savepipe;

	/* I suppose we could alloc on demand in this case (XXX). */
	if (bufsiz == 0) {
		errno = EINVAL;
		return(NULL);
	}

restart:
	for (i = 0; i < NSIG; i++)
		signo[i] = 0;
	nr = -1;
	save_errno = 0;
	need_restart = 0;
	/*
	 * Read and write to /dev/tty if available.  If not, read from
	 * stdin and write to stderr unless a tty is required.
	 */
	input_is_tty = 0;
	if (!(flags & RPP_STDIN)) {
        	input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC);
		if (input == -1) {
			if (flags & RPP_REQUIRE_TTY) {
				errno = ENOTTY;
				return(NULL);
			}
			input = STDIN_FILENO;
			output = STDERR_FILENO;
		} else {
			input_is_tty = 1;
		}
	} else {
		input = STDIN_FILENO;
		output = STDERR_FILENO;
	}

	/*
	 * Turn off echo if possible.
	 * If we are using a tty but are not the foreground pgrp this will
	 * generate SIGTTOU, so do it *before* installing the signal handlers.
	 */
	if (input_is_tty && tcgetattr(input, &oterm) == 0) {
		memcpy(&term, &oterm, sizeof(term));
		if (!(flags & RPP_ECHO_ON))
			term.c_lflag &= ~(ECHO | ECHONL);
		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
	} else {
		memset(&term, 0, sizeof(term));
		term.c_lflag |= ECHO;
		memset(&oterm, 0, sizeof(oterm));
		oterm.c_lflag |= ECHO;
	}

	/*
	 * Catch signals that would otherwise cause the user to end
	 * up with echo turned off in the shell.  Don't worry about
	 * things like SIGXCPU and SIGVTALRM for now.
	 */
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;		/* don't restart system calls */
	sa.sa_handler = handler;
	(void)__libc_sigaction(SIGALRM, &sa, &savealrm);
	(void)__libc_sigaction(SIGHUP, &sa, &savehup);
	(void)__libc_sigaction(SIGINT, &sa, &saveint);
	(void)__libc_sigaction(SIGPIPE, &sa, &savepipe);
	(void)__libc_sigaction(SIGQUIT, &sa, &savequit);
	(void)__libc_sigaction(SIGTERM, &sa, &saveterm);
	(void)__libc_sigaction(SIGTSTP, &sa, &savetstp);
	(void)__libc_sigaction(SIGTTIN, &sa, &savettin);
	(void)__libc_sigaction(SIGTTOU, &sa, &savettou);

	if (!(flags & RPP_STDIN))
		(void)_write(output, prompt, strlen(prompt));
	end = buf + bufsiz - 1;
	p = buf;
	while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
		if (p < end) {
			if ((flags & RPP_SEVENBIT))
				ch &= 0x7f;
			if (isalpha((unsigned char)ch)) {
				if ((flags & RPP_FORCELOWER))
					ch = (char)tolower((unsigned char)ch);
				if ((flags & RPP_FORCEUPPER))
					ch = (char)toupper((unsigned char)ch);
			}
			*p++ = ch;
		}
	}
	*p = '\0';
	save_errno = errno;
	if (!(term.c_lflag & ECHO))
		(void)_write(output, "\n", 1);

	/* Restore old terminal settings and signals. */
	if (memcmp(&term, &oterm, sizeof(term)) != 0) {
		while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
		    errno == EINTR && !signo[SIGTTOU])
			continue;
	}
	(void)__libc_sigaction(SIGALRM, &savealrm, NULL);
	(void)__libc_sigaction(SIGHUP, &savehup, NULL);
	(void)__libc_sigaction(SIGINT, &saveint, NULL);
	(void)__libc_sigaction(SIGQUIT, &savequit, NULL);
	(void)__libc_sigaction(SIGPIPE, &savepipe, NULL);
	(void)__libc_sigaction(SIGTERM, &saveterm, NULL);
	(void)__libc_sigaction(SIGTSTP, &savetstp, NULL);
	(void)__libc_sigaction(SIGTTIN, &savettin, NULL);
	(void)__libc_sigaction(SIGTTOU, &savettou, NULL);
	if (input_is_tty)
		(void)_close(input);

	/*
	 * If we were interrupted by a signal, resend it to ourselves
	 * now that we have restored the signal handlers.
	 */
	for (i = 0; i < NSIG; i++) {
		if (signo[i]) {
			kill(getpid(), i);
			switch (i) {
			case SIGTSTP:
			case SIGTTIN:
			case SIGTTOU:
				need_restart = 1;
			}
		}
	}
	if (need_restart)
		goto restart;

	if (save_errno)
		errno = save_errno;
	return(nr == -1 ? NULL : buf);
}
Ejemplo n.º 14
0
void
__pthread_initialize_minimal_internal (void)
{
#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);

  /* We must prevent gcc from being clever and move any of the
     following code ahead of the __libc_setup_tls call.  This function
     will initialize the thread register which is subsequently
     used.  */
  __asm __volatile ("");
#endif

  /* Minimal initialization of the thread descriptor.  */
  struct pthread *pd = THREAD_SELF;
  INTERNAL_SYSCALL_DECL (err);
  pd->pid = pd->tid = INTERNAL_SYSCALL (set_tid_address, err, 1, &pd->tid);
#ifdef __PTHREAD_MUTEX_HAVE_PREV
  pd->robust_list.__prev = &pd->robust_list;
#endif
  pd->robust_list.__next = &pd->robust_list;
  THREAD_SETMEM (pd, specific[0], &pd->specific_1stblock[0]);
  THREAD_SETMEM (pd, user_stack, true);
  if (LLL_LOCK_INITIALIZER != 0)
    THREAD_SETMEM (pd, lock, LLL_LOCK_INITIALIZER);
#if HP_TIMING_AVAIL
  THREAD_SETMEM (pd, cpuclock_offset, GL(dl_cpuclock_offset));
#endif

  /* Set initial thread's stack block from 0 up to __libc_stack_end.
     It will be bigger than it actually is, but for unwind.c/pt-longjmp.c
     purposes this is good enough.  */
  THREAD_SETMEM (pd, stackblock_size, (size_t) __libc_stack_end);

  /* Initialize the list of all running threads with the main thread.  */
  INIT_LIST_HEAD (&__stack_user);
  list_add (&pd->list, &__stack_user);


  /* Install the cancellation signal handler.  If for some reason we
     cannot install the handler we do not abort.  Maybe we should, but
     it is only asynchronous cancellation which is affected.  */
  struct sigaction sa;
  sa.sa_sigaction = sigcancel_handler;
  sa.sa_flags = SA_SIGINFO;
  __sigemptyset (&sa.sa_mask);

  (void) __libc_sigaction (SIGCANCEL, &sa, NULL);

  /* Install the handle to change the threads' uid/gid.  */
  sa.sa_sigaction = sighandler_setxid;
  sa.sa_flags = SA_SIGINFO | SA_RESTART;

  (void) __libc_sigaction (SIGSETXID, &sa, NULL);

  /* The parent process might have left the signals blocked.  Just in
     case, unblock it.  We reuse the signal mask in the sigaction
     structure.  It is already cleared.  */
  __sigaddset (&sa.sa_mask, SIGCANCEL);
  __sigaddset (&sa.sa_mask, SIGSETXID);
  (void) INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_UNBLOCK, &sa.sa_mask,
			   NULL, _NSIG / 8);

  /* Get the size of the static and alignment requirements for the TLS
     block.  */
  size_t static_tls_align;
  _dl_get_tls_static_info (&__static_tls_size, &static_tls_align);

  /* Make sure the size takes all the alignments into account.  */
  if (STACK_ALIGN > static_tls_align)
    static_tls_align = STACK_ALIGN;
  __static_tls_align_m1 = static_tls_align - 1;

  __static_tls_size = roundup (__static_tls_size, static_tls_align);

  /* Determine the default allowed stack size.  This is the size used
     in case the user does not specify one.  */
  struct rlimit limit;
  if (getrlimit (RLIMIT_STACK, &limit) != 0
      || limit.rlim_cur == RLIM_INFINITY)
    /* The system limit is not usable.  Use an architecture-specific
       default.  */
    limit.rlim_cur = ARCH_STACK_DEFAULT_SIZE;
  else if (limit.rlim_cur < PTHREAD_STACK_MIN)
    /* The system limit is unusably small.
       Use the minimal size acceptable.  */
    limit.rlim_cur = PTHREAD_STACK_MIN;

  /* Make sure it meets the minimum size that allocate_stack
     (allocatestack.c) will demand, which depends on the page size.  */
  const uintptr_t pagesz = __sysconf (_SC_PAGESIZE);
  const size_t minstack = pagesz + __static_tls_size + MINIMAL_REST_STACK;
  if (limit.rlim_cur < minstack)
    limit.rlim_cur = minstack;

  /* Round the resource limit up to page size.  */
  limit.rlim_cur = (limit.rlim_cur + pagesz - 1) & -pagesz;
  __default_stacksize = limit.rlim_cur;

#ifdef SHARED
  /* Transfer the old value from the dynamic linker's internal location.  */
  *__libc_dl_error_tsd () = *(*GL(dl_error_catch_tsd)) ();
  GL(dl_error_catch_tsd) = &__libc_dl_error_tsd;

  /* Make __rtld_lock_{,un}lock_recursive use pthread_mutex_{,un}lock,
     keep the lock count from the ld.so implementation.  */
  GL(dl_rtld_lock_recursive) = (void *) INTUSE (__pthread_mutex_lock);
  GL(dl_rtld_unlock_recursive) = (void *) INTUSE (__pthread_mutex_unlock);
  unsigned int rtld_lock_count = GL(dl_load_lock).mutex.__data.__count;
  GL(dl_load_lock).mutex.__data.__count = 0;
  while (rtld_lock_count-- > 0)
    INTUSE (__pthread_mutex_lock) (&GL(dl_load_lock).mutex);

  GL(dl_make_stack_executable_hook) = &__make_stacks_executable;
#endif

  GL(dl_init_static_tls) = &__pthread_init_static_tls;

  /* Register the fork generation counter with the libc.  */
#ifndef TLS_MULTIPLE_THREADS_IN_TCB
  __libc_multiple_threads_ptr =
#endif
    __libc_pthread_init (&__fork_generation, __reclaim_stacks,
			 ptr_pthread_functions);

  /* Determine whether the machine is SMP or not.  */
  __is_smp = is_smp_system ();
}
Ejemplo n.º 15
0
static int child(void *args_vp)
{
	int i, ret;
	struct sigaction sa;
	struct args *args = args_vp;
	int p = args->p[1];
	const posix_spawn_file_actions_t *fa = args->fa;
	const posix_spawnattr_t *restrict attr = args->attr;

	close(args->p[0]);

	/* All signal dispositions must be either SIG_DFL or SIG_IGN
	 * before signals are unblocked. Otherwise a signal handler
	 * from the parent might get run in the child while sharing
	 * memory, with unpredictable and dangerous results. */
	for (i=1; i<_NSIG; i++) {
		__libc_sigaction(i, 0, &sa);
		if (sa.sa_handler!=SIG_DFL && (sa.sa_handler!=SIG_IGN ||
		    ((attr->__flags & POSIX_SPAWN_SETSIGDEF)
		     && sigismember(&attr->__def, i) ))) {
			sa.sa_handler = SIG_DFL;
			__libc_sigaction(i, &sa, 0);
		}
	}

	if (attr->__flags & POSIX_SPAWN_SETPGROUP)
		if ((ret=__syscall(SYS_setpgid, 0, attr->__pgrp)))
			goto fail;

	/* Use syscalls directly because pthread state because the
	 * library functions attempt to do a multi-threaded synchronized
	 * id-change, which would trash the parent's state. */
	if (attr->__flags & POSIX_SPAWN_RESETIDS)
		if ((ret=__syscall(SYS_setgid, __syscall(SYS_getgid))) ||
		    (ret=__syscall(SYS_setuid, __syscall(SYS_getuid))) )
			goto fail;

	if (fa && fa->__actions) {
		struct fdop *op;
		int fd;
		for (op = fa->__actions; op->next; op = op->next);
		for (; op; op = op->prev) {
			/* It's possible that a file operation would clobber
			 * the pipe fd used for synchronizing with the
			 * parent. To avoid that, we dup the pipe onto
			 * an unoccupied fd. */
			if (op->fd == p) {
				ret = __syscall(SYS_dup, p);
				if (ret < 0) goto fail;
				__syscall(SYS_close, p);
				p = ret;
			}
			switch(op->cmd) {
			case FDOP_CLOSE:
				if ((ret=__syscall(SYS_close, op->fd)))
					goto fail;
				break;
			case FDOP_DUP2:
				if ((ret=__syscall(SYS_dup2, op->srcfd, op->fd))<0)
					goto fail;
				break;
			case FDOP_OPEN:
				fd = __syscall(SYS_open, op->path,
					op->oflag | O_LARGEFILE, op->mode);
				if ((ret=fd) < 0) goto fail;
				if (fd != op->fd) {
					if ((ret=__syscall(SYS_dup2, fd, op->fd))<0)
						goto fail;
					__syscall(SYS_close, fd);
				}
				break;
			}
		}
	}

	/* Close-on-exec flag may have been lost if we moved the pipe
	 * to a different fd. We don't use F_DUPFD_CLOEXEC above because
	 * it would fail on older kernels and atomicity is not needed --
	 * in this process there are no threads or signal handlers. */
	__syscall(SYS_fcntl, p, F_SETFD, FD_CLOEXEC);

	pthread_sigmask(SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
		? &attr->__mask : &args->oldmask, 0);

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

fail:
	/* Since sizeof errno < PIPE_BUF, the write is atomic. */
	ret = -ret;
	if (ret) while (write(p, &ret, sizeof ret) < 0);
	_exit(127);
}
Ejemplo n.º 16
0
static void pthread_initialize(void)
{
  struct sigaction sa;
  sigset_t mask;

  /* If already done (e.g. by a constructor called earlier!), bail out */
  if (__pthread_initial_thread_bos != NULL) return;
#ifdef TEST_FOR_COMPARE_AND_SWAP
  /* Test if compare-and-swap is available */
  __pthread_has_cas = compare_and_swap_is_available();
#endif
#ifdef FLOATING_STACKS
  /* We don't need to know the bottom of the stack.  Give the pointer some
     value to signal that initialization happened.  */
  __pthread_initial_thread_bos = (void *) -1l;
#else
  /* Determine stack size limits .  */
  __pthread_init_max_stacksize ();
# ifdef _STACK_GROWS_UP
  /* The initial thread already has all the stack it needs */
  __pthread_initial_thread_bos = (char *)
    ((long)CURRENT_STACK_FRAME &~ (STACK_SIZE - 1));
# else
  /* For the initial stack, reserve at least STACK_SIZE bytes of stack
     below the current stack address, and align that on a
     STACK_SIZE boundary. */
  __pthread_initial_thread_bos =
    (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
# endif
#endif
  /* Update the descriptor for the initial thread. */
  __pthread_initial_thread.p_pid = __getpid();
  /* Likewise for the resolver state _res.  */
  __pthread_initial_thread.p_resp = &_res;
#ifdef __SIGRTMIN
  /* Initialize real-time signals. */
  init_rtsigs ();
#endif
  /* Setup signal handlers for the initial thread.
     Since signal handlers are shared between threads, these settings
     will be inherited by all other threads. */
  sa.sa_handler = pthread_handle_sigrestart;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  __libc_sigaction(__pthread_sig_restart, &sa, NULL);
  sa.sa_handler = pthread_handle_sigcancel;
  // sa.sa_flags = 0;
  __libc_sigaction(__pthread_sig_cancel, &sa, NULL);
  if (__pthread_sig_debug > 0) {
    sa.sa_handler = pthread_handle_sigdebug;
    sigemptyset(&sa.sa_mask);
    // sa.sa_flags = 0;
    __libc_sigaction(__pthread_sig_debug, &sa, NULL);
  }
  /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */
  sigemptyset(&mask);
  sigaddset(&mask, __pthread_sig_restart);
  sigprocmask(SIG_BLOCK, &mask, NULL);
  /* Register an exit function to kill all other threads. */
  /* Do it early so that user-registered atexit functions are called
     before pthread_*exit_process. */
#ifndef HAVE_Z_NODELETE
  if (__builtin_expect (&__dso_handle != NULL, 1))
    __cxa_atexit ((void (*) (void *)) pthread_atexit_process, NULL,
		  __dso_handle);
  else
#endif
    on_exit (pthread_onexit_process, NULL);
  /* How many processors.  */
  __pthread_smp_kernel = is_smp_system ();
}
Ejemplo n.º 17
0
void __synccall(void (*func)(void *), void *ctx)
{
	sigset_t oldmask;
	int cs, i, r, pid, self;;
	DIR dir = {0};
	struct dirent *de;
	struct sigaction sa = { .sa_flags = 0, .sa_handler = handler };
	struct chain *cp, *next;
	struct timespec ts;

	/* Blocking signals in two steps, first only app-level signals
	 * before taking the lock, then all signals after taking the lock,
	 * is necessary to achieve AS-safety. Blocking them all first would
	 * deadlock if multiple threads called __synccall. Waiting to block
	 * any until after the lock would allow re-entry in the same thread
	 * with the lock already held. */
	__block_app_sigs(&oldmask);
	LOCK(synccall_lock);
	__block_all_sigs(0);
	pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);

	head = 0;

	if (!libc.threaded) goto single_threaded;

	callback = func;
	context = ctx;

	/* This atomic store ensures that any signaled threads will see the
	 * above stores, and prevents more than a bounded number of threads,
	 * those already in pthread_create, from creating new threads until
	 * the value is cleared to zero again. */
	a_store(&__block_new_threads, 1);

	/* Block even implementation-internal signals, so that nothing
	 * interrupts the SIGSYNCCALL handlers. The main possible source
	 * of trouble is asynchronous cancellation. */
	memset(&sa.sa_mask, -1, sizeof sa.sa_mask);
	__libc_sigaction(SIGSYNCCALL, &sa, 0);

	pid = __syscall(SYS_getpid);
	self = __syscall(SYS_gettid);

	/* Since opendir is not AS-safe, the DIR needs to be setup manually
	 * in automatic storage. Thankfully this is easy. */
	dir.fd = open("/proc/self/task", O_RDONLY|O_DIRECTORY|O_CLOEXEC);
	if (dir.fd < 0) goto out;

	/* Initially send one signal per counted thread. But since we can't
	 * synchronize with thread creation/exit here, there could be too
	 * few signals. This initial signaling is just an optimization, not
	 * part of the logic. */
	for (i=libc.threads_minus_1; i; i--)
		__syscall(SYS_kill, pid, SIGSYNCCALL);

	/* Loop scanning the kernel-provided thread list until it shows no
	 * threads that have not already replied to the signal. */
	for (;;) {
		int miss_cnt = 0;
		while ((de = readdir(&dir))) {
			if (!isdigit(de->d_name[0])) continue;
			int tid = atoi(de->d_name);
			if (tid == self || !tid) continue;

			/* Set the target thread as the PI futex owner before
			 * checking if it's in the list of caught threads. If it
			 * adds itself to the list after we check for it, then
			 * it will see its own tid in the PI futex and perform
			 * the unlock operation. */
			a_store(&target_tid, tid);

			/* Thread-already-caught is a success condition. */
			for (cp = head; cp && cp->tid != tid; cp=cp->next);
			if (cp) continue;

			r = -__syscall(SYS_tgkill, pid, tid, SIGSYNCCALL);

			/* Target thread exit is a success condition. */
			if (r == ESRCH) continue;

			/* The FUTEX_LOCK_PI operation is used to loan priority
			 * to the target thread, which otherwise may be unable
			 * to run. Timeout is necessary because there is a race
			 * condition where the tid may be reused by a different
			 * process. */
			clock_gettime(CLOCK_REALTIME, &ts);
			ts.tv_nsec += 10000000;
			if (ts.tv_nsec >= 1000000000) {
				ts.tv_sec++;
				ts.tv_nsec -= 1000000000;
			}
			r = -__syscall(SYS_futex, &target_tid,
				FUTEX_LOCK_PI|FUTEX_PRIVATE, 0, &ts);

			/* Obtaining the lock means the thread responded. ESRCH
			 * means the target thread exited, which is okay too. */
			if (!r || r == ESRCH) continue;

			miss_cnt++;
		}
		if (!miss_cnt) break;
		rewinddir(&dir);
	}
	close(dir.fd);

	/* Serialize execution of callback in caught threads. */
	for (cp=head; cp; cp=cp->next) {
		sem_post(&cp->target_sem);
		sem_wait(&cp->caller_sem);
	}

	sa.sa_handler = SIG_IGN;
	__libc_sigaction(SIGSYNCCALL, &sa, 0);

single_threaded:
	func(ctx);

	/* Only release the caught threads once all threads, including the
	 * caller, have returned from the callback function. */
	for (cp=head; cp; cp=next) {
		next = cp->next;
		sem_post(&cp->target_sem);
	}

out:
	a_store(&__block_new_threads, 0);
	__wake(&__block_new_threads, -1, 1);

	pthread_setcancelstate(cs, 0);
	UNLOCK(synccall_lock);
	__restore_sigs(&oldmask);
}
Ejemplo n.º 18
0
static void pthread_initialize(void)
{
  struct sigaction sa;
  sigset_t mask;
#ifdef __ARCH_USE_MMU__
  struct rlimit limit;
  rlim_t max_stack;
#endif

  /* If already done (e.g. by a constructor called earlier!), bail out */
  if (__pthread_initial_thread_bos != NULL) return;
#ifdef TEST_FOR_COMPARE_AND_SWAP
  /* Test if compare-and-swap is available */
  __pthread_has_cas = compare_and_swap_is_available();
#endif
  /* For the initial stack, reserve at least STACK_SIZE bytes of stack
     below the current stack address, and align that on a
     STACK_SIZE boundary. */
  __pthread_initial_thread_bos =
    (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
  /* Update the descriptor for the initial thread. */
  __pthread_initial_thread.p_pid = getpid();
  /* If we have special thread_self processing, initialize that for the
     main thread now.  */
#ifdef INIT_THREAD_SELF
  INIT_THREAD_SELF(&__pthread_initial_thread, 0);
#endif
  /* The errno/h_errno variable of the main thread are the global ones.  */
  __pthread_initial_thread.p_errnop = &_errno;
  __pthread_initial_thread.p_h_errnop = &_h_errno;

#ifdef __UCLIBC_HAS_XLOCALE__
  /* The locale of the main thread is the current locale in use. */
  __pthread_initial_thread.locale = __curlocale_var;
#endif /* __UCLIBC_HAS_XLOCALE__ */

 {			   /* uClibc-specific stdio initialization for threads. */
	 FILE *fp;

	 _stdio_user_locking = 0;	/* 2 if threading not initialized */
	 for (fp = _stdio_openlist; fp != NULL; fp = fp->__nextopen) {
		 if (fp->__user_locking != 1) {
			 fp->__user_locking = 0;
		 }
	 }
 }

  /* Play with the stack size limit to make sure that no stack ever grows
     beyond STACK_SIZE minus two pages (one page for the thread descriptor
     immediately beyond, and one page to act as a guard page). */

#ifdef __ARCH_USE_MMU__
  /* We cannot allocate a huge chunk of memory to mmap all thread stacks later
   * on a non-MMU system. Thus, we don't need the rlimit either. -StS */
  getrlimit(RLIMIT_STACK, &limit);
  max_stack = STACK_SIZE - 2 * getpagesize();
  if (limit.rlim_cur > max_stack) {
    limit.rlim_cur = max_stack;
    setrlimit(RLIMIT_STACK, &limit);
  }
#else
  /* For non-MMU, the initial thread stack can reside anywhere in memory.
   * We don't have a way of knowing where the kernel started things -- top
   * or bottom (well, that isn't exactly true, but the solution is fairly
   * complex and error prone).  All we can determine here is an address
   * that lies within that stack.  Save that address as a reference so that
   * as other thread stacks are created, we can adjust the estimated bounds
   * of the initial thread's stack appropriately.
   *
   * This checking is handled in NOMMU_INITIAL_THREAD_BOUNDS(), so see that
   * for a few more details.
   */
  __pthread_initial_thread_mid = CURRENT_STACK_FRAME;
  __pthread_initial_thread_tos = (char *) -1;
  __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know we have been here */
  PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n",
	 __pthread_initial_thread_bos, __pthread_initial_thread_tos);
#endif /* __ARCH_USE_MMU__ */

  /* Setup signal handlers for the initial thread.
     Since signal handlers are shared between threads, these settings
     will be inherited by all other threads. */
  memset(&sa, 0, sizeof(sa));
  sa.sa_handler = pthread_handle_sigrestart;
  __libc_sigaction(__pthread_sig_restart, &sa, NULL);
  sa.sa_handler = pthread_handle_sigcancel;
  sigaddset(&sa.sa_mask, __pthread_sig_restart);
  __libc_sigaction(__pthread_sig_cancel, &sa, NULL);
  if (__pthread_sig_debug > 0) {
      sa.sa_handler = pthread_handle_sigdebug;
      __sigemptyset(&sa.sa_mask);
      __libc_sigaction(__pthread_sig_debug, &sa, NULL);
  }
  /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */
  __sigemptyset(&mask);
  sigaddset(&mask, __pthread_sig_restart);
  sigprocmask(SIG_BLOCK, &mask, NULL);
  /* And unblock __pthread_sig_cancel if it has been blocked. */
  sigdelset(&mask, __pthread_sig_restart);
  sigaddset(&mask, __pthread_sig_cancel);
  sigprocmask(SIG_UNBLOCK, &mask, NULL);
  /* Register an exit function to kill all other threads. */
  /* Do it early so that user-registered atexit functions are called
     before pthread_onexit_process. */
  on_exit(pthread_onexit_process, NULL);
}
Ejemplo n.º 19
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);
}
static void pthread_initialize(void)
{
  struct sigaction sa;
  sigset_t mask;
  struct rlimit limit;
  int max_stack;

  /* If already done (e.g. by a constructor called earlier!), bail out */
  if (__pthread_initial_thread_bos != NULL) return;
#ifdef TEST_FOR_COMPARE_AND_SWAP
  /* Test if compare-and-swap is available */
  __pthread_has_cas = compare_and_swap_is_available();
#endif
  /* For the initial stack, reserve at least STACK_SIZE bytes of stack
     below the current stack address, and align that on a
     STACK_SIZE boundary. */
  __pthread_initial_thread_bos =
    (char *)(((long)CURRENT_STACK_FRAME - 2 * STACK_SIZE) & ~(STACK_SIZE - 1));
  /* Update the descriptor for the initial thread. */
  __pthread_initial_thread.p_pid = __getpid();
  /* If we have special thread_self processing, initialize that for the
     main thread now.  */
#ifdef INIT_THREAD_SELF
  INIT_THREAD_SELF(&__pthread_initial_thread, 0);
#endif
  /* The errno/h_errno variable of the main thread are the global ones.  */
  __pthread_initial_thread.p_errnop = &_errno;
  __pthread_initial_thread.p_h_errnop = &_h_errno;
  /* Play with the stack size limit to make sure that no stack ever grows
     beyond STACK_SIZE minus two pages (one page for the thread descriptor
     immediately beyond, and one page to act as a guard page). */

#ifdef __UCLIBC_HAS_MMU__
  /* We cannot allocate a huge chunk of memory to mmap all thread stacks later
   * on a non-MMU system. Thus, we don't need the rlimit either. -StS */
  getrlimit(RLIMIT_STACK, &limit);
  max_stack = STACK_SIZE - 2 * __getpagesize();
  if (limit.rlim_cur > max_stack) {
    limit.rlim_cur = max_stack;
    setrlimit(RLIMIT_STACK, &limit);
  }
#else
  /* For non-MMU assume __pthread_initial_thread_tos at upper page boundary, and
   * __pthread_initial_thread_bos at address 0. These bounds are refined as we 
   * malloc other stack frames such that they don't overlap. -StS
   */
  __pthread_initial_thread_tos =
    (char *)(((long)CURRENT_STACK_FRAME + __getpagesize()) & ~(__getpagesize() - 1));
  __pthread_initial_thread_bos = (char *) 1; /* set it non-zero so we know we have been here */
  PDEBUG("initial thread stack bounds: bos=%p, tos=%p\n",
	 __pthread_initial_thread_bos, __pthread_initial_thread_tos);
#endif /* __UCLIBC_HAS_MMU__ */

  /* Setup signal handlers for the initial thread.
     Since signal handlers are shared between threads, these settings
     will be inherited by all other threads. */
  sa.sa_handler = pthread_handle_sigrestart;
  sigemptyset(&sa.sa_mask);
  sa.sa_flags = 0;
  __libc_sigaction(__pthread_sig_restart, &sa, NULL);
  sa.sa_handler = pthread_handle_sigcancel;
  // sa.sa_flags = 0;
  __libc_sigaction(__pthread_sig_cancel, &sa, NULL);
  if (__pthread_sig_debug > 0) {
      sa.sa_handler = pthread_handle_sigdebug;
      sigemptyset(&sa.sa_mask);
      // sa.sa_flags = 0;
      __libc_sigaction(__pthread_sig_debug, &sa, NULL);
  }
  /* Initially, block __pthread_sig_restart. Will be unblocked on demand. */
  sigemptyset(&mask);
  sigaddset(&mask, __pthread_sig_restart);
  sigprocmask(SIG_BLOCK, &mask, NULL);
  /* Register an exit function to kill all other threads. */
  /* Do it early so that user-registered atexit functions are called
     before pthread_onexit_process. */
  on_exit(pthread_onexit_process, NULL);
}