Hi,
Please read this post first:
https://cygwin.com/ml/cygwin/2017-08/msg00048.html
( Signal delivered while blocked -- by Noah Misch, August 4th 2017 )
This post is not intended to "hijack" the post by Noah Misch; this post
only
ships an alternative (i.e. revised) testcase for the one by provided by
Noah
Misch.
The alternative testcase in fact consists of 2 testcases (2 files):
1. sigprocmask-exclusion4.c
2. sigprocmask-exclusion5.c
The 1st testcase uses sigaction() (i.c. sa_mask) in order to keep both
signal
handlers "out of each other's hair".
The 2nd testcase achieves this by protecting the "vital part" of each of
the
signal handlers using sigprocmask() ...
Using sigprocmask() and SIG_BLOCK (1st argument), the other signal is
added
to the signal mask at the start of the "vital part" of the signal
handler.
To restore the signal mask at the end of the "vital part" of the
handler, it
is possible to choose between the following options:
a. using sigprocmask() and SIG_SETMASK in order to reinstate the mask
as it
was at the beginning of the "vital part" of the handler
b. using sigprocmask() and SIG_UNBLOCK to remove the other signal from
the
signal mask
Both testcases confirm that Cygwin _sometimes_ delivers a signal,
although
the signal mask specifies (verified by the test case) it should not.
Typical runs:
64-@@ ./sigprocmask-exclusion4
-
pid=2728 inundating pid=3504 with SIGUSR1 and SIGCHLD
--
ERROR: handler2: No 1 running
cnt_usr1 = 424, cnt_chld = 305, cnt_int = 0
ERROR: handler2: No 1 running
cnt_usr1 = 1212, cnt_chld = 1262, cnt_int = 0
ERROR: handler: No 2 running
cnt_usr1 = 4341, cnt_chld = 3827, cnt_int = 0
ERROR: handler: No 2 running
cnt_usr1 = 5289, cnt_chld = 4171, cnt_int = 0
ERROR: handler: No 2 running
cnt_usr1 = 5499, cnt_chld = 4354, cnt_int = 0
ERROR: handler: No 2 running
cnt_usr1 = 6769, cnt_chld = 6295, cnt_int = 0
ERROR: handler2: nesting self!
cnt_usr1 = 10463, cnt_chld = 9243, cnt_int = 0
ERROR: handler2: nesting self!
cnt_usr1 = 12390, cnt_chld = 10869, cnt_int = 0
ERROR: handler: No 2 running
cnt_usr1 = 14046, cnt_chld = 14771, cnt_int = 0
ERROR: handler2: No 1 running
cnt_usr1 = 16111, cnt_chld = 15785, cnt_int = 0
cnt_usr1 = 16959, cnt_chld = 16790, cnt_int = 1
child done
xcnt_usr1 = 13295798, xcnt_chld = 13295797
64-@@
64-@@ ./sigprocmask-exclusion5
-
--
pid=4132 inundating pid=5976 with SIGUSR1 and SIGCHLD
ERROR: handler: No 2 running
cnt_usr1 = 1, cnt_chld = 2, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 228, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 1444, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 1585, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 1830, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 2588, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 2719, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 2795, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 3332, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 3340, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 3353, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 4130, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 4136, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 5256, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 6548, cnt_chld = 6, cnt_int = 0
ERROR: handler: nesting self!
cnt_usr1 = 8292, cnt_chld = 6, cnt_int = 0
cnt_usr1 = 11223, cnt_chld = 6, cnt_int = 1
child done
xcnt_usr1 = 4149717, xcnt_chld = 4149717
64-@@
Both runs were terminated by SIGINT (^C).
When running for an extended period (hours), the run-away stack did not
show
up (Linux).
Environment:
64-@@ uname -a
CYGWIN_NT-6.1 Seven 2.9.0(0.316/5/3) x86_64 Cygwin
64-@@ gcc --version
gcc (GCC) 5.4.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is
NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE
Regards,
Henri
// gcc -std=c11 -D_POSIX_SOURCE -o sigprocmask-exclusion sigprocmask-exclusion.c
// gcc -std=c11 -D_DEFAULT_SOURCE -o sigprocmask-exclusion sigprocmask-exclusion.c
/* ... cfm 2
kopie van origineel
gewijzigd:
- forbid, permit verwijderd (forbid en permit opgenomen in main() )
- handlers: geen bewerking van het signal mask
- sigaction: het andere signal wordt verhinderd
this test case fails on Cygwin; period!
*/
/*
* Demonstrate improper delivery of a blocked signal.
*
* This program prints "ERROR: already forbidden" and aborts within one
* second on this configuration (uname -srvm):
* CYGWIN_NT-10.0 2.7.0(0.306/5/3) 2017-02-12 13:18 x86_64
*
* It runs indefinitely (>600s) without trouble on these configurations:
* CYGWIN_NT-6.0 1.7.27(0.271/5/3) 2013-12-09 11:57 i686
* Linux 3.10.0-514.16.1.el7.x86_64 #1 SMP Wed Apr 12 15:04:24 UTC 2017 x86_64 [CentOS 7]
* AIX 7100-03-02-1412
* SunOS 5.10 Generic_147147-26 sun4u
*/
#include <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static sigset_t block, unblock;
static char *stack_base;
static sigjmp_buf jmp;
static int cnt_usr1; static int cnt_chld = 0; static int cnt_int = 0;
static volatile sig_atomic_t i = 0;
static volatile sig_atomic_t j = 0;
static int r = 0;
static ptrdiff_t stack_usage_prev = 0;
/*
* Start fresh in main() when the stack gets too deep. This is not essential
* to the test, but it allows for long runs without huge RLIMIT_STACK.
*/
static void
clear_stack_if_needed(void)
{
char stack_position;
ptrdiff_t stack_usage;
stack_usage = stack_base - &stack_position;
if (stack_usage < 0)
{
puts("NEGATIVE");
stack_usage = -stack_usage;
}
#if 0
if (stack_usage != stack_usage_prev) {
printf("stack_usage: %d\n", stack_usage);
stack_usage_prev = stack_usage;
}
#endif
//if (stack_usage > 1024 * 1024)
if (stack_usage > 4 * 1024) // 4 = 4096, 5 => 5120, 6 => 6144
{
//sigprocmask(SIG_SETMASK, &block, NULL);
puts("releasing excess stack");
//abort(); // if SA_NODEFER has been specified
siglongjmp(jmp, 1);
}
}
static void
handler(int arg)
{
const char errmsg[] = "ERROR: handler: No 2 running\n";
const char errmsg2[] = "ERROR: handler: nesting self!\n";
cnt_usr1++;
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerB: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerB: CHLD missing");
}
#endif
//puts("H ");
if (i == 1) {
write(2, errmsg2, sizeof(errmsg2) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
if (j == 1) {
write(2, errmsg, sizeof(errmsg) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
i = 1;
clear_stack_if_needed();
usleep(5000);
i = 0;
//puts("H-e ");
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerE: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerE: CHLD missing");
}
#endif
}
static void
handler2(int arg)
{
const char errmsg[] = "ERROR: handler2: No 1 running\n";
const char errmsg2[] = "ERROR: handler2: nesting self!\n";
cnt_chld++;
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2B: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2B: CHLD missing");
}
#endif
//puts(" H2");
if (j == 1) {
write(2, errmsg2, sizeof(errmsg2) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
if (i == 1) {
write(2, errmsg, sizeof(errmsg) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
j = 1;
clear_stack_if_needed();
usleep(5000);
j = 0;
//puts(" H2-e");
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2E: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2E: CHLD missing");
}
#endif
}
#if 1
static void
handler3(int arg) // note: exhibits racing between bash and child
{
cnt_int++;
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int);
}
#endif
int main(int argc, char **argv)
{
char stack_position;
/* initial signal mask setup */
r = sigemptyset(&unblock);
r = sigfillset(&block);
r = sigdelset(&block, SIGTRAP);
r = sigdelset(&block, SIGABRT);
r = sigdelset(&block, SIGILL);
r = sigdelset(&block, SIGFPE);
r = sigdelset(&block, SIGSEGV);
r = sigdelset(&block, SIGBUS);
r = sigdelset(&block, SIGSYS);
r = sigdelset(&block, SIGCONT);
if (r != 0) puts("retval0");
if (sigprocmask(SIG_SETMASK, &block, NULL) != 0) // forbid
perror("sigprocmask");
/* Register signal handlers. Problem somehow requires two signals. */
{
struct sigaction act, oact;
// the sa_mask is only applied during the execution of the handler
act.sa_handler = handler;
r = sigemptyset(&act.sa_mask); // however SIGUSR is auto added to mask during execution of the handler, is it not?
r = sigaddset(&act.sa_mask, SIGCHLD); // added
if (r != 0) puts("retval1");
act.sa_flags = 0;
//act.sa_flags = SA_NODEFER; // be stupid
if (sigaction(SIGUSR1, &act, &oact) != 0)
perror("sigaction");
struct sigaction act2, oact2;
act2.sa_handler = handler2;
r = sigemptyset(&act2.sa_mask);
r = sigaddset(&act2.sa_mask, SIGUSR1); // added
if (r != 0) puts("retval2");
act2.sa_flags = 0;
//act2.sa_flags = SA_NODEFER; // be stupid
if (sigaction(SIGCHLD, &act2, &oact2) != 0)
perror("sigaction");
#if 1
struct sigaction act3, oact3;
act3.sa_handler = handler3;
r = sigfillset(&act3.sa_mask);
r = sigdelset(&act3.sa_mask, SIGINT); // remove
if (r != 0) puts("retval3");
act3.sa_flags = SA_RESETHAND;
if (sigaction(SIGINT, &act3, &oact3) != 0)
perror("sigaction");
#endif
}
/* start a child to inundate me with signals */
{
pid_t pid, ppid;
pid = fork();
switch (pid)
{
case -1:
perror("fork");
return 1;
case 0:
ppid = getppid();
printf("pid=%d inundating pid=%d with SIGUSR1 and SIGCHLD\n",
getpid(), ppid);
#if 0
while (kill(ppid, random() % 2 ? SIGUSR1 : SIGCHLD) == 0)
;
#else
volatile int i = 0;
//volatile int i = 1;
int xcnt_usr1 = 0; int xcnt_chld = 0;
while (1) {
i = i ? 0 : 1;
if (1) {
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
} else {
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
}
#if defined(__linux__)
usleep(10000); // if disabled, cnt_chld stays zero ?????
// enabled: 2 : 1, disabled: 100.000 : 1
#endif
#if defined(__CYGWIN__)
//usleep(10000); // if disabled, it will fail (abort) after some time (... nesting?)
// enabled: 10 : 1, disabled: 1000 : 1
#endif
}
#endif
puts("child done");
printf("xcnt_usr1 = %d, xcnt_chld = %d\n", xcnt_usr1, xcnt_chld);
return 0;
}
}
/* loop forever while we receive signals */
stack_base = &stack_position;
sigsetjmp(jmp, 1);
for (;;)
{
puts("-");
if (sigprocmask(SIG_SETMASK, &unblock, NULL) != 0) // permit
perror("sigprocmask");
puts("--");
usleep(1000);
puts("---");
if (sigprocmask(SIG_SETMASK, &block, NULL) != 0) // forbid
perror("sigprocmask");
puts("----");
}
}
// gcc -std=c11 -D_POSIX_SOURCE -o sigprocmask-exclusion sigprocmask-exclusion.c
// gcc -std=c11 -D_DEFAULT_SOURCE -o sigprocmask-exclusion sigprocmask-exclusion.c
// if defined than the original signal mask is restored(SIG_SETMASK); otherwise the signal is removed from the mask (SIG_UNBLOCK)
//#define option1
/* ... cfm 3
kopie van origineel
gewijzigd:
- forbid, permit verwijderd (forbid en permit opgenomen in main() )
- handlers: toevoeging en verwijdering van het andere signal
- options: 1. either restore original mask (using SIG_SETMASK) or 2. removal signal from mask (using SIG_UNBLOCK)
- 1st option fails after a long while, 2nd option fails mostly fails immediately
- sigaction: het andere signal wordt niet verhinderd
this test case fails on Cygwin; immediately when the 2nd option is used, after some time when the 1st option is used
*/
/*
* Demonstrate improper delivery of a blocked signal.
*
* This program prints "ERROR: already forbidden" and aborts within one
* second on this configuration (uname -srvm):
* CYGWIN_NT-10.0 2.7.0(0.306/5/3) 2017-02-12 13:18 x86_64
*
* It runs indefinitely (>600s) without trouble on these configurations:
* CYGWIN_NT-6.0 1.7.27(0.271/5/3) 2013-12-09 11:57 i686
* Linux 3.10.0-514.16.1.el7.x86_64 #1 SMP Wed Apr 12 15:04:24 UTC 2017 x86_64 [CentOS 7]
* AIX 7100-03-02-1412
* SunOS 5.10 Generic_147147-26 sun4u
*/
#include <setjmp.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static sigset_t block, unblock;
static char *stack_base;
static sigjmp_buf jmp;
static int cnt_usr1; static int cnt_chld = 0; static int cnt_int = 0;
static volatile sig_atomic_t i = 0;
static volatile sig_atomic_t j = 0;
static int r = 0;
static ptrdiff_t stack_usage_prev = 0;
/*
* Start fresh in main() when the stack gets too deep. This is not essential
* to the test, but it allows for long runs without huge RLIMIT_STACK.
*/
static void
clear_stack_if_needed(void)
{
char stack_position;
ptrdiff_t stack_usage;
stack_usage = stack_base - &stack_position;
if (stack_usage < 0)
{
puts("NEGATIVE");
stack_usage = -stack_usage;
}
#if 0
if (stack_usage != stack_usage_prev) {
printf("stack_usage: %d\n", stack_usage);
stack_usage_prev = stack_usage;
}
#endif
//if (stack_usage > 1024 * 1024)
if (stack_usage > 5 * 1024) // 5 => 5120, 6 => 6144
{
//sigprocmask(SIG_SETMASK, &block, NULL);
puts("releasing excess stack");
//abort(); // if SA_NODEFER has been specified
siglongjmp(jmp, 1);
}
}
static void
handler(int arg)
{
const char errmsg[] = "ERROR: handler: No 2 running\n";
const char errmsg2[] = "ERROR: handler: nesting self!\n";
sigset_t set, oset;
r= sigemptyset(&set);
r = sigaddset(&set, SIGCHLD);
if (r != 0) puts("retvalH1");
if (sigprocmask(SIG_BLOCK, &set, &oset) != 0) // voeg toe
perror("sigprocmask");
cnt_usr1++;
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerB: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerB: CHLD missing");
}
#endif
//puts("H ");
if (i == 1) {
write(2, errmsg2, sizeof(errmsg2) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
if (j == 1) {
write(2, errmsg, sizeof(errmsg) - 1);
// whoa, not shown ... ?????
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
i = 1;
clear_stack_if_needed();
usleep(5000);
i = 0;
//puts("H-e ");
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerE: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handlerE: CHLD missing");
}
#endif
#if defined(option1)
if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) // herstel
perror("sigprocmask");
#else
r = sigdelset(&set, SIGCHLD);
if (r != 0) puts("retvalH1b");
if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) // verwijder
perror("sigprocmask");
// Cygwin: aborts, almost immediately
#endif
}
static void
handler2(int arg)
{
const char errmsg[] = "ERROR: handler2: No 1 running\n";
const char errmsg2[] = "ERROR: handler2: nesting self!\n";
sigset_t set, oset;
r = sigemptyset(&set);
r = sigaddset(&set, SIGUSR1);
if (r != 0) puts("retvalH2");
if (sigprocmask(SIG_BLOCK, &set, &oset) != 0) // voeg toe
perror("sigprocmask");
cnt_chld++;
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2B: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2B: CHLD missing");
}
#endif
//puts(" H2");
if (j == 1) {
write(2, errmsg2, sizeof(errmsg2) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
if (i == 1) {
write(2, errmsg, sizeof(errmsg) - 1);
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int); // not safe
//abort();
}
j = 1;
clear_stack_if_needed();
usleep(5000);
j = 0;
//puts(" H2-e");
#if defined(__CYGWIN__)
{ sigset_t oset;
sigemptyset(&oset);
int rv = 0;
if (sigprocmask(SIG_BLOCK, NULL, &oset) != 0) // fetch current mask/ verify
perror("sigprocmask");
if ( (rv = sigismember(&oset, SIGUSR1)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2E: USR1 missing");
if ( (rv = sigismember(&oset, SIGCHLD)) == -1)
perror("sigismember");
if (rv == 0) puts ("handler2E: CHLD missing");
}
#endif
#if defined(option1)
if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) // herstel
perror("sigprocmask");
#else
r = sigdelset(&set, SIGUSR1);
if (r != 0) puts("retvalH2b");
if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) // verwijder
perror("sigprocmask");
#endif
}
#if 1
static void
handler3(int arg) // note: exhibits racing between bash and child
{
cnt_int++;
printf("cnt_usr1 = %d, cnt_chld = %d, cnt_int = %d\n", cnt_usr1, cnt_chld, cnt_int);
}
#endif
int main(int argc, char **argv)
{
char stack_position;
/* initial signal mask setup */
r = sigemptyset(&unblock);
r = sigfillset(&block);
r = sigdelset(&block, SIGTRAP);
r = sigdelset(&block, SIGABRT);
r = sigdelset(&block, SIGILL);
r = sigdelset(&block, SIGFPE);
r = sigdelset(&block, SIGSEGV);
r = sigdelset(&block, SIGBUS);
r = sigdelset(&block, SIGSYS);
r = sigdelset(&block, SIGCONT);
if (r != 0) puts("retval0");
if (sigprocmask(SIG_SETMASK, &block, NULL) != 0) // forbid
perror("sigprocmask");
/* Register signal handlers. Problem somehow requires two signals. */
{
struct sigaction act, oact;
// the sa_mask is only applied during the execution of the handler
act.sa_handler = handler;
r = sigemptyset(&act.sa_mask); // however SIGUSR is auto added to mask during execution of the handler, is it not?
// do it in the handler
//r = sigaddset(&act.sa_mask, SIGCHLD); // added
if (r != 0) puts("retval1");
act.sa_flags = 0;
//act.sa_flags = SA_NODEFER; // be stupid
if (sigaction(SIGUSR1, &act, &oact) != 0)
perror("sigaction");
struct sigaction act2, oact2;
act2.sa_handler = handler2;
r = sigemptyset(&act2.sa_mask);
//r = sigaddset(&act2.sa_mask, SIGUSR1); // added
if (r != 0) puts("retval2");
act2.sa_flags = 0;
//act2.sa_flags = SA_NODEFER; // be stupid
if (sigaction(SIGCHLD, &act2, &oact2) != 0)
perror("sigaction");
#if 1
struct sigaction act3, oact3;
act3.sa_handler = handler3;
r = sigfillset(&act3.sa_mask);
r = sigdelset(&act3.sa_mask, SIGINT); // remove
if (r != 0) puts("retval3");
act3.sa_flags = SA_RESETHAND;
if (sigaction(SIGINT, &act3, &oact3) != 0)
perror("sigaction");
#endif
}
/* start a child to inundate me with signals */
{
pid_t pid, ppid;
pid = fork();
switch (pid)
{
case -1:
perror("fork");
return 1;
case 0:
ppid = getppid();
printf("pid=%d inundating pid=%d with SIGUSR1 and SIGCHLD\n",
getpid(), ppid);
#if 0
while (kill(ppid, random() % 2 ? SIGUSR1 : SIGCHLD) == 0)
;
#else
volatile int i = 0;
//volatile int i = 1;
int xcnt_usr1 = 0; int xcnt_chld = 0;
while (1) {
i = i ? 0 : 1;
if (1) {
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
} else {
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
if (kill(ppid, SIGCHLD) != 0) break;
xcnt_chld++;
if (kill(ppid, SIGUSR1) != 0) break; // LOST! WHY?
xcnt_usr1++;
}
#if defined(__linux__)
usleep(10000); // if disabled, either cnt_usr1 stays zero ?????
// enabked: 2 : 1, disabled: 10.000 : 1
#endif
#if defined(__CYGWIN__)
//usleep(10000); // if disabled ...
// using SIG_SETMASK (restore mask, saved at the start of the handler): ... abort, but after a long while (it seems)
// using SIG_UNBLOCK: abort (almost immediately) ... Sigh!
#endif
}
#endif
puts("child done");
printf("xcnt_usr1 = %d, xcnt_chld = %d\n", xcnt_usr1, xcnt_chld);
return 0;
}
}
/* loop forever while we receive signals */
stack_base = &stack_position;
sigsetjmp(jmp, 1);
for (;;)
{
puts("-");
if (sigprocmask(SIG_SETMASK, &unblock, NULL) != 0) // permit
perror("sigprocmask");
puts("--");
usleep(1000);
puts("---");
if (sigprocmask(SIG_SETMASK, &block, NULL) != 0) // forbid
perror("sigprocmask");
puts("----");
}
}
--
Problem reports: http://cygwin.com/problems.html
FAQ: http://cygwin.com/faq/
Documentation: http://cygwin.com/docs.html
Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple