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 fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list")); 1148 } else { 1149 rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed; 1150 } 1151 nohang = true; 1152 parallel_process_cnt--; 1153 1154 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000) 1155 if (job_adjust_mode == ADJUST_M2) { 1156 if (m2_release_job()) { 1157 job_adjust_error(); 1158 } 1159 } 1160 #endif 1161 } 1162 } 1163 1164 /* 1165 * finish_children(docheck) 1166 * 1167 * Finishes the processing for all targets which were running 1168 * and have now completed. 1169 * 1170 * Parameters: 1171 * docheck Completely check the finished target 1172 * 1173 * Static variables used: 1174 * running_tail The tail of the running list 1175 * 1176 * Global variables used: 1177 * continue_after_error -k flag 1178 * fatal_in_progress True if we are finishing up after fatal err 1179 * running_list List of running processes 1180 */ 1181 void 1182 finish_children(Boolean docheck) 1183 { 1184 int cmds_length; 1185 Property line; 1186 Property line2; 1187 struct stat out_buf; 1188 Running rp; 1189 Running *rp_prev; 1190 Cmd_line rule; 1191 Boolean silent_flag; 1192 1193 for (rp_prev = &running_list, rp = running_list; 1194 rp != NULL; 1195 rp = rp->next) { 1196 bypass_for_loop_inc_4: 1197 /* 1198 * If the state is ok or failed, then this target has 1199 * finished building. 1200 * In parallel_mode, output the accumulated stdout/stderr. 1201 * Read the auto dependency stuff, handle a failed build, 1202 * update the target, then finish the doname process for 1203 * that target. 1204 */ 1205 if (rp->state == build_ok || rp->state == build_failed) { 1206 *rp_prev = rp->next; 1207 if (rp->next == NULL) { 1208 running_tail = rp_prev; 1209 } 1210 if ((line2 = rp->command) == NULL) { 1211 line2 = get_prop(rp->target->prop, line_prop); 1212 } 1213 1214 1215 /* 1216 * Check if there were any job output 1217 * from the parallel build. 1218 */ 1219 if (rp->stdout_file != NULL) { 1220 if (stat(rp->stdout_file, &out_buf) < 0) { 1221 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"), 1222 rp->stdout_file, 1223 errmsg(errno)); 1224 } 1225 1226 if ((line2 != NULL) && 1227 (out_buf.st_size > 0)) { 1228 cmds_length = 0; 1229 for (rule = line2->body.line.command_used, 1230 silent_flag = silent; 1231 rule != NULL; 1232 rule = rule->next) { 1233 cmds_length += rule->command_line->hash.length + 1; 1234 silent_flag = BOOLEAN(silent_flag || rule->silent); 1235 } 1236 if (out_buf.st_size != cmds_length || silent_flag || 1237 output_mode == txt2_mode) { 1238 dump_out_file(rp->stdout_file, false); 1239 } 1240 } 1241 (void) unlink(rp->stdout_file); 1242 retmem_mb(rp->stdout_file); 1243 rp->stdout_file = NULL; 1244 } 1245 1246 if (!out_err_same && (rp->stderr_file != NULL)) { 1247 if (stat(rp->stderr_file, &out_buf) < 0) { 1248 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"), 1249 rp->stderr_file, 1250 errmsg(errno)); 1251 } 1252 if ((line2 != NULL) && 1253 (out_buf.st_size > 0)) { 1254 dump_out_file(rp->stderr_file, true); 1255 } 1256 (void) unlink(rp->stderr_file); 1257 retmem_mb(rp->stderr_file); 1258 rp->stderr_file = NULL; 1259 } 1260 1261 check_state(rp->temp_file); 1262 if (rp->temp_file != NULL) { 1263 free_name(rp->temp_file); 1264 } 1265 rp->temp_file = NULL; 1266 if (rp->state == build_failed) { 1267 line = get_prop(rp->target->prop, line_prop); 1268 if (line != NULL) { 1269 line->body.line.command_used = NULL; 1270 } 1271 if (continue_after_error || 1272 fatal_in_progress || 1273 !docheck) { 1274 warning(catgets(catd, 1, 256, "Command failed for target `%s'"), 1275 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb); 1276 build_failed_seen = true; 1277 } else { 1278 /* 1279 * XXX??? - DMake needs to exit(), 1280 * but shouldn't call fatal(). 1281 */ 1282 #ifdef PRINT_EXIT_STATUS 1283 warning(NOCATGETS("I'm in finish_children. rp->state == build_failed.")); 1284 #endif 1285 1286 fatal(catgets(catd, 1, 258, "Command failed for target `%s'"), 1287 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb); 1288 } 1289 } 1290 if (!docheck) { 1291 delete_running_struct(rp); 1292 rp = *rp_prev; 1293 if (rp == NULL) { 1294 break; 1295 } else { 1296 goto bypass_for_loop_inc_4; 1297 } 1298 } 1299 update_target(get_prop(rp->target->prop, line_prop), 1300 rp->state); 1301 finish_doname(rp); 1302 delete_running_struct(rp); 1303 rp = *rp_prev; 1304 if (rp == NULL) { 1305 break; 1306 } else { 1307 goto bypass_for_loop_inc_4; 1308 } 1309 } else { 1310 rp_prev = &rp->next; 1311 } 1312 } 1313 } 1314 1315 /* 1316 * dump_out_file(filename, err) 1317 * 1318 * Write the contents of the file to stdout, then unlink the file. 1319 * 1320 * Parameters: 1321 * filename Name of temp file containing output 1322 * 1323 * Global variables used: 1324 */ 1325 static void 1326 dump_out_file(char *filename, Boolean err) 1327 { 1328 int chars_read; 1329 char copybuf[BUFSIZ]; 1330 int fd; 1331 int out_fd = (err ? 2 : 1); 1332 1333 if ((fd = open(filename, O_RDONLY)) < 0) { 1334 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"), 1335 filename, 1336 errmsg(errno)); 1337 } 1338 if (!silent && output_mode != txt2_mode) { 1339 (void) fprintf(err ? stderr : stdout, 1340 err ? 1341 catgets(catd, 1, 338, "%s --> Job errors\n") : 1342 catgets(catd, 1, 259, "%s --> Job output\n"), 1343 local_host); 1344 (void) fflush(err ? stderr : stdout); 1345 } 1346 for (chars_read = read(fd, copybuf, BUFSIZ); 1347 chars_read > 0; 1348 chars_read = read(fd, copybuf, BUFSIZ)) { 1349 /* 1350 * Read buffers from the source file until end or error. 1351 */ 1352 if (write(out_fd, copybuf, chars_read) < 0) { 1353 fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"), 1354 filename, 1355 errmsg(errno)); 1356 } 1357 } 1358 (void) close(fd); 1359 (void) unlink(filename); 1360 } 1361 1362 /* 1363 * finish_doname(rp) 1364 * 1365 * Completes the processing for a target which was left running. 1366 * 1367 * Parameters: 1368 * rp Running list entry for target 1369 * 1370 * Global variables used: 1371 * debug_level Debug flag 1372 * recursion_level Indentation for debug output 1373 */ 1374 static void 1375 finish_doname(Running rp) 1376 { 1377 int auto_count = rp->auto_count; 1378 Name *automatics = rp->automatics; 1379 Doname result = rp->state; 1380 Name target = rp->target; 1381 Name true_target = rp->true_target; 1382 Property *conditionals; 1383 1384 recursion_level = rp->recursion_level; 1385 if (result == build_ok) { 1386 if (true_target == NULL) { 1387 (void) printf(NOCATGETS("Target = %s\n"), target->string_mb); 1388 (void) printf(NOCATGETS(" State = %d\n"), result); 1389 fatal(NOCATGETS("Internal error: NULL true_target in finish_doname")); 1390 } 1391 /* If all went OK, set a nice timestamp */ 1392 if (true_target->stat.time == file_doesnt_exist) { 1393 true_target->stat.time = file_max_time; 1394 } 1395 } 1396 target->state = result; 1397 if (target->is_member) { 1398 Property member; 1399 1400 /* Propagate the timestamp from the member file to the member */ 1401 if ((target->stat.time != file_max_time) && 1402 ((member = get_prop(target->prop, member_prop)) != NULL) && 1403 (exists(member->body.member.member) > file_doesnt_exist)) { 1404 target->stat.time = 1405 /* 1406 exists(member->body.member.member); 1407 */ 1408 member->body.member.member->stat.time; 1409 } 1410 } 1411 /* 1412 * Check if we found any new auto dependencies when we 1413 * built the target. 1414 */ 1415 if ((result == build_ok) && check_auto_dependencies(target, 1416 auto_count, 1417 automatics)) { 1418 if (debug_level > 0) { 1419 (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"), 1420 recursion_level, 1421 "", 1422 true_target->string_mb); 1423 } 1424 target->rechecking_target = true; 1425 target->state = build_running; 1426 1427 /* [tolik, Tue Mar 25 1997] 1428 * Fix for bug 4038824: 1429 * command line options set by conditional macros get dropped 1430 * rp->conditional_cnt and rp->conditional_targets must be copied 1431 * to new 'rp' during add_pending(). Set_conditionals() stores 1432 * rp->conditional_targets to the global variable 'conditional_targets' 1433 * Add_pending() will use this variable to set up 'rp'. 1434 */ 1435 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets); 1436 add_pending(target, 1437 recursion_level, 1438 rp->do_get, 1439 rp->implicit, 1440 true); 1441 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals); 1442 } 1443 } 1444 1445 /* 1446 * new_running_struct() 1447 * 1448 * Constructor for Running struct. Creates a structure and initializes 1449 * its fields. 1450 * 1451 */ 1452 static Running new_running_struct() 1453 { 1454 Running rp; 1455 1456 rp = ALLOC(Running); 1457 rp->target = NULL; 1458 rp->true_target = NULL; 1459 rp->command = NULL; 1460 rp->sprodep_value = NULL; 1461 rp->sprodep_env = NULL; 1462 rp->auto_count = 0; 1463 rp->automatics = NULL; 1464 rp->pid = -1; 1465 rp->job_msg_id = -1; 1466 rp->stdout_file = NULL; 1467 rp->stderr_file = NULL; 1468 rp->temp_file = NULL; 1469 rp->next = NULL; 1470 return rp; 1471 } 1472 1473 /* 1474 * add_running(target, true_target, command, recursion_level, auto_count, 1475 * automatics, do_get, implicit) 1476 * 1477 * Adds a record on the running list for this target, which 1478 * was just spawned and is running. 1479 * 1480 * Parameters: 1481 * target Target being built 1482 * true_target True target for target 1483 * command Running command. 1484 * recursion_level Debug indentation level 1485 * auto_count Count of automatic dependencies 1486 * automatics List of automatic dependencies 1487 * do_get Sccs get flag 1488 * implicit Implicit flag 1489 * 1490 * Static variables used: 1491 * running_tail Tail of running list 1492 * process_running PID of process 1493 * 1494 * Global variables used: 1495 * current_line Current line for target 1496 * current_target Current target being built 1497 * stderr_file Temporary file for stdout 1498 * stdout_file Temporary file for stdout 1499 * temp_file_name Temporary file for auto dependencies 1500 */ 1501 void 1502 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit) 1503 { 1504 Running rp; 1505 Name *p; 1506 1507 rp = new_running_struct(); 1508 rp->state = build_running; 1509 rp->target = target; 1510 rp->true_target = true_target; 1511 rp->command = command; 1512 rp->recursion_level = recursion_level; 1513 rp->do_get = do_get; 1514 rp->implicit = implicit; 1515 rp->auto_count = auto_count; 1516 if (auto_count > 0) { 1517 rp->automatics = (Name *) getmem(auto_count * sizeof (Name)); 1518 for (p = rp->automatics; auto_count > 0; auto_count--) { 1519 *p++ = *automatics++; 1520 } 1521 } else { 1522 rp->automatics = NULL; 1523 } 1524 { 1525 rp->pid = process_running; 1526 process_running = -1; 1527 childPid = -1; 1528 } 1529 rp->job_msg_id = job_msg_id; 1530 rp->stdout_file = stdout_file; 1531 rp->stderr_file = stderr_file; 1532 rp->temp_file = temp_file_name; 1533 rp->redo = false; 1534 rp->next = NULL; 1535 store_conditionals(rp); 1536 stdout_file = NULL; 1537 stderr_file = NULL; 1538 temp_file_name = NULL; 1539 current_target = NULL; 1540 current_line = NULL; 1541 *running_tail = rp; 1542 running_tail = &rp->next; 1543 } 1544 1545 /* 1546 * add_pending(target, recursion_level, do_get, implicit, redo) 1547 * 1548 * Adds a record on the running list for a pending target 1549 * (waiting for its dependents to finish running). 1550 * 1551 * Parameters: 1552 * target Target being built 1553 * recursion_level Debug indentation level 1554 * do_get Sccs get flag 1555 * implicit Implicit flag 1556 * redo True if this target is being redone 1557 * 1558 * Static variables used: 1559 * running_tail Tail of running list 1560 */ 1561 void 1562 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo) 1563 { 1564 Running rp; 1565 rp = new_running_struct(); 1566 rp->state = build_pending; 1567 rp->target = target; 1568 rp->recursion_level = recursion_level; 1569 rp->do_get = do_get; 1570 rp->implicit = implicit; 1571 rp->redo = redo; 1572 store_conditionals(rp); 1573 *running_tail = rp; 1574 running_tail = &rp->next; 1575 } 1576 1577 /* 1578 * add_serial(target, recursion_level, do_get, implicit) 1579 * 1580 * Adds a record on the running list for a target which must be 1581 * executed in serial after others have finished. 1582 * 1583 * Parameters: 1584 * target Target being built 1585 * recursion_level Debug indentation level 1586 * do_get Sccs get flag 1587 * implicit Implicit flag 1588 * 1589 * Static variables used: 1590 * running_tail Tail of running list 1591 */ 1592 void 1593 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit) 1594 { 1595 Running rp; 1596 1597 rp = new_running_struct(); 1598 rp->target = target; 1599 rp->recursion_level = recursion_level; 1600 rp->do_get = do_get; 1601 rp->implicit = implicit; 1602 rp->state = build_serial; 1603 rp->redo = false; 1604 store_conditionals(rp); 1605 *running_tail = rp; 1606 running_tail = &rp->next; 1607 } 1608 1609 /* 1610 * add_subtree(target, recursion_level, do_get, implicit) 1611 * 1612 * Adds a record on the running list for a target which must be 1613 * executed in isolation after others have finished. 1614 * 1615 * Parameters: 1616 * target Target being built 1617 * recursion_level Debug indentation level 1618 * do_get Sccs get flag 1619 * implicit Implicit flag 1620 * 1621 * Static variables used: 1622 * running_tail Tail of running list 1623 */ 1624 void 1625 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit) 1626 { 1627 Running rp; 1628 1629 rp = new_running_struct(); 1630 rp->target = target; 1631 rp->recursion_level = recursion_level; 1632 rp->do_get = do_get; 1633 rp->implicit = implicit; 1634 rp->state = build_subtree; 1635 rp->redo = false; 1636 store_conditionals(rp); 1637 *running_tail = rp; 1638 running_tail = &rp->next; 1639 } 1640 1641 /* 1642 * store_conditionals(rp) 1643 * 1644 * Creates an array of the currently active targets with conditional 1645 * macros (found in the chain conditional_targets) and puts that 1646 * array in the Running struct. 1647 * 1648 * Parameters: 1649 * rp Running struct for storing chain 1650 * 1651 * Global variables used: 1652 * conditional_targets Chain of current dynamic conditionals 1653 */ 1654 static void 1655 store_conditionals(Running rp) 1656 { 1657 int cnt; 1658 Chain cond_name; 1659 1660 if (conditional_targets == NULL) { 1661 rp->conditional_cnt = 0; 1662 rp->conditional_targets = NULL; 1663 return; 1664 } 1665 cnt = 0; 1666 for (cond_name = conditional_targets; 1667 cond_name != NULL; 1668 cond_name = cond_name->next) { 1669 cnt++; 1670 } 1671 rp->conditional_cnt = cnt; 1672 rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name)); 1673 for (cond_name = conditional_targets; 1674 cond_name != NULL; 1675 cond_name = cond_name->next) { 1676 rp->conditional_targets[--cnt] = cond_name->name; 1677 } 1678 } 1679 1680 /* 1681 * parallel_ok(target, line_prop_must_exists) 1682 * 1683 * Returns true if the target can be run in parallel 1684 * 1685 * Return value: 1686 * True if can run in parallel 1687 * 1688 * Parameters: 1689 * target Target being tested 1690 * 1691 * Global variables used: 1692 * all_parallel True if all targets default to parallel 1693 * only_parallel True if no targets default to parallel 1694 */ 1695 Boolean 1696 parallel_ok(Name target, Boolean line_prop_must_exists) 1697 { 1698 Boolean assign; 1699 Boolean make_refd; 1700 Property line; 1701 Cmd_line rule; 1702 1703 assign = make_refd = false; 1704 if (((line = get_prop(target->prop, line_prop)) == NULL) && 1705 line_prop_must_exists) { 1706 return false; 1707 } 1708 if (line != NULL) { 1709 for (rule = line->body.line.command_used; 1710 rule != NULL; 1711 rule = rule->next) { 1712 if (rule->assign) { 1713 assign = true; 1714 } else if (rule->make_refd) { 1715 make_refd = true; 1716 } 1717 } 1718 } 1719 if (assign) { 1720 return false; 1721 } else if (target->parallel) { 1722 return true; 1723 } else if (target->no_parallel) { 1724 return false; 1725 } else if (all_parallel) { 1726 return true; 1727 } else if (only_parallel) { 1728 return false; 1729 } else if (make_refd) { 1730 return false; 1731 } else { 1732 return true; 1733 } 1734 } 1735 1736 /* 1737 * is_running(target) 1738 * 1739 * Returns true if the target is running. 1740 * 1741 * Return value: 1742 * True if target is running 1743 * 1744 * Parameters: 1745 * target Target to check 1746 * 1747 * Global variables used: 1748 * running_list List of running processes 1749 */ 1750 Boolean 1751 is_running(Name target) 1752 { 1753 Running rp; 1754 1755 if (target->state != build_running) { 1756 return false; 1757 } 1758 for (rp = running_list; 1759 rp != NULL && target != rp->target; 1760 rp = rp->next); 1761 if (rp == NULL) { 1762 return false; 1763 } else { 1764 return (rp->state == build_running) ? true : false; 1765 } 1766 } 1767 1768 /* 1769 * This function replaces the makesh binary. 1770 */ 1771 1772 1773 static pid_t 1774 run_rule_commands(char *host, char **commands) 1775 { 1776 Boolean always_exec; 1777 Name command; 1778 Boolean ignore; 1779 int length; 1780 Doname result; 1781 Boolean silent_flag; 1782 wchar_t *tmp_wcs_buffer; 1783 1784 childPid = fork(); 1785 switch (childPid) { 1786 case -1: /* Error */ 1787 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"), 1788 errmsg(errno)); 1789 break; 1790 case 0: /* Child */ 1791 /* To control the processed targets list is not the child's business */ 1792 running_list = NULL; 1793 if(out_err_same) { 1794 redirect_io(stdout_file, (char*)NULL); 1795 } else { 1796 redirect_io(stdout_file, stderr_file); 1797 } 1798 for (commands = commands; 1799 (*commands != (char *)NULL); 1800 commands++) { 1801 silent_flag = silent; 1802 ignore = false; 1803 always_exec = false; 1804 while ((**commands == (int) at_char) || 1805 (**commands == (int) hyphen_char) || 1806 (**commands == (int) plus_char)) { 1807 if (**commands == (int) at_char) { 1808 silent_flag = true; 1809 } 1810 if (**commands == (int) hyphen_char) { 1811 ignore = true; 1812 } 1813 if (**commands == (int) plus_char) { 1814 always_exec = true; 1815 } 1816 (*commands)++; 1817 } 1818 if ((length = strlen(*commands)) >= MAXPATHLEN) { 1819 tmp_wcs_buffer = ALLOC_WC(length + 1); 1820 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1); 1821 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH); 1822 retmem(tmp_wcs_buffer); 1823 } else { 1824 MBSTOWCS(wcs_buffer, *commands); 1825 command = GETNAME(wcs_buffer, FIND_LENGTH); 1826 } 1827 if ((command->hash.length > 0) && 1828 !silent_flag) { 1829 (void) printf("%s\n", command->string_mb); 1830 } 1831 result = dosys(command, 1832 ignore, 1833 false, 1834 false, /* bugs #4085164 & #4990057 */ 1835 /* BOOLEAN(silent_flag && ignore), */ 1836 always_exec, 1837 (Name) NULL); 1838 if (result == build_failed) { 1839 if (silent_flag) { 1840 (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb); 1841 } 1842 if (!ignore) { 1843 _exit(1); 1844 } 1845 } 1846 } 1847 _exit(0); 1848 break; 1849 default: 1850 break; 1851 } 1852 return childPid; 1853 } 1854 1855 static void 1856 maybe_reread_make_state(void) 1857 { 1858 /* Copying dosys()... */ 1859 if (report_dependencies_level == 0) { 1860 make_state->stat.time = file_no_time; 1861 (void) exists(make_state); 1862 if (make_state_before == make_state->stat.time) { 1863 return; 1864 } 1865 makefile_type = reading_statefile; 1866 if (read_trace_level > 1) { 1867 trace_reader = true; 1868 } 1869 temp_file_number++; 1870 (void) read_simple_file(make_state, 1871 false, 1872 false, 1873 false, 1874 false, 1875 false, 1876 true); 1877 trace_reader = false; 1878 } 1879 } 1880 1881 1882 static void 1883 delete_running_struct(Running rp) 1884 { 1885 if ((rp->conditional_cnt > 0) && 1886 (rp->conditional_targets != NULL)) { 1887 retmem_mb((char *) rp->conditional_targets); 1888 } 1889 /**/ 1890 if ((rp->auto_count > 0) && 1891 (rp->automatics != NULL)) { 1892 retmem_mb((char *) rp->automatics); 1893 } 1894 /**/ 1895 if(rp->sprodep_value) { 1896 free_name(rp->sprodep_value); 1897 } 1898 if(rp->sprodep_env) { 1899 retmem_mb(rp->sprodep_env); 1900 } 1901 retmem_mb((char *) rp); 1902 1903 } 1904 1905