1 /* Tests for PM signal handling robustness - by D.C. van Moolenbroek */ 2 /* 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. 11 */ 12 #include <stdlib.h> 13 #include <stdio.h> 14 #include <signal.h> 15 #include <sys/wait.h> 16 #include <sys/time.h> 17 #include <sys/utsname.h> 18 19 #define ITERATIONS 1 20 21 #include "common.h" 22 23 #define NR_SIGNALS 20000 24 25 #define MAX_SIGNALERS 3 26 27 static const int signaler_sig[MAX_SIGNALERS] = { SIGUSR1, SIGUSR2, SIGHUP }; 28 static pid_t signaler_pid[MAX_SIGNALERS]; 29 static int sig_counter; 30 31 enum { 32 JOB_RUN = 0, 33 JOB_CALL_PM, 34 JOB_CALL_VFS, 35 JOB_SET_MASK, 36 JOB_BLOCK_PM, 37 JOB_BLOCK_VFS, 38 JOB_CALL_PM_VFS, 39 JOB_FORK, 40 NR_JOBS 41 }; 42 43 #define OPT_NEST 0x1 44 #define OPT_ALARM 0x2 45 #define OPT_ALL 0x3 46 47 struct link { 48 pid_t pid; 49 int sndfd; 50 int rcvfd; 51 }; 52 53 /* 54 * Spawn a child process, with a pair of pipes to talk to it bidirectionally. 55 */ 56 static void 57 spawn(struct link *link, void (*proc)(struct link *)) 58 { 59 int up[2], dn[2]; 60 61 fflush(stdout); 62 fflush(stderr); 63 64 if (pipe(up) != 0) e(0); 65 if (pipe(dn) != 0) e(0); 66 67 link->pid = fork(); 68 69 switch (link->pid) { 70 case 0: 71 close(up[1]); 72 close(dn[0]); 73 74 link->rcvfd = up[0]; 75 link->sndfd = dn[1]; 76 77 errct = 0; 78 79 proc(link); 80 81 /* Close our pipe FDs on exit, so that we can make zombies. */ 82 exit(errct); 83 case -1: 84 e(0); 85 break; 86 } 87 88 close(up[0]); 89 close(dn[1]); 90 91 link->sndfd = up[1]; 92 link->rcvfd = dn[0]; 93 } 94 95 /* 96 * Wait for a child process to terminate, and clean up. 97 */ 98 static void 99 collect(struct link *link) 100 { 101 int status; 102 103 close(link->sndfd); 104 close(link->rcvfd); 105 106 if (waitpid(link->pid, &status, 0) <= 0) e(0); 107 108 if (!WIFEXITED(status)) e(0); 109 else errct += WEXITSTATUS(status); 110 } 111 112 /* 113 * Forcibly terminate a child process, and clean up. 114 */ 115 static void 116 terminate(struct link *link) 117 { 118 int status; 119 120 if (kill(link->pid, SIGKILL) != 0) e(0); 121 122 close(link->sndfd); 123 close(link->rcvfd); 124 125 if (waitpid(link->pid, &status, 0) <= 0) e(0); 126 127 if (WIFSIGNALED(status)) { 128 if (WTERMSIG(status) != SIGKILL) e(0); 129 } else { 130 if (!WIFEXITED(status)) e(0); 131 else errct += WEXITSTATUS(status); 132 } 133 } 134 135 /* 136 * Send an integer value to the child or parent. 137 */ 138 static void 139 snd(struct link *link, int val) 140 { 141 if (write(link->sndfd, (void *) &val, sizeof(val)) != sizeof(val)) 142 e(0); 143 } 144 145 /* 146 * Receive an integer value from the child or parent, or -1 on EOF. 147 */ 148 static int 149 rcv(struct link *link) 150 { 151 int r, val; 152 153 if ((r = read(link->rcvfd, (void *) &val, sizeof(val))) == 0) 154 return -1; 155 156 if (r != sizeof(val)) e(0); 157 158 return val; 159 } 160 161 /* 162 * Set a signal handler for a particular signal, blocking either all or no 163 * signals when the signal handler is invoked. 164 */ 165 static void 166 set_handler(int sig, void (*proc)(int), int block) 167 { 168 struct sigaction act; 169 170 memset(&act, 0, sizeof(act)); 171 if (block) sigfillset(&act.sa_mask); 172 act.sa_handler = proc; 173 174 if (sigaction(sig, &act, NULL) != 0) e(0); 175 } 176 177 /* 178 * Generic signal handler for the worker process. 179 */ 180 static void 181 worker_handler(int sig) 182 { 183 int i; 184 185 switch (sig) { 186 case SIGUSR1: 187 case SIGUSR2: 188 case SIGHUP: 189 for (i = 0; i < MAX_SIGNALERS; i++) { 190 if (signaler_sig[i] != sig) continue; 191 192 if (signaler_pid[i] == -1) e(0); 193 else if (kill(signaler_pid[i], SIGUSR1) != 0) e(0); 194 break; 195 } 196 if (i == MAX_SIGNALERS) e(0); 197 break; 198 case SIGTERM: 199 exit(errct); 200 break; 201 case SIGALRM: 202 /* Do nothing. */ 203 break; 204 default: 205 e(0); 206 } 207 } 208 209 /* 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. 213 */ 214 static void __dead 215 worker_proc(struct link *parent) 216 { 217 struct utsname name; 218 struct itimerval it; 219 struct timeval tv; 220 sigset_t set, oset; 221 uid_t uid; 222 int i, job, options; 223 224 job = rcv(parent); 225 options = rcv(parent); 226 227 for (i = 0; i < MAX_SIGNALERS; i++) { 228 set_handler(signaler_sig[i], worker_handler, 229 !(options & OPT_NEST)); 230 231 signaler_pid[i] = rcv(parent); 232 } 233 234 set_handler(SIGTERM, worker_handler, 1 /* block */); 235 set_handler(SIGALRM, worker_handler, !(options & OPT_NEST)); 236 237 snd(parent, 0); 238 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); 248 } 249 } 250 251 switch (job) { 252 case JOB_RUN: 253 for (;;); 254 break; 255 case JOB_CALL_PM: 256 /* 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. 265 */ 266 for (;;) { 267 if (sigprocmask(SIG_BLOCK, NULL, &set) != 0) e(0); 268 if (sigismember(&set, SIGUSR1)) e(0); 269 } 270 break; 271 case JOB_CALL_VFS: 272 for (;;) { 273 tv.tv_sec = 0; 274 tv.tv_usec = 0; 275 select(0, NULL, NULL, NULL, &tv); 276 } 277 break; 278 case JOB_SET_MASK: 279 for (;;) { 280 sigfillset(&set); 281 if (sigprocmask(SIG_SETMASK, &set, &oset) != 0) e(0); 282 if (sigprocmask(SIG_SETMASK, &oset, NULL) != 0) e(0); 283 } 284 break; 285 case JOB_BLOCK_PM: 286 for (;;) { 287 sigemptyset(&set); 288 sigsuspend(&set); 289 } 290 break; 291 case JOB_BLOCK_VFS: 292 for (;;) 293 select(0, NULL, NULL, NULL, NULL); 294 break; 295 case JOB_CALL_PM_VFS: 296 uid = getuid(); 297 for (;;) 298 setuid(uid); 299 break; 300 case JOB_FORK: 301 /* 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. 305 */ 306 for (;;) { 307 pid_t pid = fork(); 308 switch (pid) { 309 case 0: 310 exit(0); 311 case -1: 312 e(1); 313 break; 314 default: 315 kill(pid, SIGKILL); 316 if (wait(NULL) != pid) e(0); 317 } 318 } 319 break; 320 default: 321 e(0); 322 exit(1); 323 } 324 } 325 326 /* 327 * Signal handler procedure for the signaler processes, counting the number of 328 * signals received from the worker process. 329 */ 330 static void 331 signaler_handler(int sig) 332 { 333 sig_counter++; 334 } 335 336 /* 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. 341 */ 342 static void 343 signaler_proc(struct link *parent) 344 { 345 sigset_t set, oset; 346 pid_t pid; 347 int i, sig, nr; 348 349 pid = rcv(parent); 350 sig = rcv(parent); 351 nr = rcv(parent); 352 sig_counter = 0; 353 354 sigfillset(&set); 355 if (sigprocmask(SIG_SETMASK, &set, &oset) != 0) e(0); 356 357 set_handler(SIGUSR1, signaler_handler, 1 /*block*/); 358 359 for (i = 0; nr == 0 || i < nr; i++) { 360 if (sig_counter != i) e(0); 361 362 if (kill(pid, sig) != 0 && nr > 0) e(0); 363 364 sigsuspend(&oset); 365 } 366 367 if (sig_counter != nr) e(0); 368 } 369 370 /* 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. 373 */ 374 static void 375 sub79a(int job, int signalers, int options) 376 { 377 struct link worker, signaler[MAX_SIGNALERS]; 378 int i; 379 380 spawn(&worker, worker_proc); 381 382 snd(&worker, job); 383 snd(&worker, options); 384 385 for (i = 0; i < signalers; i++) { 386 spawn(&signaler[i], signaler_proc); 387 388 snd(&worker, signaler[i].pid); 389 } 390 for (; i < MAX_SIGNALERS; i++) 391 snd(&worker, -1); 392 393 if (rcv(&worker) != 0) e(0); 394 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); 399 } 400 401 for (i = 0; i < signalers; i++) 402 collect(&signaler[i]); 403 404 if (kill(worker.pid, SIGTERM) != 0) e(0); 405 406 collect(&worker); 407 } 408 409 /* 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. 419 */ 420 static void 421 test79a(void) 422 { 423 int job, signalers, options; 424 425 subtest = 1; 426 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); 431 } 432 433 /* 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. 436 */ 437 static void 438 sub79b(int job, int use_signaler, int options) 439 { 440 struct link worker, signaler; 441 struct timeval tv; 442 int i; 443 444 spawn(&worker, worker_proc); 445 446 snd(&worker, job); 447 snd(&worker, options); 448 449 if ((i = use_signaler) != 0) { 450 spawn(&signaler, signaler_proc); 451 452 snd(&worker, signaler.pid); 453 } 454 for (; i < MAX_SIGNALERS; i++) 455 snd(&worker, -1); 456 457 if (rcv(&worker) != 0) e(0); 458 459 if (use_signaler) { 460 snd(&signaler, worker.pid); 461 snd(&signaler, signaler_sig[0]); 462 snd(&signaler, 0); 463 } 464 465 /* Use select() so that we can verify we don't get signals. */ 466 tv.tv_sec = 0; 467 tv.tv_usec = 100000; 468 if (select(0, NULL, NULL, NULL, &tv) != 0) e(0); 469 470 terminate(&worker); 471 472 if (use_signaler) 473 terminate(&signaler); 474 } 475 476 /* 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. 483 */ 484 static void 485 test79b(void) 486 { 487 int job, signalers, options; 488 489 subtest = 2; 490 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); 495 496 } 497 498 /* 499 * PM signal handling robustness test program. 500 */ 501 int 502 main(int argc, char **argv) 503 { 504 int i, m; 505 506 start(79); 507 508 if (argc == 2) 509 m = atoi(argv[1]); 510 else 511 m = 0xFF; 512 513 for (i = 0; i < ITERATIONS; i++) { 514 if (m & 0x01) test79a(); 515 if (m & 0x02) test79b(); 516 } 517 518 quit(); 519 } 520