From owner-freebsd-hackers Thu Jun 7 5:31: 8 2001 Delivered-To: freebsd-hackers@freebsd.org Received: from boco.fee.vutbr.cz (boco.fee.vutbr.cz [147.229.9.11]) by hub.freebsd.org (Postfix) with ESMTP id AF65E37B406 for ; Thu, 7 Jun 2001 05:30:52 -0700 (PDT) (envelope-from cejkar@dcse.fee.vutbr.cz) Received: from kazi.dcse.fee.vutbr.cz (kazi.dcse.fee.vutbr.cz [147.229.8.12]) by boco.fee.vutbr.cz (8.11.4/8.11.3) with ESMTP id f57CUoD06629 (using TLSv1/SSLv3 with cipher EDH-RSA-DES-CBC3-SHA (168 bits) verified OK) for ; Thu, 7 Jun 2001 14:30:51 +0200 (CEST) Received: (from cejkar@localhost) by kazi.dcse.fee.vutbr.cz (8.11.3/8.11.3) id f57CUoO16108 for freebsd-hackers@freebsd.org; Thu, 7 Jun 2001 14:30:50 +0200 (CEST) Date: Thu, 7 Jun 2001 14:30:50 +0200 From: Cejka Rudolf To: freebsd-hackers@freebsd.org Subject: [Patch?] signal(SIGCHLD, SIG_IGN) is against SUSv2 Message-ID: <20010607143050.A13932@dcse.fee.vutbr.cz> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5i Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.ORG There is following paragraph in SUSv2: If a process sets the action for the SIGCHLD signal to SIG_IGN, the behaviour is unspecified, except as specified below. If the action for the SIGCHLD signal is set to SIG_IGN, child processes of the calling processes will not be transformed into zombie processes when they terminate. If the calling process subsequently waits for its children, and the process has no unwaited for children that were transformed into zombie processes, it will block until all of its children terminate, and wait(), wait3(), waitid() and waitpid() will fail and set errno to [ECHILD]. ... However, if I use "signal(SIGCHLD, SIG_IGN)", zombies are still created in FreeBSD, which is against SUSv2. What do you think about following patch for -stable (it is usable with -current too)? Furthermore, it seems that the test "if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] = SIG_IGN)" is unnecessary. After patch there are: one more question, comparison results among different systems (unbelievable how much they are different :-) and my sigtest.c program: -- Patch --- sys/kern/kern_sig.c.orig Wed Jun 6 11:52:37 2001 +++ sys/kern/kern_sig.c Thu Jun 7 11:57:45 2001 @@ -438,6 +438,8 @@ * Reset no zombies if child dies flag as Solaris does. */ p->p_procsig->ps_flag &= ~PS_NOCLDWAIT; + if (ps->ps_sigact[_SIG_IDX(SIGCHLD)] = SIG_IGN) + ps->ps_sigact[_SIG_IDX(SIGCHLD)] = SIG_DFL; } /* --- sys/kern/kern_exit.c.orig Wed Jun 6 13:13:43 2001 +++ sys/kern/kern_exit.c Thu Jun 7 11:24:03 2001 @@ -316,7 +316,8 @@ * flag set, notify process 1 instead (and hope it will handle * this situation). */ - if (p->p_pptr->p_procsig->ps_flag & PS_NOCLDWAIT) { + if (p->p_pptr->p_procsig->ps_flag & PS_NOCLDWAIT + || p->p_sigacts->ps_sigact[_SIG_IDX(SIGCHLD)] == SIG_IGN) { struct proc *pp = p->p_pptr; proc_reparent(p, initproc); /* -- Question In sys/kern/kern_sig.c in do_sigaction(), there is: if (act->sa_flags & SA_SIGINFO) { ps->ps_sigact[_SIG_IDX(sig)] = act->sa_handler; SIGADDSET(ps->ps_siginfo, sig); } else { ps->ps_sigact[_SIG_IDX(sig)] = (__sighandler_t *)act->sa_sigaction; SIGDELSET(ps->ps_siginfo, sig); } Why? I know that sa_handler and sa_sigaction are the same pointer in an union, but I think that "act->sa_handler" should be exchanged with "(__sighandler_t *)act->sa_sigaction" for clarification purposes. -- Comparison results ABCD(Z = zombie created): SIGCHLD properties before exec() -> after exec() A) SIG_IGN before exec (instead of SIG_DFL) B) SA_NOCLDWAIT before exec (instead of 0) C) SIG_IGN after exec (instead of SIG_DFL) D) SA_NOCLDWAIT after exec (instead of 0) Solaris 2.7, FreeBSD 4.3 with proposed patch: 0000(Z), 0001( ), 0010( ), 0011( ): SIG_DFL() -> SIG_DFL() 0100(Z), 0101( ), 0110( ), 0111( ): SIG_DFL(SA_NOCLDWAIT) -> SIG_DFL() 1000(Z), 1001( ), 1010( ), 1011( ): SIG_IGN() -> SIG_DFL() 1100(Z), 1101( ), 1110( ), 1111( ): SIG_IGN(SA_NOCLDWAIT) -> SIG_DFL() Irix 6.5, Unixware 7.0.1: 0000(Z), 0001( ), 0010( ), 0011( ): SIG_DFL() -> SIG_DFL() 0100(Z), 0101( ), 0110( ), 0111( ): SIG_DFL(SA_NOCLDWAIT) -> SIG_DFL() 1000(Z), 1001( ), 1010( ), 1011( ): SIG_IGN(SA_NOCLDWAIT) -> SIG_IGN() 1100(Z), 1101( ), 1110( ), 1111( ): SIG_IGN(SA_NOCLDWAIT) -> SIG_IGN() FreeBSD 4.3 without proposed patch, FreeBSD-current (Apr 27): 0000(Z), 0001( ), 0010(Z), 0011( ): SIG_DFL() -> SIG_DFL() 0100(Z), 0101( ), 0110(Z), 0111( ): SIG_DFL(SA_NOCLDWAIT) -> SIG_DFL() 1000(Z), 1001( ), 1010(Z), 1011( ): SIG_IGN() -> SIG_IGN() 1100(Z), 1101( ), 1110(Z), 1111( ): SIG_IGN(SA_NOCLDWAIT) -> SIG_IGN() Linux 2.2.17: 0000(Z), 0001(Z), 0010( ), 0011( ): SIG_DFL() -> SIG_DFL() 0100(Z), 0101(Z), 0110( ), 0111( ): SIG_DFL(SA_NOCLDWAIT) -> SIG_DFL() 1000( ), 1001(Z), 1010( ), 1011( ): SIG_IGN() -> SIG_IGN() 1100( ), 1101(Z), 1110( ), 1111( ): SIG_IGN(SA_NOCLDWAIT) -> SIG_IGN() -- testsig.c #include #include #include #include #include #include #include #include int main(int argc, char *argv[]) { int childs = 0; struct sigaction sa, so; int status; int value; if (argc > 1) { value = atoi(argv[1]); } else { printf("Usage: sigtest \n"); exit(1); } if (argc > 2 && strcmp(argv[2], "-x") == 0) { /* After exec() */ sigaction(SIGCHLD, NULL, &so); printf("After exec(): %s(%s)\n", (so.sa_handler == SIG_IGN) ? "SIG_IGN" : ((so.sa_handler == SIG_DFL) ? "SIG_DFL" : "?"), (so.sa_flags & SA_NOCLDWAIT) ? "SA_NOCLDWAIT" : ""); sigemptyset(&sa.sa_mask); if (value & 3) { sa.sa_flags = (value & 1) ? SA_NOCLDWAIT : 0; sa.sa_handler = (value & 2) ? SIG_IGN : SIG_DFL; sigaction(SIGCHLD, &sa, NULL); } sigaction(SIGCHLD, NULL, &so); printf("Before fork(): %s(%s)\n", (so.sa_handler == SIG_IGN) ? "SIG_IGN" : ((so.sa_handler == SIG_DFL) ? "SIG_DFL" : "?"), (so.sa_flags & SA_NOCLDWAIT) ? "SA_NOCLDWAIT" : ""); while (++childs <= 10) { switch (fork()) { case 0: printf("Child %d exiting...\n", childs); exit(0); case -1: printf("fork(): %s\n", strerror(errno)); exit(-1); default: break; } } printf("Sleeping...\n"); sleep(3); } else { /* Main process before exec() */ switch (fork()) { case 0: sigaction(SIGCHLD, NULL, &so); printf("Default: %s(%s)\n", (so.sa_handler == SIG_IGN) ? "SIG_IGN" : ((so.sa_handler == SIG_DFL) ? "SIG_DFL" : "?"), (so.sa_flags & SA_NOCLDWAIT) ? "SA_NOCLDWAIT" : ""); sigemptyset(&sa.sa_mask); if (value & 12) { sa.sa_flags = (value & 4) ? SA_NOCLDWAIT : 0; sa.sa_handler = (value & 8) ? SIG_IGN : SIG_DFL; sigaction(SIGCHLD, &sa, NULL); } sigaction(SIGCHLD, NULL, &so); printf("Before exec(): %s(%s)\n", (so.sa_handler == SIG_IGN) ? "SIG_IGN" : ((so.sa_handler == SIG_DFL) ? "SIG_DFL" : "?"), (so.sa_flags & SA_NOCLDWAIT) ? "SA_NOCLDWAIT" : ""); execl(argv[0], argv[0], argv[1], "-x", NULL); printf("exec(%s %s): %s\n", argv[0], "-x", strerror(errno)); return 0; case -1: printf("fork(): %s\n", strerror(errno)); exit(-1); default: (void)wait(&status); break; } } return 0; } -- Rudolf Cejka (cejkar@dcse.fee.vutbr.cz; http://www.fee.vutbr.cz/~cejkar) Brno University of Technology, Faculty of El. Engineering and Comp. Science Bozetechova 2, 612 66 Brno, Czech Republic To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message