示例#1
0
int
pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask)
{
  sigset_t local_newmask;

  /* The only thing we have to make sure here is that SIGCANCEL and
     SIGSETXID is not blocked.  */
  if (newmask != NULL
      && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0)
	  || __builtin_expect (__sigismember (newmask, SIGSETXID), 0)))
    {
      local_newmask = *newmask;
      __sigdelset (&local_newmask, SIGCANCEL);
      __sigdelset (&local_newmask, SIGSETXID);
      newmask = &local_newmask;
    }

#ifdef INTERNAL_SYSCALL
  /* We know that realtime signals are available if NPTL is used.  */
  INTERNAL_SYSCALL_DECL (err);
  int result = INTERNAL_SYSCALL (rt_sigprocmask, err, 4, how, newmask,
				 oldmask, _NSIG / 8);

  return (INTERNAL_SYSCALL_ERROR_P (result, err)
	  ? INTERNAL_SYSCALL_ERRNO (result, err)
	  : 0);
#else
  return sigprocmask (how, newmask, oldmask) == -1 ? errno : 0;
#endif
}
示例#2
0
int sigprocmask(int how, const sigset_t * set, sigset_t * oldset)
{
#ifdef SIGCANCEL
	sigset_t local_newmask;

	/*
	 * The only thing we have to make sure here is that SIGCANCEL and
	 * SIGSETXID are not blocked.
	 */
	if (set != NULL && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
# ifdef SIGSETXID
		|| __builtin_expect (__sigismember (set, SIGSETXID), 0)
# endif
		))
	{
		local_newmask = *set;
		__sigdelset (&local_newmask, SIGCANCEL);
# ifdef SIGSETXID
		__sigdelset (&local_newmask, SIGSETXID);
# endif
		set = &local_newmask;
	}
#endif

	return (__syscall_sigprocmask(how, set, oldset));
}
示例#3
0
/* Return any pending signal or wait for one for the given time.  */
static int
do_sigwait (const sigset_t *set, int *sig)
{
  int ret;

#ifdef SIGCANCEL
  sigset_t tmpset;
  if (set != NULL
      && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
# ifdef SIGSETXID
	  || __builtin_expect (__sigismember (set, SIGSETXID), 0)
# endif
	  ))
    {
      /* Create a temporary mask without the bit for SIGCANCEL set.  */
      // We are not copying more than we have to.
      memcpy (&tmpset, set, _NSIG / 8);
      __sigdelset (&tmpset, SIGCANCEL);
# ifdef SIGSETXID
      __sigdelset (&tmpset, SIGSETXID);
# endif
      set = &tmpset;
    }
#endif

  /* XXX The size argument hopefully will have to be changed to the
     real size of the user-level sigset_t.  */
#ifdef INTERNAL_SYSCALL
  INTERNAL_SYSCALL_DECL (err);
  do
    ret = INTERNAL_SYSCALL (rt_sigtimedwait, err, 4, set,
			    NULL, NULL, _NSIG / 8);
  while (INTERNAL_SYSCALL_ERROR_P (ret, err)
	 && INTERNAL_SYSCALL_ERRNO (ret, err) == EINTR);
  if (! INTERNAL_SYSCALL_ERROR_P (ret, err))
    {
      *sig = ret;
      ret = 0;
    }
  else
    ret = INTERNAL_SYSCALL_ERRNO (ret, err);
#else
  do
    ret = INLINE_SYSCALL (rt_sigtimedwait, 4, set, NULL, NULL, _NSIG / 8);
  while (ret == -1 && errno == EINTR);
  if (ret != -1)
    {
      *sig = ret;
      ret = 0;
    }
  else
    ret = errno;
#endif

  return ret;
}
示例#4
0
文件: hurdsig.c 项目: VGEAREN/mygit
/* Clear a pending signal and return the associated detailed
   signal information. SS must be locked, and must have signal SIGNO
   pending, either directly or through the global sigstate.  */
static struct hurd_signal_detail
sigstate_clear_pending (struct hurd_sigstate *ss, int signo)
{
  if (sigstate_is_global_rcv (ss)
      && __sigismember (&_hurd_global_sigstate->pending, signo))
    {
      __sigdelset (&_hurd_global_sigstate->pending, signo);
      return _hurd_global_sigstate->pending_data[signo];
    }

  assert (__sigismember (&ss->pending, signo));
  __sigdelset (&ss->pending, signo);
  return ss->pending_data[signo];
}
示例#5
0
文件: sigwait.c 项目: Jaden-J/uClibc
static int __NC(sigwait)(const sigset_t *set, int *sig)
{
  sigset_t tmp_mask;
  struct sigaction saved[NSIG];
  struct sigaction action;
  int save_errno;
  int this;

  /* Prepare set.  */
  __sigfillset (&tmp_mask);

  /* Unblock all signals in the SET and register our nice handler.  */
  action.sa_handler = ignore_signal;
  action.sa_flags = 0;
  __sigfillset (&action.sa_mask);       /* Block all signals for handler.  */

  /* Make sure we recognize error conditions by setting WAS_SIG to a
     value which does not describe a legal signal number.  */
  was_sig = -1;

  for (this = 1; this < NSIG; ++this)
    if (__sigismember (set, this))
      {
        /* Unblock this signal.  */
        __sigdelset (&tmp_mask, this);

        /* Register temporary action handler.  */
        /* In Linux (as of 2.6.25), fails only if sig is SIGKILL or SIGSTOP */
        /* (so, will it work correctly if set has, say, SIGSTOP?) */
        if (sigaction (this, &action, &saved[this]) != 0)
          goto restore_handler;
      }

  /* Now we can wait for signals.  */
  __NC(sigsuspend)(&tmp_mask);

 restore_handler:
  save_errno = errno;

  while (--this >= 1)
    if (__sigismember (set, this))
      /* We ignore errors here since we must restore all handlers.  */
      sigaction (this, &saved[this], NULL);

  __set_errno (save_errno);

  /* Store the result and return.  */
  *sig = was_sig;
  return was_sig == -1 ? -1 : 0;
}
示例#6
0
void __handle_signal (shim_tcb_t * tcb, int sig, ucontext_t * uc)
{
    struct shim_thread * thread = (struct shim_thread *) tcb->tp;
    int begin_sig = 1, end_sig = NUM_KNOWN_SIGS;

    if (sig)
        end_sig = (begin_sig = sig) + 1;

    sig = begin_sig;

    if (!thread->has_signal.counter)
        return;

    while (atomic_read(&thread->has_signal)) {
        struct shim_signal * signal = NULL;

        for ( ; sig < end_sig ; sig++)
            if (!__sigismember(&thread->signal_mask, sig) &&
                (signal = fetch_signal_log(tcb, thread, sig)))
                break;

        if (!signal)
            break;

        if (!signal->context_stored)
            __store_context(tcb, NULL, signal);

        __handle_one_signal(tcb, sig, signal);
        free(signal);
        DkThreadYieldExecution();
    }

    tcb->context.preempt &= ~SIGNAL_DELAYED;
}
示例#7
0
error_t
_hurd_ctty_output (io_t port, io_t ctty, error_t (*rpc) (io_t))
{
  if (ctty == MACH_PORT_NULL)
    return (*rpc) (port);
  else
    {
      struct hurd_sigstate *ss = _hurd_self_sigstate ();
      error_t err;

      do
	{
	  /* Don't use the ctty io port if we are blocking or ignoring
	     SIGTTOU.  We redo this check at the top of the loop in case
	     the signal handler changed the state.  */
	  __spin_lock (&ss->lock);
	  if (__sigismember (&ss->blocked, SIGTTOU) ||
	      ss->actions[SIGTTOU].sa_handler == SIG_IGN)
	    err = EIO;
	  else
	    err = 0;
	  __spin_unlock (&ss->lock);

	  if (err)
	    return (*rpc) (port);

	  err = (*rpc) (ctty);
	  if (err == EBACKGROUND)
	    {
	      if (_hurd_orphaned)
		/* Our process group is orphaned, so we never generate a
		   signal; we just fail.  */
		err = EIO;
	      else
		{
		  /* Send a SIGTTOU signal to our process group.

		     We must remember here not to clobber ERR, since
		     the loop condition below uses it to recall that
		  we should retry after a stop.  */

		  __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTOU, port));
		  /* XXX what to do if error here? */

		  /* At this point we should have just run the handler for
		     SIGTTOU or resumed after being stopped.  Now this is
		     still a "system call", so check to see if we should
		  restart it.  */
		  __spin_lock (&ss->lock);
		  if (!(ss->actions[SIGTTOU].sa_flags & SA_RESTART))
		    err = EINTR;
		  __spin_unlock (&ss->lock);
		}
	    }
	  /* If the last RPC generated a SIGTTOU, loop to try it again.  */
	} while (err == EBACKGROUND);

      return err;
    }
}
示例#8
0
int sigismember(__const sigset_t *__set, int __signo)
{
	if (__signo == 0 || __signo >= _NSIG) {
		errno = EINVAL;
		return -1;
	}
	__sigismember(__set, __signo);
	return 0;
}
示例#9
0
文件: sigismem.c 项目: 16rd/rt-n56u
/* Return 1 if SIGNO is in SET, 0 if not.  */
int sigismember (const sigset_t *set, int signo)
{
  if (set == NULL || signo <= 0 || signo >= NSIG)
    {
      __set_errno (EINVAL);
      return -1;
    }

  return __sigismember (set, signo);
}
示例#10
0
error_t
_hurd_ctty_input (io_t port, io_t ctty, error_t (*rpc) (io_t))
{
  error_t err;

  if (ctty == MACH_PORT_NULL)
    return (*rpc) (port);

  do
    {
      err = (*rpc) (ctty);
      if (err == EBACKGROUND)
	{
	  /* We are a background job and tried to read from the tty.
	     We should probably get a SIGTTIN signal.  */
	  if (_hurd_orphaned)
	    /* Our process group is orphaned.  Don't stop; just fail.  */
	    err = EIO;
	  else
	    {
	      struct hurd_sigstate *ss = _hurd_self_sigstate ();
	      __spin_lock (&ss->lock);
	      if (__sigismember (&ss->blocked, SIGTTIN) ||
		  ss->actions[SIGTTIN].sa_handler == SIG_IGN)
		/* We are blocking or ignoring SIGTTIN.  Just fail.  */
		err = EIO;
	      __spin_unlock (&ss->lock);

	      if (err == EBACKGROUND)
		{
		  /* Send a SIGTTIN signal to our process group.

		     We must remember here not to clobber ERR, since
		     the loop condition below uses it to recall that
		  we should retry after a stop.  */

		  __USEPORT (CTTYID, _hurd_sig_post (0, SIGTTIN, port));
		  /* XXX what to do if error here? */

		  /* At this point we should have just run the handler for
		     SIGTTIN or resumed after being stopped.  Now this is
		     still a "system call", so check to see if we should
		  restart it.  */
		  __spin_lock (&ss->lock);
		  if (!(ss->actions[SIGTTIN].sa_flags & SA_RESTART))
		    err = EINTR;
		  __spin_unlock (&ss->lock);
		}
	    }
	}
      /* If the last RPC generated a SIGTTIN, loop to try it again.  */
    } while (err == EBACKGROUND);

  return err;
}
示例#11
0
文件: pthread.c 项目: windyuuy/akaros
/* Run through all pending sighandlers and trigger them with a NULL info field.
 * These handlers are triggered as the result of a pthread_kill(), and thus
 * don't require individual 'info' structs. */
