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