#include #include #include #include #include #include #include #include #include // // Purpose: Test waitpid when process group sent SIGINT // Usage: test40 [xxx] // any arg indicates you want to ignore SIGINT // Note: // o Child sends SIGINT to its own process group which causes it to terminate // and interrupts the waitpid system call in the parent. If you run like // this: // test40 // the signal handler will be called (i.e., handler_called = 1). // If you run like this: // test40 xxx // the signal handler will NOT be called (i.e., handler_called = 0). // int ignore_sigint = 0; int handler_called = 0; pid_t cpid; // pid of children void print_mask (void) { sigset_t sigset; int errno_save; errno_save = errno; /* just in case we get called by ** a signal handler */ if (sigprocmask (0, NULL, &sigset) < 0) { // get signal sets printf ("sigprocmask() error\n"); exit(1); } printf ("print_mask:\n"); // *** solaris only // printf ("Signal mask = <%x,%x,%x,%x>\n", sigset.__sigbits[0], // sigset.__sigbits[1], sigset.__sigbits[2], // sigset.__sigbits[3]); if (sigismember (&sigset, SIGINT)) printf (" SIGINT"); if (sigismember (&sigset, SIGQUIT)) printf (" SIGQUIT"); if (sigismember (&sigset, SIGUSR1)) printf (" SIGUSR1"); if (sigismember (&sigset, SIGALRM)) printf (" SIGALRM"); if (sigismember (&sigset, SIGCHLD)) printf (" SIGCHLD"); printf ("\n"); errno = errno_save; } /* ** Signal mask in effect is action.sa_mask. After returning, ** signal mask in effect will be oaction.sa_mask. */ static void handle_sig (int signo) { handler_called = 1; return; } int main(int argc, char *argv[]) { struct sigaction action, oaction; if (argc > 1) ignore_sigint = 1; sigemptyset (&action.sa_mask); // no signals blocked action.sa_flags = 0; // no special options if (!ignore_sigint) action.sa_handler = handle_sig; // signal handler is ... else action.sa_handler = SIG_IGN; // ignore SIGINT if (sigaction (SIGINT, &action, &oaction) < 0) { fprintf (stderr, "sigaction(SIGINT) error\n"); return 1; } printf("procmask should be empty:\n"); print_mask(); printf ("\n"); printf("parent pid = %d, pgrp = %d\n", getpid(), getpgrp()); cpid = fork(); if (cpid < 0) { fprintf(stderr, "*** bad 1st fork\n"); exit(1); } if (cpid == 0) { // child if (sigaction (SIGINT, &oaction, NULL) < 0) { // restore default printf ("sigaction(SIGINT) error in child\n"); return 1; } sleep(1); printf ("Child pid = %d, sending SIGINT = %d to pgrp = %d\n", getpid(), SIGINT, getpgrp()); printf ("Child exit code would be -3 if it got past kill, but it won't\n"); kill(-getpgrp(), SIGINT); // send SIGINT to process group exit(-3); } else { // parent int rc; int status; int pgrp = getpgrp(); rc = waitpid(-pgrp, &status, 0); printf("++ Return from waitpid, rc = %d, handler_called = %d\n", rc, handler_called); printf("++ Expect rc = -1 and handler_called = %d\n", 1-ignore_sigint); if (rc == -1) { fprintf(stderr, "++ waitpid returned %d when pgrp = %d\n", rc, pgrp); fprintf(stderr, "++ Expect rc = -1, pgrp = %d (Child terminates from SIGINT)\n", getpgrp()); fprintf(stderr, "errno = %d: ", errno); perror(""); } else { if (WIFEXITED(status)) { printf("pgrp = %d, cpid = %d, rc = %d, status = %d, WEXITSTATUS(status) = %d\n", pgrp, cpid, rc, status, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("pgrp = %d, cpid = %d, rc = %d, status = %d, WTERMSIG(status) = %d\n", pgrp, cpid, rc, status, WTERMSIG(status)); } else { printf("Neither WIFEXTED or WIFSIGNALED:\n"); printf("pgrp = %d, cpid = %d, rc = %d, status = %d\n", pgrp, cpid, rc, status); } } } return 0; }