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