1 /*
2 * Copyright (C) Bull S.A. 1996
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 /*---------------------------------------------------------------------+
20 | signal_test_04 |
21 | ==================================================================== |
22 | |
23 | Description: Verify default signal actions (for SIGSTOP & SIGCONT) |
24 | by spawning a child process and sending the signals |
25 | to the child. Meanwhile, checking to insure that the |
26 | child process takes the default action for each signal |
27 | received. |
28 | |
29 | Algorithm: o Use sigaction (SIG_DFL) to take the default action |
30 | for all signals except for SIGCHLD, SIGUSR1 |
31 | SIGUSR2 |
32 | |
33 | o Spawn a child |
34 | |
35 | (parent) |
36 | o Ensure that child process is running by waiting |
37 | for the child process to send a SIGUSR1 signal |
38 | o Send a SIGSTOP signal to stop the execution of the |
39 | child process |
40 | o Verify that the child process received the SIGSTOP |
41 | signal by waiting for the childs SIGCHLD signal |
42 | o Send a SIGCONT signal to resume the execution of |
43 | child process. |
44 | o Verify that the child process resumed execution by |
45 | waiting for the child to send another SIGUSR1 |
46 | signal |
47 | o Kill child process with SIGUSR2 signal.. |
48 | |
49 | (child) |
50 | o Take default action for each received signal |
51 | o Continuously send SIGUSR1 signals to the parent |
52 | process |
53 | |
54 | |
55 | System calls: The following system calls are tested: |
56 | |
57 | sigaction () - specify the action to take upon |
58 | delivery of a signal |
59 | wait () - waits for a child process to stop or |
60 | terminate |
61 | kill () - sends a signal to a process |
62 | |
63 | Usage: signal_test_04 |
64 | |
65 | To compile: cc -o signal_test_04 signal_test_04 |
66 | |
67 | Last update: Ver. 1.3, 4/8/94 13:07:38 |
68 | |
69 | Change Activity |
70 | |
71 | Version Date Name Reason |
72 | 0.1 112993 DJK Initial program |
73 | 1.2 020794 DJK Move to "prod" directory |
74 | |
75 +---------------------------------------------------------------------*/
76
77 #include <stdio.h>
78 #include <string.h>
79 #ifdef _LINUX_
80 #define __USE_XOPEN
81 #endif
82 #include <unistd.h>
83 #include <stdlib.h>
84 #include <sys/signal.h>
85 #include <sys/wait.h>
86 #include <errno.h>
87
88 #ifdef _LINUX_
89 // bits/signum.h defines _NSIG as 64
90 #define SIGMAX 64
91 #endif
92
93 /* Function prototypes */
94 void signal_init();
95 void child(int);
96 void handler(int, int, struct sigcontext *);
97 void sys_error(const char *, int);
98 void error(const char *, int);
99
100 /* Flag set upon receiving SIGCHLD signal */
101 volatile int sigchld_flag = 0;
102 volatile int sigusr1_count = 0;
103
104 /*---------------------------------------------------------------------+
105 | main () |
106 | ==================================================================== |
107 | |
108 | Function: Main program (see prolog for more details) |
109 | |
110 +---------------------------------------------------------------------*/
main(int argc,char ** argv)111 int main(int argc, char **argv)
112 {
113 pid_t pid = getpid(), /* Process ID (of parent process) */
114 cpid; /* Process ID (of child process) */
115 int sigusr1_interrupts; /* xxx */
116 int status; /* Child's exit status */
117 int timeout = 10; /* How long to wait for SIGCHILD */
118 char msg[100]; /* Buffer for error message */
119
120 /* Print out program header */
121 printf("%s: IPC TestSuite program\n\n", *argv);
122 fflush(stdout);
123
124 /* Set up our signal handler */
125 signal_init();
126
127 /*
128 * Spawn a child process & have the child process send SIGUSR1
129 * signals to the parent.
130 */
131 switch (cpid = fork()) {
132 case -1: /* Unable to create child process */
133 sys_error("fork failed", __LINE__);
134 exit(-1);
135
136 case 0: /* Child process */
137 child(pid);
138
139 default: /* Parent process */
140 break;
141 }
142
143 /*
144 * Interrupt the child process
145 *
146 * Send SIGSTOP signal to child process (child process will
147 * stop upon receiving the signal).
148 *
149 * Wait for the child process to receive the SIGSTOP signal
150 * and send a corresponding SIGCLD interrupt to the parent.
151 *
152 * Send SIGKILL signal to child process (child process
153 * will exit upon receiving the signal).
154 */
155 printf("\tWait for SIGUSR1 signal from child process\n");
156 #ifdef _IA64
157 while (sigusr1_count < 1)
158 sleep(1);
159 #else
160 while (sigusr1_count < 1) ;
161 #endif
162 printf("\tReceived SIGUSR1 (30)\n");
163 sigusr1_interrupts = sigusr1_count;
164
165 printf("\n\tStop the child process\n");
166 kill(cpid, SIGSTOP);
167
168 printf("\n\tWait for SIGCHLD signal from stopped child process\n");
169 alarm(timeout);
170 while (sigchld_flag < 1) ;
171 printf("\tReceived SIGCHLD (20)\n");
172
173 printf
174 ("\n\tResume child process & wait for it to send SIGUSR1 signal\n");
175 kill(cpid, SIGCONT);
176
177 #ifdef _IA64
178 while (sigusr1_interrupts == sigusr1_count)
179 sleep(1);
180 #else
181 while (sigusr1_interrupts == sigusr1_count) ;
182 #endif
183 printf("\tReceived SIGUSR1 (20)\n");
184
185 printf("\n\tNow kill the child process with SIGUSR2 signal\n");
186 kill(cpid, SIGUSR2);
187
188 /*
189 * Wait for the child process to abort
190 *
191 * Suspend execution of the parent process until the SIGCHLD signal
192 * is received upon termination of the child process.
193 *
194 * Check the child process's exit status (with POSIX macros) to
195 * verify that the child process terminated due to the SIGKILL signal
196 * from the parent.
197 *
198 * Additionally verify that the number of SIGCHLD signals received
199 * has increased.
200 */
201 printf("\n\tWait for SIGCHLD signal from killed child process\n");
202
203 wait(&status);
204
205 if (WIFSIGNALED(status)) {
206 if (WTERMSIG(status) != SIGUSR2) {
207 sprintf(msg,
208 "child process was killed with signal (%d)",
209 WTERMSIG(status));
210 error(msg, __LINE__);
211 }
212 } else {
213 error("child process did not receive SIGUSR2 signal", __LINE__);
214 }
215 if (sigchld_flag < 2)
216 error("child process failed to send SIGCHLD signal", __LINE__);
217
218 printf("\tReceived SIGCHLD (30)\n");
219
220 /* Program completed successfully -- exit */
221 printf("\nsuccessful!\n");
222
223 return 0;
224 }
225
226 /*---------------------------------------------------------------------+
227 | child () |
228 | ==================================================================== |
229 | |
230 | Function: Child process -- loop until killed. |
231 | o continuously send SIGUSR1 interrupts to parent |
232 | |
233 +---------------------------------------------------------------------*/
child(pid_t pid)234 void child(pid_t pid)
235 {
236 while (1) {
237 sleep(2);
238 #ifdef _IA64
239 if (kill(pid, SIGUSR1) < 0)
240 perror("child: kill");
241 #else
242 kill(pid, SIGUSR1);
243 #endif
244 }
245
246 error("child process failed to terminate correctly", __LINE__);
247 }
248
249 /*---------------------------------------------------------------------+
250 | handler () |
251 | ==================================================================== |
252 | |
253 | Function: Signal handler |
254 | |
255 | Parms: signal - signal number caught |
256 | |
257 | Returns: Aborts if an unexpected signal is caught |
258 | |
259 +---------------------------------------------------------------------*/
handler(int signal,int code,struct sigcontext * scp)260 void handler(int signal, int code, struct sigcontext *scp)
261 {
262 char msg[100];
263
264 if (signal == SIGCHLD) {
265 sigchld_flag++;
266 } else if (signal == SIGUSR1) {
267 sigusr1_count++;
268 } else if (signal == SIGALRM) {
269 sprintf(msg,
270 "Timed out waiting for SIGCHLD signal from child, defect # 124551");
271 error(msg, __LINE__);
272 } else {
273 sprintf(msg, "caught an unexpected signal (%d)", signal);
274 error(msg, __LINE__);
275 }
276 }
277
278 /*---------------------------------------------------------------------+
279 | signal_init () |
280 | ==================================================================== |
281 | |
282 | Function: Take default action for all signals except for SIGCHLD. |
283 | Particularily interrested in the following: |
284 | |
285 | o SIGSTOP (17) - default action: stop |
286 | o SIGCONT (19) - default action: stop |
287 | o SIGKILL (09) - default action: abort process |
288 | |
289 | Process signal handler upon receiving the following: |
290 | (Sent when child process stops or exits) |
291 | |
292 | o SIGCHLD (20) |
293 | |
294 | Returns: n/a |
295 | |
296 +---------------------------------------------------------------------*/
signal_init()297 void signal_init()
298 {
299 struct sigaction action;
300 char msg[100];
301 int i;
302
303 for (i = 1; i <= SIGMAX; i++) {
304
305 /* Do not ignore SIGCHILD signal */
306 #ifdef _IA64 /* SIGWAITING not supported, RESERVED */
307 if (i == SIGCHLD || i == SIGALRM ||
308 i == SIGUSR1 || i == SIGWAITING)
309 continue;
310 #else
311 #ifdef _LINUX_
312 if ((i == SIGKILL) || (i == SIGSTOP)
313 || ((i >= 32) && (i <= 34)))
314 continue;
315 #else
316 if ((i == SIGKILL) || (i == SIGSTOP) || (i == SIGCONT))
317 continue;
318 #endif
319 #endif
320
321 action.sa_handler = SIG_DFL;
322 sigfillset(&action.sa_mask);
323 action.sa_flags = SA_RESTART;
324
325 if (sigaction(i, &action, NULL) < 0) {
326 sprintf(msg, "sigaction failed on signal %d", i);
327 error(msg, __LINE__);
328 }
329 }
330
331 /* Setup signal handler for SIGCHLD & SIGUSR1 signals */
332 action.sa_handler = (void (*)(int))handler;
333 sigfillset(&action.sa_mask);
334
335 /* changing */
336 /*action.sa_flags = 0; */
337 action.sa_flags = SA_RESTART;
338
339 if (sigaction(SIGCHLD, &action, NULL) < 0)
340 sys_error("sigaction (SIGCHLD) failed", __LINE__);
341
342 /* changing */
343 action.sa_flags = SA_RESTART;
344 /* end of changing */
345
346 if (sigaction(SIGUSR1, &action, NULL) < 0)
347 sys_error("sigaction (SIGUSR1) failed", __LINE__);
348
349 /* Setup signal handler for SIGALRM */
350 action.sa_handler = (void (*)(int))handler;
351 if (sigaction(SIGALRM, &action, NULL) < 0)
352 sys_error("sigaction (SIGCHLD) failed", __LINE__);
353 }
354
355 /*---------------------------------------------------------------------+
356 | sys_error () |
357 | ==================================================================== |
358 | |
359 | Function: Creates system error message and calls error () |
360 | |
361 +---------------------------------------------------------------------*/
sys_error(const char * msg,int line)362 void sys_error(const char *msg, int line)
363 {
364 char syserr_msg[256];
365
366 sprintf(syserr_msg, "%s: %s\n", msg, strerror(errno));
367 error(syserr_msg, line);
368 }
369
370 /*---------------------------------------------------------------------+
371 | error () |
372 | ==================================================================== |
373 | |
374 | Function: Prints out message and exits... |
375 | |
376 +---------------------------------------------------------------------*/
error(const char * msg,int line)377 void error(const char *msg, int line)
378 {
379 fprintf(stderr, "ERROR [line: %d] %s\n", line, msg);
380 #ifdef _IA64
381 fflush(stderr);
382 #endif
383 exit(-1);
384 }
385