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 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: Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit 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: List-Subscribe: List-Archive: List-Post: List-Help: , 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 #include /* waitpid() */ #include #include /* strerror() */ #include /* exit() */ #include #include #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