Date: Sun, 2 Feb 1997 19:13:10 +0200 (IST) From: Eli Zaretskii To: djgpp-workers AT delorie DOT com cc: DJ Delorie Subject: POSIX signal functions (1/2) Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Attached below are additions to the POSIX signal functions. The most significant is `sigprocmask' (which has been tested in Emacs). I also added `sigpending', since it is a trivial one-liner. Sorry, I didn't have time to make `sigsuspend' right. The sources are entirely new, so I append the entire file instead if a diff. The docs are in a separate mail, which see. I also included the (missing) docs of the sigaddset, sigdelset etc. functions. ---------------------------- sigprocm.c ------------------------------- /* Copyright (C) 1997 DJ Delorie, see COPYING.DJ for details */ /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */ #include #include #include #include /* A counter to know when to re-initialize the static sets. */ static int sigprocmask_count = -1; /* Which signals are currently blocked (initially none). */ static sigset_t current_mask; /* Which signals are pending (initially none). */ static sigset_t pending_signals; /* Previous handlers to restore when the blocked signals are unblocked. */ typedef void (*sighandler_t)(int); static sighandler_t prev_handlers[320]; /* A signal handler which just records that a signal occured (it will be raised later, if and when the signal is unblocked). */ static void sig_suspender (int signo) { sigaddset (&pending_signals, signo); } int sigprocmask (int how, const sigset_t *new_set, sigset_t *old_set) { int signo; sigset_t new_mask; /* If called for the first time, initialize. */ if (sigprocmask_count != __bss_count) { sigprocmask_count = __bss_count; sigemptyset (&pending_signals); sigemptyset (¤t_mask); for (signo = 0; signo < 320; signo++) prev_handlers[signo] = SIG_ERR; } if (old_set) *old_set = current_mask; if (new_set == 0) return 0; if (how != SIG_BLOCK && how != SIG_UNBLOCK && how != SIG_SETMASK) { errno = EINVAL; return -1; } sigemptyset (&new_mask); /* DJGPP supports upto 320 signals. FIXME: we shouldn't need to say 320 explicitly. */ for (signo = 0; signo < 320; signo++) { if (sigismember (¤t_mask, signo)) sigaddset (&new_mask, signo); else if (sigismember (new_set, signo) && how != SIG_UNBLOCK) { sigaddset (&new_mask, signo); /* SIGKILL is silently ignored, as on other platforms. */ if (signo != SIGKILL && prev_handlers[signo] == SIG_ERR) prev_handlers[signo] = signal (signo, sig_suspender); } if (( how == SIG_UNBLOCK && sigismember (&new_mask, signo) && sigismember (new_set, signo)) || (how == SIG_SETMASK && sigismember (&new_mask, signo) && !sigismember (new_set, signo))) { sigdelset (&new_mask, signo); if (prev_handlers[signo] != SIG_ERR) { signal (signo, prev_handlers[signo]); prev_handlers[signo] = SIG_ERR; } if (sigismember (&pending_signals, signo)) { sigdelset (&pending_signals, signo); raise (signo); } } } current_mask = new_mask; return 0; } int sigpending(sigset_t *set) { if (set == (sigset_t *)0) { errno = EFAULT; return -1; } *set = pending_signals; return 0; } #ifdef TEST #include #include static void sig_catcher (int signo) { cprintf ("\r\nGot signal %d\r\n", signo); } int main (void) { int *p = 0; sigset_t sigmask, prevmask; signal (SIGINT, sig_catcher); sigemptyset (&sigmask); sigaddset (&sigmask, SIGINT); if (sigprocmask (SIG_SETMASK, &sigmask, &prevmask) == 0) cputs ("SIGINT blocked. Try to interrupt me now.\r\n"); while (!kbhit ()) ; cputs ("See? I wasn't interrupted.\r\n"); cputs ("But now I will unblock SIGINT, and then get the signal.\r\n"); sigprocmask (SIG_UNBLOCK, &sigmask, &prevmask); sigemptyset (&sigmask); sigaddset (&sigmask, SIGFPE); signal (SIGFPE, sig_catcher); sigprocmask (SIG_SETMASK, &sigmask, &prevmask); cputs ("SIGFPE is blocked. Let's try some FP exception.\r\n"); cprintf ("asin (2.0) = %f, sqrt(-4.0) = %f\r\n", asin (2.0), sqrt (-4.0)); cputs ("Did we get the signal? If not, Let's see if we get it now.\r\n"); sigprocmask (SIG_UNBLOCK, &sigmask, &prevmask); sigemptyset (&sigmask); sigaddset (&sigmask, SIGSEGV); signal (SIGSEGV, sig_catcher); sigprocmask (SIG_SETMASK, &sigmask, &prevmask); cputs ("SIGSEGV is blocked. Let's try a null pointer dereference.\r\n"); cprintf ("Zero address has this value: %d\r\n", *p); cputs ("Did we get Page Fault? If not, Let's see if we get it now.\r\n"); sigprocmask (SIG_SETMASK, &prevmask, &sigmask); cputs ("Are we still alive? If so, that's all, folks!\r\n"); return 0; } #endif