1 /*
2 Test assertion #10 by verifying that SIGCHLD signals are sent to a parent
3 when their children are stopped.
4 * 12/18/02 - Adding in include of sys/time.h per
5 * rodrigc REMOVE-THIS AT attbi DOT com input that it needs
6 * to be included whenever the timeval struct is used.
7 *
8 */
9
10 #include <signal.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <sys/select.h>
14 #include <sys/wait.h>
15 #include <sys/time.h>
16 #include <sys/types.h>
17 #include <unistd.h>
18
19 #define NUMSTOPS 10
20
21 int child_stopped = 0;
22 int child_continued = 0;
23 int notification;
24
handler(int signo,siginfo_t * info,void * context)25 void handler(int signo, siginfo_t * info, void *context)
26 {
27 if (!info)
28 return;
29
30 notification = info->si_code;
31
32 switch (notification) {
33 case CLD_STOPPED:
34 printf("Child has been stopped\n");
35 child_stopped++;
36 break;
37 case CLD_CONTINUED:
38 printf("Child has been continued\n");
39 child_continued++;
40 break;
41 }
42 }
43
wait_for_notification(int val)44 void wait_for_notification(int val)
45 {
46 struct timeval tv;
47
48 while (notification != val) {
49 tv.tv_sec = 1;
50 tv.tv_usec = 0;
51 if (!select(0, NULL, NULL, NULL, &tv))
52 break;
53 }
54 }
55
main(void)56 int main(void)
57 {
58 pid_t pid;
59 struct sigaction act;
60 struct timeval tv;
61
62 act.sa_sigaction = handler;
63 act.sa_flags = SA_SIGINFO;
64 sigemptyset(&act.sa_mask);
65 sigaction(SIGCHLD, &act, 0);
66
67 if ((pid = fork()) == 0) {
68 /* child */
69 while (1) {
70 /* wait forever, or until we are
71 interrupted by a signal */
72 tv.tv_sec = 0;
73 tv.tv_usec = 0;
74 select(0, NULL, NULL, NULL, &tv);
75 }
76 return 0;
77 } else {
78 /* parent */
79 int s;
80 int i;
81
82 for (i = 0; i < NUMSTOPS; i++) {
83 printf("--> Sending SIGSTOP\n");
84 notification = 0;
85 kill(pid, SIGSTOP);
86
87 /*
88 Don't let the kernel optimize away queued
89 SIGSTOP/SIGCONT signals.
90 */
91
92 wait_for_notification(CLD_STOPPED);
93
94 printf("--> Sending SIGCONT\n");
95 notification = 0;
96 kill(pid, SIGCONT);
97 /*
98 SIGCHLD doesn't queue, make sure CLD_CONTINUED
99 doesn't mask the next CLD_STOPPED
100 */
101 wait_for_notification(CLD_CONTINUED);
102 }
103
104 kill(pid, SIGKILL);
105 waitpid(pid, &s, 0);
106 }
107
108 if (child_stopped == NUMSTOPS && child_continued == NUMSTOPS) {
109 printf("Test PASSED\n");
110 return 0;
111 }
112
113 printf("Test FAILED\n");
114 return -1;
115 }
116