Web lists-archives.com

REVISITED: Signal delivered while blocked




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