summaryrefslogtreecommitdiff
path: root/tests/sigaction.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sigaction.c')
-rw-r--r--tests/sigaction.c204
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;
-}