The logic of sigset() (sysdeps/posix/sigset.c) is tangled: when a signal is blocked, it does not correctly return the previous disposition of the signal in cases where the signal is currently blocked, or where the disposition is being set to SIG_HOLD. SUSv3 says the following: Upon successful completion, sigset() shall return SIG_HOLD if the signal had been blocked and the signal's previous disposition if it had not been blocked. Otherwise, SIG_ERR shall be returned and errno set to indicate the error. In other words: -- if the signal is currently blocked, then the return value of of a successful sigset() should always be SIG_HOLD, regardless of whether or not SIG_HOLD was specified as the new disposition. "TEST 1" below shows that glibc sigset() does not do this. -- A successful sigset() call that specifies the new disposition as SIG_HOLD should return the previous disposition of the signal. Instead (see "TEST 2" below), glibc sigset() always returns SIG_HOLD in this case. I have included a test program at the foot of this mail. When run on Linux/x86 glibc 2.3.5 (SUSE 10.0), we see the following: Linux tekapo 2.6.15-rc1-mm2 #6 SMP PREEMPT Wed Nov 23 12:50:50 CET 2005 i686 i686 i386 GNU/Linux Wed Nov 30 13:38:12 CET 2005 ===== TEST 1 ===== Blocking signal with sighold() Signal mask after sighold() 2 (Interrupt) About to use sigset() to establish handler Previous disposition: SIG_DFL (should be SIG_HOLD) TEST FAILED!!! ===== TEST 2 ===== About to use sigset() to set SIG_HOLD Previous disposition: SIG_HOLD (should be SIG_DFL) TEST FAILED!!! ===== TEST 3 ===== About to use sigset() to set SIG_HOLD About to use sigset() to set SIG_HOLD (again) Previous disposition: SIG_HOLD (should be SIG_HOLD) By contrast, here are the results on Solaris 8: SunOS sunbox 5.8 Generic_108528-27 sun4u sparc SUNW,Ultra-4 Wed Nov 30 13:41:34 MET 2005 ===== TEST 1 ===== Blocking signal with sighold() Signal mask after sighold() 2 (Interrupt) About to use sigset() to establish handler Previous disposition: SIG_HOLD (should be SIG_HOLD) ===== TEST 2 ===== About to use sigset() to set SIG_HOLD Previous disposition: SIG_DFL (should be SIG_DFL) ===== TEST 3 ===== About to use sigset() to set SIG_HOLD About to use sigset() to set SIG_HOLD (again) Previous disposition: SIG_HOLD (should be SIG_HOLD) And on HP-UX 11: HP-UX td192 B.11.11 U 9000/800 1839940656 unlimited-user license Wed Nov 30 07:42:00 EST 2005 ===== TEST 1 ===== Blocking signal with sighold() Signal mask after sighold() 2 (SIG-2) About to use sigset() to establish handler Previous disposition: SIG_HOLD (should be SIG_HOLD) ===== TEST 2 ===== About to use sigset() to set SIG_HOLD Previous disposition: SIG_DFL (should be SIG_DFL) ===== TEST 3 ===== About to use sigset() to set SIG_HOLD About to use sigset() to set SIG_HOLD (again) Previous disposition: SIG_HOLD (should be SIG_HOLD) Cheers, Michael ========================== /* sigset_SIG_HOLD_bug.c */ #ifdef __sun #define __EXTENSIONS__ /* To get NSIG defn */ #endif #define _GNU_SOURCE #define _XOPEN_SOURCE 500 #include <signal.h> #include <sys/types.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #define TEST_SIG SIGINT typedef void (*sighandler_t)(int); #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) #ifdef __hpux /* A very minimal implementation of strsignal()... */ #define BUF_SIZE 100 char * strsignal(int sig) { static char buf[BUF_SIZE]; snprintf(buf, BUF_SIZE, "SIG-%d", sig); return buf; } /* strsignal */ #endif static void /* Print mask of blocked signals for this process */ printSigMask(const char *msg) { sigset_t currMask; int sig, cnt; if (msg != NULL) printf("%s", msg); if (sigprocmask(SIG_BLOCK, NULL, &currMask) == -1) errExit("sigaction"); cnt = 0; for (sig = 1; sig < NSIG; sig++) { if (sigismember(&currMask, sig)) { cnt++; printf("\t\t%d (%s)\n", sig, strsignal(sig)); } } if (cnt == 0) printf("\t\t<empty signal set>\n"); } /* printSigMask */ static void handler(int sig) { printf("Caught signal %d\n", sig); printSigMask("Signal mask in handler\n"); sleep(3); printf("Handler returning\n"); } /* handler */ static void printDisposition(sighandler_t disp) { if (disp == SIG_HOLD) printf("SIG_HOLD"); else if (disp == SIG_DFL) printf("SIG_DFL"); else if (disp == SIG_IGN) printf("SIG_IGN"); else printf("handled at %lx", (long) disp); } /* printDisposition */ static void returnTest1(void) { sighandler_t prev; printf("===== TEST 1 =====\n"); printf("Blocking signal with sighold()\n"); if (sighold(TEST_SIG) == -1)errExit("sighold"); printSigMask("Signal mask after sighold()\n"); printf("About to use sigset() to establish handler\n"); prev = sigset(TEST_SIG, handler); if (prev == SIG_ERR) errExit("sigset"); printf("Previous disposition: "); printDisposition(prev); printf(" (should be SIG_HOLD)\n"); if (prev != SIG_HOLD) printf("TEST FAILED!!!\n"); } /* returnTest1 */ static void returnTest2(void) { sighandler_t prev; printf("\n===== TEST 2 =====\n"); printf("About to use sigset() to set SIG_HOLD\n"); prev = sigset(TEST_SIG, SIG_HOLD); if (prev == SIG_ERR) errExit("sigset"); printf("Previous disposition: "); printDisposition(prev); printf(" (should be SIG_DFL)\n"); if (prev != SIG_DFL) printf("TEST FAILED!!!\n"); } /* returnTest2 */ static void returnTest3(void) { sighandler_t prev; printf("\n===== TEST 3 =====\n"); printf("About to use sigset() to set SIG_HOLD\n"); prev = sigset(TEST_SIG, SIG_HOLD); if (prev == SIG_ERR) errExit("sigset"); printf("About to use sigset() to set SIG_HOLD (again)\n"); prev = sigset(TEST_SIG, SIG_HOLD); if (prev == SIG_ERR) errExit("sigset"); printf("Previous disposition: "); printDisposition(prev); printf(" (should be SIG_HOLD)\n"); if (prev != SIG_HOLD) printf("TEST FAILED!!!\n"); } /* returnTest3 */ int main(int argc, char *argv[]) { pid_t childPid; system("uname -a; date\n"); childPid = fork(); if (childPid == -1) errExit("fork"); if (childPid == 0) { returnTest1(); exit(EXIT_SUCCESS); } else wait(NULL); childPid = fork(); if (childPid == -1) errExit("fork"); if (childPid == 0) { returnTest2(); exit(EXIT_SUCCESS); } else wait(NULL); childPid = fork(); if (childPid == -1) errExit("fork"); if (childPid == 0) { returnTest3(); exit(EXIT_SUCCESS); } else wait(NULL); exit(EXIT_SUCCESS); } /* main */
I've checked in a patch which adjusts the return value. I also added the test case. But the man page should say that this behavior is useful only (if ever) in signal threaded code. The handler is a process property and other threads might as well change it. The result if sigset cannot be used to reliably restore the previous signal setting.
Subject: Re: sigset() does not correctly return SIG_HOLD > I've checked in a patch which adjusts the return value. I > also added the test case. Thanks. > But the man page should say that this behavior is useful only (if ever) in > signal threaded code. The handler is a process property and other threads > might as well change it. The result if sigset cannot be used to reliably > restore the previous signal setting. Yes, the same comments hold for signal() and sigaction() too. Maybe I will add something to signal(7) on this point.
*** Bug 260998 has been marked as a duplicate of this bug. *** Seen from the domain http://volichat.com Page where seen: http://volichat.com/adult-chat-rooms Marked for reference. Resolved as fixed @bugzilla.