Commit cfb3906f authored by Eric Blake's avatar Eric Blake

New module sigaction, for mingw.

* modules/sigaction: New module...
* modules/sigaction-tests: ...and its test.
* m4/sigaction.m4: New file.
* lib/sigaction.c: Likewise.
* tests/test-sigaction.c: Likewise.
* m4/signal_h.m4 (gl_SIGNAL_H_DEFAULTS): Add sigaction variables.
* modules/signal (Makefile.am): Likewise.
* lib/signal.in.h (!@HAVE_SIGACTION@): Define replacements when
needed.
* doc/posix-headers/signal.texi (signal.h): Mention provided
types.
* doc/posix-functions/siginterrupt.texi (siginterrupt): Mention
that sigaction is preferable.
* doc/posix-functions/sigaction.texi (sigaction): Mention new
module.
* MODULES.html.sh (Support for systems lacking POSIX:2001): Add
sigaction.
Signed-off-by: 's avatarEric Blake <ebb9@byu.net>
parent 6dbadedb
2008-06-21 Eric Blake <ebb9@byu.net>
New module sigaction, for mingw.
* modules/sigaction: New module...
* modules/sigaction-tests: ...and its test.
* m4/sigaction.m4: New file.
* lib/sigaction.c: Likewise.
* tests/test-sigaction.c: Likewise.
* m4/signal_h.m4 (gl_SIGNAL_H_DEFAULTS): Add sigaction variables.
* modules/signal (Makefile.am): Likewise.
* lib/signal.in.h (!@HAVE_SIGACTION@): Define replacements when
needed.
* doc/posix-headers/signal.texi (signal.h): Mention provided
types.
* doc/posix-functions/siginterrupt.texi (siginterrupt): Mention
that sigaction is preferable.
* doc/posix-functions/sigaction.texi (sigaction): Mention new
module.
* MODULES.html.sh (Support for systems lacking POSIX:2001): Add
sigaction.
Improve robustness of sigprocmask by overriding signal.
* lib/signal.in.h (rpl_signal): Override signal when sigprocmask
is in use.
......@@ -2131,6 +2131,7 @@ func_all_modules ()
func_module rename
func_module rmdir
func_module search
func_module sigaction
func_module sigprocmask
func_module socklen
func_module ssize_t
......
......@@ -4,17 +4,38 @@
POSIX specification: @url{http://www.opengroup.org/susv3xsh/sigaction.html}
Gnulib module: ---
Gnulib module: sigaction
Portability problems fixed by Gnulib:
@itemize
@item
This function is missing on some platforms:
mingw.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item
This function is missing on some platforms:
POSIX recommends that when specifying SA_RESETHAND, SA_NODEFER must
also be specified.
@item
Support for SA_ONSTACK is missing on some platforms:
mingw, cygwin.
@item
Support for SA_SIGINFO is missing on some platforms:
mingw, Interix 3.5.
@item
Support for SIGCHLD, and thus for SA_NOCLDSTOP and SA_NOCLDWAIT, is
missing on some platforms:
mingw.
@item
Support for SA_RESTART is missing on some platforms:
mingw.
@item
The symbolic value @code{SIG_IGN} for the @code{SIGCHLD} signal is equivalent
to a signal handler
......
......@@ -15,4 +15,7 @@ Portability problems not fixed by Gnulib:
@item
This function is missing on some platforms:
Solaris 2.5.1, mingw, Interix 3.5, BeOS.
@item
POSIX recommends using @code{sigaction} with SA_NODEFER instead.
@end itemize
......@@ -3,12 +3,24 @@
POSIX specification: @url{http://www.opengroup.org/susv3xbd/signal.h.html}
Gnulib module: ---
Gnulib module: signal
Portability problems fixed by Gnulib:
@itemize
@item
@code{sigset_t} is only declared in <sys/types.h> on some platforms:
mingw.
@item
@code{struct sigaction} and @code{siginfo_t} are missing on some
platforms:
mingw.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item
@code{struct sigaction} lacks the @code{sa_sigaction} member on some
platforms; this can also be detected by whether @code{SA_SIGINFO} is defined:
Interix 3.5.
@end itemize
/* POSIX compatible signal blocking.
Copyright (C) 2008 Free Software Foundation, Inc.
Written by Eric Blake <ebb9@byu.net>, 2008.
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 3 of the License, 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, see <http://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 Woe32 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, SIGCHLD is not defined, so we don't implement
SA_NOCLDSTOP or SA_NOCLDWAIT; sigaltstack() is not present, so we
don't implement SA_ONSTACK; and siginterrupt() is not present, so
we don't implement SA_RESTART. Supporting SA_SIGINFO is impossible
to do 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
/* 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;
}
/* 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;
}
......@@ -34,9 +34,7 @@
/* The definition of GL_LINK_WARNING is copied here. */
/* Mingw defines sigset_t not in <signal.h>, but in <sys/types.h>. */
#if !@HAVE_POSIX_SIGNALBLOCKING@
# include <sys/types.h>
#endif
#include <sys/types.h>
#ifdef __cplusplus
extern "C" {
......@@ -91,7 +89,63 @@ extern int sigprocmask (int operation, const sigset_t *set, sigset_t *old_set);
handler. */
extern void (*signal (int sig, void (*func) (int))) (int);
#endif
#endif /* !@HAVE_POSIX_SIGNALBLOCKING@ */
#if !@HAVE_SIGACTION@
# if !@HAVE_SIGINFO_T@
/* Present to allow compilation, but unsupported by gnulib. */
union sigval
{
int sival_int;
void *sival_ptr;
};
/* Present to allow compilation, but unsupported by gnulib. */
struct siginfo_t
{
int si_signo;
int si_code;
int si_errno;
pid_t si_pid;
uid_t si_uid;
void *si_addr;
int si_status;
long si_band;
union sigval si_value;
};
typedef struct siginfo_t siginfo_t;
# endif /* !@HAVE_SIGINFO_T@ */
/* Due to autoconf conventions, we can't tell if HAVE_SIGACTION
means we have the type or means we have the function. We assume
that all implementations either have both or neither. */
struct sigaction
{
union
{
void (*_sa_handler) (int);
/* Present to allow compilation, but unsupported by gnulib. POSIX
says that implementations may, but not must, make sa_sigaction
overlap with sa_handler, but we know of no implementation where
they do not overlap. */
void (*_sa_sigaction) (int, siginfo_t *, void *);
} _sa_func;
sigset_t sa_mask;
/* Not all POSIX flags are supported. */
int sa_flags;
};
# define sa_handler _sa_func._sa_handler
# define sa_sigaction _sa_func._sa_sigaction
/* Unsupported flags are not present. */
# define SA_RESETHAND 1
# define SA_NODEFER 2
extern int sigaction (int, const struct sigaction *restrict,
struct sigaction *restrict);
#endif /* !@HAVE_SIGACTION@ */
#ifdef __cplusplus
......
# sigaction.m4 serial 1
dnl Copyright (C) 2008 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.
# Determine if sigaction interface is present.
AC_DEFUN([gl_SIGACTION],
[
dnl Due to autoconf conventions, we can't tell if HAVE_SIGACTION
dnl means we have the type or means we have the function. We assume
dnl that all implementations either have both or neither.
AC_REPLACE_FUNCS([sigaction])
if test $ac_cv_func_sigaction = no ; then
HAVE_SIGACTION=0
AC_SUBST([HAVE_SIGACTION])
gl_PREREQ_SIGACTION
fi
])
# Prerequisites of the part of lib/signal.in.h and of lib/sigprocmask.c.
AC_DEFUN([gl_PREREQ_SIGACTION],
[
AC_REQUIRE([AC_C_RESTRICT])
AC_REQUIRE([AC_TYPE_UID_T])
AC_REQUIRE([gl_SIGNAL_H_DEFAULTS])
AC_CHECK_FUNCS_ONCE([sigaltstack siginterrupt])
AC_CHECK_TYPES([siginfo_t], [], [], [[
#include <signal.h>
]])
if test $ac_cv_type_siginfo_t = no; then
HAVE_SIGINFO_T=0
AC_SUBST([HAVE_SIGINFO_T])
fi
])
# signal_h.m4 serial 3
dnl Copyright (C) 2007 Free Software Foundation, Inc.
# signal_h.m4 serial 4
dnl Copyright (C) 2007, 2008 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.
......@@ -20,7 +20,10 @@ AC_DEFUN([gl_SIGNAL_MODULE_INDICATOR],
AC_DEFUN([gl_SIGNAL_H_DEFAULTS],
[
GNULIB_SIGPROCMASK=0; AC_SUBST([GNULIB_SIGPROCMASK])
GNULIB_SIGACTION=0; AC_SUBST([GNULIB_SIGACTION])
dnl Assume proper GNU behavior unless another module says otherwise.
HAVE_POSIX_SIGNALBLOCKING=1; AC_SUBST([HAVE_POSIX_SIGNALBLOCKING])
HAVE_SIGSET_T=1; AC_SUBST([HAVE_SIGSET_T])
HAVE_SIGINFO_T=1; AC_SUBST([HAVE_SIGINFO_T])
HAVE_SIGACTION=1; AC_SUBST([HAVE_SIGACTION])
])
Description:
POSIX compatible signal handlers.
Files:
lib/sigaction.c
m4/sigaction.m4
Depends-on:
signal
sigprocmask
configure.ac:
gl_SIGACTION
gl_SIGNAL_MODULE_INDICATOR([sigaction])
Makefile.am:
Include:
<signal.h>
License:
LGPL
Maintainer:
Eric Blake
Files:
tests/test-sigaction.c
Depends-on:
configure.ac:
Makefile.am:
TESTS += test-sigaction
check_PROGRAMS += test-sigaction
......@@ -23,8 +23,11 @@ signal.h: signal.in.h
sed -e 's/@''INCLUDE_NEXT''@/$(INCLUDE_NEXT)/g' \
-e 's|@''NEXT_SIGNAL_H''@|$(NEXT_SIGNAL_H)|g' \
-e 's|@''GNULIB_SIGPROCMASK''@|$(GNULIB_SIGPROCMASK)|g' \
-e 's|@''GNULIB_SIGACTION''@|$(GNULIB_SIGACTION)|g' \
-e 's|@''HAVE_POSIX_SIGNALBLOCKING''@|$(HAVE_POSIX_SIGNALBLOCKING)|g' \
-e 's|@''HAVE_SIGSET_T''@|$(HAVE_SIGSET_T)|g' \
-e 's|@''HAVE_SIGINFO_T''@|$(HAVE_SIGINFO_T)|g' \
-e 's|@''HAVE_SIGACTION''@|$(HAVE_SIGACTION)|g' \
-e '/definition of GL_LINK_WARNING/r $(LINK_WARNING_H)' \
< $(srcdir)/signal.in.h; \
} > $@-t
......
/* Test of sigaction() function.
Copyright (C) 2008 Free Software Foundation, Inc.
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 3 of the License, 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, see <http://www.gnu.org/licenses/>. */
/* Written by Eric Blake <ebb9@byu.net>, 2008. */
#include <config.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#define ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
fflush (stderr); \
signal (SIGABRT, SIG_DFL); \
abort (); \
} \
} \
while (0)
#ifndef SA_SIGINFO
# define SA_SIGINFO 0
#endif
/* This test is unsafe in the presence of an asynchronous SIGABRT,
because we install a signal-handler that is intentionally not
async-safe. Hopefully, this does not lead to too many reports of
false failures, since people don't generally use 'kill -s SIGABRT'
to end a runaway program. */
static void
handler (int sig)
{
static int entry_count;
struct sigaction sa;
ASSERT (sig == SIGABRT);
ASSERT (sigaction (SIGABRT, NULL, &sa) == 0);
ASSERT ((sa.sa_flags & SA_SIGINFO) == 0);
switch (entry_count++)
{
case 0:
ASSERT ((sa.sa_flags & SA_RESETHAND) == 0);
ASSERT (sa.sa_handler == handler);
break;
case 1:
ASSERT (sa.sa_handler == SIG_DFL);
break;
default:
ASSERT (0);
}
}
int
main (int argc, char *argv[])
{
struct sigaction sa;
struct sigaction old_sa;
sa.sa_handler = handler;
sa.sa_flags = 0;
ASSERT (sigemptyset (&sa.sa_mask) == 0);
ASSERT (sigaction (SIGABRT, &sa, NULL) == 0);
ASSERT (raise (SIGABRT) == 0);
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
ASSERT (sigaction (SIGABRT, &sa, &old_sa) == 0);
ASSERT (old_sa.sa_flags == 0);
ASSERT (old_sa.sa_handler == handler);
ASSERT (raise (SIGABRT) == 0);
sa.sa_handler = SIG_DFL;
ASSERT (sigaction (SIGABRT, &sa, &old_sa) == 0);
ASSERT ((old_sa.sa_flags & SA_SIGINFO) == 0);
ASSERT (old_sa.sa_handler == SIG_DFL);
sa.sa_handler = SIG_IGN;
ASSERT (sigaction (SIGABRT, &sa, NULL) == 0);
ASSERT (raise (SIGABRT) == 0);
ASSERT (sigaction (SIGABRT, NULL, &old_sa) == 0);
ASSERT (old_sa.sa_handler == SIG_IGN);
ASSERT (raise (SIGABRT) == 0);
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment