• Home
  • History
  • Annotate
  • 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 receive 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 received 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