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