xref: /minix3/minix/tests/test79.c (revision 433d6423c39e34ec4b79c950597bb2d236f886be)
1*433d6423SLionel Sambuc /* Tests for PM signal handling robustness - by D.C. van Moolenbroek */
2*433d6423SLionel Sambuc /*
3*433d6423SLionel Sambuc  * The signal handling code must not rely on priorities assigned to services,
4*433d6423SLionel Sambuc  * and so, this test (like any test!) must also pass if PM and/or VFS are not
5*433d6423SLionel Sambuc  * given a fixed high priority.  A good way to verify this is to let PM and VFS
6*433d6423SLionel Sambuc  * be scheduled by SCHED rather than KERNEL, and to give them the same priority
7*433d6423SLionel Sambuc  * as (or slightly lower than) normal user processes.  Note that if VFS is
8*433d6423SLionel Sambuc  * configured to use a priority *far lower* than user processes, starvation may
9*433d6423SLionel Sambuc  * cause this test not to complete in some scenarios.  In that case, Ctrl+C
10*433d6423SLionel Sambuc  * should still be able to kill the test.
11*433d6423SLionel Sambuc  */
12*433d6423SLionel Sambuc #include <stdlib.h>
13*433d6423SLionel Sambuc #include <stdio.h>
14*433d6423SLionel Sambuc #include <signal.h>
15*433d6423SLionel Sambuc #include <sys/wait.h>
16*433d6423SLionel Sambuc #include <sys/time.h>
17*433d6423SLionel Sambuc #include <sys/utsname.h>
18*433d6423SLionel Sambuc 
19*433d6423SLionel Sambuc #define ITERATIONS 1
20*433d6423SLionel Sambuc 
21*433d6423SLionel Sambuc #include "common.h"
22*433d6423SLionel Sambuc 
23*433d6423SLionel Sambuc #define NR_SIGNALS	20000
24*433d6423SLionel Sambuc 
25*433d6423SLionel Sambuc #define MAX_SIGNALERS	3
26*433d6423SLionel Sambuc 
27*433d6423SLionel Sambuc static const int signaler_sig[MAX_SIGNALERS] = { SIGUSR1, SIGUSR2, SIGHUP };
28*433d6423SLionel Sambuc static pid_t signaler_pid[MAX_SIGNALERS];
29*433d6423SLionel Sambuc static int sig_counter;
30*433d6423SLionel Sambuc 
31*433d6423SLionel Sambuc enum {
32*433d6423SLionel Sambuc 	JOB_RUN = 0,
33*433d6423SLionel Sambuc 	JOB_CALL_PM,
34*433d6423SLionel Sambuc 	JOB_CALL_VFS,
35*433d6423SLionel Sambuc 	JOB_SET_MASK,
36*433d6423SLionel Sambuc 	JOB_BLOCK_PM,
37*433d6423SLionel Sambuc 	JOB_BLOCK_VFS,
38*433d6423SLionel Sambuc 	JOB_CALL_PM_VFS,
39*433d6423SLionel Sambuc 	JOB_FORK,
40*433d6423SLionel Sambuc 	NR_JOBS
41*433d6423SLionel Sambuc };
42*433d6423SLionel Sambuc 
43*433d6423SLionel Sambuc #define OPT_NEST	0x1
44*433d6423SLionel Sambuc #define OPT_ALARM	0x2
45*433d6423SLionel Sambuc #define OPT_ALL		0x3
46*433d6423SLionel Sambuc 
47*433d6423SLionel Sambuc struct link {
48*433d6423SLionel Sambuc 	pid_t pid;
49*433d6423SLionel Sambuc 	int sndfd;
50*433d6423SLionel Sambuc 	int rcvfd;
51*433d6423SLionel Sambuc };
52*433d6423SLionel Sambuc 
53*433d6423SLionel Sambuc /*
54*433d6423SLionel Sambuc  * Spawn a child process, with a pair of pipes to talk to it bidirectionally.
55*433d6423SLionel Sambuc  */
56*433d6423SLionel Sambuc static void
spawn(struct link * link,void (* proc)(struct link *))57*433d6423SLionel Sambuc spawn(struct link *link, void (*proc)(struct link *))
58*433d6423SLionel Sambuc {
59*433d6423SLionel Sambuc 	int up[2], dn[2];
60*433d6423SLionel Sambuc 
61*433d6423SLionel Sambuc 	fflush(stdout);
62*433d6423SLionel Sambuc 	fflush(stderr);
63*433d6423SLionel Sambuc 
64*433d6423SLionel Sambuc 	if (pipe(up) != 0) e(0);
65*433d6423SLionel Sambuc 	if (pipe(dn) != 0) e(0);
66*433d6423SLionel Sambuc 
67*433d6423SLionel Sambuc 	link->pid = fork();
68*433d6423SLionel Sambuc 
69*433d6423SLionel Sambuc 	switch (link->pid) {
70*433d6423SLionel Sambuc 	case 0:
71*433d6423SLionel Sambuc 		close(up[1]);
72*433d6423SLionel Sambuc 		close(dn[0]);
73*433d6423SLionel Sambuc 
74*433d6423SLionel Sambuc 		link->rcvfd = up[0];
75*433d6423SLionel Sambuc 		link->sndfd = dn[1];
76*433d6423SLionel Sambuc 
77*433d6423SLionel Sambuc 		errct = 0;
78*433d6423SLionel Sambuc 
79*433d6423SLionel Sambuc 		proc(link);
80*433d6423SLionel Sambuc 
81*433d6423SLionel Sambuc 		/* Close our pipe FDs on exit, so that we can make zombies. */
82*433d6423SLionel Sambuc 		exit(errct);
83*433d6423SLionel Sambuc 	case -1:
84*433d6423SLionel Sambuc 		e(0);
85*433d6423SLionel Sambuc 		break;
86*433d6423SLionel Sambuc 	}
87*433d6423SLionel Sambuc 
88*433d6423SLionel Sambuc 	close(up[0]);
89*433d6423SLionel Sambuc 	close(dn[1]);
90*433d6423SLionel Sambuc 
91*433d6423SLionel Sambuc 	link->sndfd = up[1];
92*433d6423SLionel Sambuc 	link->rcvfd = dn[0];
93*433d6423SLionel Sambuc }
94*433d6423SLionel Sambuc 
95*433d6423SLionel Sambuc /*
96*433d6423SLionel Sambuc  * Wait for a child process to terminate, and clean up.
97*433d6423SLionel Sambuc  */
98*433d6423SLionel Sambuc static void
collect(struct link * link)99*433d6423SLionel Sambuc collect(struct link *link)
100*433d6423SLionel Sambuc {
101*433d6423SLionel Sambuc 	int status;
102*433d6423SLionel Sambuc 
103*433d6423SLionel Sambuc 	close(link->sndfd);
104*433d6423SLionel Sambuc 	close(link->rcvfd);
105*433d6423SLionel Sambuc 
106*433d6423SLionel Sambuc 	if (waitpid(link->pid, &status, 0) <= 0) e(0);
107*433d6423SLionel Sambuc 
108*433d6423SLionel Sambuc 	if (!WIFEXITED(status)) e(0);
109*433d6423SLionel Sambuc 	else errct += WEXITSTATUS(status);
110*433d6423SLionel Sambuc }
111*433d6423SLionel Sambuc 
112*433d6423SLionel Sambuc /*
113*433d6423SLionel Sambuc  * Forcibly terminate a child process, and clean up.
114*433d6423SLionel Sambuc  */
115*433d6423SLionel Sambuc static void
terminate(struct link * link)116*433d6423SLionel Sambuc terminate(struct link *link)
117*433d6423SLionel Sambuc {
118*433d6423SLionel Sambuc 	int status;
119*433d6423SLionel Sambuc 
120*433d6423SLionel Sambuc 	if (kill(link->pid, SIGKILL) != 0) e(0);
121*433d6423SLionel Sambuc 
122*433d6423SLionel Sambuc 	close(link->sndfd);
123*433d6423SLionel Sambuc 	close(link->rcvfd);
124*433d6423SLionel Sambuc 
125*433d6423SLionel Sambuc 	if (waitpid(link->pid, &status, 0) <= 0) e(0);
126*433d6423SLionel Sambuc 
127*433d6423SLionel Sambuc 	if (WIFSIGNALED(status)) {
128*433d6423SLionel Sambuc 		if (WTERMSIG(status) != SIGKILL) e(0);
129*433d6423SLionel Sambuc 	} else {
130*433d6423SLionel Sambuc 		if (!WIFEXITED(status)) e(0);
131*433d6423SLionel Sambuc 		else errct += WEXITSTATUS(status);
132*433d6423SLionel Sambuc 	}
133*433d6423SLionel Sambuc }
134*433d6423SLionel Sambuc 
135*433d6423SLionel Sambuc /*
136*433d6423SLionel Sambuc  * Send an integer value to the child or parent.
137*433d6423SLionel Sambuc  */
138*433d6423SLionel Sambuc static void
snd(struct link * link,int val)139*433d6423SLionel Sambuc snd(struct link *link, int val)
140*433d6423SLionel Sambuc {
141*433d6423SLionel Sambuc 	if (write(link->sndfd, (void *) &val, sizeof(val)) != sizeof(val))
142*433d6423SLionel Sambuc 		e(0);
143*433d6423SLionel Sambuc }
144*433d6423SLionel Sambuc 
145*433d6423SLionel Sambuc /*
146*433d6423SLionel Sambuc  * Receive an integer value from the child or parent, or -1 on EOF.
147*433d6423SLionel Sambuc  */
148*433d6423SLionel Sambuc static int
rcv(struct link * link)149*433d6423SLionel Sambuc rcv(struct link *link)
150*433d6423SLionel Sambuc {
151*433d6423SLionel Sambuc 	int r, val;
152*433d6423SLionel Sambuc 
153*433d6423SLionel Sambuc 	if ((r = read(link->rcvfd, (void *) &val, sizeof(val))) == 0)
154*433d6423SLionel Sambuc 		return -1;
155*433d6423SLionel Sambuc 
156*433d6423SLionel Sambuc 	if (r != sizeof(val)) e(0);
157*433d6423SLionel Sambuc 
158*433d6423SLionel Sambuc 	return val;
159*433d6423SLionel Sambuc }
160*433d6423SLionel Sambuc 
161*433d6423SLionel Sambuc /*
162*433d6423SLionel Sambuc  * Set a signal handler for a particular signal, blocking either all or no
163*433d6423SLionel Sambuc  * signals when the signal handler is invoked.
164*433d6423SLionel Sambuc  */
165*433d6423SLionel Sambuc static void
set_handler(int sig,void (* proc)(int),int block)166*433d6423SLionel Sambuc set_handler(int sig, void (*proc)(int), int block)
167*433d6423SLionel Sambuc {
168*433d6423SLionel Sambuc 	struct sigaction act;
169*433d6423SLionel Sambuc 
170*433d6423SLionel Sambuc 	memset(&act, 0, sizeof(act));
171*433d6423SLionel Sambuc 	if (block) sigfillset(&act.sa_mask);
172*433d6423SLionel Sambuc 	act.sa_handler = proc;
173*433d6423SLionel Sambuc 
174*433d6423SLionel Sambuc 	if (sigaction(sig, &act, NULL) != 0) e(0);
175*433d6423SLionel Sambuc }
176*433d6423SLionel Sambuc 
177*433d6423SLionel Sambuc /*
178*433d6423SLionel Sambuc  * Generic signal handler for the worker process.
179*433d6423SLionel Sambuc  */
180*433d6423SLionel Sambuc static void
worker_handler(int sig)181*433d6423SLionel Sambuc worker_handler(int sig)
182*433d6423SLionel Sambuc {
183*433d6423SLionel Sambuc 	int i;
184*433d6423SLionel Sambuc 
185*433d6423SLionel Sambuc 	switch (sig) {
186*433d6423SLionel Sambuc 	case SIGUSR1:
187*433d6423SLionel Sambuc 	case SIGUSR2:
188*433d6423SLionel Sambuc 	case SIGHUP:
189*433d6423SLionel Sambuc 		for (i = 0; i < MAX_SIGNALERS; i++) {
190*433d6423SLionel Sambuc 			if (signaler_sig[i] != sig) continue;
191*433d6423SLionel Sambuc 
192*433d6423SLionel Sambuc 			if (signaler_pid[i] == -1) e(0);
193*433d6423SLionel Sambuc 			else if (kill(signaler_pid[i], SIGUSR1) != 0) e(0);
194*433d6423SLionel Sambuc 			break;
195*433d6423SLionel Sambuc 		}
196*433d6423SLionel Sambuc 		if (i == MAX_SIGNALERS) e(0);
197*433d6423SLionel Sambuc 		break;
198*433d6423SLionel Sambuc 	case SIGTERM:
199*433d6423SLionel Sambuc 		exit(errct);
200*433d6423SLionel Sambuc 		break;
201*433d6423SLionel Sambuc 	case SIGALRM:
202*433d6423SLionel Sambuc 		/* Do nothing. */
203*433d6423SLionel Sambuc 		break;
204*433d6423SLionel Sambuc 	default:
205*433d6423SLionel Sambuc 		e(0);
206*433d6423SLionel Sambuc 	}
207*433d6423SLionel Sambuc }
208*433d6423SLionel Sambuc 
209*433d6423SLionel Sambuc /*
210*433d6423SLionel Sambuc  * Procedure for the worker process.  Sets up its own environment using
211*433d6423SLionel Sambuc  * information sent to it by the parent, sends an acknowledgement to the
212*433d6423SLionel Sambuc  * parent, and loops executing the job given to it until a SIGTERM comes in.
213*433d6423SLionel Sambuc  */
214*433d6423SLionel Sambuc static void __dead
worker_proc(struct link * parent)215*433d6423SLionel Sambuc worker_proc(struct link *parent)
216*433d6423SLionel Sambuc {
217*433d6423SLionel Sambuc 	struct utsname name;
218*433d6423SLionel Sambuc 	struct itimerval it;
219*433d6423SLionel Sambuc 	struct timeval tv;
220*433d6423SLionel Sambuc 	sigset_t set, oset;
221*433d6423SLionel Sambuc 	uid_t uid;
222*433d6423SLionel Sambuc 	int i, job, options;
223*433d6423SLionel Sambuc 
224*433d6423SLionel Sambuc 	job = rcv(parent);
225*433d6423SLionel Sambuc 	options = rcv(parent);
226*433d6423SLionel Sambuc 
227*433d6423SLionel Sambuc 	for (i = 0; i < MAX_SIGNALERS; i++) {
228*433d6423SLionel Sambuc 		set_handler(signaler_sig[i], worker_handler,
229*433d6423SLionel Sambuc 		    !(options & OPT_NEST));
230*433d6423SLionel Sambuc 
231*433d6423SLionel Sambuc 		signaler_pid[i] = rcv(parent);
232*433d6423SLionel Sambuc 	}
233*433d6423SLionel Sambuc 
234*433d6423SLionel Sambuc 	set_handler(SIGTERM, worker_handler, 1 /* block */);
235*433d6423SLionel Sambuc 	set_handler(SIGALRM, worker_handler, !(options & OPT_NEST));
236*433d6423SLionel Sambuc 
237*433d6423SLionel Sambuc 	snd(parent, 0);
238*433d6423SLionel Sambuc 
239*433d6423SLionel Sambuc 	if (options & OPT_ALARM) {
240*433d6423SLionel Sambuc 		/* The timer would kill wimpy platforms such as ARM. */
241*433d6423SLionel Sambuc 		if (uname(&name) < 0) e(0);
242*433d6423SLionel Sambuc 		if (strcmp(name.machine, "arm")) {
243*433d6423SLionel Sambuc 			it.it_value.tv_sec = 0;
244*433d6423SLionel Sambuc 			it.it_value.tv_usec = 1;
245*433d6423SLionel Sambuc 			it.it_interval.tv_sec = 0;
246*433d6423SLionel Sambuc 			it.it_interval.tv_usec = 1;
247*433d6423SLionel Sambuc 			if (setitimer(ITIMER_REAL, &it, NULL) != 0) e(0);
248*433d6423SLionel Sambuc 		}
249*433d6423SLionel Sambuc 	}
250*433d6423SLionel Sambuc 
251*433d6423SLionel Sambuc 	switch (job) {
252*433d6423SLionel Sambuc 	case JOB_RUN:
253*433d6423SLionel Sambuc 		for (;;);
254*433d6423SLionel Sambuc 		break;
255*433d6423SLionel Sambuc 	case JOB_CALL_PM:
256*433d6423SLionel Sambuc 		/*
257*433d6423SLionel Sambuc 		 * Part of the complication of the current system in PM comes
258*433d6423SLionel Sambuc 		 * from the fact that when a process is being stopped, it might
259*433d6423SLionel Sambuc 		 * already have started sending a message.  That message will
260*433d6423SLionel Sambuc 		 * arrive at its destination regardless of the process's run
261*433d6423SLionel Sambuc 		 * state.  PM must avoid setting up a signal handler (and
262*433d6423SLionel Sambuc 		 * changing the process's signal mask as part of that) if such
263*433d6423SLionel Sambuc 		 * a message is still in transit, because that message might,
264*433d6423SLionel Sambuc 		 * for example, query (or even change) the signal mask.
265*433d6423SLionel Sambuc 		 */
266*433d6423SLionel Sambuc 		for (;;) {
267*433d6423SLionel Sambuc 			if (sigprocmask(SIG_BLOCK, NULL, &set) != 0) e(0);
268*433d6423SLionel Sambuc 			if (sigismember(&set, SIGUSR1)) e(0);
269*433d6423SLionel Sambuc 		}
270*433d6423SLionel Sambuc 		break;
271*433d6423SLionel Sambuc 	case JOB_CALL_VFS:
272*433d6423SLionel Sambuc 		for (;;) {
273*433d6423SLionel Sambuc 			tv.tv_sec = 0;
274*433d6423SLionel Sambuc 			tv.tv_usec = 0;
275*433d6423SLionel Sambuc 			select(0, NULL, NULL, NULL, &tv);
276*433d6423SLionel Sambuc 		}
277*433d6423SLionel Sambuc 		break;
278*433d6423SLionel Sambuc 	case JOB_SET_MASK:
279*433d6423SLionel Sambuc 		for (;;) {
280*433d6423SLionel Sambuc 			sigfillset(&set);
281*433d6423SLionel Sambuc 			if (sigprocmask(SIG_SETMASK, &set, &oset) != 0) e(0);
282*433d6423SLionel Sambuc 			if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) e(0);
283*433d6423SLionel Sambuc 		}
284*433d6423SLionel Sambuc 		break;
285*433d6423SLionel Sambuc 	case JOB_BLOCK_PM:
286*433d6423SLionel Sambuc 		for (;;) {
287*433d6423SLionel Sambuc 			sigemptyset(&set);
288*433d6423SLionel Sambuc 			sigsuspend(&set);
289*433d6423SLionel Sambuc 		}
290*433d6423SLionel Sambuc 		break;
291*433d6423SLionel Sambuc 	case JOB_BLOCK_VFS:
292*433d6423SLionel Sambuc 		for (;;)
293*433d6423SLionel Sambuc 			select(0, NULL, NULL, NULL, NULL);
294*433d6423SLionel Sambuc 		break;
295*433d6423SLionel Sambuc 	case JOB_CALL_PM_VFS:
296*433d6423SLionel Sambuc 		uid = getuid();
297*433d6423SLionel Sambuc 		for (;;)
298*433d6423SLionel Sambuc 			setuid(uid);
299*433d6423SLionel Sambuc 		break;
300*433d6423SLionel Sambuc 	case JOB_FORK:
301*433d6423SLionel Sambuc 		/*
302*433d6423SLionel Sambuc 		 * The child exits immediately; the parent kills the child
303*433d6423SLionel Sambuc 		 * immediately.  The outcome mostly depends on scheduling.
304*433d6423SLionel Sambuc 		 * Varying process priorities may yield different tests.
305*433d6423SLionel Sambuc 		 */
306*433d6423SLionel Sambuc 		for (;;) {
307*433d6423SLionel Sambuc 			pid_t pid = fork();
308*433d6423SLionel Sambuc 			switch (pid) {
309*433d6423SLionel Sambuc 			case 0:
310*433d6423SLionel Sambuc 				exit(0);
311*433d6423SLionel Sambuc 			case -1:
312*433d6423SLionel Sambuc 				e(1);
313*433d6423SLionel Sambuc 				break;
314*433d6423SLionel Sambuc 			default:
315*433d6423SLionel Sambuc 				kill(pid, SIGKILL);
316*433d6423SLionel Sambuc 				if (wait(NULL) != pid) e(0);
317*433d6423SLionel Sambuc 			}
318*433d6423SLionel Sambuc 		}
319*433d6423SLionel Sambuc 		break;
320*433d6423SLionel Sambuc 	default:
321*433d6423SLionel Sambuc 		e(0);
322*433d6423SLionel Sambuc 		exit(1);
323*433d6423SLionel Sambuc 	}
324*433d6423SLionel Sambuc }
325*433d6423SLionel Sambuc 
326*433d6423SLionel Sambuc /*
327*433d6423SLionel Sambuc  * Signal handler procedure for the signaler processes, counting the number of
328*433d6423SLionel Sambuc  * signals received from the worker process.
329*433d6423SLionel Sambuc  */
330*433d6423SLionel Sambuc static void
signaler_handler(int sig)331*433d6423SLionel Sambuc signaler_handler(int sig)
332*433d6423SLionel Sambuc {
333*433d6423SLionel Sambuc 	sig_counter++;
334*433d6423SLionel Sambuc }
335*433d6423SLionel Sambuc 
336*433d6423SLionel Sambuc /*
337*433d6423SLionel Sambuc  * Procedure for the signaler processes.  Gets the pid of the worker process
338*433d6423SLionel Sambuc  * and the signal to use, and then repeatedly sends that signal to the worker
339*433d6423SLionel Sambuc  * process, waiting for a SIGUSR1 signal back from the worker before
340*433d6423SLionel Sambuc  * continuing.  This signal ping-pong is repeated for a set number of times.
341*433d6423SLionel Sambuc  */
342*433d6423SLionel Sambuc static void
signaler_proc(struct link * parent)343*433d6423SLionel Sambuc signaler_proc(struct link *parent)
344*433d6423SLionel Sambuc {
345*433d6423SLionel Sambuc 	sigset_t set, oset;
346*433d6423SLionel Sambuc 	pid_t pid;
347*433d6423SLionel Sambuc 	int i, sig, nr;
348*433d6423SLionel Sambuc 
349*433d6423SLionel Sambuc 	pid = rcv(parent);
350*433d6423SLionel Sambuc 	sig = rcv(parent);
351*433d6423SLionel Sambuc 	nr = rcv(parent);
352*433d6423SLionel Sambuc 	sig_counter = 0;
353*433d6423SLionel Sambuc 
354*433d6423SLionel Sambuc 	sigfillset(&set);
355*433d6423SLionel Sambuc 	if (sigprocmask(SIG_SETMASK, &set, &oset) != 0) e(0);
356*433d6423SLionel Sambuc 
357*433d6423SLionel Sambuc 	set_handler(SIGUSR1, signaler_handler, 1 /*block*/);
358*433d6423SLionel Sambuc 
359*433d6423SLionel Sambuc 	for (i = 0; nr == 0 || i < nr; i++) {
360*433d6423SLionel Sambuc 		if (sig_counter != i) e(0);
361*433d6423SLionel Sambuc 
362*433d6423SLionel Sambuc 		if (kill(pid, sig) != 0 && nr > 0) e(0);
363*433d6423SLionel Sambuc 
364*433d6423SLionel Sambuc 		sigsuspend(&oset);
365*433d6423SLionel Sambuc 	}
366*433d6423SLionel Sambuc 
367*433d6423SLionel Sambuc 	if (sig_counter != nr) e(0);
368*433d6423SLionel Sambuc }
369*433d6423SLionel Sambuc 
370*433d6423SLionel Sambuc /*
371*433d6423SLionel Sambuc  * Set up the worker and signaler processes, wait for the signaler processes to
372*433d6423SLionel Sambuc  * do their work and terminate, and then terminate the worker process.
373*433d6423SLionel Sambuc  */
374*433d6423SLionel Sambuc static void
sub79a(int job,int signalers,int options)375*433d6423SLionel Sambuc sub79a(int job, int signalers, int options)
376*433d6423SLionel Sambuc {
377*433d6423SLionel Sambuc 	struct link worker, signaler[MAX_SIGNALERS];
378*433d6423SLionel Sambuc 	int i;
379*433d6423SLionel Sambuc 
380*433d6423SLionel Sambuc 	spawn(&worker, worker_proc);
381*433d6423SLionel Sambuc 
382*433d6423SLionel Sambuc 	snd(&worker, job);
383*433d6423SLionel Sambuc 	snd(&worker, options);
384*433d6423SLionel Sambuc 
385*433d6423SLionel Sambuc 	for (i = 0; i < signalers; i++) {
386*433d6423SLionel Sambuc 		spawn(&signaler[i], signaler_proc);
387*433d6423SLionel Sambuc 
388*433d6423SLionel Sambuc 		snd(&worker, signaler[i].pid);
389*433d6423SLionel Sambuc 	}
390*433d6423SLionel Sambuc 	for (; i < MAX_SIGNALERS; i++)
391*433d6423SLionel Sambuc 		snd(&worker, -1);
392*433d6423SLionel Sambuc 
393*433d6423SLionel Sambuc 	if (rcv(&worker) != 0) e(0);
394*433d6423SLionel Sambuc 
395*433d6423SLionel Sambuc 	for (i = 0; i < signalers; i++) {
396*433d6423SLionel Sambuc 		snd(&signaler[i], worker.pid);
397*433d6423SLionel Sambuc 		snd(&signaler[i], signaler_sig[i]);
398*433d6423SLionel Sambuc 		snd(&signaler[i], NR_SIGNALS);
399*433d6423SLionel Sambuc 	}
400*433d6423SLionel Sambuc 
401*433d6423SLionel Sambuc 	for (i = 0; i < signalers; i++)
402*433d6423SLionel Sambuc 		collect(&signaler[i]);
403*433d6423SLionel Sambuc 
404*433d6423SLionel Sambuc 	if (kill(worker.pid, SIGTERM) != 0) e(0);
405*433d6423SLionel Sambuc 
406*433d6423SLionel Sambuc 	collect(&worker);
407*433d6423SLionel Sambuc }
408*433d6423SLionel Sambuc 
409*433d6423SLionel Sambuc /*
410*433d6423SLionel Sambuc  * Stress test for signal handling.  One worker process gets signals from up to
411*433d6423SLionel Sambuc  * three signaler processes while performing one of a number of jobs.  It
412*433d6423SLionel Sambuc  * replies to each signal by signaling the source, thus creating a ping-pong
413*433d6423SLionel Sambuc  * effect for each of the signaler processes.  The signal ping-ponging is
414*433d6423SLionel Sambuc  * supposed to be reliable, and the most important aspect of the test is that
415*433d6423SLionel Sambuc  * no signals get lost.  The test is performed a number of times, varying the
416*433d6423SLionel Sambuc  * job executed by the worker process, the number of signalers, whether signals
417*433d6423SLionel Sambuc  * are blocked while executing a signal handler in the worker, and whether the
418*433d6423SLionel Sambuc  * worker process has a timer running at high frequency.
419*433d6423SLionel Sambuc  */
420*433d6423SLionel Sambuc static void
test79a(void)421*433d6423SLionel Sambuc test79a(void)
422*433d6423SLionel Sambuc {
423*433d6423SLionel Sambuc 	int job, signalers, options;
424*433d6423SLionel Sambuc 
425*433d6423SLionel Sambuc 	subtest = 1;
426*433d6423SLionel Sambuc 
427*433d6423SLionel Sambuc 	for (options = 0; options <= OPT_ALL; options++)
428*433d6423SLionel Sambuc 		for (signalers = 1; signalers <= MAX_SIGNALERS; signalers++)
429*433d6423SLionel Sambuc 			for (job = 0; job < NR_JOBS; job++)
430*433d6423SLionel Sambuc 				sub79a(job, signalers, options);
431*433d6423SLionel Sambuc }
432*433d6423SLionel Sambuc 
433*433d6423SLionel Sambuc /*
434*433d6423SLionel Sambuc  * Set up the worker process and optionally a signaler process, wait for a
435*433d6423SLionel Sambuc  * predetermined amount of time, and then kill all the child processes.
436*433d6423SLionel Sambuc  */
437*433d6423SLionel Sambuc static void
sub79b(int job,int use_signaler,int options)438*433d6423SLionel Sambuc sub79b(int job, int use_signaler, int options)
439*433d6423SLionel Sambuc {
440*433d6423SLionel Sambuc 	struct link worker, signaler;
441*433d6423SLionel Sambuc 	struct timeval tv;
442*433d6423SLionel Sambuc 	int i;
443*433d6423SLionel Sambuc 
444*433d6423SLionel Sambuc 	spawn(&worker, worker_proc);
445*433d6423SLionel Sambuc 
446*433d6423SLionel Sambuc 	snd(&worker, job);
447*433d6423SLionel Sambuc 	snd(&worker, options);
448*433d6423SLionel Sambuc 
449*433d6423SLionel Sambuc 	if ((i = use_signaler) != 0) {
450*433d6423SLionel Sambuc 		spawn(&signaler, signaler_proc);
451*433d6423SLionel Sambuc 
452*433d6423SLionel Sambuc 		snd(&worker, signaler.pid);
453*433d6423SLionel Sambuc 	}
454*433d6423SLionel Sambuc 	for (; i < MAX_SIGNALERS; i++)
455*433d6423SLionel Sambuc 		snd(&worker, -1);
456*433d6423SLionel Sambuc 
457*433d6423SLionel Sambuc 	if (rcv(&worker) != 0) e(0);
458*433d6423SLionel Sambuc 
459*433d6423SLionel Sambuc 	if (use_signaler) {
460*433d6423SLionel Sambuc 		snd(&signaler, worker.pid);
461*433d6423SLionel Sambuc 		snd(&signaler, signaler_sig[0]);
462*433d6423SLionel Sambuc 		snd(&signaler, 0);
463*433d6423SLionel Sambuc 	}
464*433d6423SLionel Sambuc 
465*433d6423SLionel Sambuc 	/* Use select() so that we can verify we don't get signals. */
466*433d6423SLionel Sambuc 	tv.tv_sec = 0;
467*433d6423SLionel Sambuc 	tv.tv_usec = 100000;
468*433d6423SLionel Sambuc 	if (select(0, NULL, NULL, NULL, &tv) != 0) e(0);
469*433d6423SLionel Sambuc 
470*433d6423SLionel Sambuc 	terminate(&worker);
471*433d6423SLionel Sambuc 
472*433d6423SLionel Sambuc 	if (use_signaler)
473*433d6423SLionel Sambuc 		terminate(&signaler);
474*433d6423SLionel Sambuc }
475*433d6423SLionel Sambuc 
476*433d6423SLionel Sambuc /*
477*433d6423SLionel Sambuc  * This test is similar to the previous one, except that we now kill the worker
478*433d6423SLionel Sambuc  * process after a while.  This should trigger various process transitions to
479*433d6423SLionel Sambuc  * the exiting state.  Not much can be verified from this test program, but we
480*433d6423SLionel Sambuc  * intend to trigger as many internal state verification statements of PM
481*433d6423SLionel Sambuc  * itself as possible this way.  A signaler process is optional in this test,
482*433d6423SLionel Sambuc  * and if used, it will not stop after a predetermined number of signals.
483*433d6423SLionel Sambuc  */
484*433d6423SLionel Sambuc static void
test79b(void)485*433d6423SLionel Sambuc test79b(void)
486*433d6423SLionel Sambuc {
487*433d6423SLionel Sambuc 	int job, signalers, options;
488*433d6423SLionel Sambuc 
489*433d6423SLionel Sambuc 	subtest = 2;
490*433d6423SLionel Sambuc 
491*433d6423SLionel Sambuc 	for (options = 0; options <= OPT_ALL; options++)
492*433d6423SLionel Sambuc 		for (signalers = 0; signalers <= 1; signalers++)
493*433d6423SLionel Sambuc 			for (job = 0; job < NR_JOBS; job++)
494*433d6423SLionel Sambuc 				sub79b(job, signalers, options);
495*433d6423SLionel Sambuc 
496*433d6423SLionel Sambuc }
497*433d6423SLionel Sambuc 
498*433d6423SLionel Sambuc /*
499*433d6423SLionel Sambuc  * PM signal handling robustness test program.
500*433d6423SLionel Sambuc  */
501*433d6423SLionel Sambuc int
main(int argc,char ** argv)502*433d6423SLionel Sambuc main(int argc, char **argv)
503*433d6423SLionel Sambuc {
504*433d6423SLionel Sambuc 	int i, m;
505*433d6423SLionel Sambuc 
506*433d6423SLionel Sambuc 	start(79);
507*433d6423SLionel Sambuc 
508*433d6423SLionel Sambuc 	if (argc == 2)
509*433d6423SLionel Sambuc 		m = atoi(argv[1]);
510*433d6423SLionel Sambuc 	else
511*433d6423SLionel Sambuc 		m = 0xFF;
512*433d6423SLionel Sambuc 
513*433d6423SLionel Sambuc 	for (i = 0; i < ITERATIONS; i++) {
514*433d6423SLionel Sambuc 		if (m & 0x01) test79a();
515*433d6423SLionel Sambuc 		if (m & 0x02) test79b();
516*433d6423SLionel Sambuc 	}
517*433d6423SLionel Sambuc 
518*433d6423SLionel Sambuc 	quit();
519*433d6423SLionel Sambuc }
520