changeset 27194:ff45a735a164

New module 'sigprocmask'.
author Bruno Haible <bruno@clisp.org>
date Mon, 16 Oct 2006 11:55:35 +0000
parents ad10f91db6fc
children d29433257548
files ChangeLog MODULES.html.sh lib/fatal-signal.c lib/sigprocmask.c lib/sigprocmask.h m4/fatal-signal.m4 m4/signalblocking.m4 modules/fatal-signal modules/sigprocmask
diffstat 9 files changed, 324 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Sun Oct 15 22:38:35 2006 +0000
+++ b/ChangeLog	Mon Oct 16 11:55:35 2006 +0000
@@ -1,3 +1,22 @@
+2006-10-14  Bruno Haible  <bruno@clisp.org>
+
+	* 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  <eggert@cs.ucla.edu>
 
 	Sync from Automake.
--- a/MODULES.html.sh	Sun Oct 15 22:38:35 2006 +0000
+++ b/MODULES.html.sh	Mon Oct 16 11:55:35 2006 +0000
@@ -1849,6 +1849,7 @@
   func_module regex
   func_module rename
   func_module rmdir
+  func_module sigprocmask
   func_module ssize_t
   func_module strtok_r
   func_module sys_stat
--- a/lib/fatal-signal.c	Sun Oct 15 22:38:35 2006 +0000
+++ b/lib/fatal-signal.c	Mon Oct 16 11:55:35 2006 +0000
@@ -27,6 +27,7 @@
 #include <signal.h>
 #include <unistd.h>
 
+#include "sigprocmask.h"
 #include "xalloc.h"
 
 #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
@@ -231,8 +232,6 @@
 /* ========================================================================= */
 
 
-#if HAVE_POSIX_SIGNALBLOCKING
-
 static sigset_t fatal_signal_set;
 
 static void
@@ -269,20 +268,3 @@
   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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/sigprocmask.c	Mon Oct 16 11:55:35 2006 +0000
@@ -0,0 +1,192 @@
+/* POSIX compatible signal blocking.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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 <config.h>
+
+/* Specification.  */
+#include "sigprocmask.h"
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* 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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/sigprocmask.h	Mon Oct 16 11:55:35 2006 +0000
@@ -0,0 +1,64 @@
+/* POSIX compatible signal blocking.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+   Written by Bruno Haible <bruno@clisp.org>, 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 <signal.h>
+
+#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
--- a/m4/fatal-signal.m4	Sun Oct 15 22:38:35 2006 +0000
+++ b/m4/fatal-signal.m4	Mon Oct 16 11:55:35 2006 +0000
@@ -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)
 ])
--- a/m4/signalblocking.m4	Sun Oct 15 22:38:35 2006 +0000
+++ b/m4/signalblocking.m4	Mon Oct 16 11:55:35 2006 +0000
@@ -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 @@
 # 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)
+])
--- a/modules/fatal-signal	Sun Oct 15 22:38:35 2006 +0000
+++ b/modules/fatal-signal	Mon Oct 16 11:55:35 2006 +0000
@@ -5,13 +5,13 @@
 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/modules/sigprocmask	Mon Oct 16 11:55:35 2006 +0000
@@ -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
+