/* * If act is not NULL, set the action for signum. * If oact is not NULL. store the old action to oact. */ int sigaction(int signum, const struct sigaction *act, struct sigaction *oact) { struct sigaction *sa; if (signum <= 0 || signum >= NSIG || signum == SIGSTOP || signum == SIGKILL) { errno = EINVAL; return -1; } SIGNAL_LOCK(); sa = &__sig_act[signum]; if (oact != NULL) *oact = *sa; if (act != NULL) *sa = *act; /* Discard pending signal in some cases */ if (sa->sa_handler == SIG_IGN || (sa->sa_handler == SIG_DFL && signum == SIGCHLD)) __sig_pending &= ~sigmask(signum); SIGNAL_UNLOCK(); /* Process pending signal */ __sig_flush(); return 0; }
/* * Exception handler for signal emulation */ static void __exception_handler(int excpt) { if (excpt > 0 && excpt <= NSIG) { SIGNAL_LOCK(); if (__sig_act[excpt].sa_handler != SIG_IGN) __sig_pending |= sigmask(excpt); SIGNAL_UNLOCK(); } __sig_flush(); exception_return(); }
int pause(void) { int sig, wait; /* Wait signal if no pending singal */ if (__sig_flush()) { wait = 1; while (wait) { exception_wait(&sig); SIGNAL_LOCK(); /* It is ok if processed signal is not masked and not pending */ if (!(__sig_mask & sigmask(sig)) && !(__sig_pending & sigmask(sig))) wait = 0; SIGNAL_UNLOCK(); } } /* Always returns error */ errno = EINTR; return -1; }
/* * Process all pending and unmasked signal * * return 0 if at least one pending signal was processed. * return -1 if no signal was processed. */ int __sig_flush(void) { int sig; sigset_t active, org_mask; struct sigaction action; struct siginfo si; int rc = -1; sig = 1; for (;;) { SIGNAL_LOCK(); active = __sig_pending & ~__sig_mask; action = __sig_act[sig]; SIGNAL_UNLOCK(); if (active == 0) break; if (active & sigmask(sig)) { SIGNAL_LOCK(); org_mask = __sig_mask; __sig_mask |= action.sa_mask; SIGNAL_UNLOCK(); if (action.sa_handler == SIG_DFL) { /* Default */ switch (sig) { case SIGCHLD: /* XXX: */ break; default: exit(0); } } else if (action.sa_handler != SIG_IGN) { /* User defined */ if (action.sa_flags & SA_SIGINFO) { si.si_signo = sig; si.si_code = 0; si.si_value.sival_int = 0; action.sa_sigaction(sig, &si, NULL); } else { action.sa_handler(sig); } } SIGNAL_LOCK(); __sig_pending &= ~sigmask(sig); __sig_mask = org_mask; SIGNAL_UNLOCK(); switch (sig) { case SIGILL: case SIGTRAP: case SIGFPE: case SIGSEGV: for (;;); /* exception from kernel */ break; } if (action.sa_handler != SIG_IGN) rc = 0; /* Signal is processed */ } if (++sig >= NSIG) sig = 1; } return rc; }