delorie.com/archives/browse.cgi   search  
Mail Archives: cygwin/2009/09/18/12:58:31

X-Recipient: archive-cygwin AT delorie DOT com
X-SWARE-Spam-Status: No, hits=-0.9 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_43,J_CHICKENPOX_47,RCVD_IN_BL_SPAMCOP_NET,SPF_HELO_PASS,SPF_PASS
X-Spam-Check-By: sourceware.org
To: cygwin AT cygwin DOT com
From: Waldemar Rachwal <waldemar DOT rachwal AT gmail DOT com>
Subject: [1.7] sigwait bug (SIGCHLD delayed to a next regular signal)
Date: Fri, 18 Sep 2009 16:57:56 +0000 (UTC)
Lines: 165
Message-ID: <loom.20090918T184921-716@post.gmane.org>
Mime-Version: 1.0
User-Agent: Loom/3.14 (http://gmane.org/)
X-IsSubscribed: yes
Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm
List-Id: <cygwin.cygwin.com>
List-Subscribe: <mailto:cygwin-subscribe AT cygwin DOT com>
List-Archive: <http://sourceware.org/ml/cygwin/>
List-Post: <mailto:cygwin AT cygwin DOT com>
List-Help: <mailto:cygwin-help AT cygwin DOT com>, <http://sourceware.org/ml/#faqs>
Sender: cygwin-owner AT cygwin DOT com
Mail-Followup-To: cygwin AT cygwin DOT com
Delivered-To: mailing list cygwin AT cygwin DOT com

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

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019