X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fsigprocmask.c;h=6780a37b14f0f8f77793a50719417db82693157b;hb=64ee293cdac319d0f38cd0d31e758a823b7163ad;hp=a8f2eb4e396568de7c7412e65f34640fe721f3b4;hpb=4b2f21b36a615728ebf2a0e1bc2c8def175703a8;p=gnulib.git diff --git a/lib/sigprocmask.c b/lib/sigprocmask.c index a8f2eb4e3..6780a37b1 100644 --- a/lib/sigprocmask.c +++ b/lib/sigprocmask.c @@ -1,5 +1,5 @@ /* POSIX compatible signal blocking. - Copyright (C) 2006-2008 Free Software Foundation, Inc. + Copyright (C) 2006-2011 Free Software Foundation, Inc. Written by Bruno Haible , 2006. This program is free software: you can redistribute it and/or modify @@ -24,8 +24,6 @@ #include #include -#include "sig-handler.h" - /* We assume that a platform without POSIX signal blocking functions also does not have the POSIX sigaction() function, only the signal() function. We also assume signal() has SysV semantics, @@ -45,11 +43,58 @@ # define SIGSTOP (-1) #endif +/* On native Windows, as of 2008, the signal SIGABRT_COMPAT is an alias + for the signal SIGABRT. Only one signal handler is stored for both + SIGABRT and SIGABRT_COMPAT. SIGABRT_COMPAT is not a signal of its own. */ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# undef SIGABRT_COMPAT +# define SIGABRT_COMPAT 6 +#endif +#ifdef SIGABRT_COMPAT +# define SIGABRT_COMPAT_MASK (1U << SIGABRT_COMPAT) +#else +# define SIGABRT_COMPAT_MASK 0 +#endif + +typedef void (*handler_t) (int); + +/* Handling of gnulib defined signals. */ + +#if GNULIB_defined_SIGPIPE +static handler_t SIGPIPE_handler = SIG_DFL; +#endif + +#if GNULIB_defined_SIGPIPE +static handler_t +ext_signal (int sig, handler_t handler) +{ + switch (sig) + { + case SIGPIPE: + { + handler_t old_handler = SIGPIPE_handler; + SIGPIPE_handler = handler; + return old_handler; + } + default: /* System defined signal */ + return signal (sig, handler); + } +} +# define signal ext_signal +#endif + int sigismember (const sigset_t *set, int sig) { if (sig >= 0 && sig < NSIG) - return (*set >> sig) & 1; + { + #ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; + #endif + + return (*set >> sig) & 1; + } else return 0; } @@ -66,6 +111,11 @@ sigaddset (sigset_t *set, int sig) { if (sig >= 0 && sig < NSIG) { + #ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; + #endif + *set |= 1U << sig; return 0; } @@ -81,6 +131,11 @@ sigdelset (sigset_t *set, int sig) { if (sig >= 0 && sig < NSIG) { + #ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; + #endif + *set &= ~(1U << sig); return 0; } @@ -91,10 +146,11 @@ sigdelset (sigset_t *set, int sig) } } + int sigfillset (sigset_t *set) { - *set = (2U << (NSIG - 1)) - 1; + *set = ((2U << (NSIG - 1)) - 1) & ~ SIGABRT_COMPAT_MASK; return 0; } @@ -133,7 +189,7 @@ sigpending (sigset_t *set) /* The previous signal handlers. Only the array elements corresponding to blocked signals are relevant. */ -static volatile sa_handler_t old_handlers[NSIG]; +static volatile handler_t old_handlers[NSIG]; int sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) @@ -148,89 +204,96 @@ sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) sigset_t to_block; switch (operation) - { - case SIG_BLOCK: - new_blocked_set = blocked_set | *set; - break; - case SIG_SETMASK: - new_blocked_set = *set; - break; - case SIG_UNBLOCK: - new_blocked_set = blocked_set & ~*set; - break; - default: - errno = EINVAL; - return -1; - } + { + case SIG_BLOCK: + new_blocked_set = blocked_set | *set; + break; + case SIG_SETMASK: + new_blocked_set = *set; + break; + case SIG_UNBLOCK: + new_blocked_set = blocked_set & ~*set; + break; + default: + errno = EINVAL; + return -1; + } to_unblock = blocked_set & ~new_blocked_set; to_block = new_blocked_set & ~blocked_set; if (to_block != 0) - { - int sig; - - for (sig = 0; sig < NSIG; sig++) - if ((to_block >> sig) & 1) - { - pending_array[sig] = 0; - if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) - blocked_set |= 1U << sig; - } - } + { + int sig; + + for (sig = 0; sig < NSIG; sig++) + if ((to_block >> sig) & 1) + { + pending_array[sig] = 0; + if ((old_handlers[sig] = signal (sig, blocked_handler)) != SIG_ERR) + blocked_set |= 1U << sig; + } + } if (to_unblock != 0) - { - sig_atomic_t received[NSIG]; - int sig; - - for (sig = 0; sig < NSIG; sig++) - if ((to_unblock >> sig) & 1) - { - if (signal (sig, old_handlers[sig]) != blocked_handler) - /* The application changed a signal handler while the signal - was blocked. We don't support this. */ - abort (); - received[sig] = pending_array[sig]; - blocked_set &= ~(1U << sig); - pending_array[sig] = 0; - } - else - received[sig] = 0; - - for (sig = 0; sig < NSIG; sig++) - if (received[sig]) - raise (sig); - } + { + sig_atomic_t received[NSIG]; + int sig; + + for (sig = 0; sig < NSIG; sig++) + if ((to_unblock >> sig) & 1) + { + if (signal (sig, old_handlers[sig]) != blocked_handler) + /* The application changed a signal handler while the signal + was blocked, bypassing our rpl_signal replacement. + We don't support this. */ + abort (); + received[sig] = pending_array[sig]; + blocked_set &= ~(1U << sig); + pending_array[sig] = 0; + } + else + received[sig] = 0; + + for (sig = 0; sig < NSIG; sig++) + if (received[sig]) + raise (sig); + } } return 0; } /* Install the handler FUNC for signal SIG, and return the previous handler. */ -sa_handler_t -rpl_signal (int sig, sa_handler_t handler) +handler_t +rpl_signal (int sig, handler_t handler) { /* We must provide a wrapper, so that a user can query what handler they installed even if that signal is currently blocked. */ if (sig >= 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP && handler != SIG_ERR) { + #ifdef SIGABRT_COMPAT + if (sig == SIGABRT_COMPAT) + sig = SIGABRT; + #endif + if (blocked_set & (1U << sig)) - { - /* POSIX states that sigprocmask and signal are both - async-signal-safe. This is not true of our - implementation - there is a slight data race where an - asynchronous interrupt on signal A can occur after we - install blocked_handler but before we have updated - old_handlers for signal B, such that handler A can see - stale information if it calls signal(B). Oh well - - signal handlers really shouldn't try to manipulate the - installed handlers of unrelated signals. */ - sa_handler_t result = old_handlers[sig]; - old_handlers[sig] = handler; - return result; - } - return signal (sig, handler); + { + /* POSIX states that sigprocmask and signal are both + async-signal-safe. This is not true of our + implementation - there is a slight data race where an + asynchronous interrupt on signal A can occur after we + install blocked_handler but before we have updated + old_handlers for signal B, such that handler A can see + stale information if it calls signal(B). Oh well - + signal handlers really shouldn't try to manipulate the + installed handlers of unrelated signals. */ + handler_t result = old_handlers[sig]; + old_handlers[sig] = handler; + return result; + } + else + return signal (sig, handler); } else { @@ -238,3 +301,29 @@ rpl_signal (int sig, sa_handler_t handler) return SIG_ERR; } } + +#if GNULIB_defined_SIGPIPE +/* Raise the signal SIG. */ +int +rpl_raise (int sig) +# undef raise +{ + switch (sig) + { + case SIGPIPE: + if (blocked_set & (1U << sig)) + pending_array[sig] = 1; + else + { + handler_t handler = SIGPIPE_handler; + if (handler == SIG_DFL) + exit (128 + SIGPIPE); + else if (handler != SIG_IGN) + (*handler) (sig); + } + return 0; + default: /* System defined signal */ + return raise (sig); + } +} +#endif