Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 21 May 2013 15:24:26 +1000
From:      Noel Hunt <noel.hunt@gmail.com>
To:        freebsd-questions@freebsd.org
Subject:   signal vs. sigaction and SIGCHLD
Message-ID:  <CAGfO01wE7ZROQWTv7TXZdSySqWCkRqj7dcqDDc28-jvhqMuVDw@mail.gmail.com>

next in thread | raw e-mail | index | archive | help
I have a small test program which simply forks and execs
its command line arguments, but after the fork and before
the exec, it sends a SIGSTOP to the child. The parent then
sleeps for 3 seconds before exiting. However, a signal
handler for SIGCHLD has been installed and I was expecting
the parent to be notified of the SIGSTOP sent to the child,
but with the `signal' interface this doesn't appear to work.

If I change the code to use `sigaction' and `sigprocmask'
(to unblock any blocked SIGCHLD), this program works the
way intended, that is, the signal handler is called:

     1 #include <stdio.h>
     2 #include <signal.h>
     3 #include <stdlib.h>
     4 #include <fcntl.h>
     5 #include <sys/types.h>
     6 #include <sys/wait.h>
     7 #include <sys/time.h>
     8 #include <sys/resource.h>
     9
    10 #define SIGACTION
    11
    12 static void waithandler(int i){
    13 int pid, cursig;
    14 int tstat;
    15
    16 #ifdef SIGACTION
    17 pid = waitpid(-1, &tstat, WUNTRACED);
    18 #else
    19 pid = wait(&tstat);
    20 signal(SIGCHLD, waithandler);
    21 #endif
    22 if (pid < 0)
    23 return;
    24
    25 printf("waithandler: child (%d)", pid);
    26 if (WIFSTOPPED(tstat)) {
    27 printf(" received");
    28 cursig = WSTOPSIG(tstat);
    29 if (cursig == SIGSTOP)
    30 printf(" SIGSTOP\n");
    31 else if (cursig == SIGTRAP)
    32 printf(" SIGTRAP\n");
    33 else
    34 printf(" %d\n", cursig);
    35 } else {
    36 printf(" exited status=%d\n", WEXITSTATUS(tstat));
    37 }
    38 }
    39
    40 main(int argc, char **argv){
    41 int i, j;
    42 int fd, hangpid;
    43 FILE *ttyerr;
    44 char ctl[16];
    45 #ifdef SIGACTION
    46 sigset_t sigmask[2];
    47 struct sigaction sa;
    48
    49 sa.sa_flags = 0;
    50 sigemptyset(&sa.sa_mask);
    51 sa.sa_handler = waithandler;
    52 sigaction(SIGCHLD, &sa, NULL);
    53 sigemptyset(&sigmask[0]);
    54 sigaddset(&sigmask[0], SIGCHLD);
    55 sigprocmask(SIG_UNBLOCK, &sigmask[0], &sigmask[1]);
    56 #else
    57
    58 signal(SIGCHLD, waithandler);
    59 #endif
    60 ttyerr = fopen("/dev/tty", "w");
    61 if (argc <= 1) {
    62 if( ttyerr )
    63 fprintf(ttyerr,"Usage: %s cmd [args...]\n",argv[0],*argv);
    64 exit(1);
    65 }
    66 if( (hangpid=fork())==0 ){
    67 kill(getpid(), SIGSTOP);
    68 execvp(argv[1], argv+1);
    69 perror(argv[1]);
    70 exit(1);
    71 }
    72 if(hangpid==-1){
    73 perror("fork");
    74 exit(1);
    75 }
    76 if( ttyerr ){
    77 fprintf(ttyerr,"/proc/%d\n",hangpid);
    78 fclose(ttyerr);
    79 }
    80 sleep(3);
    81 }

The file is `hang.c'. I compile and run it like this:

% ./hang echo foo bar baz
waithandler: child (2280) received SIGSTOP
/proc/2280

If I recompile with `#undef SIGACTION', waithandler is not
called.

I should add that even with the sigaction(2) interface, without
the `sigprocmask' call, it still doesn't work, which suggests
that SIGCHLD is being blocked.

Can anyone explain why?



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