From fa9f85a436cb8239695046be4feb68211fe71af1 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Mon, 16 Oct 2006 11:55:35 +0000 Subject: [PATCH] New module 'sigprocmask'. --- ChangeLog | 19 +++++ MODULES.html.sh | 1 + lib/fatal-signal.c | 20 +----- lib/sigprocmask.c | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/sigprocmask.h | 64 +++++++++++++++++ m4/fatal-signal.m4 | 8 +-- m4/signalblocking.m4 | 22 ++++-- modules/fatal-signal | 2 +- modules/sigprocmask | 26 +++++++ 9 files changed, 324 insertions(+), 30 deletions(-) create mode 100644 lib/sigprocmask.c create mode 100644 lib/sigprocmask.h create mode 100644 modules/sigprocmask diff --git a/ChangeLog b/ChangeLog index 5d46d8843..8393e8cb1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2006-10-14 Bruno Haible + + * modules/sigprocmask: New file. + * lib/sigprocmask.h: New file. + * lib/sigprocmask.c: New file. + * m4/signalblocking.m4 (gl_SIGNALBLOCKING): Renamed from + gt_SIGNALBLOCKING. When not defining HAVE_POSIX_SIGNALBLOCKING, + request sigprocmask.o. + (gl_PREREQ_SIGPROCMASK): New macro. + * modules/fatal-signal (Files): Remove m4/signalblocking.m4. + (Depends-on): Add sigprocmask. + * m4/fatal-signal.m4 (gl_FATAL_SIGNAL): Don't require + gt_SIGNALBLOCKING. Test for 'raise' only once. + * lib/fatal-signal.c: Include sigprocmask.h. + (fatal_signal_set, init_fatal_signal_set, block_fatal_signals, + unblock_fatal_signals): Define always. + * MODULES.html.sh (Support for systems lacking POSIX:2001): Add + sigprocmask. + 2006-10-14 Paul Eggert Sync from Automake. diff --git a/MODULES.html.sh b/MODULES.html.sh index 17e7244a0..1196121e0 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1849,6 +1849,7 @@ func_all_modules () func_module regex func_module rename func_module rmdir + func_module sigprocmask func_module ssize_t func_module strtok_r func_module sys_stat diff --git a/lib/fatal-signal.c b/lib/fatal-signal.c index 8a3a99c36..f85b60f41 100644 --- a/lib/fatal-signal.c +++ b/lib/fatal-signal.c @@ -27,6 +27,7 @@ #include #include +#include "sigprocmask.h" #include "xalloc.h" #define SIZEOF(a) (sizeof(a) / sizeof(a[0])) @@ -231,8 +232,6 @@ at_fatal_signal (action_t action) /* ========================================================================= */ -#if HAVE_POSIX_SIGNALBLOCKING - static sigset_t fatal_signal_set; static void @@ -269,20 +268,3 @@ unblock_fatal_signals () init_fatal_signal_set (); sigprocmask (SIG_UNBLOCK, &fatal_signal_set, NULL); } - -#else - -/* Don't bother caring about the old systems which don't have POSIX signal - blocking. */ - -void -block_fatal_signals () -{ -} - -void -unblock_fatal_signals () -{ -} - -#endif diff --git a/lib/sigprocmask.c b/lib/sigprocmask.c new file mode 100644 index 000000000..149d27003 --- /dev/null +++ b/lib/sigprocmask.c @@ -0,0 +1,192 @@ +/* POSIX compatible signal blocking. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include + +/* Specification. */ +#include "sigprocmask.h" + +#include +#include +#include + +/* We assume that a platform without POSIX signal blocking functions also + does not have the POSIX sigaction() function, only the signal() function. + This is true for Woe32 platforms. */ + +/* A signal handler. */ +typedef void (*handler_t) (int signal); + +int +sigismember (const sigset_t *set, int sig) +{ + if (sig >= 0 && sig < NSIG) + return (*set >> sig) & 1; + else + return 0; +} + +int +sigemptyset (sigset_t *set) +{ + *set = 0; + return 0; +} + +int +sigaddset (sigset_t *set, int sig) +{ + if (sig >= 0 && sig < NSIG) + { + *set |= 1U << sig; + return 0; + } + else + { + errno = EINVAL; + return -1; + } +} + +int +sigdelset (sigset_t *set, int sig) +{ + if (sig >= 0 && sig < NSIG) + { + *set &= ~(1U << sig); + return 0; + } + else + { + errno = EINVAL; + return -1; + } +} + +int +sigfillset (sigset_t *set) +{ + *set = (2U << (NSIG - 1)) - 1; + return 0; +} + +/* Set of currently blocked signals. */ +static sigset_t blocked_set /* = 0 */; + +/* Set of currently blocked and pending signals. */ +static volatile sig_atomic_t pending_array[NSIG] /* = { 0 } */; + +/* Signal handler that is installed for blocked signals. */ +static void +blocked_handler (int sig) +{ + if (sig >= 0 && sig < NSIG) + pending_array[sig] = 1; +} + +int +sigpending (sigset_t *set) +{ + sigset_t pending = 0; + int sig; + + for (sig = 0; sig < NSIG; sig++) + if (pending_array[sig]) + pending |= 1U << sig; + return pending; +} + +/* The previous signal handlers. + Only the array elements corresponding to blocked signals are relevant. */ +static handler_t old_handlers[NSIG]; + +int +sigprocmask (int operation, const sigset_t *set, sigset_t *old_set) +{ + if (old_set != NULL) + *old_set = blocked_set; + + if (set != NULL) + { + sigset_t new_blocked_set; + sigset_t to_unblock; + 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; + } + 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; + } + } + + 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[NSIG]) + { + #if HAVE_RAISE + raise (sig); + #else + kill (getpid (), sig); + #endif + } + } + } + return 0; +} diff --git a/lib/sigprocmask.h b/lib/sigprocmask.h new file mode 100644 index 000000000..f88351f47 --- /dev/null +++ b/lib/sigprocmask.h @@ -0,0 +1,64 @@ +/* POSIX compatible signal blocking. + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Bruno Haible , 2006. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include + +#if ! HAVE_POSIX_SIGNALBLOCKING + +# include "verify.h" + +/* Maximum signal number + 1. */ +# ifndef NSIG +# define NSIG 32 +# endif + +/* This code supports only 32 signals. */ +verify (NSIG <= 32); + +/* A set or mask of signals. */ +typedef unsigned int sigset_t; + +/* Test whether a given signal is contained in a signal set. */ +extern int sigismember (const sigset_t *set, int sig); + +/* Initialize a signal set to the empty set. */ +extern int sigemptyset (sigset_t *set); + +/* Add a signal to a signal set. */ +extern int sigaddset (sigset_t *set, int sig); + +/* Remove a signal from a signal set. */ +extern int sigdelset (sigset_t *set, int sig); + +/* Fill a signal set with all possible signals. */ +extern int sigfillset (sigset_t *set); + +/* Return the set of those blocked signals that are pending. */ +extern int sigpending (sigset_t *set); + +/* If OLD_SET is not NULL, put the current set of blocked signals in *OLD_SET. + Then, if SET is not NULL, affect the current set of blocked signals by + combining it with *SET as indicated in OPERATION. + In this implementation, you are not allowed to change a signal handler + while the signal is blocked. */ +# define SIG_BLOCK 0 /* blocked_set = blocked_set | *set; */ +# define SIG_SETMASK 1 /* blocked_set = *set; */ +# define SIG_UNBLOCK 2 /* blocked_set = blocked_set & ~*set; */ +extern int sigprocmask (int operation, const sigset_t *set, sigset_t *old_set); + +#endif diff --git a/m4/fatal-signal.m4 b/m4/fatal-signal.m4 index 062f6e0a7..c188b1439 100644 --- a/m4/fatal-signal.m4 +++ b/m4/fatal-signal.m4 @@ -1,13 +1,13 @@ -# fatal-signal.m4 serial 3 -dnl Copyright (C) 2003-2004 Free Software Foundation, Inc. +# fatal-signal.m4 serial 4 +dnl Copyright (C) 2003-2004, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. AC_DEFUN([gl_FATAL_SIGNAL], [ - AC_REQUIRE([gt_SIGNALBLOCKING]) AC_REQUIRE([gt_TYPE_SIG_ATOMIC_T]) AC_CHECK_HEADERS_ONCE(unistd.h) - AC_CHECK_FUNCS(raise sigaction) + AC_CHECK_FUNCS_ONCE(raise) + AC_CHECK_FUNCS(sigaction) ]) diff --git a/m4/signalblocking.m4 b/m4/signalblocking.m4 index fe91f2984..bb120f55c 100644 --- a/m4/signalblocking.m4 +++ b/m4/signalblocking.m4 @@ -1,5 +1,5 @@ -# signalblocking.m4 serial 1 (gettext-0.11) -dnl Copyright (C) 2001-2002 Free Software Foundation, Inc. +# signalblocking.m4 serial 2 (gettext-0.15.1) +dnl Copyright (C) 2001-2002, 2006 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, dnl with or without modifications, as long as this notice is preserved. @@ -9,13 +9,23 @@ dnl with or without modifications, as long as this notice is preserved. # 2) SYSV: sighold, sigrelse # 3) BSD: sigblock, sigsetmask # For simplicity, here we check only for the POSIX signal blocking. -AC_DEFUN([gt_SIGNALBLOCKING], +AC_DEFUN([gl_SIGNALBLOCKING], [ signals_not_posix= AC_EGREP_HEADER(sigset_t, signal.h, , signals_not_posix=1) if test -z "$signals_not_posix"; then - AC_CHECK_FUNC(sigprocmask, - AC_DEFINE(HAVE_POSIX_SIGNALBLOCKING, 1, - [Define to 1 if you have the sigset_t type and the sigprocmask function.])) + AC_CHECK_FUNC(sigprocmask, [gl_cv_func_sigprocmask=1]) fi + if test -n "$gl_cv_func_sigprocmask"; then + AC_DEFINE([HAVE_POSIX_SIGNALBLOCKING], 1, + [Define to 1 if you have the sigset_t type and the sigprocmask function.]) + else + AC_LIBOBJ([sigprocmask]) + gl_PREREQ_SIGPROCMASK + fi +]) + +# Prerequisites of lib/sigprocmask.c. +AC_DEFUN([gl_PREREQ_SIGPROCMASK], [ + AC_CHECK_FUNCS_ONCE(raise) ]) diff --git a/modules/fatal-signal b/modules/fatal-signal index dce33bd42..4365b3a61 100644 --- a/modules/fatal-signal +++ b/modules/fatal-signal @@ -5,13 +5,13 @@ Files: lib/fatal-signal.h lib/fatal-signal.c m4/fatal-signal.m4 -m4/signalblocking.m4 m4/sig_atomic_t.m4 Depends-on: xalloc stdbool unistd +sigprocmask configure.ac: gl_FATAL_SIGNAL diff --git a/modules/sigprocmask b/modules/sigprocmask new file mode 100644 index 000000000..314e4be45 --- /dev/null +++ b/modules/sigprocmask @@ -0,0 +1,26 @@ +Description: +POSIX compatible signal blocking. + +Files: +lib/sigprocmask.h +lib/sigprocmask.c +m4/signalblocking.m4 + +Depends-on: +verify +stdint + +configure.ac: +gl_SIGNALBLOCKING + +Makefile.am: + +Include: +"sigprocmask.h" + +License: +LGPL + +Maintainer: +Bruno Haible + -- 2.11.0