1 /* Tests for PM signal handling robustness - by D.C. van Moolenbroek */
3 * The signal handling code must not rely on priorities assigned to services,
4 * and so, this test (like any test!) must also pass if PM and/or VFS are not
5 * given a fixed high priority. A good way to verify this is to let PM and VFS
6 * be scheduled by SCHED rather than KERNEL, and to give them the same priority
7 * as (or slightly lower than) normal user processes. Note that if VFS is
8 * configured to use a priority *far lower* than user processes, starvation may
9 * cause this test not to complete in some scenarios. In that case, Ctrl+C
10 * should still be able to kill the test.
17 #include <sys/utsname.h>
23 #define NR_SIGNALS 20000
25 #define MAX_SIGNALERS 3
27 static const int signaler_sig
[MAX_SIGNALERS
] = { SIGUSR1
, SIGUSR2
, SIGHUP
};
28 static pid_t signaler_pid
[MAX_SIGNALERS
];
29 static int sig_counter
;
54 * Spawn a child process, with a pair of pipes to talk to it bidirectionally.
57 spawn(struct link
*link
, void (*proc
)(struct link
*))
64 if (pipe(up
) != 0) e(0);
65 if (pipe(dn
) != 0) e(0);
81 /* Close our pipe FDs on exit, so that we can make zombies. */
96 * Wait for a child process to terminate, and clean up.
99 collect(struct link
*link
)
106 if (waitpid(link
->pid
, &status
, 0) <= 0) e(0);
108 if (!WIFEXITED(status
)) e(0);
109 else errct
+= WEXITSTATUS(status
);
113 * Forcibly terminate a child process, and clean up.
116 terminate(struct link
*link
)
120 if (kill(link
->pid
, SIGKILL
) != 0) e(0);
125 if (waitpid(link
->pid
, &status
, 0) <= 0) e(0);
127 if (WIFSIGNALED(status
)) {
128 if (WTERMSIG(status
) != SIGKILL
) e(0);
130 if (!WIFEXITED(status
)) e(0);
131 else errct
+= WEXITSTATUS(status
);
136 * Send an integer value to the child or parent.
139 snd(struct link
*link
, int val
)
141 if (write(link
->sndfd
, (void *) &val
, sizeof(val
)) != sizeof(val
))
146 * Receive an integer value from the child or parent, or -1 on EOF.
149 rcv(struct link
*link
)
153 if ((r
= read(link
->rcvfd
, (void *) &val
, sizeof(val
))) == 0)
156 if (r
!= sizeof(val
)) e(0);
162 * Set a signal handler for a particular signal, blocking either all or no
163 * signals when the signal handler is invoked.
166 set_handler(int sig
, void (*proc
)(int), int block
)
168 struct sigaction act
;
170 memset(&act
, 0, sizeof(act
));
171 if (block
) sigfillset(&act
.sa_mask
);
172 act
.sa_handler
= proc
;
174 if (sigaction(sig
, &act
, NULL
) != 0) e(0);
178 * Generic signal handler for the worker process.
181 worker_handler(int sig
)
189 for (i
= 0; i
< MAX_SIGNALERS
; i
++) {
190 if (signaler_sig
[i
] != sig
) continue;
192 if (signaler_pid
[i
] == -1) e(0);
193 else if (kill(signaler_pid
[i
], SIGUSR1
) != 0) e(0);
196 if (i
== MAX_SIGNALERS
) e(0);
210 * Procedure for the worker process. Sets up its own environment using
211 * information sent to it by the parent, sends an acknowledgement to the
212 * parent, and loops executing the job given to it until a SIGTERM comes in.
215 worker_proc(struct link
*parent
)
225 options
= rcv(parent
);
227 for (i
= 0; i
< MAX_SIGNALERS
; i
++) {
228 set_handler(signaler_sig
[i
], worker_handler
,
229 !(options
& OPT_NEST
));
231 signaler_pid
[i
] = rcv(parent
);
234 set_handler(SIGTERM
, worker_handler
, 1 /* block */);
235 set_handler(SIGALRM
, worker_handler
, !(options
& OPT_NEST
));
239 if (options
& OPT_ALARM
) {
240 /* The timer would kill wimpy platforms such as ARM. */
241 if (uname(&name
) < 0) e(0);
242 if (strcmp(name
.machine
, "arm")) {
243 it
.it_value
.tv_sec
= 0;
244 it
.it_value
.tv_usec
= 1;
245 it
.it_interval
.tv_sec
= 0;
246 it
.it_interval
.tv_usec
= 1;
247 if (setitimer(ITIMER_REAL
, &it
, NULL
) != 0) e(0);
257 * Part of the complication of the current system in PM comes
258 * from the fact that when a process is being stopped, it might
259 * already have started sending a message. That message will
260 * arrive at its destination regardless of the process's run
261 * state. PM must avoid setting up a signal handler (and
262 * changing the process's signal mask as part of that) if such
263 * a message is still in transit, because that message might,
264 * for example, query (or even change) the signal mask.
267 if (sigprocmask(SIG_BLOCK
, NULL
, &set
) != 0) e(0);
268 if (sigismember(&set
, SIGUSR1
)) e(0);
275 select(0, NULL
, NULL
, NULL
, &tv
);
281 if (sigprocmask(SIG_SETMASK
, &set
, &oset
) != 0) e(0);
282 if (sigprocmask(SIG_SETMASK
, &oset
, NULL
) != 0) e(0);
293 select(0, NULL
, NULL
, NULL
, NULL
);
295 case JOB_CALL_PM_VFS
:
302 * The child exits immediately; the parent kills the child
303 * immediately. The outcome mostly depends on scheduling.
304 * Varying process priorities may yield different tests.
316 if (wait(NULL
) != pid
) e(0);
327 * Signal handler procedure for the signaler processes, counting the number of
328 * signals received from the worker process.
331 signaler_handler(int sig
)
337 * Procedure for the signaler processes. Gets the pid of the worker process
338 * and the signal to use, and then repeatedly sends that signal to the worker
339 * process, waiting for a SIGUSR1 signal back from the worker before
340 * continuing. This signal ping-pong is repeated for a set number of times.
343 signaler_proc(struct link
*parent
)
355 if (sigprocmask(SIG_SETMASK
, &set
, &oset
) != 0) e(0);
357 set_handler(SIGUSR1
, signaler_handler
, 1 /*block*/);
359 for (i
= 0; nr
== 0 || i
< nr
; i
++) {
360 if (sig_counter
!= i
) e(0);
362 if (kill(pid
, sig
) != 0 && nr
> 0) e(0);
367 if (sig_counter
!= nr
) e(0);
371 * Set up the worker and signaler processes, wait for the signaler processes to
372 * do their work and terminate, and then terminate the worker process.
375 sub79a(int job
, int signalers
, int options
)
377 struct link worker
, signaler
[MAX_SIGNALERS
];
380 spawn(&worker
, worker_proc
);
383 snd(&worker
, options
);
385 for (i
= 0; i
< signalers
; i
++) {
386 spawn(&signaler
[i
], signaler_proc
);
388 snd(&worker
, signaler
[i
].pid
);
390 for (; i
< MAX_SIGNALERS
; i
++)
393 if (rcv(&worker
) != 0) e(0);
395 for (i
= 0; i
< signalers
; i
++) {
396 snd(&signaler
[i
], worker
.pid
);
397 snd(&signaler
[i
], signaler_sig
[i
]);
398 snd(&signaler
[i
], NR_SIGNALS
);
401 for (i
= 0; i
< signalers
; i
++)
402 collect(&signaler
[i
]);
404 if (kill(worker
.pid
, SIGTERM
) != 0) e(0);
410 * Stress test for signal handling. One worker process gets signals from up to
411 * three signaler processes while performing one of a number of jobs. It
412 * replies to each signal by signaling the source, thus creating a ping-pong
413 * effect for each of the signaler processes. The signal ping-ponging is
414 * supposed to be reliable, and the most important aspect of the test is that
415 * no signals get lost. The test is performed a number of times, varying the
416 * job executed by the worker process, the number of signalers, whether signals
417 * are blocked while executing a signal handler in the worker, and whether the
418 * worker process has a timer running at high frequency.
423 int job
, signalers
, options
;
427 for (options
= 0; options
<= OPT_ALL
; options
++)
428 for (signalers
= 1; signalers
<= MAX_SIGNALERS
; signalers
++)
429 for (job
= 0; job
< NR_JOBS
; job
++)
430 sub79a(job
, signalers
, options
);
434 * Set up the worker process and optionally a signaler process, wait for a
435 * predetermined amount of time, and then kill all the child processes.
438 sub79b(int job
, int use_signaler
, int options
)
440 struct link worker
, signaler
;
444 spawn(&worker
, worker_proc
);
447 snd(&worker
, options
);
449 if ((i
= use_signaler
) != 0) {
450 spawn(&signaler
, signaler_proc
);
452 snd(&worker
, signaler
.pid
);
454 for (; i
< MAX_SIGNALERS
; i
++)
457 if (rcv(&worker
) != 0) e(0);
460 snd(&signaler
, worker
.pid
);
461 snd(&signaler
, signaler_sig
[0]);
465 /* Use select() so that we can verify we don't get signals. */
468 if (select(0, NULL
, NULL
, NULL
, &tv
) != 0) e(0);
473 terminate(&signaler
);
477 * This test is similar to the previous one, except that we now kill the worker
478 * process after a while. This should trigger various process transitions to
479 * the exiting state. Not much can be verified from this test program, but we
480 * intend to trigger as many internal state verification statements of PM
481 * itself as possible this way. A signaler process is optional in this test,
482 * and if used, it will not stop after a predetermined number of signals.
487 int job
, signalers
, options
;
491 for (options
= 0; options
<= OPT_ALL
; options
++)
492 for (signalers
= 0; signalers
<= 1; signalers
++)
493 for (job
= 0; job
< NR_JOBS
; job
++)
494 sub79b(job
, signalers
, options
);
499 * PM signal handling robustness test program.
502 main(int argc
, char **argv
)
513 for (i
= 0; i
< ITERATIONS
; i
++) {
514 if (m
& 0x01) test79a();
515 if (m
& 0x02) test79b();