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>