static void __run_pending_sighandlers()
{
	struct pthread_tcb *me = pthread_self();
	sigset_t andset = me->sigpending & (~me->sigmask);
	for (int i = 1; i < _NSIG; i++) {
		if (__sigismember(&andset, i)) {
			__sigdelset(&me->sigpending, i);
			trigger_posix_signal(i, NULL, &me->sigdata->u_ctx);
		}
	}
	uthread_yield(FALSE, __exit_sighandler_cb, 0);
}
示例#12
0
static int
do_sigtimedwait (const sigset_t *set, siginfo_t *info,
                 const struct timespec *timeout)
{
#ifdef SIGCANCEL
    sigset_t tmpset;
    if (set != NULL
            && (__builtin_expect (__sigismember (set, SIGCANCEL), 0)
# ifdef SIGSETXID
                || __builtin_expect (__sigismember (set, SIGSETXID), 0)
# endif
               ))
    {
        /* Create a temporary mask without the bit for SIGCANCEL set.  */
        // We are not copying more than we have to.
        memcpy (&tmpset, set, _NSIG / 8);
        __sigdelset (&tmpset, SIGCANCEL);
# ifdef SIGSETXID
        __sigdelset (&tmpset, SIGSETXID);
# endif
        set = &tmpset;
    }
#endif

    /* XXX The size argument hopefully will have to be changed to the
       real size of the user-level sigset_t.  */
    int result = INLINE_SYSCALL (rt_sigtimedwait, 4, set,
                                 info, timeout, _NSIG / 8);

    /* The kernel generates a SI_TKILL code in si_code in case tkill is
       used.  tkill is transparently used in raise().  Since having
       SI_TKILL as a code is useful in general we fold the results
       here.  */
    if (result != -1 && info != NULL && info->si_code == SI_TKILL)
        info->si_code = SI_USER;

    return result;
}
示例#13
0
文件: hurdmsg.c 项目: AubrCool/glibc
static kern_return_t
set_int (int which, int value)
{
  switch (which)
    {
    case INIT_UMASK:
      _hurd_umask = value;
      return 0;

      /* These are pretty odd things to do.  But you asked for it.  */
    case INIT_SIGMASK:
      {
	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
	__spin_lock (&ss->lock);
	ss->blocked = value;
	__spin_unlock (&ss->lock);
	return 0;
      }
    case INIT_SIGPENDING:
      {
	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
	__spin_lock (&ss->lock);
	ss->pending = value;
	__spin_unlock (&ss->lock);
	return 0;
      }
    case INIT_SIGIGN:
      {
	struct hurd_sigstate *ss = _hurd_thread_sigstate (_hurd_sigthread);
	int sig;
	const sigset_t ign = value;
	__spin_lock (&ss->lock);
	for (sig = 1; sig < NSIG; ++sig)
	  {
	    if (__sigismember (&ign, sig))
	      ss->actions[sig].sa_handler = SIG_IGN;
	    else if (ss->actions[sig].sa_handler == SIG_IGN)
	      ss->actions[sig].sa_handler = SIG_DFL;
	  }
	__spin_unlock (&ss->lock);
	return 0;

      case INIT_TRACEMASK:
	_hurdsig_traced = value;
	return 0;
      }
    default:
      return EINVAL;
    }
}
示例#14
0
文件: pthread.c 项目: windyuuy/akaros
/* If the given signal is unmasked, prep the pthread to run it's signal
 * handler, but don't run it yet. In either case, make the pthread runnable
 * again. Once the signal handler is complete, the original context will be
 * restored and restarted. */
static void __pthread_signal_and_restart(struct pthread_tcb *pthread,
                                          int signo, int code, void *addr)
{
	if (!__sigismember(&pthread->sigmask, signo)) {
		if (pthread->sigdata) {
			printf("Pthread sighandler faulted, signal: %d\n", signo);
			/* uthread.c already copied out the faulting ctx into the uth */
			print_user_context(&pthread->uthread.u_ctx);
			exit(-1);
		}
		struct siginfo info = {0};
		info.si_signo = signo;
		info.si_code = code;
		info.si_addr = addr;
		__pthread_prep_sighandler(pthread, __run_sighandler, &info);
	}
	pth_thread_runnable(&pthread->uthread);
}
示例#15
0
void deliver_signal (siginfo_t * info, PAL_CONTEXT * context)
{
    shim_tcb_t * tcb = SHIM_GET_TLS();
    struct shim_thread * cur_thread = (struct shim_thread *) tcb->tp;
    int sig = info->si_signo;

    __disable_preempt(tcb);

    struct shim_signal * signal = __alloca(sizeof(struct shim_signal));
    /* save in signal */
    memset(signal, 0, sizeof(struct shim_signal));
    __store_info(info, signal);
    __store_context(tcb, context, signal);

    if ((tcb->context.preempt & ~SIGNAL_DELAYED) > 1)
        goto delay;

    if (__sigismember(&cur_thread->signal_mask, sig))
        goto delay;

    __handle_signal(tcb, sig, &signal->context);
    __handle_one_signal(tcb, sig, signal);
    goto out;

delay:
    {
        if (!(signal = remalloc(signal,sizeof(struct shim_signal))))
            goto out;

        struct shim_signal ** signal_log = allocate_signal_log(cur_thread, sig);

        if (!signal_log) {
            sys_printf("signal queue is full (TID = %u, SIG = %d)\n",
                       tcb->tid, sig);
            free(signal);
            goto out;
        }

        *signal_log = signal;
    }

out:
    __enable_preempt(tcb);
}
/* Select any of pending signals from SET or wait for any to arrive.  */
int
__sigwait (const sigset_t *set, int *sig)
{
  struct hurd_sigstate *ss;
  sigset_t mask, ready;
  int signo = 0;
  struct hurd_signal_preemptor preemptor;
  jmp_buf buf;
  mach_port_t wait;
  mach_msg_header_t msg;

  sighandler_t
    preempt_fun (struct hurd_signal_preemptor *pe,
		 struct hurd_sigstate *ss,
		 int *sigp,
		 struct hurd_signal_detail *detail)
    {
      if (signo)
	/* We've already been run; don't interfere. */
	return SIG_ERR;

      signo = *sigp;

      /* Make sure this is all kosher */
      assert (__sigismember (&mask, signo));

      /* Make sure this signal is unblocked */
      __sigdelset (&ss->blocked, signo);

      return pe->handler;
    }

  void
    handler (int sig)
    {
      assert (sig == signo);
      longjmp (buf, 1);
    }
示例#17
0
文件: sleep.c 项目: Jaden-J/uClibc
/* This is a quick and dirty, but not 100% compliant with
 * the stupid SysV SIGCHLD vs. SIG_IGN behaviour.  It is
 * fine unless you are messing with SIGCHLD...  */
unsigned int sleep (unsigned int sec)
{
	unsigned int res;
	struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 };
	res = nanosleep(&ts, &ts);
	if (res) res = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
	return res;
}

