signal vs. sigaction and SIGCHLD
Noel Hunt
noel.hunt at gmail.com
Tue May 21 05:24:30 UTC 2013
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?
More information about the freebsd-questions
mailing list