public inbox for cygwin@cygwin.com
 help / color / mirror / Atom feed
From: Houder <houder@xs4all.nl>
To: cygwin@cygwin.com
Subject: REVISITED: Signal delivered while blocked
Date: Wed, 16 Aug 2017 21:22:00 -0000	[thread overview]
Message-ID: <c05c742f0f3809e6d1afb8fb2c646ad7@xs4all.nl> (raw)

[-- Attachment #1: Type: text/plain, Size: 4168 bytes --]

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

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: sigprocmask-exclusion4.c --]
[-- Type: text/x-c; name=sigprocmask-exclusion4.c, Size: 8685 bytes --]

// 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("----");
	}
}

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: sigprocmask-exclusion5.c --]
[-- Type: text/x-c; name=sigprocmask-exclusion5.c, Size: 10252 bytes --]

// 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("----");
	}
}

[-- Attachment #4: Type: text/plain, Size: 219 bytes --]


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

             reply	other threads:[~2017-08-16 21:22 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-16 21:22 Houder [this message]
2017-08-18 16:20 ` Corinna Vinschen
2017-08-20 13:20   ` Houder
2017-08-20 12:59 ` Houder
2017-08-20 15:44 ` Kaz Kylheku

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c05c742f0f3809e6d1afb8fb2c646ad7@xs4all.nl \
    --to=houder@xs4all.nl \
    --cc=cygwin@cygwin.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).