• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2000 Silicon Graphics, Inc.  All Rights Reserved.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms of version 2 of the GNU General Public License as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it would be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11  *
12  * Further, this software is distributed without any warranty that it is
13  * free of the rightful claim of any third person regarding infringement
14  * or the like.  Any license provided herein, whether implied or
15  * otherwise, applies only to this software file.  Patent licenses, if
16  * any, provided herein do not apply to combinations of this program with
17  * other software, or any other product whatsoever.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write the Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  *
23  * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24  * Mountain View, CA  94043, or:
25  *
26  * http://www.sgi.com
27  *
28  * For further information regarding this notice, see:
29  *
30  * http://oss.sgi.com/projects/GenInfo/NoticeExplan/
31  *
32  */
33 /* $Id: kill10.c,v 1.7 2009/03/23 13:35:53 subrata_modak Exp $ */
34 /**********************************************************
35  *
36  *    OS Test - Silicon Graphics, Inc.
37  *
38  *    TEST IDENTIFIER	: kill10
39  *
40  *    EXECUTED BY	: anyone
41  *
42  *    TEST TITLE	: signal flooding test
43  *
44  *    TEST CASE TOTAL	: 1
45  *
46  *    WALL CLOCK TIME	:
47  *
48  *    CPU TYPES		: ALL
49  *
50  *    AUTHOR		: Nate Straz
51  *
52  *    DATE STARTED	: 04/09/2001
53  *
54  *    INITIAL RELEASE	: Linux 2.4.x
55  *
56  *    TEST CASES
57  *
58  * 	1.) Create a large number of processes and signal between them.
59  *
60  *    INPUT SPECIFICATIONS
61  * 	The standard options for system call tests are accepted.
62  *	(See the parse_opts(3) man page).
63  *
64  *    OUTPUT SPECIFICATIONS
65  *$
66  *    DURATION
67  * 	Terminates - with frequency and infinite modes.
68  *
69  *    SIGNALS
70  * 	Uses SIGUSR1 to pause before test if option set.
71  * 	(See the parse_opts(3) man page).
72  *
73  *    RESOURCES
74  * 	None
75  *
76  *    ENVIRONMENTAL NEEDS
77  *      No run-time environmental needs.
78  *
79  *    SPECIAL PROCEDURAL REQUIREMENTS
80  * 	None
81  *
82  *    INTERCASE DEPENDENCIES
83  * 	None
84  *
85  *    DETAILED DESCRIPTION
86  *  This test creates -g groups of -n processes each and prepares them to send
87  *  large numbers of signals.  All process fall into three levels.
88  *    * Level 1 - Master
89  *                This is the parent of all processes.  It handles test looping
90  *                and making sure that all level 2 Managers report in.
91  *                SIGUSR1 -> ack Manager is ready
92  *                SIGUSR2 -> ack Manager is done and sends reset
93  *    * Level 2 - Managers
94  *                There are -g (default 2) of these processes.  They handle
95  *                forking off -n procs and setting up their signal handling.
96  *                Managers are in a pgid with their Children.
97  *                SIGALRM -> Process making your children
98  *                SIGUSR1 ->
99  *                SIGUSR2 -> Reply to Child to stop
100  *                SIGHUP  -> Reset child signal counter
101  *                SIGQUIT -> Exit gracefully
102  *    * Level 3 - Child
103  *                There are -n (default 10) of these process per Manager.  Their
104  *                only job is to send signals to their Managers when told to by
105  *                the Master.
106  *                SIGUSR1 -> Start signaling Manager
107  *                SIGUSR2 -> Stop signaling Manager
108  *                SIGHUP  -> IGNORE
109  *                SIGQUIT -> Exit gracefully
110  *
111  *  During each test loop, Master sends SIGUSR1 to the pgid of each Manager.
112  *  This tells the Children to start signalling their manager.  They do this
113  *  until the manager signals them to stop.  Once the manager finds that all
114  *  children have been signaled (by checking them off in the checklist), the
115  *  Manager signals the Master.  Once the Master acknowledges that all Managers
116  *  have talked to all their Children, the test iteration is over.
117  *
118  * 	Setup:
119  *	  Pause for SIGUSR1 if option specified.
120  *	  Fork -g Managers
121  *	    Set up signal handling for Children
122  *	    Fork -n Children for each manager
123  *	    Set up signal handling for Managers
124  *	  Set up signal handling for Master
125  *
126  * 	Test:
127  *	 Loop if the proper options are given.
128  *	   Send SIGUSR1 to all Managers and their Children
129  *	   Wait for Managers to send SIGUSR2
130  *
131  * 	Cleanup:
132  * 	  Send SIGQUIT to all Manager process groups and wait for Manager to quit.
133  * 	  Print errno log and/or timing stats if options given
134  *
135  *  Debugging:
136  *    0 - normal operations
137  *    1 - Master setup
138  *    2 - Master processing
139  *    3 - Master - Manager interaction
140  *    4 - Manager setup
141  *    5 - Manager processing
142  *    6 - Manager - Child interaction
143  *    7 - Child setup
144  *    8 - Child processing
145  *
146  *
147  *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/
148 
149 #include <sys/types.h>
150 #include <sys/wait.h>
151 #include <fcntl.h>
152 #include <dirent.h>
153 #include <unistd.h>
154 #include <stdlib.h>
155 #include <errno.h>
156 #include <string.h>
157 #include <signal.h>
158 #include "test.h"
159 
160 void setup();
161 void help();
162 void cleanup();
163 void fork_pgrps(int pgrps_left);
164 void manager(int num_procs);
165 void fork_procs(int procs_left);
166 
167 /* signal handlers */
168 void ack_ready(int sig, siginfo_t * si, void *data);
169 void ack_done(int sig, siginfo_t * si, void *data);
170 void set_create_procs(int sig);
171 void graceful_exit(int sig);
172 void set_signal_parents(int sig);
173 void clear_signal_parents(int sig);
174 void set_confirmed_ready(int sig);
175 void reset_counter(int sig);
176 void reply_to_child(int sig, siginfo_t * si, void *data);
177 void wakeup(int sig);
178 
179 /* pid checklist management */
180 struct pid_list_item {
181 	pid_t pid;
182 	short flag;
183 } *child_checklist = NULL;
184 int child_checklist_total = 0;
185 int checklist_cmp(const void *a, const void *b);
186 void checklist_reset(int bit);
187 
188 static inline int k_sigaction(int sig, struct sigaction *sa, struct sigaction *osa);
189 
190 char *TCID = "kill10";
191 int TST_TOTAL = 1;
192 
193 int num_procs = 10;
194 int num_pgrps = 2;
195 int pgrps_ready = 0;
196 int child_signal_counter = 0;
197 
198 int create_procs_flag = 0;
199 int signal_parents_flag = 0;
200 int confirmed_ready_flag = 0;
201 int debug_flag = 0;
202 pid_t mypid = 0;
203 
204 char *narg, *garg, *darg;
205 int nflag = 0, gflag = 0, dflag = 0;
206 
207 option_t options[] = {
208 	{"n:", &nflag, &narg},	/* -n #procs */
209 	{"g:", &gflag, &garg},	/* -g #pgrps */
210 	{"d:", &dflag, &darg},	/* -d <debug level>  */
211 	{NULL, NULL, NULL}
212 };
213 
main(int ac,char ** av)214 int main(int ac, char **av)
215 {
216 	int lc;
217 	int cnt;
218 
219 	tst_parse_opts(ac, av, options, &help);
220 
221 	if (nflag) {
222 		if (sscanf(narg, "%i", &num_procs) != 1) {
223 			tst_brkm(TBROK, NULL, "-n option arg is not a number");
224 		}
225 	}
226 	if (gflag) {
227 		if (sscanf(garg, "%i", &num_pgrps) != 1) {
228 			tst_brkm(TBROK, NULL, "-g option arg is not a number");
229 		}
230 	}
231 
232 	if (dflag) {
233 		if (sscanf(darg, "%i", &debug_flag) != 1) {
234 			tst_brkm(TBROK, NULL, "-d option arg is not a number");
235 		}
236 	}
237 
238 	setup();
239 
240 	for (lc = 0; TEST_LOOPING(lc); lc++) {
241 
242 		tst_count = 0;
243 		child_signal_counter = 0;
244 		pgrps_ready = 0;
245 		checklist_reset(0x03);
246 
247 		/* send SIGUSR1 to each pgroup */
248 		for (cnt = 0; cnt < child_checklist_total; ++cnt) {
249 			if (debug_flag >= 2)
250 				printf("%d: test_loop, SIGUSR1 -> %d\n",
251 				       mypid, -child_checklist[cnt].pid);
252 			kill(-child_checklist[cnt].pid, SIGUSR1);
253 		}
254 
255 		/* wait for the managers to signal they are done */
256 		while (child_signal_counter < num_pgrps) {
257 			alarm(1);
258 			if (debug_flag >= 2)
259 				printf("%d: Master pausing for done (%d/%d)\n",
260 				       mypid, child_signal_counter, num_pgrps);
261 			pause();
262 		}
263 		tst_resm(TPASS, "All %d pgrps received their signals",
264 			 child_signal_counter);
265 
266 	}
267 
268 	cleanup();
269 
270 	tst_exit();
271 }
272 
help(void)273 void help(void)
274 {
275 	printf("  -g n    Create n process groups (default: %d)\n", num_pgrps);
276 	printf
277 	    ("  -n n    Create n children in each process group (default: %d)\n",
278 	     num_procs);
279 	printf("  -d n    Set debug level to n (default: %d)\n", debug_flag);
280 }
281 
setup(void)282 void setup(void)
283 {
284 	struct sigaction sa;
285 	int i;
286 
287 	/* You will want to enable some signal handling so you can capture
288 	 * unexpected signals like SIGSEGV.
289 	 */
290 	tst_sig(FORK, DEF_HANDLER, cleanup);
291 
292 	/* One cavet that hasn't been fixed yet.  TEST_PAUSE contains the code to
293 	 * fork the test with the -c option.  You want to make sure you do this
294 	 * before you create your temporary directory.
295 	 */
296 	TEST_PAUSE;
297 
298 	mypid = getpid();
299 	sa.sa_handler = SIG_DFL;
300 	sigemptyset(&sa.sa_mask);
301 	sa.sa_flags = 0;
302 	if (debug_flag >= 1)
303 		printf("%d: setting SIGTRAP -> SIG_DFL\n", mypid);
304 	k_sigaction(SIGTRAP, &sa, NULL);
305 	if (debug_flag >= 1)
306 		printf("%d: setting SIGCONT -> SIG_DFL\n", mypid);
307 	k_sigaction(SIGCONT, &sa, NULL);
308 
309 	sa.sa_handler = set_create_procs;
310 	if (debug_flag >= 4)
311 		printf("%d: setting SIGALRM -> set_create_procs\n", mypid);
312 	k_sigaction(SIGALRM, &sa, NULL);
313 
314 	sa.sa_handler = NULL;
315 	sa.sa_sigaction = ack_ready;
316 	sa.sa_flags = SA_SIGINFO;
317 	if (debug_flag >= 1)
318 		printf("%d: setting SIGUSR1 -> ack_ready\n", mypid);
319 	k_sigaction(SIGUSR1, &sa, NULL);
320 
321 	fork_pgrps(num_pgrps);
322 
323 	/* wait for all pgrps to report in */
324 	if (debug_flag)
325 		printf("Master: %d\n", mypid);
326 	while (pgrps_ready < num_pgrps) {
327 		if (debug_flag >= 3)
328 			printf
329 			    ("%d: Master pausing for Managers to check in (%d/%d)\n",
330 			     mypid, pgrps_ready, num_pgrps);
331 		/*
332 		 * We might recieve the signal from the (last manager) before
333 		 * we issue a pause. In that case we might hang even if we have
334 		 * all the managers reported in. So set an alarm so that we can
335 		 * wake up.
336 		 */
337 		alarm(1);
338 
339 		pause();
340 	}
341 	checklist_reset(0x03);
342 	if (debug_flag) {
343 		printf("Managers: \n");
344 		for (i = 0; i < num_pgrps; i++) {
345 			printf("%d ", child_checklist[i].pid);
346 		}
347 		printf("\n");
348 	}
349 
350 	/* set up my signal processing */
351 	/* continue on ALRM */
352 	sa.sa_handler = wakeup;
353 	if (debug_flag >= 4)
354 		printf("%d: setting SIGALRM -> wakeup\n", mypid);
355 	k_sigaction(SIGALRM, &sa, NULL);
356 	/* reply to child on USR2 */
357 	sa.sa_handler = NULL;
358 	sa.sa_sigaction = ack_done;
359 	sa.sa_flags = SA_SIGINFO;
360 	if (debug_flag >= 1)
361 		printf("%d: setting SIGUSR2 -> ack_done\n", mypid);
362 	k_sigaction(SIGUSR2, &sa, NULL);
363 }
364 
ack_ready(int sig,siginfo_t * si,void * data)365 void ack_ready(int sig, siginfo_t * si, void *data)
366 {
367 	struct pid_list_item findit, *result;
368 
369 	findit.pid = si->si_pid;
370 
371 	result = bsearch(&findit, child_checklist, child_checklist_total,
372 			 sizeof(*child_checklist), checklist_cmp);
373 	if (result) {
374 		if (!(result->flag & 0x01)) {
375 			if (debug_flag >= 3)
376 				printf("%d: ack_ready, SIGUSR1 -> %d\n", mypid,
377 				       si->si_pid);
378 			kill(si->si_pid, SIGUSR1);
379 			result->flag = result->flag | 0x01;
380 			++pgrps_ready;
381 		} else {
382 			if (debug_flag >= 3)
383 				printf("%d: ack_ready, already acked %d\n",
384 				       mypid, si->si_pid);
385 		}
386 	} else {
387 		printf("received unexpected signal %d from %d",
388 		       sig, si->si_pid);
389 	}
390 }
391 
ack_done(int sig,siginfo_t * si,void * data)392 void ack_done(int sig, siginfo_t * si, void *data)
393 {
394 	struct pid_list_item findit, *result;
395 
396 	findit.pid = si->si_pid;
397 
398 	result = bsearch(&findit, child_checklist, child_checklist_total,
399 			 sizeof(*child_checklist), checklist_cmp);
400 	if (result) {
401 		if (!(result->flag & 0x02)) {
402 			if (debug_flag >= 3)
403 				printf("%d: ack_done, SIGHUP -> %d\n", mypid,
404 				       si->si_pid);
405 			kill(si->si_pid, SIGHUP);
406 			++child_signal_counter;
407 			result->flag = result->flag | 0x02;
408 		} else {
409 			if (debug_flag >= 3)
410 				printf("%d: ack_done, already told %d\n", mypid,
411 				       si->si_pid);
412 		}
413 	} else {
414 		printf("received unexpected signal %d from %d",
415 		       sig, si->si_pid);
416 	}
417 }
418 
419 /***************************************************************
420  * cleanup() - performs all ONE TIME cleanup for this test at
421  *		completion or premature exit.
422  ***************************************************************/
cleanup(void)423 void cleanup(void)
424 {
425 	int i;
426 	/* send SIGHUP to all pgroups */
427 	for (i = 0; i < num_pgrps; ++i) {
428 		/* try to do this as nicely as possible */
429 		kill(-child_checklist[i].pid, SIGQUIT);
430 		waitpid(child_checklist[i].pid, NULL, 0);
431 	}
432 	free(child_checklist);
433 
434 }
435 
436 /*********************************************************************
437  * fork_pgrps() forks off a child, changes it's pgrp, then continues
438  ********************************************************************/
fork_pgrps(int pgrps_left)439 void fork_pgrps(int pgrps_left)
440 {
441 	pid_t child;
442 
443 	if (!(child_checklist = calloc(pgrps_left, sizeof(*child_checklist)))) {
444 		tst_brkm(TBROK, cleanup,
445 			 "%d: couldn't calloc child_checklist, errno=%d : %s",
446 			 mypid, errno, strerror(errno));
447 	}
448 	child_checklist_total = 0;
449 	while (pgrps_left) {
450 		if (debug_flag >= 1)
451 			printf("%d: forking new Manager\n", mypid);
452 		switch (child = fork()) {
453 		case -1:
454 			tst_brkm(TBROK | TERRNO, cleanup,
455 				 "fork() failed in fork_pgrps(%d)", pgrps_left);
456 			break;
457 		case 0:
458 			mypid = getpid();
459 			free(child_checklist);
460 			child_checklist = NULL;
461 			manager(num_procs);
462 			break;
463 		default:
464 			child_checklist[child_checklist_total++].pid = child;
465 			setpgid(child, child);
466 			if (debug_flag >= 3)
467 				printf("%d: fork_pgrps, SIGALRM -> %d\n", mypid,
468 				       child);
469 			kill(child, SIGALRM);
470 		}
471 		--pgrps_left;
472 	}
473 	qsort(child_checklist, child_checklist_total, sizeof(*child_checklist),
474 	      checklist_cmp);
475 }
476 
set_create_procs(int sig)477 void set_create_procs(int sig)
478 {
479 	if (debug_flag >= 3)
480 		printf("%d: Manager cleared to fork\n", getpid());
481 	create_procs_flag++;
482 	return;
483 }
484 
485 /*********************************************************************
486  * new_pgrg() - handle the creation of the pgrp managers and their
487  *              children
488  ********************************************************************/
manager(int num_procs)489 void manager(int num_procs)
490 {
491 	struct sigaction sa;
492 
493 	/* Wait for the parent to change our pgid before we start forking */
494 	while (!create_procs_flag) {
495 		alarm(1);
496 		if (debug_flag >= 3)
497 			printf("%d: Manager pausing, not cleared to fork\n",
498 			       mypid);
499 		pause();
500 	}
501 
502 	/* set up the signal handling the children will use */
503 
504 	/* ignore HUP */
505 	sa.sa_handler = SIG_IGN;
506 	sigemptyset(&sa.sa_mask);
507 	sa.sa_flags = 0;
508 	if (debug_flag >= 4)
509 		printf("%d: setting SIGHUP -> SIG_IGN\n", mypid);
510 	k_sigaction(SIGHUP, &sa, NULL);
511 
512 	/* We use ALRM to make sure that we don't miss the signal effects ! */
513 	sa.sa_handler = wakeup;
514 	if (debug_flag >= 4)
515 		printf("%d: setting SIGALRM -> wakeup\n", mypid);
516 	k_sigaction(SIGALRM, &sa, NULL);
517 
518 	/* exit on QUIT */
519 	sa.sa_handler = graceful_exit;
520 	if (debug_flag >= 4)
521 		printf("%d: setting SIGQUIT -> graceful_exit\n", mypid);
522 	k_sigaction(SIGQUIT, &sa, NULL);
523 
524 	/* start signaling on USR1 */
525 	sa.sa_handler = set_signal_parents;
526 	sigfillset(&sa.sa_mask);
527 	if (debug_flag >= 7)
528 		printf("%d: setting SIGUSR1 -> set_signal_parents\n", mypid);
529 	k_sigaction(SIGUSR1, &sa, NULL);
530 	/* stop signaling on USR2 */
531 	sa.sa_handler = clear_signal_parents;
532 	if (debug_flag >= 7)
533 		printf("%d: setting SIGUSR2 -> clear_signal_parents\n", mypid);
534 	k_sigaction(SIGUSR2, &sa, NULL);
535 
536 	fork_procs(num_procs);
537 	sleep(1);		/* wait a sec to let all the children pause */
538 
539 	/* now set up my signal handling */
540 
541 	/* continue on ALRM */
542 	sa.sa_handler = wakeup;
543 	if (debug_flag >= 4)
544 		printf("%d: setting SIGALRM -> wakeup\n", mypid);
545 	k_sigaction(SIGALRM, &sa, NULL);
546 	/* mark ready confirmation on USR1 */
547 	sa.sa_handler = set_confirmed_ready;
548 	if (debug_flag >= 4)
549 		printf("%d: setting SIGUSR1 -> set_confirmed_ready\n", mypid);
550 	k_sigaction(SIGUSR1, &sa, NULL);
551 	/* reset our counter on HUP */
552 	sa.sa_handler = reset_counter;
553 	if (debug_flag >= 4)
554 		printf("%d: setting SIGHUP -> reset_counter\n", mypid);
555 	k_sigaction(SIGHUP, &sa, NULL);
556 
557 	/* reply to child on USR2 */
558 	sa.sa_handler = NULL;
559 	sa.sa_sigaction = reply_to_child;
560 	sa.sa_flags = SA_SIGINFO;
561 	if (debug_flag >= 4)
562 		printf("%d: setting SIGUSR2 -> reply_to_child\n", mypid);
563 	k_sigaction(SIGUSR2, &sa, NULL);
564 
565 	/* tell our parent that we are ready to rock */
566 	while (!confirmed_ready_flag) {
567 		if (debug_flag >= 3)
568 			printf("%d: Manager, SIGUSR1 -> %d\n", mypid,
569 			       getppid());
570 		if (kill(getppid(), SIGUSR1) == -1) {
571 			printf("%d: Couldn't signal master (%d) that we're "
572 			       "ready. %d: %s",
573 			       mypid, getppid(), errno, strerror(errno));
574 			exit(errno);
575 		}
576 		usleep(100);
577 	}
578 
579 	/* handle pgroup management while the tests are running */
580 	while (1) {
581 		alarm(1);
582 		if (debug_flag >= 5)
583 			printf("%d: Manager pausing (%d/%d)\n",
584 			       mypid, child_signal_counter, num_procs);
585 		pause();
586 		if (child_signal_counter >= num_procs) {
587 			confirmed_ready_flag = 0;
588 			printf("%d: All %d children reported in\n",
589 			       mypid, child_signal_counter);
590 			while (child_signal_counter) {
591 				if (debug_flag >= 3)
592 					printf("%d: Manager, SIGUSR2 -> %d\n",
593 					       mypid, getppid());
594 				if (kill(getppid(), SIGUSR2) == -1) {
595 					printf("%d: Couldn't signal master "
596 					       "(%d) that we're ready. %d: %s\n",
597 					       mypid, getppid(), errno,
598 					       strerror(errno));
599 					exit(errno);
600 				}
601 				usleep(100);
602 			}
603 		}
604 	}
605 }
606 
607 /* some simple signal handlers for the kids */
graceful_exit(int sig)608 void graceful_exit(int sig)
609 {
610 	exit(0);
611 }
612 
set_signal_parents(int sig)613 void set_signal_parents(int sig)
614 {
615 	if (debug_flag >= 8)
616 		printf("%d: Child start signaling\n", mypid);
617 	signal_parents_flag = 1;
618 }
619 
clear_signal_parents(int sig)620 void clear_signal_parents(int sig)
621 {
622 	if (debug_flag >= 8)
623 		printf("%d: Child stop signaling\n", mypid);
624 	signal_parents_flag = 0;
625 }
626 
set_confirmed_ready(int sig)627 void set_confirmed_ready(int sig)
628 {
629 
630 	if (debug_flag >= 3)
631 		printf("%d: Manager confirmed ready\n", mypid);
632 	confirmed_ready_flag = 1;
633 }
634 
reset_counter(int sig)635 void reset_counter(int sig)
636 {
637 	checklist_reset(0xFF);
638 	child_signal_counter = 0;
639 	if (debug_flag >= 3)
640 		printf("%d: reset_counter\n", mypid);
641 }
642 
reply_to_child(int sig,siginfo_t * si,void * data)643 void reply_to_child(int sig, siginfo_t * si, void *data)
644 {
645 	struct pid_list_item findit, *result;
646 
647 	findit.pid = si->si_pid;
648 
649 	result = bsearch(&findit, child_checklist, child_checklist_total,
650 			 sizeof(*child_checklist), checklist_cmp);
651 	if (result) {
652 		if (!result->flag) {
653 			if (debug_flag >= 6)
654 				printf("%d: reply_to_child, SIGUSR1 -> %d\n",
655 				       mypid, si->si_pid);
656 			kill(si->si_pid, SIGUSR2);
657 			++child_signal_counter;
658 			result->flag = 1;
659 		} else {
660 			if (debug_flag >= 6)
661 				printf("%d: reply_to_child, already told %d\n",
662 				       mypid, si->si_pid);
663 		}
664 	} else {
665 		tst_brkm(TBROK, cleanup,
666 			 "received unexpected signal from %d", si->si_pid);
667 	}
668 }
669 
wakeup(int sig)670 void wakeup(int sig)
671 {
672 	return;
673 }
674 
675 /*************************************************
676  * fork_procs() - create all the children
677  ************************************************/
fork_procs(int procs_left)678 void fork_procs(int procs_left)
679 {
680 	pid_t child;
681 
682 	if (!(child_checklist = calloc(procs_left, sizeof(*child_checklist)))) {
683 		tst_brkm(TBROK, cleanup,
684 			 "%d: couldn't calloc child_checklist, errno=%d : %s",
685 			 mypid, errno, strerror(errno));
686 	}
687 	child_checklist_total = 0;
688 
689 	/* We are setting the flag for children, to avoid missing any signals */
690 	signal_parents_flag = 0;
691 
692 	while (procs_left) {
693 		if (debug_flag >= 4)
694 			printf("%d: forking new child\n", mypid);
695 		switch (child = fork()) {
696 		case -1:
697 			tst_brkm(TBROK | TERRNO, cleanup,
698 				 "fork() failed in fork_procs(%d)", procs_left);
699 			break;
700 		case 0:
701 			mypid = getpid();
702 			while (1) {
703 				/* wait to start */
704 				if (debug_flag >= 8)
705 					printf("%d: child pausing\n", mypid);
706 				/*
707 				 * If we have already recieved the signal, we dont
708 				 * want to pause for it !
709 				 */
710 				while (!signal_parents_flag) {
711 					alarm(2);
712 					pause();
713 				}
714 
715 				/* if we started, call mama */
716 				while (signal_parents_flag) {
717 					if (debug_flag >= 6)
718 						printf("%d: child, SIGUSR2 "
719 						       "-> %d\n",
720 						       mypid, getppid());
721 					if (kill(getppid(), SIGUSR2) == -1) {
722 						/* something went wrong */
723 						printf("%d: kill(ppid:%d, "
724 						       "SIGUSR2) failed. %d: %s",
725 						       mypid, getppid(), errno,
726 						       strerror(errno));
727 						exit(errno);
728 					}
729 					usleep(100);
730 				}
731 			}
732 			break;
733 		default:
734 			child_checklist[child_checklist_total++].pid = child;
735 		}
736 		procs_left--;
737 	}
738 	qsort(child_checklist, child_checklist_total, sizeof(*child_checklist),
739 	      checklist_cmp);
740 }
741 
checklist_cmp(const void * a,const void * b)742 int checklist_cmp(const void *a, const void *b)
743 {
744 	const struct pid_list_item *pa = (const struct pid_list_item *)a;
745 	const struct pid_list_item *pb = (const struct pid_list_item *)b;
746 
747 	return (pa->pid > pb->pid) - (pa->pid < pb->pid);
748 }
749 
checklist_reset(int bit)750 void checklist_reset(int bit)
751 {
752 	int i;
753 	for (i = 0; i < child_checklist_total; i++) {
754 		child_checklist[i].flag = child_checklist[i].flag & (~bit);
755 	}
756 
757 }
758 
k_sigaction(int sig,struct sigaction * sa,struct sigaction * osa)759 static inline int k_sigaction(int sig, struct sigaction *sa, struct sigaction *osa)
760 {
761 	int ret;
762 	if ((ret = sigaction(sig, sa, osa)) == -1) {
763 		tst_brkm(TBROK | TERRNO, cleanup, "sigaction(%d, ...) failed",
764 			 sig);
765 	}
766 	return ret;
767 }
768