bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

new module 'sigprocmask'


From: Bruno Haible
Subject: new module 'sigprocmask'
Date: Fri, 13 Oct 2006 14:45:24 +0200
User-agent: KMail/1.9.1

Hi,

The 'fatal-signal' module attempts to guarantee a certain cleanup action.
In order to do so without race conditions, it needs to block signals for a
certain time. But on Woe32 (msvc, mingw), there is no sigprocmask(),
no sighold(), no sigblock().

Likewise for the color output facility in GNU ls and (soon also) GNU msgcat.

This module adds a sigprocmask() emulation based on signal().

Comments are welcome, as this is new and so far untested code.

Bruno


2006-10-12  Bruno Haible  <address@hidden>

        * 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.

*** /dev/null   2003-09-23 19:59:22.000000000 +0200
--- gnulib-20061012-modified/modules/sigprocmask        2006-10-13 
03:36:47.000000000 +0200
***************
*** 0 ****
--- 1,24 ----
+ Description:
+ POSIX compatible signal blocking.
+ 
+ Files:
+ lib/sigprocmask.h
+ lib/sigprocmask.c
+ m4/signalblocking.m4
+ 
+ Depends-on:
+ 
+ configure.ac:
+ gl_SIGNALBLOCKING
+ 
+ Makefile.am:
+ 
+ Include:
+ "sigprocmask.h"
+ 
+ License:
+ LGPL
+ 
+ Maintainer:
+ Bruno Haible
+ 
*** /dev/null   2003-09-23 19:59:22.000000000 +0200
--- gnulib-20061012-modified/lib/sigprocmask.h  2006-10-13 03:53:03.000000000 
+0200
***************
*** 0 ****
--- 1,64 ----
+ /* POSIX compatible signal blocking.
+    Copyright (C) 2006 Free Software Foundation, Inc.
+    Written by Bruno Haible <address@hidden>, 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
*** /dev/null   2003-09-23 19:59:22.000000000 +0200
--- gnulib-20061012-modified/lib/sigprocmask.c  2006-10-13 03:57:50.000000000 
+0200
***************
*** 0 ****
--- 1,191 ----
+ /* POSIX compatible signal blocking.
+    Copyright (C) 2006 Free Software Foundation, Inc.
+    Written by Bruno Haible <address@hidden>, 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 <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);
+   return 0;
+ }
+ 
+ /* Set of currently blocked signals.  */
+ static sigset_t blocked_set /* = 0 */;
+ 
+ /* Set of currently blocked and pending signals.  */
+ static volatile char 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)
+       {
+         char 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;
+ }
*** gnulib-20061012/m4/signalblocking.m4        2005-01-18 14:07:56.000000000 
+0100
--- gnulib-20061012-modified/m4/signalblocking.m4       2006-10-13 
03:40:07.000000000 +0200
***************
*** 1,5 ****
! # signalblocking.m4 serial 1 (gettext-0.11)
! dnl Copyright (C) 2001-2002 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.
--- 1,5 ----
! # 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,21 ****
  # 2) SYSV: sighold, sigrelse
  # 3) BSD: sigblock, sigsetmask
  # For simplicity, here we check only for the POSIX signal blocking.
! AC_DEFUN([gt_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.]))
    fi
  ])
--- 9,31 ----
  # 2) SYSV: sighold, sigrelse
  # 3) BSD: sigblock, sigsetmask
  # For simplicity, here we check only for the POSIX signal blocking.
! 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, [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)
  ])
*** gnulib-20061012/modules/fatal-signal        2006-04-24 13:38:06.000000000 
+0200
--- gnulib-20061012-modified/modules//fatal-signal      2006-10-13 
03:33:44.000000000 +0200
***************
*** 5,17 ****
  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
  
  configure.ac:
  gl_FATAL_SIGNAL
--- 5,17 ----
  lib/fatal-signal.h
  lib/fatal-signal.c
  m4/fatal-signal.m4
  m4/sig_atomic_t.m4
  
  Depends-on:
  xalloc
  stdbool
  unistd
+ sigprocmask
  
  configure.ac:
  gl_FATAL_SIGNAL
*** gnulib-20061012/m4/fatal-signal.m4  2005-01-18 14:07:56.000000000 +0100
--- gnulib-20061012-modified/m4/fatal-signal.m4 2006-10-13 03:35:15.000000000 
+0200
***************
*** 1,13 ****
! # fatal-signal.m4 serial 3
! dnl Copyright (C) 2003-2004 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)
  ])
--- 1,13 ----
! # 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_TYPE_SIG_ATOMIC_T])
    AC_CHECK_HEADERS_ONCE(unistd.h)
!   AC_CHECK_FUNCS_ONCE(raise)
!   AC_CHECK_FUNCS(sigaction)
  ])
*** gnulib-20061012/lib/fatal-signal.c  2006-10-07 01:01:48.000000000 +0200
--- gnulib-20061012-modified/lib/fatal-signal.c 2006-10-13 03:34:33.000000000 
+0200
***************
*** 27,32 ****
--- 27,33 ----
  #include <signal.h>
  #include <unistd.h>
  
+ #include "sigprocmask.h"
  #include "xalloc.h"
  
  #define SIZEOF(a) (sizeof(a) / sizeof(a[0]))
***************
*** 231,238 ****
  /* ========================================================================= 
*/
  
  
- #if HAVE_POSIX_SIGNALBLOCKING
- 
  static sigset_t fatal_signal_set;
  
  static void
--- 236,241 ----
***************
*** 269,288 ****
    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
--- 272,274 ----




reply via email to

[Prev in Thread] Current Thread [Next in Thread]