# else

/* We are going to use the `nanosleep' syscall of the kernel.  But the
   kernel does not implement the sstupid SysV SIGCHLD vs. SIG_IGN
   behaviour for this syscall.  Therefore we have to emulate it here.  */
unsigned int sleep (unsigned int seconds)
{
    struct timespec ts = { .tv_sec = (long int) seconds, .tv_nsec = 0 };
    sigset_t set;
    struct sigaction oact;
    unsigned int result;

    /* This is not necessary but some buggy programs depend on this.  */
    if (seconds == 0) {
#  ifdef CANCELLATION_P
	int cancelhandling;
	CANCELLATION_P (THREAD_SELF);
#  endif
	return 0;
    }

    /* Linux will wake up the system call, nanosleep, when SIGCHLD
       arrives even if SIGCHLD is ignored.  We have to deal with it
       in libc.  */

    __sigemptyset (&set);
    __sigaddset (&set, SIGCHLD);

    /* Is SIGCHLD set to SIG_IGN? */
    sigaction (SIGCHLD, NULL, &oact); /* never fails */
    if (oact.sa_handler == SIG_IGN) {
	/* Yes.  Block SIGCHLD, save old mask.  */
	sigprocmask (SIG_BLOCK, &set, &set); /* never fails */
    }

    /* Run nanosleep, with SIGCHLD blocked if SIGCHLD is SIG_IGNed.  */
    result = nanosleep (&ts, &ts);
    if (result != 0) {
	/* Got EINTR. Return remaining time.  */
	result = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);
    }

    if (!__sigismember (&set, SIGCHLD)) {
	/* We did block SIGCHLD, and old mask had no SIGCHLD bit.
	   IOW: we need to unblock SIGCHLD now. Do it.  */
	/* this sigprocmask call never fails, thus never updates errno,
	   and therefore we don't need to save/restore it.  */
	sigprocmask (SIG_SETMASK, &set, NULL); /* never fails */
    }

    return result;
}

# endif

#else /* __UCLIBC_HAS_REALTIME__ */

/* no nanosleep, use signals and alarm() */
static void sleep_alarm_handler(int attribute_unused sig)
{
}
unsigned int sleep (unsigned int seconds)
{
    struct sigaction act, oact;
    sigset_t set, oset;
    unsigned int result, remaining;
    time_t before, after;
    int old_errno = errno;

    /* This is not necessary but some buggy programs depend on this.  */
    if (seconds == 0)
	return 0;

    /* block SIGALRM */
    __sigemptyset (&set);
    __sigaddset (&set, SIGALRM);
    sigprocmask (SIG_BLOCK, &set, &oset); /* can't fail */

    act.sa_handler = sleep_alarm_handler;
    act.sa_flags = 0;
    act.sa_mask = oset;
    sigaction(SIGALRM, &act, &oact); /* never fails */

    before = time(NULL);
    remaining = alarm(seconds);
    if (remaining && remaining > seconds) {
	/* restore user's alarm */
	sigaction(SIGALRM, &oact, NULL);
	alarm(remaining); /* restore old alarm */
	sigsuspend(&oset);
	after = time(NULL);
    } else {
	sigsuspend (&oset);
	after = time(NULL);
	sigaction (SIGALRM, &oact, NULL);
    }
    result = after - before;
    alarm(remaining > result ? remaining - result : 0);
    sigprocmask (SIG_SETMASK, &oset, NULL);

    __set_errno(old_errno);

    return result > seconds ? 0 : seconds - result;
}

#endif /* __UCLIBC_HAS_REALTIME__ */

libc_hidden_def(sleep)
示例#18
0
/* Set the disposition for SIG.  */
__sighandler_t
sigset (int sig, __sighandler_t disp)
{
  struct sigaction act;
  struct sigaction oact;
  sigset_t set;
  sigset_t oset;

#ifdef SIG_HOLD
  /* Handle SIG_HOLD first.  */
  if (disp == SIG_HOLD)
    {
      /* Create an empty signal set.  */
      if (__sigemptyset (&set) < 0)
	return SIG_ERR;

      /* Add the specified signal.  */
      if (__sigaddset (&set, sig) < 0)
	return SIG_ERR;

      /* Add the signal set to the current signal mask.  */
      if (__sigprocmask (SIG_BLOCK, &set, &oset) < 0)
	return SIG_ERR;

      /* If the signal was already blocked signal this to the caller.  */
      if (__sigismember (&oset, sig))
	return SIG_HOLD;

      /* We need to determine whether a specific handler is installed.  */
      if (__sigaction (sig, NULL, &oact) < 0)
	return SIG_ERR;

      return oact.sa_handler;
    }
#endif	/* SIG_HOLD */

  /* Check signal extents to protect __sigismember.  */
  if (disp == SIG_ERR || sig < 1 || sig >= NSIG)
    {
      __set_errno (EINVAL);
      return SIG_ERR;
    }

  act.sa_handler = disp;
  if (__sigemptyset (&act.sa_mask) < 0)
    return SIG_ERR;
  act.sa_flags = 0;
  if (__sigaction (sig, &act, &oact) < 0)
    return SIG_ERR;

  /* Create an empty signal set.  */
  if (__sigemptyset (&set) < 0)
    return SIG_ERR;

  /* Add the specified signal.  */
  if (__sigaddset (&set, sig) < 0)
    return SIG_ERR;

  /* Remove the signal set from the current signal mask.  */
  if (__sigprocmask (SIG_UNBLOCK, &set, &oset) < 0)
    return SIG_ERR;

  /* If the signal was already blocked return SIG_HOLD.  */
  return __sigismember (&oset, sig) ? SIG_HOLD : oact.sa_handler;
}
示例#19
0
/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
   Before running the process perform the actions described in FILE-ACTIONS. */
int
__spawni (pid_t *pid, const char *file,
	  const posix_spawn_file_actions_t *file_actions,
	  const posix_spawnattr_t *attrp, char *const argv[],
	  char *const envp[], int xflags)
{
  pid_t new_pid;
  char *path, *p, *name;
  size_t len;
  size_t pathlen;

  /* Do this once.  */
  short int flags = attrp == NULL ? 0 : attrp->__flags;

  /* Generate the new process.  */
  if ((flags & POSIX_SPAWN_USEVFORK) != 0
      /* If no major work is done, allow using vfork.  Note that we
	 might perform the path searching.  But this would be done by
	 a call to execvp(), too, and such a call must be OK according
	 to POSIX.  */
      || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF
		    | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER
		    | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS)) == 0
	  && file_actions == NULL))
    new_pid = __vfork ();
  else
    new_pid = __fork ();

  if (new_pid != 0)
    {
      if (new_pid < 0)
	return errno;

      /* The call was successful.  Store the PID if necessary.  */
      if (pid != NULL)
	*pid = new_pid;

      return 0;
    }

  /* Set signal mask.  */
  if ((flags & POSIX_SPAWN_SETSIGMASK) != 0
      && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0)
    _exit (SPAWN_ERROR);

  /* Set signal default action.  */
  if ((flags & POSIX_SPAWN_SETSIGDEF) != 0)
    {
      /* We have to iterate over all signals.  This could possibly be
	 done better but it requires system specific solutions since
	 the sigset_t data type can be very different on different
	 architectures.  */
      int sig;
      struct sigaction sa;

      memset (&sa, '\0', sizeof (sa));
      sa.sa_handler = SIG_DFL;

      for (sig = 1; sig <= _NSIG; ++sig)
	if (__sigismember (&attrp->__sd, sig) != 0
	    && __sigaction (sig, &sa, NULL) != 0)
	  _exit (SPAWN_ERROR);

    }

#ifdef _POSIX_PRIORITY_SCHEDULING
  /* Set the scheduling algorithm and parameters.  */
  if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
      == POSIX_SPAWN_SETSCHEDPARAM)
    {
      if (__sched_setparam (0, &attrp->__sp) == -1)
	_exit (SPAWN_ERROR);
    }
  else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0)
    {
      if (__sched_setscheduler (0, attrp->__policy, &attrp->__sp) == -1)
	_exit (SPAWN_ERROR);
    }
#endif

  /* Set the process group ID.  */
  if ((flags & POSIX_SPAWN_SETPGROUP) != 0
      && __setpgid (0, attrp->__pgrp) != 0)
    _exit (SPAWN_ERROR);

  /* Set the effective user and group IDs.  */
  if ((flags & POSIX_SPAWN_RESETIDS) != 0
      && (local_seteuid (__getuid ()) != 0
	  || local_setegid (__getgid ()) != 0))
    _exit (SPAWN_ERROR);

  /* Execute the file actions.  */
  if (file_actions != NULL)
    {
      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];

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

		  /* Only signal errors for file descriptors out of range.  */
		  if (action->action.close_action.fd < 0
		      || action->action.close_action.fd >= fdlimit.rlim_cur)
		    /* Signal the error.  */
		    _exit (SPAWN_ERROR);
		}
	      break;

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

		if (new_fd == -1)
		  /* The `open' call failed.  */
		  _exit (SPAWN_ERROR);

		/* Make sure the desired file descriptor is used.  */
		if (new_fd != action->action.open_action.fd)
		  {
		    if (__dup2 (new_fd, action->action.open_action.fd)
			!= action->action.open_action.fd)
		      /* The `dup2' call failed.  */
		      _exit (SPAWN_ERROR);

		    if (close_not_cancel (new_fd) != 0)
		      /* The `close' call failed.  */
		      _exit (SPAWN_ERROR);
		  }
	      }
	      break;

	    case spawn_do_dup2:
	      if (__dup2 (action->action.dup2_action.fd,
			  action->action.dup2_action.newfd)
		  != action->action.dup2_action.newfd)
		/* The `dup2' call failed.  */
		_exit (SPAWN_ERROR);
	      break;
	    }
	}
    }

  if ((xflags & SPAWN_XFLAGS_USE_PATH) == 0 || strchr (file, '/') != NULL)
    {
      /* The FILE parameter is actually a path.  */
      __execve (file, argv, envp);

      maybe_script_execute (file, argv, envp, xflags);

      /* Oh, oh.  `execve' returns.  This is bad.  */
      _exit (SPAWN_ERROR);
    }

  /* We have to search for FILE on the path.  */
  path = getenv ("PATH");
  if (path == NULL)
    {
      /* There is no `PATH' in the environment.
	 The default search path is the current directory
	 followed by the path `confstr' returns for `_CS_PATH'.  */
      len = confstr (_CS_PATH, (char *) NULL, 0);
      path = (char *) __alloca (1 + len);
      path[0] = ':';
      (void) confstr (_CS_PATH, path + 1, len);
    }

  len = strlen (file) + 1;
  pathlen = strlen (path);
  name = __alloca (pathlen + len + 1);
  /* Copy the file name at the top.  */
  name = (char *) memcpy (name + pathlen + 1, file, len);
  /* And add the slash.  */
  *--name = '/';

  p = path;
  do
    {
      char *startp;

      path = p;
      p = __strchrnul (path, ':');

      if (p == path)
	/* Two adjacent colons, or a colon at the beginning or the end
	   of `PATH' means to search the current directory.  */
	startp = name + 1;
      else
	startp = (char *) memcpy (name - (p - path), path, p - path);

      /* Try to execute this name.  If it works, execv will not return.  */
      __execve (startp, argv, envp);

      maybe_script_execute (startp, argv, envp, xflags);

      switch (errno)
	{
	case EACCES:
	case ENOENT:
	case ESTALE:
	case ENOTDIR:
	  /* Those errors indicate the file is missing or not executable
	     by us, in which case we want to just try the next path
	     directory.  */
	  break;

	default:
	  /* Some other error means we found an executable file, but
	     something went wrong executing it; return the error to our
	     caller.  */
	  _exit (SPAWN_ERROR);
	    }
    }
  while (*p++ != '\0');

  /* Return with an error.  */
  _exit (SPAWN_ERROR);
}
示例#20
0
文件: sleep.c 项目: AubrCool/glibc
/* We are going to use the `nanosleep' syscall of the kernel.  But the
   kernel does not implement the stupid SysV SIGCHLD vs. SIG_IGN
   behaviour for this syscall.  Therefore we have to emulate it here.  */
