diff options
Diffstat (limited to 'tests/sigaction.c')
-rw-r--r-- | tests/sigaction.c | 204 |
1 files changed, 0 insertions, 204 deletions
diff --git a/tests/sigaction.c b/tests/sigaction.c deleted file mode 100644 index 953a6cae..00000000 --- a/tests/sigaction.c +++ /dev/null @@ -1,204 +0,0 @@ -/* POSIX compatible signal blocking. - Copyright (C) 2008-2022 Free Software Foundation, Inc. - Written by Eric Blake <ebb9@byu.net>, 2008. - - This file is free software: you can redistribute it and/or modify - it under the terms of the GNU Lesser General Public License as - published by the Free Software Foundation; either version 2.1 of the - License, or (at your option) any later version. - - This file 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 Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with this program. If not, see <https://www.gnu.org/licenses/>. */ - -#include <config.h> - -/* Specification. */ -#include <signal.h> - -#include <errno.h> -#include <stdint.h> -#include <stdlib.h> - -/* This implementation of sigaction is tailored to native Windows behavior: - signal() has SysV semantics (ie. the handler is uninstalled before - it is invoked). This is an inherent data race if an asynchronous - signal is sent twice in a row before we can reinstall our handler, - but there's nothing we can do about it. Meanwhile, sigprocmask() - is not present, and while we can use the gnulib replacement to - provide critical sections, it too suffers from potential data races - in the face of an ill-timed asynchronous signal. And we compound - the situation by reading static storage in a signal handler, which - POSIX warns is not generically async-signal-safe. Oh well. - - Additionally: - - We don't implement SA_NOCLDSTOP or SA_NOCLDWAIT, because SIGCHLD - is not defined. - - We don't implement SA_ONSTACK, because sigaltstack() is not present. - - We ignore SA_RESTART, because blocking native Windows API calls are - not interrupted anyway when an asynchronous signal occurs, and the - MSVCRT runtime never sets errno to EINTR. - - We don't implement SA_SIGINFO because it is impossible to do so - portably. - - POSIX states that an application should not mix signal() and - sigaction(). We support the use of signal() within the gnulib - sigprocmask() substitute, but all other application code linked - with this module should stick with only sigaction(). */ - -/* Check some of our assumptions. */ -#if defined SIGCHLD || defined HAVE_SIGALTSTACK || defined HAVE_SIGINTERRUPT -# error "Revisit the assumptions made in the sigaction module" -#endif - -/* Out-of-range substitutes make a good fallback for uncatchable - signals. */ -#ifndef SIGKILL -# define SIGKILL (-1) -#endif -#ifndef SIGSTOP -# 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 __CYGWIN__ -# undef SIGABRT_COMPAT -# define SIGABRT_COMPAT 6 -#endif - -/* A signal handler. */ -typedef void (*handler_t) (int signal); - -/* Set of current actions. If sa_handler for an entry is NULL, then - that signal is not currently handled by the sigaction handler. */ -static struct sigaction volatile action_array[NSIG] /* = 0 */; - -/* Signal handler that is installed for signals. */ -static void -sigaction_handler (int sig) -{ - handler_t handler; - sigset_t mask; - sigset_t oldmask; - int saved_errno = errno; - if (sig < 0 || NSIG <= sig || !action_array[sig].sa_handler) - { - /* Unexpected situation; be careful to avoid recursive abort. */ - if (sig == SIGABRT) - signal (SIGABRT, SIG_DFL); - abort (); - } - - /* Reinstall the signal handler when required; otherwise update the - bookkeeping so that the user's handler may call sigaction and get - accurate results. We know the signal isn't currently blocked, or - we wouldn't be in its handler, therefore we know that we are not - interrupting a sigaction() call. There is a race where any - asynchronous instance of the same signal occurring before we - reinstall the handler will trigger the default handler; oh - well. */ - handler = action_array[sig].sa_handler; - if ((action_array[sig].sa_flags & SA_RESETHAND) == 0) - signal (sig, sigaction_handler); - else - action_array[sig].sa_handler = NULL; - - /* Block appropriate signals. */ - mask = action_array[sig].sa_mask; - if ((action_array[sig].sa_flags & SA_NODEFER) == 0) - sigaddset (&mask, sig); - sigprocmask (SIG_BLOCK, &mask, &oldmask); - - /* Invoke the user's handler, then restore prior mask. */ - errno = saved_errno; - handler (sig); - saved_errno = errno; - sigprocmask (SIG_SETMASK, &oldmask, NULL); - errno = saved_errno; -} - -/* Change and/or query the action that will be taken on delivery of - signal SIG. If not NULL, ACT describes the new behavior. If not - NULL, OACT is set to the prior behavior. Return 0 on success, or - set errno and return -1 on failure. */ -int -sigaction (int sig, const struct sigaction *restrict act, - struct sigaction *restrict oact) -{ - sigset_t mask; - sigset_t oldmask; - int saved_errno; - - if (sig < 0 || NSIG <= sig || sig == SIGKILL || sig == SIGSTOP - || (act && act->sa_handler == SIG_ERR)) - { - errno = EINVAL; - return -1; - } - -#ifdef SIGABRT_COMPAT - if (sig == SIGABRT_COMPAT) - sig = SIGABRT; -#endif - - /* POSIX requires sigaction() to be async-signal-safe. In other - words, if an asynchronous signal can occur while we are anywhere - inside this function, the user's handler could then call - sigaction() recursively and expect consistent results. We meet - this rule by using sigprocmask to block all signals before - modifying any data structure that could be read from a signal - handler; this works since we know that the gnulib sigprocmask - replacement does not try to use sigaction() from its handler. */ - if (!act && !oact) - return 0; - sigfillset (&mask); - sigprocmask (SIG_BLOCK, &mask, &oldmask); - if (oact) - { - if (action_array[sig].sa_handler) - *oact = action_array[sig]; - else - { - /* Safe to change the handler at will here, since all - signals are currently blocked. */ - oact->sa_handler = signal (sig, SIG_DFL); - if (oact->sa_handler == SIG_ERR) - goto failure; - signal (sig, oact->sa_handler); - oact->sa_flags = SA_RESETHAND | SA_NODEFER; - sigemptyset (&oact->sa_mask); - } - } - - if (act) - { - /* Safe to install the handler before updating action_array, - since all signals are currently blocked. */ - if (act->sa_handler == SIG_DFL || act->sa_handler == SIG_IGN) - { - if (signal (sig, act->sa_handler) == SIG_ERR) - goto failure; - action_array[sig].sa_handler = NULL; - } - else - { - if (signal (sig, sigaction_handler) == SIG_ERR) - goto failure; - action_array[sig] = *act; - } - } - sigprocmask (SIG_SETMASK, &oldmask, NULL); - return 0; - - failure: - saved_errno = errno; - sigprocmask (SIG_SETMASK, &oldmask, NULL); - errno = saved_errno; - return -1; -} |