This is the mail archive of the cygwin mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[1.7] sigwait bug (SIGCHLD delayed to a next regular signal)


A problem seems very close to one described in
http://sourceware.org/ml/cygwin/2009-08/msg00797.html
and now I don't think it can be easily explained by
"limitation in Cygwin's implementation of SIGWINCH".

What I did this time...

When I fork children and next observe their termination in
the parent process by means of sigwait(),
*none* of the SIGCHLD signals is returned immediately until some other
"regular" signal, let's say SIGINT, is sent to the parent.

Apparently, signals like SIGWINCH and SIGCHLD, which are a little bit
special, need to be kicked by other signal to be eventually returned by
sigwait().
What makes these signals "special" is that their default action is `to
IGNORE' and to be useful for sigwait() they need to register some dummy
handler.
Maybe this has something to do why sigwait() doesn't work as
expected.


Here is example session from running the program attached below
(kill and ps command were typed in other console, comments preceded by //).

$ ./sigwait2.exe 
## parent (5680)
## forked child (4840)
## forked child (4972)
## forked child (4508)
## sigwait() loop...

// 1) signal a child (from other console)
$ kill -INT 4840
// no output; ps shows the child has been killed

// 2) signal the parent (not Ctrl+C)
$ kill -INT 5680
// sigint catched, delayed sigchld processed
** SIGINT!
** SIGCHLD
:: waitpid --> pid = 4840, stat = 2

// 3) signal the parent again
$ kill -INT 5680
** SIGINT!

// 4) now two last children at once
$ kill -INT 4972 4508
// as above no output; ps shows only the parent 

// 5) signal the parent to kick "sticky" CHLD signal
$ kill -INT 5680
** SIGINT!
** SIGCHLD
:: waitpid --> pid = 4508, stat = 2
:: waitpid --> pid = 4972, stat = 2

// 6) last two signals

$ kill -INT 5680
** SIGINT!

$ kill -INT 5680
** SIGINT!
Bye!

=======================================

/* sigwait2.c -- cygwin 1.7 bug: SIGCHLD not delivered to sigwait() */

#include <signal.h>
#include <sys/wait.h>   /* waitpid() */
#include <unistd.h>
#include <string.h>     /* strerror() */
#include <stdlib.h>     /* exit() */
#include <stdio.h>
#include <errno.h>

#define KIDS  3

#define ESYS(fun, args)                                                 \
    do {                                                                \
        if ((fun args) == -1) {                                         \
            fprintf(stderr, "%s, line %d: %s%s: %s\n",                  \
                    __FILE__, __LINE__, #fun, #args, strerror(errno));  \
            exit(1);                                                    \
        }                                                               \
    } while(0)

/*--------------------------------------------------------------------------*/

static void dummy_signal_handler (int sig)
{
}

/****************************************************************************/

int main ()
{
    pid_t parent = getpid();
    int intnum = 0;
    sigset_t ss;
    struct sigaction sa;
    int i;

    printf("## parent (%d)\n", parent);
    for (i = 0; i < KIDS; ++i) {
        int pid;
        ESYS(pid = fork, ());
        if (pid == 0) {     /* child */
            do {
                int ch;
                while ((ch = getchar()) != EOF)
                    putchar(ch);
                sleep(1);
            } while(getppid() == parent);
            printf("## child (%d) terminated.\n", getpid());
            exit(0);
        }
        printf("## forked child (%d)\n", pid);
    }

    sigemptyset(&ss);
    sigaddset(&ss, SIGCHLD);
    sigaddset(&ss, SIGINT);

    ESYS(sigprocmask, (SIG_BLOCK, &ss, NULL));

    sa.sa_flags = 0;
    sa.sa_handler = &dummy_signal_handler;
    sigemptyset(&sa.sa_mask);

    ESYS(sigaction, (SIGCHLD, &sa, NULL));

    printf("## sigwait() loop...\n");

    while (1) {

        int signo;
        ESYS(sigwait, (&ss, &signo));

        if (signo == SIGINT) {
            printf("** SIGINT!\n");
            if (++intnum >= 5) {
                printf("Bye!\n");
                exit(0);
            }
        }
        else if (signo == SIGCHLD) {
            pid_t   pid;
            int     stat;
            printf("** SIGCHLD\n");
            while ((pid = waitpid((pid_t)-1, &stat, WNOHANG)) > 0) {
                printf(":: waitpid --> pid = %d, stat = %d\n",
                       pid, stat);
            }
        }
        else {
            printf("!! unexpected signal (%d)\n", signo);
        }
    }
}




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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]