1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * parallel.cc 29 * 30 * Deal with the parallel processing 31 */ 32 33 /* 34 * Included files 35 */ 36 #include <errno.h> /* errno */ 37 #include <fcntl.h> 38 #include <mk/defs.h> 39 #include <mksh/dosys.h> /* redirect_io() */ 40 #include <mksh/macro.h> /* expand_value() */ 41 #include <mksh/misc.h> /* getmem() */ 42 #include <sys/signal.h> 43 #include <sys/stat.h> 44 #include <sys/types.h> 45 #include <sys/utsname.h> 46 #include <sys/wait.h> 47 #include <unistd.h> 48 #include <netdb.h> 49 #include <libintl.h> 50 51 52 53 /* 54 * Defined macros 55 */ 56 #define MAXRULES 100 57 58 /* 59 * This const should be in avo_dms/include/AvoDmakeCommand.h 60 */ 61 const int local_host_mask = 0x20; 62 63 64 /* 65 * typedefs & structs 66 */ 67 68 69 /* 70 * Static variables 71 */ 72 static Boolean just_did_subtree = false; 73 static char local_host[MAXNAMELEN] = ""; 74 static char user_name[MAXNAMELEN] = ""; 75 static int pmake_max_jobs = 0; 76 static pid_t process_running = -1; 77 static Running *running_tail = &running_list; 78 static Name subtree_conflict; 79 static Name subtree_conflict2; 80 81 82 /* 83 * File table of contents 84 */ 85 static void delete_running_struct(Running rp); 86 static Boolean dependency_conflict(Name target); 87 static Doname distribute_process(char **commands, Property line); 88 static void doname_subtree(Name target, Boolean do_get, Boolean implicit); 89 static void dump_out_file(char *filename, Boolean err); 90 static void finish_doname(Running rp); 91 static void maybe_reread_make_state(void); 92 static void process_next(void); 93 static void reset_conditionals(int cnt, Name *targets, Property *locals); 94 static pid_t run_rule_commands(char *host, char **commands); 95 static Property *set_conditionals(int cnt, Name *targets); 96 static void store_conditionals(Running rp); 97 98 99 /* 100 * execute_parallel(line, waitflg) 101 * 102 * DMake 2.x: 103 * parallel mode: spawns a parallel process to execute the command group. 104 * 105 * Return value: 106 * The result of the execution 107 * 108 * Parameters: 109 * line The command group to execute 110 */ 111 Doname 112 execute_parallel(Property line, Boolean waitflg, Boolean local) 113 { 114 int argcnt; 115 int cmd_options = 0; 116 char *commands[MAXRULES + 5]; 117 char *cp; 118 Name dmake_name; 119 Name dmake_value; 120 int ignore; 121 Name make_machines_name; 122 char **p; 123 Property prop; 124 Doname result = build_ok; 125 Cmd_line rule; 126 Boolean silent_flag; 127 Name target = line->body.line.target; 128 Boolean wrote_state_file = false; 129 130 if ((pmake_max_jobs == 0) && 131 (dmake_mode_type == parallel_mode)) { 132 if (local_host[0] == '\0') { 133 (void) gethostname(local_host, MAXNAMELEN); 134 } 135 MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS"); 136 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); 137 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && 138 ((dmake_value = prop->body.macro.value) != NULL)) { 139 pmake_max_jobs = atoi(dmake_value->string_mb); 140 if (pmake_max_jobs <= 0) { 141 warning(gettext("DMAKE_MAX_JOBS cannot be less than or equal to zero.")); 142 warning(gettext("setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS); 143 pmake_max_jobs = PMAKE_DEF_MAX_JOBS; 144 } 145 } else { 146 /* 147 * For backwards compatibility w/ PMake 1.x, when 148 * DMake 2.x is being run in parallel mode, DMake 149 * should parse the PMake startup file 150 * $(HOME)/.make.machines to get the pmake_max_jobs. 151 */ 152 MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE"); 153 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); 154 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && 155 ((dmake_value = prop->body.macro.value) != NULL)) { 156 make_machines_name = dmake_value; 157 } else { 158 make_machines_name = NULL; 159 } 160 if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) { 161 pmake_max_jobs = PMAKE_DEF_MAX_JOBS; 162 } 163 } 164 } 165 166 if ((dmake_mode_type == serial_mode) || 167 ((dmake_mode_type == parallel_mode) && (waitflg))) { 168 return (execute_serial(line)); 169 } 170 171 { 172 p = commands; 173 } 174 175 argcnt = 0; 176 for (rule = line->body.line.command_used; 177 rule != NULL; 178 rule = rule->next) { 179 if (posix && (touch || quest) && !rule->always_exec) { 180 continue; 181 } 182 if (vpath_defined) { 183 rule->command_line = 184 vpath_translation(rule->command_line); 185 } 186 187 silent_flag = false; 188 ignore = 0; 189 190 if (rule->command_line->hash.length > 0) { 191 if (++argcnt == MAXRULES) { 192 return build_serial; 193 } 194 { 195 if (rule->silent && !silent) { 196 silent_flag = true; 197 } 198 if (rule->ignore_error) { 199 ignore++; 200 } 201 /* XXX - need to add support for + prefix */ 202 if (silent_flag || ignore) { 203 *p = getmem((silent_flag ? 1 : 0) + 204 ignore + 205 (strlen(rule-> 206 command_line-> 207 string_mb)) + 208 1); 209 cp = *p++; 210 if (silent_flag) { 211 *cp++ = (int) at_char; 212 } 213 if (ignore) { 214 *cp++ = (int) hyphen_char; 215 } 216 (void) strcpy(cp, rule->command_line->string_mb); 217 } else { 218 *p++ = rule->command_line->string_mb; 219 } 220 } 221 } 222 } 223 if ((argcnt == 0) || 224 (report_dependencies_level > 0)) { 225 return build_ok; 226 } 227 { 228 *p = NULL; 229 230 Doname res = distribute_process(commands, line); 231 if (res == build_running) { 232 parallel_process_cnt++; 233 } 234 235 /* 236 * Return only those memory that were specially allocated 237 * for part of commands. 238 */ 239 for (int i = 0; commands[i] != NULL; i++) { 240 if ((commands[i][0] == (int) at_char) || 241 (commands[i][0] == (int) hyphen_char)) { 242 retmem_mb(commands[i]); 243 } 244 } 245 return res; 246 } 247 } 248 249 250 251 #include <unistd.h> /* sysconf(_SC_NPROCESSORS_ONLN) */ 252 #include <sys/ipc.h> /* ftok() */ 253 #include <sys/shm.h> /* shmget(), shmat(), shmdt(), shmctl() */ 254 #include <semaphore.h> /* sem_init(), sem_trywait(), sem_post(), sem_destroy() */ 255 #include <sys/loadavg.h> /* getloadavg() */ 256 257 /* 258 * adjust_pmake_max_jobs (int pmake_max_jobs) 259 * 260 * Parameters: 261 * pmake_max_jobs - max jobs limit set by user 262 * 263 * External functions used: 264 * sysconf() 265 * getloadavg() 266 */ 267 static int 268 adjust_pmake_max_jobs (int pmake_max_jobs) 269 { 270 static int ncpu = 0; 271 double loadavg[3]; 272 int adjustment; 273 int adjusted_max_jobs; 274 275 if (ncpu <= 0) { 276 if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) { 277 ncpu = 1; 278 } 279 } 280 if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs); 281 adjustment = ((int)loadavg[LOADAVG_1MIN]); 282 if (adjustment < 2) return(pmake_max_jobs); 283 if (ncpu > 1) { 284 adjustment = adjustment / ncpu; 285 } 286 adjusted_max_jobs = pmake_max_jobs - adjustment; 287 if (adjusted_max_jobs < 1) adjusted_max_jobs = 1; 288 return(adjusted_max_jobs); 289 } 290 291 /* 292 * M2 adjust mode data and functions 293 * 294 * m2_init() - initializes M2 shared semaphore 295 * m2_acquire_job() - decrements M2 semaphore counter 296 * m2_release_job() - increments M2 semaphore counter 297 * m2_fini() - destroys M2 semaphore and shared memory* 298 * 299 * Environment variables: 300 * __DMAKE_M2_FILE__ 301 * 302 * External functions: 303 * ftok(), shmget(), shmat(), shmdt(), shmctl() 304 * sem_init(), sem_trywait(), sem_post(), sem_destroy() 305 * creat(), close(), unlink() 306 * getenv(), putenv() 307 * 308 * Static variables: 309 * m2_file - tmp file name to create ipc key for shared memory 310 * m2_shm_id - shared memory id 311 * m2_shm_sem - shared memory semaphore 312 */ 313 314 static char m2_file[MAXPATHLEN]; 315 static int m2_shm_id = -1; 316 static sem_t* m2_shm_sem = 0; 317 318 static int 319 m2_init() { 320 char *var; 321 key_t key; 322 323 if ((var = getenv("__DMAKE_M2_FILE__")) == 0) { 324 /* compose tmp file name */ 325 sprintf(m2_file, "%s/dmake.m2.%d.XXXXXX", tmpdir, getpid()); 326 327 /* create tmp file */ 328 int fd = mkstemp(m2_file); 329 if (fd < 0) { 330 return -1; 331 } else { 332 close(fd); 333 } 334 } else { 335 /* using existing semaphore */ 336 strcpy(m2_file, var); 337 } 338 339 /* combine IPC key */ 340 if ((key = ftok(m2_file, 38)) == (key_t) -1) { 341 return -1; 342 } 343 344 /* create shared memory */ 345 if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) { 346 return -1; 347 } 348 349 /* attach shared memory */ 350 if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) { 351 return -1; 352 } 353 354 /* root process */ 355 if (var == 0) { 356 /* initialize semaphore */ 357 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) { 358 return -1; 359 } 360 361 /* alloc memory for env variable */ 362 if ((var = (char*) malloc(MAXPATHLEN)) == 0) { 363 return -1; 364 } 365 366 /* put key to env */ 367 sprintf(var, "__DMAKE_M2_FILE__=%s", m2_file); 368 if (putenv(var)) { 369 return -1; 370 } 371 } 372 return 0; 373 } 374 375 static void 376 m2_fini() { 377 if (m2_shm_id >= 0) { 378 struct shmid_ds stat; 379 380 /* determine the number of attached processes */ 381 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) { 382 if (stat.shm_nattch <= 1) { 383 /* destroy semaphore */ 384 if (m2_shm_sem != 0) { 385 (void) sem_destroy(m2_shm_sem); 386 } 387 388 /* destroy shared memory */ 389 (void) shmctl(m2_shm_id, IPC_RMID, &stat); 390 391 /* remove tmp file created for the key */ 392 (void) unlink(m2_file); 393 } else { 394 /* detach shared memory */ 395 if (m2_shm_sem != 0) { 396 (void) shmdt((char*) m2_shm_sem); 397 } 398 } 399 } 400 401 m2_shm_id = -1; 402 m2_shm_sem = 0; 403 } 404 } 405 406 static int 407 m2_acquire_job() { 408 if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) { 409 if (sem_trywait(m2_shm_sem) == 0) { 410 return 1; 411 } 412 if (errno == EAGAIN) { 413 return 0; 414 } 415 } 416 return -1; 417 } 418 419 static int 420 m2_release_job() { 421 if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) { 422 if (sem_post(m2_shm_sem) == 0) { 423 return 0; 424 } 425 } 426 return -1; 427 } 428 429 /* 430 * job adjust mode 431 * 432 * Possible values: 433 * ADJUST_M1 - adjustment by system load (default) 434 * ADJUST_M2 - fixed limit of jobs for the group of nested dmakes 435 * ADJUST_NONE - no adjustment - fixed limit of jobs for the current dmake 436 */ 437 static enum { 438 ADJUST_UNKNOWN, 439 ADJUST_M1, 440 ADJUST_M2, 441 ADJUST_NONE 442 } job_adjust_mode = ADJUST_UNKNOWN; 443 444 /* 445 * void job_adjust_fini() 446 * 447 * Description: 448 * Cleans up job adjust data. 449 * 450 * Static variables: 451 * job_adjust_mode Current job adjust mode 452 */ 453 void 454 job_adjust_fini() { 455 if (job_adjust_mode == ADJUST_M2) { 456 m2_fini(); 457 } 458 } 459 460 /* 461 * void job_adjust_error() 462 * 463 * Description: 464 * Prints warning message, cleans up job adjust data, and disables job adjustment 465 * 466 * Environment: 467 * DMAKE_ADJUST_MAX_JOBS 468 * 469 * External functions: 470 * putenv() 471 * 472 * Static variables: 473 * job_adjust_mode Current job adjust mode 474 */ 475 static void 476 job_adjust_error() { 477 if (job_adjust_mode != ADJUST_NONE) { 478 /* cleanup internals */ 479 job_adjust_fini(); 480 481 /* warning message for the user */ 482 warning(gettext("Encountered max jobs auto adjustment error - disabling auto adjustment.")); 483 484 /* switch off job adjustment for the children */ 485 putenv(strdup("DMAKE_ADJUST_MAX_JOBS=NO")); 486 487 /* and for this dmake */ 488 job_adjust_mode = ADJUST_NONE; 489 } 490 } 491 492 /* 493 * void job_adjust_init() 494 * 495 * Description: 496 * Parses DMAKE_ADJUST_MAX_JOBS env variable 497 * and performs appropriate initializations. 498 * 499 * Environment: 500 * DMAKE_ADJUST_MAX_JOBS 501 * DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment 502 * DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode 503 * other - M1 adjust mode 504 * 505 * External functions: 506 * getenv() 507 * 508 * Static variables: 509 * job_adjust_mode Current job adjust mode 510 */ 511 static void 512 job_adjust_init() { 513 if (job_adjust_mode == ADJUST_UNKNOWN) { 514 /* default mode */ 515 job_adjust_mode = ADJUST_M1; 516 517 /* determine adjust mode */ 518 if (char *var = getenv("DMAKE_ADJUST_MAX_JOBS")) { 519 if (strcasecmp(var, "NO") == 0) { 520 job_adjust_mode = ADJUST_NONE; 521 } else if (strcasecmp(var, "M2") == 0) { 522 job_adjust_mode = ADJUST_M2; 523 } 524 } 525 526 /* M2 specific initialization */ 527 if (job_adjust_mode == ADJUST_M2) { 528 if (m2_init()) { 529 job_adjust_error(); 530 } 531 } 532 } 533 } 534 535 536 /* 537 * distribute_process(char **commands, Property line) 538 * 539 * Parameters: 540 * commands argv vector of commands to execute 541 * 542 * Return value: 543 * The result of the execution 544 * 545 * Static variables used: 546 * process_running Set to the pid of the process set running 547 * job_adjust_mode Current job adjust mode 548 */ 549 static Doname 550 distribute_process(char **commands, Property line) 551 { 552 static unsigned file_number = 0; 553 wchar_t string[MAXPATHLEN]; 554 char mbstring[MAXPATHLEN]; 555 int filed; 556 int res; 557 int tmp_index; 558 char *tmp_index_str_ptr; 559 560 /* initialize adjust mode, if not initialized */ 561 if (job_adjust_mode == ADJUST_UNKNOWN) { 562 job_adjust_init(); 563 } 564 565 /* actions depend on adjust mode */ 566 switch (job_adjust_mode) { 567 case ADJUST_M1: 568 while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) { 569 await_parallel(false); 570 finish_children(true); 571 } 572 break; 573 case ADJUST_M2: 574 if ((res = m2_acquire_job()) == 0) { 575 if (parallel_process_cnt > 0) { 576 await_parallel(false); 577 finish_children(true); 578 579 if ((res = m2_acquire_job()) == 0) { 580 return build_serial; 581 } 582 } else { 583 return build_serial; 584 } 585 } 586 if (res < 0) { 587 /* job adjustment error */ 588 job_adjust_error(); 589 590 /* no adjustment */ 591 while (parallel_process_cnt >= pmake_max_jobs) { 592 await_parallel(false); 593 finish_children(true); 594 } 595 } 596 break; 597 default: 598 while (parallel_process_cnt >= pmake_max_jobs) { 599 await_parallel(false); 600 finish_children(true); 601 } 602 } 603 604 setvar_envvar(); 605 /* 606 * Tell the user what DMake is doing. 607 */ 608 if (!silent && output_mode != txt2_mode) { 609 /* 610 * Print local_host --> x job(s). 611 */ 612 (void) fprintf(stdout, 613 gettext("%s --> %d %s\n"), 614 local_host, 615 parallel_process_cnt + 1, 616 (parallel_process_cnt == 0) ? gettext("job") : gettext("jobs")); 617 618 /* Print command line(s). */ 619 tmp_index = 0; 620 while (commands[tmp_index] != NULL) { 621 /* No @ char. */ 622 /* XXX - need to add [2] when + prefix is added */ 623 if ((commands[tmp_index][0] != (int) at_char) && 624 (commands[tmp_index][1] != (int) at_char)) { 625 tmp_index_str_ptr = commands[tmp_index]; 626 if (*tmp_index_str_ptr == (int) hyphen_char) { 627 tmp_index_str_ptr++; 628 } 629 (void) fprintf(stdout, "%s\n", tmp_index_str_ptr); 630 } 631 tmp_index++; 632 } 633 (void) fflush(stdout); 634 } 635 636 (void) sprintf(mbstring, 637 "%s/dmake.stdout.%d.%d.XXXXXX", 638 tmpdir, 639 getpid(), 640 file_number++); 641 642 mktemp(mbstring); 643 644 stdout_file = strdup(mbstring); 645 stderr_file = NULL; 646 647 if (!out_err_same) { 648 (void) sprintf(mbstring, 649 "%s/dmake.stderr.%d.%d.XXXXXX", 650 tmpdir, 651 getpid(), 652 file_number++); 653 654 mktemp(mbstring); 655 656 stderr_file = strdup(mbstring); 657 } 658 659 process_running = run_rule_commands(local_host, commands); 660 661 return build_running; 662 } 663 664 /* 665 * doname_parallel(target, do_get, implicit) 666 * 667 * Processes the given target and finishes up any parallel 668 * processes left running. 669 * 670 * Return value: 671 * Result of target build 672 * 673 * Parameters: 674 * target Target to build 675 * do_get True if sccs get to be done 676 * implicit True if this is an implicit target 677 */ 678 Doname 679 doname_parallel(Name target, Boolean do_get, Boolean implicit) 680 { 681 Doname result; 682 683 result = doname_check(target, do_get, implicit, false); 684 if (result == build_ok || result == build_failed) { 685 return result; 686 } 687 finish_running(); 688 return (Doname) target->state; 689 } 690 691 /* 692 * doname_subtree(target, do_get, implicit) 693 * 694 * Completely computes an object and its dependents for a 695 * serial subtree build. 696 * 697 * Parameters: 698 * target Target to build 699 * do_get True if sccs get to be done 700 * implicit True if this is an implicit target 701 * 702 * Static variables used: 703 * running_tail Tail of the list of running processes 704 * 705 * Global variables used: 706 * running_list The list of running processes 707 */ 708 static void 709 doname_subtree(Name target, Boolean do_get, Boolean implicit) 710 { 711 Running save_running_list; 712 Running *save_running_tail; 713 714 save_running_list = running_list; 715 save_running_tail = running_tail; 716 running_list = NULL; 717 running_tail = &running_list; 718 target->state = build_subtree; 719 target->checking_subtree = true; 720 while(doname_check(target, do_get, implicit, false) == build_running) { 721 target->checking_subtree = false; 722 finish_running(); 723 target->state = build_subtree; 724 } 725 target->checking_subtree = false; 726 running_list = save_running_list; 727 running_tail = save_running_tail; 728 } 729 730 /* 731 * finish_running() 732 * 733 * Keeps processing until the running_list is emptied out. 734 * 735 * Parameters: 736 * 737 * Global variables used: 738 * running_list The list of running processes 739 */ 740 void 741 finish_running(void) 742 { 743 while (running_list != NULL) { 744 { 745 await_parallel(false); 746 finish_children(true); 747 } 748 if (running_list != NULL) { 749 process_next(); 750 } 751 } 752 } 753 754 /* 755 * process_next() 756 * 757 * Searches the running list for any targets which can start processing. 758 * This can be a pending target, a serial target, or a subtree target. 759 * 760 * Parameters: 761 * 762 * Static variables used: 763 * running_tail The end of the list of running procs 764 * subtree_conflict A target which conflicts with a subtree 765 * subtree_conflict2 The other target which conflicts 766 * 767 * Global variables used: 768 * commands_done True if commands executed 769 * debug_level Controls debug output 770 * parallel_process_cnt Number of parallel process running 771 * recursion_level Indentation for debug output 772 * running_list List of running processes 773 */ 774 static void 775 process_next(void) 776 { 777 Running rp; 778 Running *rp_prev; 779 Property line; 780 Chain target_group; 781 Dependency dep; 782 Boolean quiescent = true; 783 Running *subtree_target; 784 Boolean saved_commands_done; 785 Property *conditionals; 786 787 subtree_target = NULL; 788 subtree_conflict = NULL; 789 subtree_conflict2 = NULL; 790 /* 791 * If nothing currently running, build a serial target, if any. 792 */ 793 start_loop_1: 794 for (rp_prev = &running_list, rp = running_list; 795 rp != NULL && parallel_process_cnt == 0; 796 rp = rp->next) { 797 if (rp->state == build_serial) { 798 *rp_prev = rp->next; 799 if (rp->next == NULL) { 800 running_tail = rp_prev; 801 } 802 recursion_level = rp->recursion_level; 803 rp->target->state = build_pending; 804 (void) doname_check(rp->target, 805 rp->do_get, 806 rp->implicit, 807 false); 808 quiescent = false; 809 delete_running_struct(rp); 810 goto start_loop_1; 811 } else { 812 rp_prev = &rp->next; 813 } 814 } 815 /* 816 * Find a target to build. The target must be pending, have all 817 * its dependencies built, and not be in a target group with a target 818 * currently building. 819 */ 820 start_loop_2: 821 for (rp_prev = &running_list, rp = running_list; 822 rp != NULL; 823 rp = rp->next) { 824 if (!(rp->state == build_pending || 825 rp->state == build_subtree)) { 826 quiescent = false; 827 rp_prev = &rp->next; 828 } else if (rp->state == build_pending) { 829 line = get_prop(rp->target->prop, line_prop); 830 for (dep = line->body.line.dependencies; 831 dep != NULL; 832 dep = dep->next) { 833 if (dep->name->state == build_running || 834 dep->name->state == build_pending || 835 dep->name->state == build_serial) { 836 break; 837 } 838 } 839 if (dep == NULL) { 840 for (target_group = line->body.line.target_group; 841 target_group != NULL; 842 target_group = target_group->next) { 843 if (is_running(target_group->name)) { 844 break; 845 } 846 } 847 if (target_group == NULL) { 848 *rp_prev = rp->next; 849 if (rp->next == NULL) { 850 running_tail = rp_prev; 851 } 852 recursion_level = rp->recursion_level; 853 rp->target->state = rp->redo ? 854 build_dont_know : build_pending; 855 saved_commands_done = commands_done; 856 conditionals = 857 set_conditionals 858 (rp->conditional_cnt, 859 rp->conditional_targets); 860 rp->target->dont_activate_cond_values = true; 861 if ((doname_check(rp->target, 862 rp->do_get, 863 rp->implicit, 864 rp->target->has_target_prop ? true : false) != 865 build_running) && 866 !commands_done) { 867 commands_done = 868 saved_commands_done; 869 } 870 rp->target->dont_activate_cond_values = false; 871 reset_conditionals 872 (rp->conditional_cnt, 873 rp->conditional_targets, 874 conditionals); 875 quiescent = false; 876 delete_running_struct(rp); 877 goto start_loop_2; 878 } else { 879 rp_prev = &rp->next; 880 } 881 } else { 882 rp_prev = &rp->next; 883 } 884 } else { 885 rp_prev = &rp->next; 886 } 887 } 888 /* 889 * If nothing has been found to build and there exists a subtree 890 * target with no dependency conflicts, build it. 891 */ 892 if (quiescent) { 893 start_loop_3: 894 for (rp_prev = &running_list, rp = running_list; 895 rp != NULL; 896 rp = rp->next) { 897 if (rp->state == build_subtree) { 898 if (!dependency_conflict(rp->target)) { 899 *rp_prev = rp->next; 900 if (rp->next == NULL) { 901 running_tail = rp_prev; 902 } 903 recursion_level = rp->recursion_level; 904 doname_subtree(rp->target, 905 rp->do_get, 906 rp->implicit); 907 quiescent = false; 908 delete_running_struct(rp); 909 goto start_loop_3; 910 } else { 911 subtree_target = rp_prev; 912 rp_prev = &rp->next; 913 } 914 } else { 915 rp_prev = &rp->next; 916 } 917 } 918 } 919 /* 920 * If still nothing found to build, we either have a deadlock 921 * or a subtree with a dependency conflict with something waiting 922 * to build. 923 */ 924 if (quiescent) { 925 if (subtree_target == NULL) { 926 fatal(gettext("Internal error: deadlock detected in process_next")); 927 } else { 928 rp = *subtree_target; 929 if (debug_level > 0) { 930 warning(gettext("Conditional macro conflict encountered for %s between %s and %s"), 931 subtree_conflict2->string_mb, 932 rp->target->string_mb, 933 subtree_conflict->string_mb); 934 } 935 *subtree_target = (*subtree_target)->next; 936 if (rp->next == NULL) { 937 running_tail = subtree_target; 938 } 939 recursion_level = rp->recursion_level; 940 doname_subtree(rp->target, rp->do_get, rp->implicit); 941 delete_running_struct(rp); 942 } 943 } 944 } 945 946 /* 947 * set_conditionals(cnt, targets) 948 * 949 * Sets the conditional macros for the targets given in the array of 950 * targets. The old macro values are returned in an array of 951 * Properties for later resetting. 952 * 953 * Return value: 954 * Array of conditional macro settings 955 * 956 * Parameters: 957 * cnt Number of targets 958 * targets Array of targets 959 */ 960 static Property * 961 set_conditionals(int cnt, Name *targets) 962 { 963 Property *locals, *lp; 964 Name *tp; 965 966 locals = (Property *) getmem(cnt * sizeof(Property)); 967 for (lp = locals, tp = targets; 968 cnt > 0; 969 cnt--, lp++, tp++) { 970 *lp = (Property) getmem((*tp)->conditional_cnt * 971 sizeof(struct _Property)); 972 set_locals(*tp, *lp); 973 } 974 return locals; 975 } 976 977 /* 978 * reset_conditionals(cnt, targets, locals) 979 * 980 * Resets the conditional macros as saved in the given array of 981 * Properties. The resets are done in reverse order. Afterwards the 982 * data structures are freed. 983 * 984 * Parameters: 985 * cnt Number of targets 986 * targets Array of targets 987 * locals Array of dependency macro settings 988 */ 989 static void 990 reset_conditionals(int cnt, Name *targets, Property *locals) 991 { 992 Name *tp; 993 Property *lp; 994 995 for (tp = targets + (cnt - 1), lp = locals + (cnt - 1); 996 cnt > 0; 997 cnt--, tp--, lp--) { 998 reset_locals(*tp, 999 *lp, 1000 get_prop((*tp)->prop, conditional_prop), 1001 0); 1002 retmem_mb((caddr_t) *lp); 1003 } 1004 retmem_mb((caddr_t) locals); 1005 } 1006 1007 /* 1008 * dependency_conflict(target) 1009 * 1010 * Returns true if there is an intersection between 1011 * the subtree of the target and any dependents of the pending targets. 1012 * 1013 * Return value: 1014 * True if conflict found 1015 * 1016 * Parameters: 1017 * target Subtree target to check 1018 * 1019 * Static variables used: 1020 * subtree_conflict Target conflict found 1021 * subtree_conflict2 Second conflict found 1022 * 1023 * Global variables used: 1024 * running_list List of running processes 1025 * wait_name .WAIT, not a real dependency 1026 */ 1027 static Boolean 1028 dependency_conflict(Name target) 1029 { 1030 Property line; 1031 Property pending_line; 1032 Dependency dp; 1033 Dependency pending_dp; 1034 Running rp; 1035 1036 /* Return if we are already checking this target */ 1037 if (target->checking_subtree) { 1038 return false; 1039 } 1040 target->checking_subtree = true; 1041 line = get_prop(target->prop, line_prop); 1042 if (line == NULL) { 1043 target->checking_subtree = false; 1044 return false; 1045 } 1046 /* Check each dependency of the target for conflicts */ 1047 for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) { 1048 /* Ignore .WAIT dependency */ 1049 if (dp->name == wait_name) { 1050 continue; 1051 } 1052 /* 1053 * For each pending target, look for a dependency which 1054 * is the same as a dependency of the subtree target. Since 1055 * we can't build the subtree until all pending targets have 1056 * finished which depend on the same dependency, this is 1057 * a conflict. 1058 */ 1059 for (rp = running_list; rp != NULL; rp = rp->next) { 1060 if (rp->state == build_pending) { 1061 pending_line = get_prop(rp->target->prop, 1062 line_prop); 1063 if (pending_line == NULL) { 1064 continue; 1065 } 1066 for(pending_dp = pending_line-> 1067 body.line.dependencies; 1068 pending_dp != NULL; 1069 pending_dp = pending_dp->next) { 1070 if (dp->name == pending_dp->name) { 1071 target->checking_subtree 1072 = false; 1073 subtree_conflict = rp->target; 1074 subtree_conflict2 = dp->name; 1075 return true; 1076 } 1077 } 1078 } 1079 } 1080 if (dependency_conflict(dp->name)) { 1081 target->checking_subtree = false; 1082 return true; 1083 } 1084 } 1085 target->checking_subtree = false; 1086 return false; 1087 } 1088 1089 /* 1090 * await_parallel(waitflg) 1091 * 1092 * Waits for parallel children to exit and finishes their processing. 1093 * If waitflg is false, the function returns after update_delay. 1094 * 1095 * Parameters: 1096 * waitflg dwight 1097 */ 1098 void 1099 await_parallel(Boolean waitflg) 1100 { 1101 Boolean nohang; 1102 pid_t pid; 1103 int status; 1104 Running rp; 1105 int waiterr; 1106 1107 nohang = false; 1108 for ( ; ; ) { 1109 if (!nohang) { 1110 (void) alarm((int) update_delay); 1111 } 1112 pid = waitpid((pid_t)-1, 1113 &status, 1114 nohang ? WNOHANG : 0); 1115 waiterr = errno; 1116 if (!nohang) { 1117 (void) alarm(0); 1118 } 1119 if (pid <= 0) { 1120 if (waiterr == EINTR) { 1121 if (waitflg) { 1122 continue; 1123 } else { 1124 return; 1125 } 1126 } else { 1127 return; 1128 } 1129 } 1130 for (rp = running_list; 1131 (rp != NULL) && (rp->pid != pid); 1132 rp = rp->next) { 1133 ; 1134 } 1135 if (rp == NULL) { 1136 fatal(gettext("Internal error: returned child pid not in running_list")); 1137 } else { 1138 rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed; 1139 } 1140 nohang = true; 1141 parallel_process_cnt--; 1142 1143 if (job_adjust_mode == ADJUST_M2) { 1144 if (m2_release_job()) { 1145 job_adjust_error(); 1146 } 1147 } 1148 } 1149 } 1150 1151 /* 1152 * finish_children(docheck) 1153 * 1154 * Finishes the processing for all targets which were running 1155 * and have now completed. 1156 * 1157 * Parameters: 1158 * docheck Completely check the finished target 1159 * 1160 * Static variables used: 1161 * running_tail The tail of the running list 1162 * 1163 * Global variables used: 1164 * continue_after_error -k flag 1165 * fatal_in_progress True if we are finishing up after fatal err 1166 * running_list List of running processes 1167 */ 1168 void 1169 finish_children(Boolean docheck) 1170 { 1171 int cmds_length; 1172 Property line; 1173 Property line2; 1174 struct stat out_buf; 1175 Running rp; 1176 Running *rp_prev; 1177 Cmd_line rule; 1178 Boolean silent_flag; 1179 1180 for (rp_prev = &running_list, rp = running_list; 1181 rp != NULL; 1182 rp = rp->next) { 1183 bypass_for_loop_inc_4: 1184 /* 1185 * If the state is ok or failed, then this target has 1186 * finished building. 1187 * In parallel_mode, output the accumulated stdout/stderr. 1188 * Read the auto dependency stuff, handle a failed build, 1189 * update the target, then finish the doname process for 1190 * that target. 1191 */ 1192 if (rp->state == build_ok || rp->state == build_failed) { 1193 *rp_prev = rp->next; 1194 if (rp->next == NULL) { 1195 running_tail = rp_prev; 1196 } 1197 if ((line2 = rp->command) == NULL) { 1198 line2 = get_prop(rp->target->prop, line_prop); 1199 } 1200 1201 1202 /* 1203 * Check if there were any job output 1204 * from the parallel build. 1205 */ 1206 if (rp->stdout_file != NULL) { 1207 if (stat(rp->stdout_file, &out_buf) < 0) { 1208 fatal(gettext("stat of %s failed: %s"), 1209 rp->stdout_file, 1210 errmsg(errno)); 1211 } 1212 1213 if ((line2 != NULL) && 1214 (out_buf.st_size > 0)) { 1215 cmds_length = 0; 1216 for (rule = line2->body.line.command_used, 1217 silent_flag = silent; 1218 rule != NULL; 1219 rule = rule->next) { 1220 cmds_length += rule->command_line->hash.length + 1; 1221 silent_flag = BOOLEAN(silent_flag || rule->silent); 1222 } 1223 if (out_buf.st_size != cmds_length || silent_flag || 1224 output_mode == txt2_mode) { 1225 dump_out_file(rp->stdout_file, false); 1226 } 1227 } 1228 (void) unlink(rp->stdout_file); 1229 retmem_mb(rp->stdout_file); 1230 rp->stdout_file = NULL; 1231 } 1232 1233 if (!out_err_same && (rp->stderr_file != NULL)) { 1234 if (stat(rp->stderr_file, &out_buf) < 0) { 1235 fatal(gettext("stat of %s failed: %s"), 1236 rp->stderr_file, 1237 errmsg(errno)); 1238 } 1239 if ((line2 != NULL) && 1240 (out_buf.st_size > 0)) { 1241 dump_out_file(rp->stderr_file, true); 1242 } 1243 (void) unlink(rp->stderr_file); 1244 retmem_mb(rp->stderr_file); 1245 rp->stderr_file = NULL; 1246 } 1247 1248 check_state(rp->temp_file); 1249 if (rp->temp_file != NULL) { 1250 free_name(rp->temp_file); 1251 } 1252 rp->temp_file = NULL; 1253 if (rp->state == build_failed) { 1254 line = get_prop(rp->target->prop, line_prop); 1255 if (line != NULL) { 1256 line->body.line.command_used = NULL; 1257 } 1258 if (continue_after_error || 1259 fatal_in_progress || 1260 !docheck) { 1261 warning(gettext("Command failed for target `%s'"), 1262 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb); 1263 build_failed_seen = true; 1264 } else { 1265 /* 1266 * XXX??? - DMake needs to exit(), 1267 * but shouldn't call fatal(). 1268 */ 1269 #ifdef PRINT_EXIT_STATUS 1270 warning("I'm in finish_children. rp->state == build_failed."); 1271 #endif 1272 1273 fatal(gettext("Command failed for target `%s'"), 1274 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb); 1275 } 1276 } 1277 if (!docheck) { 1278 delete_running_struct(rp); 1279 rp = *rp_prev; 1280 if (rp == NULL) { 1281 break; 1282 } else { 1283 goto bypass_for_loop_inc_4; 1284 } 1285 } 1286 update_target(get_prop(rp->target->prop, line_prop), 1287 rp->state); 1288 finish_doname(rp); 1289 delete_running_struct(rp); 1290 rp = *rp_prev; 1291 if (rp == NULL) { 1292 break; 1293 } else { 1294 goto bypass_for_loop_inc_4; 1295 } 1296 } else { 1297 rp_prev = &rp->next; 1298 } 1299 } 1300 } 1301 1302 /* 1303 * dump_out_file(filename, err) 1304 * 1305 * Write the contents of the file to stdout, then unlink the file. 1306 * 1307 * Parameters: 1308 * filename Name of temp file containing output 1309 * 1310 * Global variables used: 1311 */ 1312 static void 1313 dump_out_file(char *filename, Boolean err) 1314 { 1315 int chars_read; 1316 char copybuf[BUFSIZ]; 1317 int fd; 1318 int out_fd = (err ? 2 : 1); 1319 1320 if ((fd = open(filename, O_RDONLY)) < 0) { 1321 fatal(gettext("open failed for output file %s: %s"), 1322 filename, 1323 errmsg(errno)); 1324 } 1325 if (!silent && output_mode != txt2_mode) { 1326 (void) fprintf(err ? stderr : stdout, 1327 err ? 1328 gettext("%s --> Job errors\n") : 1329 gettext("%s --> Job output\n"), 1330 local_host); 1331 (void) fflush(err ? stderr : stdout); 1332 } 1333 for (chars_read = read(fd, copybuf, BUFSIZ); 1334 chars_read > 0; 1335 chars_read = read(fd, copybuf, BUFSIZ)) { 1336 /* 1337 * Read buffers from the source file until end or error. 1338 */ 1339 if (write(out_fd, copybuf, chars_read) < 0) { 1340 fatal(gettext("write failed for output file %s: %s"), 1341 filename, 1342 errmsg(errno)); 1343 } 1344 } 1345 (void) close(fd); 1346 (void) unlink(filename); 1347 } 1348 1349 /* 1350 * finish_doname(rp) 1351 * 1352 * Completes the processing for a target which was left running. 1353 * 1354 * Parameters: 1355 * rp Running list entry for target 1356 * 1357 * Global variables used: 1358 * debug_level Debug flag 1359 * recursion_level Indentation for debug output 1360 */ 1361 static void 1362 finish_doname(Running rp) 1363 { 1364 int auto_count = rp->auto_count; 1365 Name *automatics = rp->automatics; 1366 Doname result = rp->state; 1367 Name target = rp->target; 1368 Name true_target = rp->true_target; 1369 Property *conditionals; 1370 1371 recursion_level = rp->recursion_level; 1372 if (result == build_ok) { 1373 if (true_target == NULL) { 1374 (void) printf("Target = %s\n", target->string_mb); 1375 (void) printf(" State = %d\n", result); 1376 fatal("Internal error: NULL true_target in finish_doname"); 1377 } 1378 /* If all went OK, set a nice timestamp */ 1379 if (true_target->stat.time == file_doesnt_exist) { 1380 true_target->stat.time = file_max_time; 1381 } 1382 } 1383 target->state = result; 1384 if (target->is_member) { 1385 Property member; 1386 1387 /* Propagate the timestamp from the member file to the member */ 1388 if ((target->stat.time != file_max_time) && 1389 ((member = get_prop(target->prop, member_prop)) != NULL) && 1390 (exists(member->body.member.member) > file_doesnt_exist)) { 1391 target->stat.time = 1392 /* 1393 exists(member->body.member.member); 1394 */ 1395 member->body.member.member->stat.time; 1396 } 1397 } 1398 /* 1399 * Check if we found any new auto dependencies when we 1400 * built the target. 1401 */ 1402 if ((result == build_ok) && check_auto_dependencies(target, 1403 auto_count, 1404 automatics)) { 1405 if (debug_level > 0) { 1406 (void) printf(gettext("%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"), 1407 recursion_level, 1408 "", 1409 true_target->string_mb); 1410 } 1411 target->rechecking_target = true; 1412 target->state = build_running; 1413 1414 /* [tolik, Tue Mar 25 1997] 1415 * Fix for bug 4038824: 1416 * command line options set by conditional macros get dropped 1417 * rp->conditional_cnt and rp->conditional_targets must be copied 1418 * to new 'rp' during add_pending(). Set_conditionals() stores 1419 * rp->conditional_targets to the global variable 'conditional_targets' 1420 * Add_pending() will use this variable to set up 'rp'. 1421 */ 1422 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets); 1423 add_pending(target, 1424 recursion_level, 1425 rp->do_get, 1426 rp->implicit, 1427 true); 1428 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals); 1429 } 1430 } 1431 1432 /* 1433 * new_running_struct() 1434 * 1435 * Constructor for Running struct. Creates a structure and initializes 1436 * its fields. 1437 * 1438 */ 1439 static Running new_running_struct() 1440 { 1441 Running rp; 1442 1443 rp = ALLOC(Running); 1444 rp->target = NULL; 1445 rp->true_target = NULL; 1446 rp->command = NULL; 1447 rp->sprodep_value = NULL; 1448 rp->sprodep_env = NULL; 1449 rp->auto_count = 0; 1450 rp->automatics = NULL; 1451 rp->pid = -1; 1452 rp->job_msg_id = -1; 1453 rp->stdout_file = NULL; 1454 rp->stderr_file = NULL; 1455 rp->temp_file = NULL; 1456 rp->next = NULL; 1457 return rp; 1458 } 1459 1460 /* 1461 * add_running(target, true_target, command, recursion_level, auto_count, 1462 * automatics, do_get, implicit) 1463 * 1464 * Adds a record on the running list for this target, which 1465 * was just spawned and is running. 1466 * 1467 * Parameters: 1468 * target Target being built 1469 * true_target True target for target 1470 * command Running command. 1471 * recursion_level Debug indentation level 1472 * auto_count Count of automatic dependencies 1473 * automatics List of automatic dependencies 1474 * do_get Sccs get flag 1475 * implicit Implicit flag 1476 * 1477 * Static variables used: 1478 * running_tail Tail of running list 1479 * process_running PID of process 1480 * 1481 * Global variables used: 1482 * current_line Current line for target 1483 * current_target Current target being built 1484 * stderr_file Temporary file for stdout 1485 * stdout_file Temporary file for stdout 1486 * temp_file_name Temporary file for auto dependencies 1487 */ 1488 void 1489 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit) 1490 { 1491 Running rp; 1492 Name *p; 1493 1494 rp = new_running_struct(); 1495 rp->state = build_running; 1496 rp->target = target; 1497 rp->true_target = true_target; 1498 rp->command = command; 1499 rp->recursion_level = recursion_level; 1500 rp->do_get = do_get; 1501 rp->implicit = implicit; 1502 rp->auto_count = auto_count; 1503 if (auto_count > 0) { 1504 rp->automatics = (Name *) getmem(auto_count * sizeof (Name)); 1505 for (p = rp->automatics; auto_count > 0; auto_count--) { 1506 *p++ = *automatics++; 1507 } 1508 } else { 1509 rp->automatics = NULL; 1510 } 1511 { 1512 rp->pid = process_running; 1513 process_running = -1; 1514 childPid = -1; 1515 } 1516 rp->job_msg_id = job_msg_id; 1517 rp->stdout_file = stdout_file; 1518 rp->stderr_file = stderr_file; 1519 rp->temp_file = temp_file_name; 1520 rp->redo = false; 1521 rp->next = NULL; 1522 store_conditionals(rp); 1523 stdout_file = NULL; 1524 stderr_file = NULL; 1525 temp_file_name = NULL; 1526 current_target = NULL; 1527 current_line = NULL; 1528 *running_tail = rp; 1529 running_tail = &rp->next; 1530 } 1531 1532 /* 1533 * add_pending(target, recursion_level, do_get, implicit, redo) 1534 * 1535 * Adds a record on the running list for a pending target 1536 * (waiting for its dependents to finish running). 1537 * 1538 * Parameters: 1539 * target Target being built 1540 * recursion_level Debug indentation level 1541 * do_get Sccs get flag 1542 * implicit Implicit flag 1543 * redo True if this target is being redone 1544 * 1545 * Static variables used: 1546 * running_tail Tail of running list 1547 */ 1548 void 1549 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo) 1550 { 1551 Running rp; 1552 rp = new_running_struct(); 1553 rp->state = build_pending; 1554 rp->target = target; 1555 rp->recursion_level = recursion_level; 1556 rp->do_get = do_get; 1557 rp->implicit = implicit; 1558 rp->redo = redo; 1559 store_conditionals(rp); 1560 *running_tail = rp; 1561 running_tail = &rp->next; 1562 } 1563 1564 /* 1565 * add_serial(target, recursion_level, do_get, implicit) 1566 * 1567 * Adds a record on the running list for a target which must be 1568 * executed in serial after others have finished. 1569 * 1570 * Parameters: 1571 * target Target being built 1572 * recursion_level Debug indentation level 1573 * do_get Sccs get flag 1574 * implicit Implicit flag 1575 * 1576 * Static variables used: 1577 * running_tail Tail of running list 1578 */ 1579 void 1580 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit) 1581 { 1582 Running rp; 1583 1584 rp = new_running_struct(); 1585 rp->target = target; 1586 rp->recursion_level = recursion_level; 1587 rp->do_get = do_get; 1588 rp->implicit = implicit; 1589 rp->state = build_serial; 1590 rp->redo = false; 1591 store_conditionals(rp); 1592 *running_tail = rp; 1593 running_tail = &rp->next; 1594 } 1595 1596 /* 1597 * add_subtree(target, recursion_level, do_get, implicit) 1598 * 1599 * Adds a record on the running list for a target which must be 1600 * executed in isolation after others have finished. 1601 * 1602 * Parameters: 1603 * target Target being built 1604 * recursion_level Debug indentation level 1605 * do_get Sccs get flag 1606 * implicit Implicit flag 1607 * 1608 * Static variables used: 1609 * running_tail Tail of running list 1610 */ 1611 void 1612 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit) 1613 { 1614 Running rp; 1615 1616 rp = new_running_struct(); 1617 rp->target = target; 1618 rp->recursion_level = recursion_level; 1619 rp->do_get = do_get; 1620 rp->implicit = implicit; 1621 rp->state = build_subtree; 1622 rp->redo = false; 1623 store_conditionals(rp); 1624 *running_tail = rp; 1625 running_tail = &rp->next; 1626 } 1627 1628 /* 1629 * store_conditionals(rp) 1630 * 1631 * Creates an array of the currently active targets with conditional 1632 * macros (found in the chain conditional_targets) and puts that 1633 * array in the Running struct. 1634 * 1635 * Parameters: 1636 * rp Running struct for storing chain 1637 * 1638 * Global variables used: 1639 * conditional_targets Chain of current dynamic conditionals 1640 */ 1641 static void 1642 store_conditionals(Running rp) 1643 { 1644 int cnt; 1645 Chain cond_name; 1646 1647 if (conditional_targets == NULL) { 1648 rp->conditional_cnt = 0; 1649 rp->conditional_targets = NULL; 1650 return; 1651 } 1652 cnt = 0; 1653 for (cond_name = conditional_targets; 1654 cond_name != NULL; 1655 cond_name = cond_name->next) { 1656 cnt++; 1657 } 1658 rp->conditional_cnt = cnt; 1659 rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name)); 1660 for (cond_name = conditional_targets; 1661 cond_name != NULL; 1662 cond_name = cond_name->next) { 1663 rp->conditional_targets[--cnt] = cond_name->name; 1664 } 1665 } 1666 1667 /* 1668 * parallel_ok(target, line_prop_must_exists) 1669 * 1670 * Returns true if the target can be run in parallel 1671 * 1672 * Return value: 1673 * True if can run in parallel 1674 * 1675 * Parameters: 1676 * target Target being tested 1677 * 1678 * Global variables used: 1679 * all_parallel True if all targets default to parallel 1680 * only_parallel True if no targets default to parallel 1681 */ 1682 Boolean 1683 parallel_ok(Name target, Boolean line_prop_must_exists) 1684 { 1685 Boolean assign; 1686 Boolean make_refd; 1687 Property line; 1688 Cmd_line rule; 1689 1690 assign = make_refd = false; 1691 if (((line = get_prop(target->prop, line_prop)) == NULL) && 1692 line_prop_must_exists) { 1693 return false; 1694 } 1695 if (line != NULL) { 1696 for (rule = line->body.line.command_used; 1697 rule != NULL; 1698 rule = rule->next) { 1699 if (rule->assign) { 1700 assign = true; 1701 } else if (rule->make_refd) { 1702 make_refd = true; 1703 } 1704 } 1705 } 1706 if (assign) { 1707 return false; 1708 } else if (target->parallel) { 1709 return true; 1710 } else if (target->no_parallel) { 1711 return false; 1712 } else if (all_parallel) { 1713 return true; 1714 } else if (only_parallel) { 1715 return false; 1716 } else if (make_refd) { 1717 return false; 1718 } else { 1719 return true; 1720 } 1721 } 1722 1723 /* 1724 * is_running(target) 1725 * 1726 * Returns true if the target is running. 1727 * 1728 * Return value: 1729 * True if target is running 1730 * 1731 * Parameters: 1732 * target Target to check 1733 * 1734 * Global variables used: 1735 * running_list List of running processes 1736 */ 1737 Boolean 1738 is_running(Name target) 1739 { 1740 Running rp; 1741 1742 if (target->state != build_running) { 1743 return false; 1744 } 1745 for (rp = running_list; 1746 rp != NULL && target != rp->target; 1747 rp = rp->next); 1748 if (rp == NULL) { 1749 return false; 1750 } else { 1751 return (rp->state == build_running) ? true : false; 1752 } 1753 } 1754 1755 /* 1756 * This function replaces the makesh binary. 1757 */ 1758 1759 1760 static pid_t 1761 run_rule_commands(char *host, char **commands) 1762 { 1763 Boolean always_exec; 1764 Name command; 1765 Boolean ignore; 1766 int length; 1767 Doname result; 1768 Boolean silent_flag; 1769 wchar_t *tmp_wcs_buffer; 1770 1771 childPid = fork(); 1772 switch (childPid) { 1773 case -1: /* Error */ 1774 fatal(gettext("Could not fork child process for dmake job: %s"), 1775 errmsg(errno)); 1776 break; 1777 case 0: /* Child */ 1778 /* To control the processed targets list is not the child's business */ 1779 running_list = NULL; 1780 if(out_err_same) { 1781 redirect_io(stdout_file, (char*)NULL); 1782 } else { 1783 redirect_io(stdout_file, stderr_file); 1784 } 1785 for (commands = commands; 1786 (*commands != (char *)NULL); 1787 commands++) { 1788 silent_flag = silent; 1789 ignore = false; 1790 always_exec = false; 1791 while ((**commands == (int) at_char) || 1792 (**commands == (int) hyphen_char) || 1793 (**commands == (int) plus_char)) { 1794 if (**commands == (int) at_char) { 1795 silent_flag = true; 1796 } 1797 if (**commands == (int) hyphen_char) { 1798 ignore = true; 1799 } 1800 if (**commands == (int) plus_char) { 1801 always_exec = true; 1802 } 1803 (*commands)++; 1804 } 1805 if ((length = strlen(*commands)) >= MAXPATHLEN) { 1806 tmp_wcs_buffer = ALLOC_WC(length + 1); 1807 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1); 1808 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH); 1809 retmem(tmp_wcs_buffer); 1810 } else { 1811 MBSTOWCS(wcs_buffer, *commands); 1812 command = GETNAME(wcs_buffer, FIND_LENGTH); 1813 } 1814 if ((command->hash.length > 0) && 1815 !silent_flag) { 1816 (void) printf("%s\n", command->string_mb); 1817 } 1818 result = dosys(command, 1819 ignore, 1820 false, 1821 false, /* bugs #4085164 & #4990057 */ 1822 /* BOOLEAN(silent_flag && ignore), */ 1823 always_exec, 1824 (Name) NULL); 1825 if (result == build_failed) { 1826 if (silent_flag) { 1827 (void) printf(gettext("The following command caused the error:\n%s\n"), command->string_mb); 1828 } 1829 if (!ignore) { 1830 _exit(1); 1831 } 1832 } 1833 } 1834 _exit(0); 1835 break; 1836 default: 1837 break; 1838 } 1839 return childPid; 1840 } 1841 1842 static void 1843 maybe_reread_make_state(void) 1844 { 1845 /* Copying dosys()... */ 1846 if (report_dependencies_level == 0) { 1847 make_state->stat.time = file_no_time; 1848 (void) exists(make_state); 1849 if (make_state_before == make_state->stat.time) { 1850 return; 1851 } 1852 makefile_type = reading_statefile; 1853 if (read_trace_level > 1) { 1854 trace_reader = true; 1855 } 1856 temp_file_number++; 1857 (void) read_simple_file(make_state, 1858 false, 1859 false, 1860 false, 1861 false, 1862 false, 1863 true); 1864 trace_reader = false; 1865 } 1866 } 1867 1868 1869 static void 1870 delete_running_struct(Running rp) 1871 { 1872 if ((rp->conditional_cnt > 0) && 1873 (rp->conditional_targets != NULL)) { 1874 retmem_mb((char *) rp->conditional_targets); 1875 } 1876 /**/ 1877 if ((rp->auto_count > 0) && 1878 (rp->automatics != NULL)) { 1879 retmem_mb((char *) rp->automatics); 1880 } 1881 /**/ 1882 if(rp->sprodep_value) { 1883 free_name(rp->sprodep_value); 1884 } 1885 if(rp->sprodep_env) { 1886 retmem_mb(rp->sprodep_env); 1887 } 1888 retmem_mb((char *) rp); 1889 1890 } 1891 1892