unsigned int
__sleep (unsigned int seconds)
{
  const unsigned int max
    = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1);
  struct timespec ts;
  sigset_t set, oset;
  unsigned int result;

  /* This is not necessary but some buggy programs depend on this.  */
  if (__glibc_unlikely (seconds == 0))
    {
#ifdef CANCELLATION_P
      CANCELLATION_P (THREAD_SELF);
#endif
      return 0;
    }

  ts.tv_sec = 0;
  ts.tv_nsec = 0;
 again:
  if (sizeof (ts.tv_sec) <= sizeof (seconds))
    {
      /* Since SECONDS is unsigned assigning the value to .tv_sec can
	 overflow it.  In this case we have to wait in steps.  */
      ts.tv_sec += MIN (seconds, max);
      seconds -= (unsigned int) ts.tv_sec;
    }
  else
    {
      ts.tv_sec = (time_t) seconds;
      seconds = 0;
    }

  /* Linux will wake up the system call, nanosleep, when SIGCHLD
     arrives even if SIGCHLD is ignored.  We have to deal with it
     in libc.  We block SIGCHLD first.  */
  __sigemptyset (&set);
  __sigaddset (&set, SIGCHLD);
  if (__sigprocmask (SIG_BLOCK, &set, &oset))
    return -1;

  /* If SIGCHLD is already blocked, we don't have to do anything.  */
  if (!__sigismember (&oset, SIGCHLD))
    {
      int saved_errno;
      struct sigaction oact;

      __sigemptyset (&set);
      __sigaddset (&set, SIGCHLD);

      /* We get the signal handler for SIGCHLD.  */
      if (__sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
	{
	  saved_errno = errno;
	  /* Restore the original signal mask.  */
	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	  __set_errno (saved_errno);
	  return -1;
	}

      /* Note the sleep() is a cancellation point.  But since we call
	 nanosleep() which itself is a cancellation point we do not
	 have to do anything here.  */
      if (oact.sa_handler == SIG_IGN)
	{
	  //__libc_cleanup_push (cl, &oset);

	  /* We should leave SIGCHLD blocked.  */
	  while (1)
	    {
	      result = __nanosleep (&ts, &ts);

	      if (result != 0 || seconds == 0)
		break;

	      if (sizeof (ts.tv_sec) <= sizeof (seconds))
		{
		  ts.tv_sec = MIN (seconds, max);
		  seconds -= (unsigned int) ts.tv_nsec;
		}
	    }

	  //__libc_cleanup_pop (0);

	  saved_errno = errno;
	  /* Restore the original signal mask.  */
	  (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	  __set_errno (saved_errno);

	  goto out;
	}

      /* We should unblock SIGCHLD.  Restore the original signal mask.  */
      (void) __sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
    }

  result = __nanosleep (&ts, &ts);
  if (result == 0 && seconds != 0)
    goto again;

 out:
  if (result != 0)
    /* Round remaining time.  */
    result = seconds + (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);

  return result;
}
示例#21
0
/* We are going to use the `nanosleep' syscall of the kernel.  But the
   kernel does not implement the sstupid SysV SIGCHLD vs. SIG_IGN
   behaviour for this syscall.  Therefore we have to emulate it here.  */
unsigned int sleep (unsigned int seconds)
{
    struct timespec ts = { tv_sec: (long int) seconds, tv_nsec: 0 };
    sigset_t set, oset;
    unsigned int result;

    /* This is not necessary but some buggy programs depend on this.  */
    if (seconds == 0)
	return 0;

    /* Linux will wake up the system call, nanosleep, when SIGCHLD
       arrives even if SIGCHLD is ignored.  We have to deal with it
       in libc.  We block SIGCHLD first.  */
    if (__sigemptyset (&set) < 0
	    || __sigaddset (&set, SIGCHLD) < 0
	    || sigprocmask (SIG_BLOCK, &set, &oset))
	return -1;

    /* If SIGCHLD is already blocked, we don't have to do anything.  */
    if (!__sigismember (&oset, SIGCHLD))
    {
	int saved_errno;
	struct sigaction oact;

	if (__sigemptyset (&set) < 0 || __sigaddset (&set, SIGCHLD) < 0)
	    return -1;

	/* We get the signal handler for SIGCHLD.  */
	if (sigaction (SIGCHLD, (struct sigaction *) NULL, &oact) < 0)
	{
	    saved_errno = errno;
	    /* Restore the original signal mask.  */
	    (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	    __set_errno (saved_errno);
	    return -1;
	}

	if (oact.sa_handler == SIG_IGN)
	{
	    /* We should leave SIGCHLD blocked.  */
	    result = nanosleep (&ts, &ts);

	    saved_errno = errno;
	    /* Restore the original signal mask.  */
	    (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	    __set_errno (saved_errno);
	}
	else
	{
	    /* We should unblock SIGCHLD.  Restore the original signal mask.  */
	    (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
	    result = nanosleep (&ts, &ts);
	}
    }
    else
	result = nanosleep (&ts, &ts);

    if (result != 0)
	/* Round remaining time.  */
	result = (unsigned int) ts.tv_sec + (ts.tv_nsec >= 500000000L);

    return result;
}