• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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