1 /* $OpenBSD: job.c,v 1.162 2020/06/02 12:24:44 espie Exp $ */ 2 /* $NetBSD: job.c,v 1.16 1996/11/06 17:59:08 christos Exp $ */ 3 4 /* 5 * Copyright (c) 2012 Marc Espie. 6 * 7 * Extensive code modifications for the OpenBSD project. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS 19 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD 22 * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 /* 31 * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. 32 * Copyright (c) 1988, 1989 by Adam de Boor 33 * Copyright (c) 1989 by Berkeley Softworks 34 * All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Adam de Boor. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 /*- 65 * job.c -- 66 * handle the creation etc. of our child processes. 67 * 68 * Interface: 69 * Job_Make Start the creation of the given target. 70 * 71 * Job_Init Called to initialize this module. 72 * 73 * can_start_job Return true if we can start job 74 * 75 * Job_Empty Return true if the job table is completely 76 * empty. 77 * 78 * Job_AbortAll Abort all current jobs. It doesn't 79 * handle output or do anything for the jobs, 80 * just kills them. 81 * 82 * Job_Wait Wait for all running jobs to finish. 83 */ 84 85 #include <sys/types.h> 86 #include <sys/wait.h> 87 #include <ctype.h> 88 #include <errno.h> 89 #include <fcntl.h> 90 #include <signal.h> 91 #include <stdarg.h> 92 #include <stdio.h> 93 #include <stdlib.h> 94 #include <string.h> 95 #include <unistd.h> 96 #include "config.h" 97 #include "defines.h" 98 #include "job.h" 99 #include "engine.h" 100 #include "pathnames.h" 101 #include "var.h" 102 #include "targ.h" 103 #include "error.h" 104 #include "extern.h" 105 #include "lst.h" 106 #include "gnode.h" 107 #include "memory.h" 108 #include "buf.h" 109 #include "enginechoice.h" 110 111 static int aborting = 0; /* why is the make aborting? */ 112 #define ABORT_ERROR 1 /* Because of an error */ 113 #define ABORT_INTERRUPT 2 /* Because it was interrupted */ 114 #define ABORT_WAIT 3 /* Waiting for jobs to finish */ 115 116 static bool no_new_jobs; /* Mark recursive shit so we shouldn't start 117 * something else at the same time 118 */ 119 bool sequential; 120 Job *runningJobs; /* Jobs currently running a process */ 121 Job *errorJobs; /* Jobs in error at end */ 122 Job *availableJobs; /* Pool of available jobs */ 123 static Job *heldJobs; /* Jobs not running yet because of expensive */ 124 static pid_t mypid; /* Used for printing debugging messages */ 125 static Job *extra_job; /* Needed for .INTERRUPT */ 126 127 static volatile sig_atomic_t got_fatal; 128 129 static volatile sig_atomic_t got_SIGINT, got_SIGHUP, got_SIGQUIT, got_SIGTERM, 130 got_SIGINFO; 131 132 static sigset_t sigset, emptyset, origset; 133 134 static void handle_fatal_signal(int); 135 static void handle_siginfo(void); 136 static void postprocess_job(Job *); 137 static void determine_job_next_step(Job *); 138 static void may_continue_job(Job *); 139 static Job *reap_finished_job(pid_t); 140 static bool reap_jobs(void); 141 static void may_continue_heldback_jobs(void); 142 143 static bool expensive_job(Job *); 144 static bool expensive_command(const char *); 145 static void setup_signal(int); 146 static void notice_signal(int); 147 static void setup_all_signals(void); 148 static const char *really_kill(Job *, int); 149 static void debug_kill_printf(const char *, ...); 150 static void debug_vprintf(const char *, va_list); 151 static void may_remove_target(Job *); 152 static void print_error(Job *); 153 static void internal_print_errors(void); 154 155 static int dying_signal = 0; 156 157 const char * basedirectory = NULL; 158 159 static const char * 160 really_kill(Job *job, int signo) 161 { 162 pid_t pid = job->pid; 163 if (getpgid(pid) != getpgrp()) { 164 if (killpg(pid, signo) == 0) 165 return "group got signal"; 166 } else { 167 if (kill(pid, signo) == 0) 168 return "process got signal"; 169 } 170 if (errno == ESRCH) 171 job->flags |= JOB_LOST; 172 return strerror(errno); 173 } 174 175 static void 176 may_remove_target(Job *j) 177 { 178 int dying = check_dying_signal(); 179 180 if (dying && !noExecute && !Targ_Precious(j->node)) { 181 const char *file = Var(TARGET_INDEX, j->node); 182 int r = eunlink(file); 183 184 if (DEBUG(JOB) && r == -1) 185 fprintf(stderr, " *** would unlink %s\n", file); 186 if (r != -1) 187 fprintf(stderr, " *** %s removed\n", file); 188 } 189 } 190 191 static void 192 buf_addcurdir(BUFFER *buf) 193 { 194 const char *v = Var_Value(".CURDIR"); 195 if (basedirectory != NULL) { 196 size_t len = strlen(basedirectory); 197 if (strncmp(basedirectory, v, len) == 0 && 198 v[len] == '/') { 199 v += len+1; 200 } else if (strcmp(basedirectory, v) == 0) { 201 Buf_AddString(buf, "."); 202 return; 203 } 204 } 205 Buf_AddString(buf, v); 206 } 207 208 static const char * 209 shortened_curdir(void) 210 { 211 static BUFFER buf; 212 static bool first = true; 213 if (first) { 214 Buf_Init(&buf, 0); 215 buf_addcurdir(&buf); 216 first = false; 217 } 218 return Buf_Retrieve(&buf); 219 } 220 221 static void 222 quick_error(Job *j, int signo, bool first) 223 { 224 if (first) { 225 fprintf(stderr, "*** Signal SIG%s", sys_signame[signo]); 226 fprintf(stderr, " in %s (", shortened_curdir()); 227 } else 228 fprintf(stderr, " "); 229 230 fprintf(stderr, "%s", j->node->name); 231 free(j->cmd); 232 } 233 234 static void 235 print_error(Job *j) 236 { 237 static bool first = true; 238 BUFFER buf; 239 240 Buf_Init(&buf, 0); 241 242 if (j->exit_type == JOB_EXIT_BAD) 243 Buf_printf(&buf, "*** Error %d", j->code); 244 else if (j->exit_type == JOB_SIGNALED) { 245 if (j->code < NSIG) 246 Buf_printf(&buf, "*** Signal SIG%s", 247 sys_signame[j->code]); 248 else 249 Buf_printf(&buf, "*** unknown signal %d", j->code); 250 } else 251 Buf_printf(&buf, "*** Should not happen %d/%d", 252 j->exit_type, j->code); 253 if (DEBUG(KILL) && (j->flags & JOB_LOST)) 254 Buf_AddChar(&buf, '!'); 255 if (first) { 256 Buf_AddString(&buf, " in "); 257 buf_addcurdir(&buf); 258 first = false; 259 } 260 Buf_printf(&buf, " (%s:%lu", j->location->fname, j->location->lineno); 261 Buf_printf(&buf, " '%s'", j->node->name); 262 if ((j->flags & (JOB_SILENT | JOB_IS_EXPENSIVE)) == JOB_SILENT 263 && Buf_Size(&buf) < 140-2) { 264 size_t len = strlen(j->cmd); 265 Buf_AddString(&buf, ": "); 266 if (len + Buf_Size(&buf) < 140) 267 Buf_AddString(&buf, j->cmd); 268 else { 269 Buf_AddChars(&buf, 140 - Buf_Size(&buf), j->cmd); 270 Buf_AddString(&buf, "..."); 271 } 272 } 273 fprintf(stderr, "%s)\n", Buf_Retrieve(&buf)); 274 Buf_Destroy(&buf); 275 free(j->cmd); 276 } 277 static void 278 quick_summary(int signo) 279 { 280 Job *j, *k, *jnext; 281 bool first = true; 282 283 k = errorJobs; 284 errorJobs = NULL; 285 for (j = k; j != NULL; j = jnext) { 286 jnext = j->next; 287 if ((j->exit_type == JOB_EXIT_BAD && j->code == signo+128) || 288 (j->exit_type == JOB_SIGNALED && j->code == signo)) { 289 quick_error(j, signo, first); 290 first = false; 291 } else { 292 j->next = errorJobs; 293 errorJobs = j; 294 } 295 } 296 if (!first) 297 fprintf(stderr, ")\n"); 298 } 299 300 static void 301 internal_print_errors() 302 { 303 Job *j, *k, *jnext; 304 int dying; 305 306 if (!errorJobs) 307 fprintf(stderr, "Stop in %s\n", shortened_curdir()); 308 309 for (j = errorJobs; j != NULL; j = j->next) 310 may_remove_target(j); 311 dying = check_dying_signal(); 312 if (dying) 313 quick_summary(dying); 314 /* Print errors grouped by file name. */ 315 while (errorJobs != NULL) { 316 /* Select the first job. */ 317 k = errorJobs; 318 errorJobs = NULL; 319 for (j = k; j != NULL; j = jnext) { 320 jnext = j->next; 321 if (j->location->fname == k->location->fname) 322 /* Print errors with the same filename. */ 323 print_error(j); 324 else { 325 /* Keep others for the next iteration. */ 326 j->next = errorJobs; 327 errorJobs = j; 328 } 329 } 330 } 331 } 332 333 void 334 print_errors(void) 335 { 336 handle_all_signals(); 337 internal_print_errors(); 338 } 339 340 static void 341 setup_signal(int sig) 342 { 343 if (signal(sig, SIG_IGN) != SIG_IGN) { 344 (void)signal(sig, notice_signal); 345 sigaddset(&sigset, sig); 346 } 347 } 348 349 static void 350 notice_signal(int sig) 351 { 352 353 switch(sig) { 354 case SIGINT: 355 got_SIGINT++; 356 got_fatal = 1; 357 break; 358 case SIGHUP: 359 got_SIGHUP++; 360 got_fatal = 1; 361 break; 362 case SIGQUIT: 363 got_SIGQUIT++; 364 got_fatal = 1; 365 break; 366 case SIGTERM: 367 got_SIGTERM++; 368 got_fatal = 1; 369 break; 370 case SIGINFO: 371 got_SIGINFO++; 372 break; 373 case SIGCHLD: 374 break; 375 } 376 } 377 378 void 379 Sigset_Init() 380 { 381 sigemptyset(&emptyset); 382 sigprocmask(SIG_BLOCK, &emptyset, &origset); 383 } 384 385 static void 386 setup_all_signals(void) 387 { 388 sigemptyset(&sigset); 389 /* 390 * Catch the four signals that POSIX specifies if they aren't ignored. 391 * handle_signal will take care of calling JobInterrupt if appropriate. 392 */ 393 setup_signal(SIGINT); 394 setup_signal(SIGHUP); 395 setup_signal(SIGQUIT); 396 setup_signal(SIGTERM); 397 /* Display running jobs on SIGINFO */ 398 setup_signal(SIGINFO); 399 /* Have to see SIGCHLD */ 400 setup_signal(SIGCHLD); 401 got_fatal = 0; 402 } 403 404 static void 405 handle_siginfo(void) 406 { 407 static BUFFER buf; 408 static size_t length = 0; 409 410 Job *job; 411 bool first = true; 412 413 got_SIGINFO = 0; 414 /* we have to store the info in a buffer, because status from all 415 * makes running would get intermixed otherwise 416 */ 417 418 if (length == 0) { 419 Buf_Init(&buf, 0); 420 Buf_printf(&buf, "%s in ", Var_Value("MAKE")); 421 buf_addcurdir(&buf); 422 Buf_AddString(&buf, ": "); 423 length = Buf_Size(&buf); 424 } else 425 Buf_Truncate(&buf, length); 426 427 for (job = runningJobs; job != NULL ; job = job->next) { 428 if (!first) 429 Buf_puts(&buf, ", "); 430 first = false; 431 Buf_puts(&buf, job->node->name); 432 } 433 Buf_puts(&buf, first ? "nothing running\n" : "\n"); 434 435 fputs(Buf_Retrieve(&buf), stderr); 436 } 437 438 int 439 check_dying_signal(void) 440 { 441 sigset_t set; 442 if (dying_signal) 443 return dying_signal; 444 sigpending(&set); 445 if (got_SIGINT || sigismember(&set, SIGINT)) 446 return dying_signal = SIGINT; 447 if (got_SIGHUP || sigismember(&set, SIGHUP)) 448 return dying_signal = SIGHUP; 449 if (got_SIGQUIT || sigismember(&set, SIGQUIT)) 450 return dying_signal = SIGQUIT; 451 if (got_SIGTERM || sigismember(&set, SIGTERM)) 452 return dying_signal = SIGTERM; 453 return 0; 454 } 455 456 void 457 handle_all_signals(void) 458 { 459 if (got_SIGINFO) 460 handle_siginfo(); 461 while (got_fatal) { 462 got_fatal = 0; 463 aborting = ABORT_INTERRUPT; 464 465 if (got_SIGINT) { 466 got_SIGINT=0; 467 handle_fatal_signal(SIGINT); 468 } 469 if (got_SIGHUP) { 470 got_SIGHUP=0; 471 handle_fatal_signal(SIGHUP); 472 } 473 if (got_SIGQUIT) { 474 got_SIGQUIT=0; 475 handle_fatal_signal(SIGQUIT); 476 } 477 if (got_SIGTERM) { 478 got_SIGTERM=0; 479 handle_fatal_signal(SIGTERM); 480 } 481 } 482 } 483 484 static void 485 debug_vprintf(const char *fmt, va_list va) 486 { 487 (void)printf("[%ld] ", (long)mypid); 488 (void)vprintf(fmt, va); 489 fflush(stdout); 490 } 491 492 void 493 debug_job_printf(const char *fmt, ...) 494 { 495 if (DEBUG(JOB)) { 496 va_list va; 497 va_start(va, fmt); 498 debug_vprintf(fmt, va); 499 va_end(va); 500 } 501 } 502 503 static void 504 debug_kill_printf(const char *fmt, ...) 505 { 506 if (DEBUG(KILL)) { 507 va_list va; 508 va_start(va, fmt); 509 debug_vprintf(fmt, va); 510 va_end(va); 511 } 512 } 513 514 /*- 515 *----------------------------------------------------------------------- 516 * postprocess_job -- 517 * Do final processing for the given job including updating 518 * parents and starting new jobs as available/necessary. 519 * 520 * Side Effects: 521 * If we got an error and are aborting (aborting == ABORT_ERROR) and 522 * the job list is now empty, we are done for the day. 523 * If we recognized an error we set the aborting flag 524 * to ABORT_ERROR so no more jobs will be started. 525 *----------------------------------------------------------------------- 526 */ 527 /*ARGSUSED*/ 528 529 static void 530 postprocess_job(Job *job) 531 { 532 if (job->exit_type == JOB_EXIT_OKAY && 533 aborting != ABORT_ERROR && 534 aborting != ABORT_INTERRUPT) { 535 /* As long as we aren't aborting and the job didn't return a 536 * non-zero status that we shouldn't ignore, we call 537 * Make_Update to update the parents. */ 538 job->node->built_status = REBUILT; 539 engine_node_updated(job->node); 540 } 541 if (job->flags & JOB_KEEPERROR) { 542 job->next = errorJobs; 543 errorJobs = job; 544 } else { 545 job->next = availableJobs; 546 availableJobs = job; 547 } 548 549 if (errorJobs != NULL && aborting != ABORT_INTERRUPT) 550 aborting = ABORT_ERROR; 551 552 if (aborting == ABORT_ERROR && DEBUG(QUICKDEATH)) 553 handle_fatal_signal(SIGINT); 554 if (aborting == ABORT_ERROR && Job_Empty()) 555 Finish(); 556 } 557 558 /* expensive jobs handling: in order to avoid forking an exponential number 559 * of jobs, make tries to figure out "recursive make" configurations. 560 * It may err on the side of caution. 561 * Basically, a command is "expensive" if it's likely to fork an extra 562 * level of make: either by looking at the command proper, or if it has 563 * some specific qualities ('+cmd' are likely to be recursive, as are 564 * .MAKE: commands). It's possible to explicitly say some targets are 565 * expensive or cheap with .EXPENSIVE or .CHEAP. 566 * 567 * While an expensive command is running, no_new_jobs 568 * is set, so jobs that would fork new processes are accumulated in the 569 * heldJobs list instead. 570 * 571 * XXX This heuristics is also used on error exit: we display silent commands 572 * that failed, unless those ARE expensive commands: expensive commands are 573 * likely to not be failing by themselves, but to be the result of a cascade of 574 * failures in descendant makes. 575 */ 576 void 577 determine_expensive_job(Job *job) 578 { 579 if (expensive_job(job)) { 580 job->flags |= JOB_IS_EXPENSIVE; 581 no_new_jobs = true; 582 } else 583 job->flags &= ~JOB_IS_EXPENSIVE; 584 if (DEBUG(EXPENSIVE)) 585 fprintf(stderr, "[%ld] Target %s running %.50s: %s\n", 586 (long)mypid, job->node->name, job->cmd, 587 job->flags & JOB_IS_EXPENSIVE ? "expensive" : "cheap"); 588 } 589 590 static bool 591 expensive_job(Job *job) 592 { 593 if (job->node->type & OP_CHEAP) 594 return false; 595 if (job->node->type & (OP_EXPENSIVE | OP_MAKE)) 596 return true; 597 return expensive_command(job->cmd); 598 } 599 600 static bool 601 expensive_command(const char *s) 602 { 603 const char *p; 604 bool include = false; 605 bool expensive = false; 606 607 /* okay, comments are cheap, always */ 608 if (*s == '#') 609 return false; 610 /* and commands we always execute are expensive */ 611 if (*s == '+') 612 return true; 613 614 for (p = s; *p != '\0'; p++) { 615 if (*p == ' ' || *p == '\t') { 616 include = false; 617 if (p[1] == '-' && p[2] == 'I') 618 include = true; 619 } 620 if (include) 621 continue; 622 /* KMP variant, avoid looking twice at the same 623 * letter. 624 */ 625 if (*p != 'm') 626 continue; 627 if (p[1] != 'a') 628 continue; 629 p++; 630 if (p[1] != 'k') 631 continue; 632 p++; 633 if (p[1] != 'e') 634 continue; 635 p++; 636 expensive = true; 637 while (p[1] != '\0' && p[1] != ' ' && p[1] != '\t') { 638 if (p[1] == '.' || p[1] == '/') { 639 expensive = false; 640 break; 641 } 642 p++; 643 } 644 if (expensive) 645 return true; 646 } 647 return false; 648 } 649 650 static void 651 may_continue_job(Job *job) 652 { 653 if (no_new_jobs) { 654 if (DEBUG(EXPENSIVE)) 655 fprintf(stderr, "[%ld] expensive -> hold %s\n", 656 (long)mypid, job->node->name); 657 job->next = heldJobs; 658 heldJobs = job; 659 } else { 660 bool finished = job_run_next(job); 661 if (finished) 662 postprocess_job(job); 663 else if (!sequential) 664 determine_expensive_job(job); 665 } 666 } 667 668 static void 669 may_continue_heldback_jobs() 670 { 671 while (!no_new_jobs) { 672 if (heldJobs != NULL) { 673 Job *job = heldJobs; 674 heldJobs = heldJobs->next; 675 if (DEBUG(EXPENSIVE)) 676 fprintf(stderr, "[%ld] cheap -> release %s\n", 677 (long)mypid, job->node->name); 678 may_continue_job(job); 679 } else 680 break; 681 } 682 } 683 684 /*- 685 *----------------------------------------------------------------------- 686 * Job_Make -- 687 * Start a target-creation process going for the target described 688 * by the graph node gn. 689 * 690 * Side Effects: 691 * A new Job node is created and its commands continued, which 692 * may fork the first command of that job. 693 *----------------------------------------------------------------------- 694 */ 695 void 696 Job_Make(GNode *gn) 697 { 698 Job *job = availableJobs; 699 700 assert(job != NULL); 701 availableJobs = availableJobs->next; 702 job_attach_node(job, gn); 703 may_continue_job(job); 704 } 705 706 static void 707 determine_job_next_step(Job *job) 708 { 709 if (job->flags & JOB_IS_EXPENSIVE) { 710 no_new_jobs = false; 711 if (DEBUG(EXPENSIVE)) 712 fprintf(stderr, "[%ld] " 713 "Returning from expensive target %s, " 714 "allowing new jobs\n", (long)mypid, 715 job->node->name); 716 } 717 718 if (job->exit_type != JOB_EXIT_OKAY || job->next_cmd == NULL) 719 postprocess_job(job); 720 else 721 may_continue_job(job); 722 } 723 724 /* 725 * job = reap_finished_job(pid): 726 * retrieve and remove a job from runningJobs, based on its pid 727 * 728 * Note that we remove it right away, so that handle_signals() 729 * is accurate. 730 */ 731 static Job * 732 reap_finished_job(pid_t pid) 733 { 734 Job **j, *job; 735 736 for (j = &runningJobs; *j != NULL; j = &((*j)->next)) 737 if ((*j)->pid == pid) { 738 job = *j; 739 *j = job->next; 740 return job; 741 } 742 743 return NULL; 744 } 745 746 /* 747 * classic waitpid handler: retrieve as many dead children as possible. 748 * returns true if succesful 749 */ 750 static bool 751 reap_jobs(void) 752 { 753 pid_t pid; /* pid of dead child */ 754 int status; /* Exit/termination status */ 755 bool reaped = false; 756 Job *job; 757 758 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) { 759 if (WIFSTOPPED(status)) 760 continue; 761 reaped = true; 762 job = reap_finished_job(pid); 763 764 if (job == NULL) { 765 Punt("Child (%ld) with status %d not in table?", 766 (long)pid, status); 767 } else { 768 handle_job_status(job, status); 769 determine_job_next_step(job); 770 } 771 may_continue_heldback_jobs(); 772 } 773 /* sanity check, should not happen */ 774 if (pid == -1 && errno == ECHILD && runningJobs != NULL) 775 Punt("Process has no children, but runningJobs is not empty ?"); 776 return reaped; 777 } 778 779 void 780 reset_signal_mask() 781 { 782 sigprocmask(SIG_SETMASK, &origset, NULL); 783 } 784 785 void 786 handle_running_jobs(void) 787 { 788 /* reaping children in the presence of caught signals */ 789 790 /* first, we make sure to hold on new signals, to synchronize 791 * reception of new stuff on sigsuspend 792 */ 793 sigprocmask(SIG_BLOCK, &sigset, NULL); 794 /* note this will NOT loop until runningJobs == NULL. 795 * It's merely an optimisation, namely that we don't need to go 796 * through the logic if no job is present. As soon as a job 797 * gets reaped, we WILL exit the loop through the break. 798 */ 799 while (runningJobs != NULL) { 800 /* did we already have pending stuff that advances things ? 801 * then handle_all_signals() will not return 802 * or reap_jobs() will reap_jobs() 803 */ 804 handle_all_signals(); 805 if (reap_jobs()) 806 break; 807 /* okay, so it's safe to suspend, we have nothing to do but 808 * wait... 809 */ 810 sigsuspend(&emptyset); 811 } 812 reset_signal_mask(); 813 } 814 815 void 816 loop_handle_running_jobs() 817 { 818 while (runningJobs != NULL) 819 handle_running_jobs(); 820 } 821 822 void 823 Job_Init(int maxJobs) 824 { 825 Job *j; 826 int i; 827 828 runningJobs = NULL; 829 heldJobs = NULL; 830 errorJobs = NULL; 831 availableJobs = NULL; 832 sequential = maxJobs == 1; 833 834 /* we allocate n+1 jobs, since we may need an extra job for 835 * running .INTERRUPT. */ 836 j = ereallocarray(NULL, sizeof(Job), maxJobs+1); 837 for (i = 0; i != maxJobs; i++) { 838 j[i].next = availableJobs; 839 availableJobs = &j[i]; 840 } 841 extra_job = &j[maxJobs]; 842 mypid = getpid(); 843 844 aborting = 0; 845 setup_all_signals(); 846 } 847 848 bool 849 can_start_job(void) 850 { 851 if (aborting || availableJobs == NULL) 852 return false; 853 else 854 return true; 855 } 856 857 bool 858 Job_Empty(void) 859 { 860 return runningJobs == NULL; 861 } 862 863 /*- 864 *----------------------------------------------------------------------- 865 * handle_fatal_signal -- 866 * Handle the receipt of a fatal interrupt 867 * 868 * Side Effects: 869 * All children are killed. Another job may be started if there 870 * is an interrupt target and the signal was SIGINT. 871 *----------------------------------------------------------------------- 872 */ 873 static void 874 handle_fatal_signal(int signo) 875 { 876 Job *job; 877 878 debug_kill_printf("handle_fatal_signal(%d) called.\n", signo); 879 880 dying_signal = signo; 881 for (job = runningJobs; job != NULL; job = job->next) { 882 debug_kill_printf("passing to " 883 "child %ld running %s: %s\n", (long)job->pid, 884 job->node->name, really_kill(job, signo)); 885 may_remove_target(job); 886 } 887 888 if (signo == SIGINT && !touchFlag) { 889 if ((interrupt_node->type & OP_DUMMY) == 0) { 890 ignoreErrors = false; 891 extra_job->next = availableJobs; 892 availableJobs = extra_job; 893 Job_Make(interrupt_node); 894 } 895 } 896 loop_handle_running_jobs(); 897 internal_print_errors(); 898 899 /* die by that signal */ 900 sigprocmask(SIG_BLOCK, &sigset, NULL); 901 signal(signo, SIG_DFL); 902 kill(getpid(), signo); 903 sigprocmask(SIG_SETMASK, &emptyset, NULL); 904 /*NOTREACHED*/ 905 fprintf(stderr, "This should never happen\n"); 906 exit(1); 907 } 908 909 /*- 910 *----------------------------------------------------------------------- 911 * Job_Wait -- 912 * Waits for all running jobs to finish and returns. Sets 'aborting' 913 * to ABORT_WAIT to prevent other jobs from starting. 914 * 915 * Side Effects: 916 * Currently running jobs finish. 917 * 918 *----------------------------------------------------------------------- 919 */ 920 void 921 Job_Wait(void) 922 { 923 aborting = ABORT_WAIT; 924 loop_handle_running_jobs(); 925 aborting = 0; 926 } 927 928 /*- 929 *----------------------------------------------------------------------- 930 * Job_AbortAll -- 931 * Abort all currently running jobs without handling output or anything. 932 * This function is to be called only in the event of a major 933 * error. 934 * 935 * Side Effects: 936 * All children are killed 937 *----------------------------------------------------------------------- 938 */ 939 void 940 Job_AbortAll(void) 941 { 942 Job *job; /* the job descriptor in that element */ 943 int foo; 944 945 aborting = ABORT_ERROR; 946 947 for (job = runningJobs; job != NULL; job = job->next) { 948 debug_kill_printf("abort: send SIGINT to " 949 "child %ld running %s: %s\n", 950 (long)job->pid, job->node->name, really_kill(job, SIGINT)); 951 debug_kill_printf("abort: send SIGKILL to " 952 "child %ld running %s: %s\n", 953 (long)job->pid, job->node->name, really_kill(job, SIGKILL)); 954 } 955 956 /* 957 * Catch as many children as want to report in at first, then give up 958 */ 959 while (waitpid(WAIT_ANY, &foo, WNOHANG) > 0) 960 continue; 961 } 962