Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 7 Jun 2001 14:30:50 +0200
From:      Cejka Rudolf <cejkar@dcse.fee.vutbr.cz>
To:        freebsd-hackers@freebsd.org
Subject:   [Patch?] signal(SIGCHLD, SIG_IGN) is against SUSv2
Message-ID:  <20010607143050.A13932@dcse.fee.vutbr.cz>

next in thread | raw e-mail | index | archive | help

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 <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

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 <value 0..15>\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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010607143050.A13932>