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 * @(#)parallel.cc 1.75 06/12/12 27 */ 28 29 #pragma ident "@(#)parallel.cc 1.75 06/12/12" 30 31 #ifdef TEAMWARE_MAKE_CMN 32 33 /* 34 * parallel.cc 35 * 36 * Deal with the parallel processing 37 */ 38 39 /* 40 * Included files 41 */ 42 #ifdef DISTRIBUTED 43 #include <avo/strings.h> /* AVO_STRDUP() */ 44 #include <dm/Avo_DoJobMsg.h> 45 #include <dm/Avo_MToolJobResultMsg.h> 46 #endif 47 #include <errno.h> /* errno */ 48 #include <fcntl.h> 49 #include <avo/util.h> /* avo_get_user(), avo_hostname() */ 50 #include <mk/defs.h> 51 #include <mksh/dosys.h> /* redirect_io() */ 52 #include <mksh/macro.h> /* expand_value() */ 53 #include <mksh/misc.h> /* getmem() */ 54 #include <sys/signal.h> 55 #include <sys/stat.h> 56 #include <sys/types.h> 57 #include <sys/utsname.h> 58 #include <sys/wait.h> 59 #include <unistd.h> 60 61 #ifdef SGE_SUPPORT 62 #include <dmthread/Avo_PathNames.h> 63 #endif 64 65 66 /* 67 * Defined macros 68 */ 69 #define MAXRULES 100 70 71 /* 72 * This const should be in avo_dms/include/AvoDmakeCommand.h 73 */ 74 const int local_host_mask = 0x20; 75 76 77 /* 78 * typedefs & structs 79 */ 80 81 82 /* 83 * Static variables 84 */ 85 #ifdef TEAMWARE_MAKE_CMN 86 static Boolean just_did_subtree = false; 87 static char local_host[MAXNAMELEN] = ""; 88 static char user_name[MAXNAMELEN] = ""; 89 #endif 90 static int pmake_max_jobs = 0; 91 static pid_t process_running = -1; 92 static Running *running_tail = &running_list; 93 static Name subtree_conflict; 94 static Name subtree_conflict2; 95 96 97 /* 98 * File table of contents 99 */ 100 #ifdef DISTRIBUTED 101 static void append_dmake_cmd(Avo_DoJobMsg *dmake_job_msg, char *orig_cmd_line, int cmd_options); 102 static void append_job_result_msg(Avo_MToolJobResultMsg *msg, char *outFn, char *errFn); 103 static void send_job_result_msg(Running rp); 104 #endif 105 static void delete_running_struct(Running rp); 106 static Boolean dependency_conflict(Name target); 107 static Doname distribute_process(char **commands, Property line); 108 static void doname_subtree(Name target, Boolean do_get, Boolean implicit); 109 static void dump_out_file(char *filename, Boolean err); 110 static void finish_doname(Running rp); 111 static void maybe_reread_make_state(void); 112 static void process_next(void); 113 static void reset_conditionals(int cnt, Name *targets, Property *locals); 114 static pid_t run_rule_commands(char *host, char **commands); 115 static Property *set_conditionals(int cnt, Name *targets); 116 static void store_conditionals(Running rp); 117 118 119 /* 120 * execute_parallel(line, waitflg) 121 * 122 * DMake 2.x: 123 * parallel mode: spawns a parallel process to execute the command group. 124 * distributed mode: sends the command group down the pipe to rxm. 125 * 126 * Return value: 127 * The result of the execution 128 * 129 * Parameters: 130 * line The command group to execute 131 */ 132 Doname 133 execute_parallel(Property line, Boolean waitflg, Boolean local) 134 { 135 int argcnt; 136 int cmd_options = 0; 137 char *commands[MAXRULES + 5]; 138 char *cp; 139 #ifdef DISTRIBUTED 140 Avo_DoJobMsg *dmake_job_msg = NULL; 141 #endif 142 Name dmake_name; 143 Name dmake_value; 144 int ignore; 145 Name make_machines_name; 146 char **p; 147 Property prop; 148 Doname result = build_ok; 149 Cmd_line rule; 150 Boolean silent_flag; 151 Name target = line->body.line.target; 152 Boolean wrote_state_file = false; 153 154 if ((pmake_max_jobs == 0) && 155 (dmake_mode_type == parallel_mode)) { 156 if (user_name[0] == '\0') { 157 avo_get_user(user_name, NULL); 158 } 159 if (local_host[0] == '\0') { 160 strcpy(local_host, avo_hostname()); 161 } 162 MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MAX_JOBS")); 163 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); 164 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && 165 ((dmake_value = prop->body.macro.value) != NULL)) { 166 pmake_max_jobs = atoi(dmake_value->string_mb); 167 if (pmake_max_jobs <= 0) { 168 warning(catgets(catd, 1, 308, "DMAKE_MAX_JOBS cannot be less than or equal to zero.")); 169 warning(catgets(catd, 1, 309, "setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS); 170 pmake_max_jobs = PMAKE_DEF_MAX_JOBS; 171 } 172 } else { 173 /* 174 * For backwards compatibility w/ PMake 1.x, when 175 * DMake 2.x is being run in parallel mode, DMake 176 * should parse the PMake startup file 177 * $(HOME)/.make.machines to get the pmake_max_jobs. 178 */ 179 MBSTOWCS(wcs_buffer, NOCATGETS("PMAKE_MACHINESFILE")); 180 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); 181 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && 182 ((dmake_value = prop->body.macro.value) != NULL)) { 183 make_machines_name = dmake_value; 184 } else { 185 make_machines_name = NULL; 186 } 187 if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) { 188 pmake_max_jobs = PMAKE_DEF_MAX_JOBS; 189 } 190 } 191 #ifdef DISTRIBUTED 192 if (send_mtool_msgs) { 193 send_rsrc_info_msg(pmake_max_jobs, local_host, user_name); 194 } 195 #endif 196 } 197 198 if ((dmake_mode_type == serial_mode) || 199 ((dmake_mode_type == parallel_mode) && (waitflg))) { 200 return (execute_serial(line)); 201 } 202 203 #ifdef DISTRIBUTED 204 if (dmake_mode_type == distributed_mode) { 205 if(local) { 206 // return (execute_serial(line)); 207 waitflg = true; 208 } 209 dmake_job_msg = new Avo_DoJobMsg(); 210 dmake_job_msg->setJobId(++job_msg_id); 211 dmake_job_msg->setTarget(target->string_mb); 212 dmake_job_msg->setImmediateOutput(0); 213 called_make = false; 214 } else 215 #endif 216 { 217 p = commands; 218 } 219 220 argcnt = 0; 221 for (rule = line->body.line.command_used; 222 rule != NULL; 223 rule = rule->next) { 224 if (posix && (touch || quest) && !rule->always_exec) { 225 continue; 226 } 227 if (vpath_defined) { 228 rule->command_line = 229 vpath_translation(rule->command_line); 230 } 231 if (dmake_mode_type == distributed_mode) { 232 cmd_options = 0; 233 if(local) { 234 cmd_options |= local_host_mask; 235 } 236 } else { 237 silent_flag = false; 238 ignore = 0; 239 } 240 if (rule->command_line->hash.length > 0) { 241 if (++argcnt == MAXRULES) { 242 if (dmake_mode_type == distributed_mode) { 243 /* XXX - tell rxm to execute on local host. */ 244 /* I WAS HERE!!! */ 245 } else { 246 /* Too many rules, run serially instead. */ 247 return build_serial; 248 } 249 } 250 #ifdef DISTRIBUTED 251 if (dmake_mode_type == distributed_mode) { 252 /* 253 * XXX - set assign_mask to tell rxm 254 * to do the following. 255 */ 256 /* From execute_serial(): 257 if (rule->assign) { 258 result = build_ok; 259 do_assign(rule->command_line, target); 260 */ 261 if (0) { 262 } else if (report_dependencies_level == 0) { 263 if (rule->ignore_error) { 264 cmd_options |= ignore_mask; 265 } 266 if (rule->silent) { 267 cmd_options |= silent_mask; 268 } 269 if (rule->command_line->meta) { 270 cmd_options |= meta_mask; 271 } 272 if (rule->make_refd) { 273 cmd_options |= make_refd_mask; 274 } 275 if (do_not_exec_rule) { 276 cmd_options |= do_not_exec_mask; 277 } 278 append_dmake_cmd(dmake_job_msg, 279 rule->command_line->string_mb, 280 cmd_options); 281 /* Copying dosys()... */ 282 if (rule->make_refd) { 283 if (waitflg) { 284 dmake_job_msg->setImmediateOutput(1); 285 } 286 called_make = true; 287 if (command_changed && 288 !wrote_state_file) { 289 write_state_file(0, false); 290 wrote_state_file = true; 291 } 292 } 293 } 294 } else 295 #endif 296 { 297 if (rule->silent && !silent) { 298 silent_flag = true; 299 } 300 if (rule->ignore_error) { 301 ignore++; 302 } 303 /* XXX - need to add support for + prefix */ 304 if (silent_flag || ignore) { 305 *p = getmem((silent_flag ? 1 : 0) + 306 ignore + 307 (strlen(rule-> 308 command_line-> 309 string_mb)) + 310 1); 311 cp = *p++; 312 if (silent_flag) { 313 *cp++ = (int) at_char; 314 } 315 if (ignore) { 316 *cp++ = (int) hyphen_char; 317 } 318 (void) strcpy(cp, rule->command_line->string_mb); 319 } else { 320 *p++ = rule->command_line->string_mb; 321 } 322 } 323 } 324 } 325 if ((argcnt == 0) || 326 (report_dependencies_level > 0)) { 327 #ifdef DISTRIBUTED 328 if (dmake_job_msg) { 329 delete dmake_job_msg; 330 } 331 #endif 332 return build_ok; 333 } 334 #ifdef DISTRIBUTED 335 if (dmake_mode_type == distributed_mode) { 336 // Send a DoJob message to the rxm process. 337 distribute_rxm(dmake_job_msg); 338 339 // Wait for an acknowledgement. 340 Avo_AcknowledgeMsg *ackMsg = getAcknowledgeMsg(); 341 if (ackMsg) { 342 delete ackMsg; 343 } 344 345 if (waitflg) { 346 // Wait for, and process a job result. 347 result = await_dist(waitflg); 348 if (called_make) { 349 maybe_reread_make_state(); 350 } 351 check_state(temp_file_name); 352 if (result == build_failed) { 353 if (!continue_after_error) { 354 355 #ifdef PRINT_EXIT_STATUS 356 warning(NOCATGETS("I'm in execute_parallel. await_dist() returned build_failed")); 357 #endif 358 359 fatal(catgets(catd, 1, 252, "Command failed for target `%s'"), 360 target->string_mb); 361 } 362 /* 363 * Make sure a failing command is not 364 * saved in .make.state. 365 */ 366 line->body.line.command_used = NULL; 367 } 368 if (temp_file_name != NULL) { 369 free_name(temp_file_name); 370 } 371 temp_file_name = NULL; 372 Property spro = get_prop(sunpro_dependencies->prop, macro_prop); 373 if(spro != NULL) { 374 Name val = spro->body.macro.value; 375 if(val != NULL) { 376 free_name(val); 377 spro->body.macro.value = NULL; 378 } 379 } 380 spro = get_prop(sunpro_dependencies->prop, env_mem_prop); 381 if(spro) { 382 char *val = spro->body.env_mem.value; 383 if(val != NULL) { 384 retmem_mb(val); 385 spro->body.env_mem.value = NULL; 386 } 387 } 388 return result; 389 } else { 390 parallel_process_cnt++; 391 return build_running; 392 } 393 } else 394 #endif 395 { 396 *p = NULL; 397 398 Doname res = distribute_process(commands, line); 399 if (res == build_running) { 400 parallel_process_cnt++; 401 } 402 403 /* 404 * Return only those memory that were specially allocated 405 * for part of commands. 406 */ 407 for (int i = 0; commands[i] != NULL; i++) { 408 if ((commands[i][0] == (int) at_char) || 409 (commands[i][0] == (int) hyphen_char)) { 410 retmem_mb(commands[i]); 411 } 412 } 413 return res; 414 } 415 } 416 417 #ifdef DISTRIBUTED 418 /* 419 * append_dmake_cmd() 420 * 421 * Replaces all escaped newline's (\<cr>) 422 * in the original command line with space's, 423 * then append the new command line to the DoJobMsg object. 424 */ 425 static void 426 append_dmake_cmd(Avo_DoJobMsg *dmake_job_msg, 427 char *orig_cmd_line, 428 int cmd_options) 429 { 430 /* 431 Avo_DmakeCommand *tmp_dmake_command; 432 433 tmp_dmake_command = new Avo_DmakeCommand(orig_cmd_line, cmd_options); 434 dmake_job_msg->appendCmd(tmp_dmake_command); 435 delete tmp_dmake_command; 436 */ 437 dmake_job_msg->appendCmd(new Avo_DmakeCommand(orig_cmd_line, cmd_options)); 438 } 439 #endif 440 441 #ifdef TEAMWARE_MAKE_CMN 442 #define MAXJOBS_ADJUST_RFE4694000 443 444 #ifdef MAXJOBS_ADJUST_RFE4694000 445 446 #include <unistd.h> /* sysconf(_SC_NPROCESSORS_ONLN) */ 447 #include <sys/ipc.h> /* ftok() */ 448 #include <sys/shm.h> /* shmget(), shmat(), shmdt(), shmctl() */ 449 #include <semaphore.h> /* sem_init(), sem_trywait(), sem_post(), sem_destroy() */ 450 #if defined(linux) 451 #define LOADAVG_1MIN 0 452 #else 453 #include <sys/loadavg.h> /* getloadavg() */ 454 #endif /* linux */ 455 456 /* 457 * adjust_pmake_max_jobs (int pmake_max_jobs) 458 * 459 * Parameters: 460 * pmake_max_jobs - max jobs limit set by user 461 * 462 * External functions used: 463 * sysconf() 464 * getloadavg() 465 */ 466 static int 467 adjust_pmake_max_jobs (int pmake_max_jobs) 468 { 469 static int ncpu = 0; 470 double loadavg[3]; 471 int adjustment; 472 int adjusted_max_jobs; 473 474 if (ncpu <= 0) { 475 if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) { 476 ncpu = 1; 477 } 478 } 479 if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs); 480 adjustment = ((int)loadavg[LOADAVG_1MIN]); 481 if (adjustment < 2) return(pmake_max_jobs); 482 if (ncpu > 1) { 483 adjustment = adjustment / ncpu; 484 } 485 adjusted_max_jobs = pmake_max_jobs - adjustment; 486 if (adjusted_max_jobs < 1) adjusted_max_jobs = 1; 487 return(adjusted_max_jobs); 488 } 489 490 /* 491 * M2 adjust mode data and functions 492 * 493 * m2_init() - initializes M2 shared semaphore 494 * m2_acquire_job() - decrements M2 semaphore counter 495 * m2_release_job() - increments M2 semaphore counter 496 * m2_fini() - destroys M2 semaphore and shared memory* 497 * 498 * Environment variables: 499 * __DMAKE_M2_FILE__ 500 * 501 * External functions: 502 * ftok(), shmget(), shmat(), shmdt(), shmctl() 503 * sem_init(), sem_trywait(), sem_post(), sem_destroy() 504 * creat(), close(), unlink() 505 * getenv(), putenv() 506 * 507 * Static variables: 508 * m2_file - tmp file name to create ipc key for shared memory 509 * m2_shm_id - shared memory id 510 * m2_shm_sem - shared memory semaphore 511 */ 512 513 static char m2_file[MAXPATHLEN]; 514 static int m2_shm_id = -1; 515 static sem_t* m2_shm_sem = 0; 516 517 static int 518 m2_init() { 519 char *var; 520 key_t key; 521 522 if ((var = getenv(NOCATGETS("__DMAKE_M2_FILE__"))) == 0) { 523 /* compose tmp file name */ 524 sprintf(m2_file, NOCATGETS("%s/dmake.m2.%d.XXXXXX"), tmpdir, getpid()); 525 526 /* create tmp file */ 527 int fd = mkstemp(m2_file); 528 if (fd < 0) { 529 return -1; 530 } else { 531 close(fd); 532 } 533 } else { 534 /* using existing semaphore */ 535 strcpy(m2_file, var); 536 } 537 538 /* combine IPC key */ 539 if ((key = ftok(m2_file, 38)) == (key_t) -1) { 540 return -1; 541 } 542 543 /* create shared memory */ 544 if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) { 545 return -1; 546 } 547 548 /* attach shared memory */ 549 if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) { 550 return -1; 551 } 552 553 /* root process */ 554 if (var == 0) { 555 /* initialize semaphore */ 556 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) { 557 return -1; 558 } 559 560 /* alloc memory for env variable */ 561 if ((var = (char*) malloc(MAXPATHLEN)) == 0) { 562 return -1; 563 } 564 565 /* put key to env */ 566 sprintf(var, NOCATGETS("__DMAKE_M2_FILE__=%s"), m2_file); 567 if (putenv(var)) { 568 return -1; 569 } 570 } 571 return 0; 572 } 573 574 static void 575 m2_fini() { 576 if (m2_shm_id >= 0) { 577 struct shmid_ds stat; 578 579 /* determine the number of attached processes */ 580 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) { 581 if (stat.shm_nattch <= 1) { 582 /* destroy semaphore */ 583 if (m2_shm_sem != 0) { 584 (void) sem_destroy(m2_shm_sem); 585 } 586 587 /* destroy shared memory */ 588 (void) shmctl(m2_shm_id, IPC_RMID, &stat); 589 590 /* remove tmp file created for the key */ 591 (void) unlink(m2_file); 592 } else { 593 /* detach shared memory */ 594 if (m2_shm_sem != 0) { 595 (void) shmdt((char*) m2_shm_sem); 596 } 597 } 598 } 599 600 m2_shm_id = -1; 601 m2_shm_sem = 0; 602 } 603 } 604 605 static int 606 m2_acquire_job() { 607 if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) { 608 if (sem_trywait(m2_shm_sem) == 0) { 609 return 1; 610 } 611 if (errno == EAGAIN) { 612 return 0; 613 } 614 } 615 return -1; 616 } 617 618 static int 619 m2_release_job() { 620 if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) { 621 if (sem_post(m2_shm_sem) == 0) { 622 return 0; 623 } 624 } 625 return -1; 626 } 627 628 /* 629 * job adjust mode 630 * 631 * Possible values: 632 * ADJUST_M1 - adjustment by system load (default) 633 * ADJUST_M2 - fixed limit of jobs for the group of nested dmakes 634 * ADJUST_NONE - no adjustment - fixed limit of jobs for the current dmake 635 */ 636 static enum { 637 ADJUST_UNKNOWN, 638 ADJUST_M1, 639 ADJUST_M2, 640 ADJUST_NONE 641 } job_adjust_mode = ADJUST_UNKNOWN; 642 643 /* 644 * void job_adjust_fini() 645 * 646 * Description: 647 * Cleans up job adjust data. 648 * 649 * Static variables: 650 * job_adjust_mode Current job adjust mode 651 */ 652 void 653 job_adjust_fini() { 654 if (job_adjust_mode == ADJUST_M2) { 655 m2_fini(); 656 } 657 } 658 659 /* 660 * void job_adjust_error() 661 * 662 * Description: 663 * Prints warning message, cleans up job adjust data, and disables job adjustment 664 * 665 * Environment: 666 * DMAKE_ADJUST_MAX_JOBS 667 * 668 * External functions: 669 * putenv() 670 * 671 * Static variables: 672 * job_adjust_mode Current job adjust mode 673 */ 674 static void 675 job_adjust_error() { 676 if (job_adjust_mode != ADJUST_NONE) { 677 /* cleanup internals */ 678 job_adjust_fini(); 679 680 /* warning message for the user */ 681 warning(catgets(catd, 1, 339, "Encountered max jobs auto adjustment error - disabling auto adjustment.")); 682 683 /* switch off job adjustment for the children */ 684 putenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS=NO")); 685 686 /* and for this dmake */ 687 job_adjust_mode = ADJUST_NONE; 688 } 689 } 690 691 /* 692 * void job_adjust_init() 693 * 694 * Description: 695 * Parses DMAKE_ADJUST_MAX_JOBS env variable 696 * and performs appropriate initializations. 697 * 698 * Environment: 699 * DMAKE_ADJUST_MAX_JOBS 700 * DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment 701 * DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode 702 * other - M1 adjust mode 703 * 704 * External functions: 705 * getenv() 706 * 707 * Static variables: 708 * job_adjust_mode Current job adjust mode 709 */ 710 static void 711 job_adjust_init() { 712 if (job_adjust_mode == ADJUST_UNKNOWN) { 713 /* default mode */ 714 job_adjust_mode = ADJUST_M1; 715 716 /* determine adjust mode */ 717 if (char *var = getenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS"))) { 718 if (strcasecmp(var, NOCATGETS("NO")) == 0) { 719 job_adjust_mode = ADJUST_NONE; 720 } else if (strcasecmp(var, NOCATGETS("M2")) == 0) { 721 job_adjust_mode = ADJUST_M2; 722 } 723 } 724 725 /* M2 specific initialization */ 726 if (job_adjust_mode == ADJUST_M2) { 727 if (m2_init()) { 728 job_adjust_error(); 729 } 730 } 731 } 732 } 733 734 #endif /* MAXJOBS_ADJUST_RFE4694000 */ 735 #endif /* TEAMWARE_MAKE_CMN */ 736 737 /* 738 * distribute_process(char **commands, Property line) 739 * 740 * Parameters: 741 * commands argv vector of commands to execute 742 * 743 * Return value: 744 * The result of the execution 745 * 746 * Static variables used: 747 * process_running Set to the pid of the process set running 748 * #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000) 749 * job_adjust_mode Current job adjust mode 750 * #endif 751 */ 752 static Doname 753 distribute_process(char **commands, Property line) 754 { 755 static unsigned file_number = 0; 756 wchar_t string[MAXPATHLEN]; 757 char mbstring[MAXPATHLEN]; 758 int filed; 759 int res; 760 int tmp_index; 761 char *tmp_index_str_ptr; 762 763 #if !defined (TEAMWARE_MAKE_CMN) || !defined (MAXJOBS_ADJUST_RFE4694000) 764 while (parallel_process_cnt >= pmake_max_jobs) { 765 await_parallel(false); 766 finish_children(true); 767 } 768 #else /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */ 769 /* initialize adjust mode, if not initialized */ 770 if (job_adjust_mode == ADJUST_UNKNOWN) { 771 job_adjust_init(); 772 } 773 774 /* actions depend on adjust mode */ 775 switch (job_adjust_mode) { 776 case ADJUST_M1: 777 while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) { 778 await_parallel(false); 779 finish_children(true); 780 } 781 break; 782 case ADJUST_M2: 783 if ((res = m2_acquire_job()) == 0) { 784 if (parallel_process_cnt > 0) { 785 await_parallel(false); 786 finish_children(true); 787 788 if ((res = m2_acquire_job()) == 0) { 789 return build_serial; 790 } 791 } else { 792 return build_serial; 793 } 794 } 795 if (res < 0) { 796 /* job adjustment error */ 797 job_adjust_error(); 798 799 /* no adjustment */ 800 while (parallel_process_cnt >= pmake_max_jobs) { 801 await_parallel(false); 802 finish_children(true); 803 } 804 } 805 break; 806 default: 807 while (parallel_process_cnt >= pmake_max_jobs) { 808 await_parallel(false); 809 finish_children(true); 810 } 811 } 812 #endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */ 813 #ifdef DISTRIBUTED 814 if (send_mtool_msgs) { 815 send_job_start_msg(line); 816 } 817 #endif 818 #ifdef DISTRIBUTED 819 setvar_envvar((Avo_DoJobMsg *)NULL); 820 #else 821 setvar_envvar(); 822 #endif 823 /* 824 * Tell the user what DMake is doing. 825 */ 826 if (!silent && output_mode != txt2_mode) { 827 /* 828 * Print local_host --> x job(s). 829 */ 830 (void) fprintf(stdout, 831 catgets(catd, 1, 325, "%s --> %d %s\n"), 832 local_host, 833 parallel_process_cnt + 1, 834 (parallel_process_cnt == 0) ? catgets(catd, 1, 124, "job") : catgets(catd, 1, 125, "jobs")); 835 836 /* Print command line(s). */ 837 tmp_index = 0; 838 while (commands[tmp_index] != NULL) { 839 /* No @ char. */ 840 /* XXX - need to add [2] when + prefix is added */ 841 if ((commands[tmp_index][0] != (int) at_char) && 842 (commands[tmp_index][1] != (int) at_char)) { 843 tmp_index_str_ptr = commands[tmp_index]; 844 if (*tmp_index_str_ptr == (int) hyphen_char) { 845 tmp_index_str_ptr++; 846 } 847 (void) fprintf(stdout, "%s\n", tmp_index_str_ptr); 848 } 849 tmp_index++; 850 } 851 (void) fflush(stdout); 852 } 853 854 (void) sprintf(mbstring, 855 NOCATGETS("%s/dmake.stdout.%d.%d.XXXXXX"), 856 tmpdir, 857 getpid(), 858 file_number++); 859 860 mktemp(mbstring); 861 862 stdout_file = strdup(mbstring); 863 stderr_file = NULL; 864 #if defined (TEAMWARE_MAKE_CMN) && defined(REDIRECT_ERR) 865 if (!out_err_same) { 866 (void) sprintf(mbstring, 867 NOCATGETS("%s/dmake.stderr.%d.%d.XXXXXX"), 868 tmpdir, 869 getpid(), 870 file_number++); 871 872 mktemp(mbstring); 873 874 stderr_file = strdup(mbstring); 875 } 876 #endif 877 878 #ifdef SGE_SUPPORT 879 if (grid) { 880 static char *dir4gridscripts = NULL; 881 static char *hostName = NULL; 882 if (dir4gridscripts == NULL) { 883 Name dmakeOdir_name, dmakeOdir_value; 884 Property prop; 885 MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_ODIR")); 886 dmakeOdir_name = GETNAME(wcs_buffer, FIND_LENGTH); 887 if (((prop = get_prop(dmakeOdir_name->prop, macro_prop)) != NULL) && 888 ((dmakeOdir_value = prop->body.macro.value) != NULL)) { 889 dir4gridscripts = dmakeOdir_value->string_mb; 890 } 891 dir4gridscripts = Avo_PathNames::pathname_output_directory(dir4gridscripts); 892 hostName = Avo_PathNames::pathname_local_host(); 893 } 894 (void) sprintf(script_file, 895 NOCATGETS("%s/dmake.script.%s.%d.%d.XXXXXX"), 896 dir4gridscripts, 897 hostName, 898 getpid(), 899 file_number++); 900 } 901 #endif /* SGE_SUPPORT */ 902 process_running = run_rule_commands(local_host, commands); 903 904 return build_running; 905 } 906 907 /* 908 * doname_parallel(target, do_get, implicit) 909 * 910 * Processes the given target and finishes up any parallel 911 * processes left running. 912 * 913 * Return value: 914 * Result of target build 915 * 916 * Parameters: 917 * target Target to build 918 * do_get True if sccs get to be done 919 * implicit True if this is an implicit target 920 */ 921 Doname 922 doname_parallel(Name target, Boolean do_get, Boolean implicit) 923 { 924 Doname result; 925 926 result = doname_check(target, do_get, implicit, false); 927 if (result == build_ok || result == build_failed) { 928 return result; 929 } 930 finish_running(); 931 return (Doname) target->state; 932 } 933 934 /* 935 * doname_subtree(target, do_get, implicit) 936 * 937 * Completely computes an object and its dependents for a 938 * serial subtree build. 939 * 940 * Parameters: 941 * target Target to build 942 * do_get True if sccs get to be done 943 * implicit True if this is an implicit target 944 * 945 * Static variables used: 946 * running_tail Tail of the list of running processes 947 * 948 * Global variables used: 949 * running_list The list of running processes 950 */ 951 static void 952 doname_subtree(Name target, Boolean do_get, Boolean implicit) 953 { 954 Running save_running_list; 955 Running *save_running_tail; 956 957 save_running_list = running_list; 958 save_running_tail = running_tail; 959 running_list = NULL; 960 running_tail = &running_list; 961 target->state = build_subtree; 962 target->checking_subtree = true; 963 while(doname_check(target, do_get, implicit, false) == build_running) { 964 target->checking_subtree = false; 965 finish_running(); 966 target->state = build_subtree; 967 } 968 target->checking_subtree = false; 969 running_list = save_running_list; 970 running_tail = save_running_tail; 971 } 972 973 /* 974 * finish_running() 975 * 976 * Keeps processing until the running_list is emptied out. 977 * 978 * Parameters: 979 * 980 * Global variables used: 981 * running_list The list of running processes 982 */ 983 void 984 finish_running(void) 985 { 986 while (running_list != NULL) { 987 #ifdef DISTRIBUTED 988 if (dmake_mode_type == distributed_mode) { 989 if ((just_did_subtree) || 990 (parallel_process_cnt == 0)) { 991 just_did_subtree = false; 992 } else { 993 (void) await_dist(false); 994 finish_children(true); 995 } 996 } else 997 #endif 998 { 999 await_parallel(false); 1000 finish_children(true); 1001 } 1002 if (running_list != NULL) { 1003 process_next(); 1004 } 1005 } 1006 } 1007 1008 /* 1009 * process_next() 1010 * 1011 * Searches the running list for any targets which can start processing. 1012 * This can be a pending target, a serial target, or a subtree target. 1013 * 1014 * Parameters: 1015 * 1016 * Static variables used: 1017 * running_tail The end of the list of running procs 1018 * subtree_conflict A target which conflicts with a subtree 1019 * subtree_conflict2 The other target which conflicts 1020 * 1021 * Global variables used: 1022 * commands_done True if commands executed 1023 * debug_level Controls debug output 1024 * parallel_process_cnt Number of parallel process running 1025 * recursion_level Indentation for debug output 1026 * running_list List of running processes 1027 */ 1028 static void 1029 process_next(void) 1030 { 1031 Running rp; 1032 Running *rp_prev; 1033 Property line; 1034 Chain target_group; 1035 Dependency dep; 1036 Boolean quiescent = true; 1037 Running *subtree_target; 1038 Boolean saved_commands_done; 1039 Property *conditionals; 1040 1041 subtree_target = NULL; 1042 subtree_conflict = NULL; 1043 subtree_conflict2 = NULL; 1044 /* 1045 * If nothing currently running, build a serial target, if any. 1046 */ 1047 start_loop_1: 1048 for (rp_prev = &running_list, rp = running_list; 1049 rp != NULL && parallel_process_cnt == 0; 1050 rp = rp->next) { 1051 if (rp->state == build_serial) { 1052 *rp_prev = rp->next; 1053 if (rp->next == NULL) { 1054 running_tail = rp_prev; 1055 } 1056 recursion_level = rp->recursion_level; 1057 rp->target->state = build_pending; 1058 (void) doname_check(rp->target, 1059 rp->do_get, 1060 rp->implicit, 1061 false); 1062 quiescent = false; 1063 delete_running_struct(rp); 1064 goto start_loop_1; 1065 } else { 1066 rp_prev = &rp->next; 1067 } 1068 } 1069 /* 1070 * Find a target to build. The target must be pending, have all 1071 * its dependencies built, and not be in a target group with a target 1072 * currently building. 1073 */ 1074 start_loop_2: 1075 for (rp_prev = &running_list, rp = running_list; 1076 rp != NULL; 1077 rp = rp->next) { 1078 if (!(rp->state == build_pending || 1079 rp->state == build_subtree)) { 1080 quiescent = false; 1081 rp_prev = &rp->next; 1082 } else if (rp->state == build_pending) { 1083 line = get_prop(rp->target->prop, line_prop); 1084 for (dep = line->body.line.dependencies; 1085 dep != NULL; 1086 dep = dep->next) { 1087 if (dep->name->state == build_running || 1088 dep->name->state == build_pending || 1089 dep->name->state == build_serial) { 1090 break; 1091 } 1092 } 1093 if (dep == NULL) { 1094 for (target_group = line->body.line.target_group; 1095 target_group != NULL; 1096 target_group = target_group->next) { 1097 if (is_running(target_group->name)) { 1098 break; 1099 } 1100 } 1101 if (target_group == NULL) { 1102 *rp_prev = rp->next; 1103 if (rp->next == NULL) { 1104 running_tail = rp_prev; 1105 } 1106 recursion_level = rp->recursion_level; 1107 rp->target->state = rp->redo ? 1108 build_dont_know : build_pending; 1109 saved_commands_done = commands_done; 1110 conditionals = 1111 set_conditionals 1112 (rp->conditional_cnt, 1113 rp->conditional_targets); 1114 rp->target->dont_activate_cond_values = true; 1115 if ((doname_check(rp->target, 1116 rp->do_get, 1117 rp->implicit, 1118 rp->target->has_target_prop ? true : false) != 1119 build_running) && 1120 !commands_done) { 1121 commands_done = 1122 saved_commands_done; 1123 } 1124 rp->target->dont_activate_cond_values = false; 1125 reset_conditionals 1126 (rp->conditional_cnt, 1127 rp->conditional_targets, 1128 conditionals); 1129 quiescent = false; 1130 delete_running_struct(rp); 1131 goto start_loop_2; 1132 } else { 1133 rp_prev = &rp->next; 1134 } 1135 } else { 1136 rp_prev = &rp->next; 1137 } 1138 } else { 1139 rp_prev = &rp->next; 1140 } 1141 } 1142 /* 1143 * If nothing has been found to build and there exists a subtree 1144 * target with no dependency conflicts, build it. 1145 */ 1146 if (quiescent) { 1147 start_loop_3: 1148 for (rp_prev = &running_list, rp = running_list; 1149 rp != NULL; 1150 rp = rp->next) { 1151 if (rp->state == build_subtree) { 1152 if (!dependency_conflict(rp->target)) { 1153 *rp_prev = rp->next; 1154 if (rp->next == NULL) { 1155 running_tail = rp_prev; 1156 } 1157 recursion_level = rp->recursion_level; 1158 doname_subtree(rp->target, 1159 rp->do_get, 1160 rp->implicit); 1161 #ifdef DISTRIBUTED 1162 just_did_subtree = true; 1163 #endif 1164 quiescent = false; 1165 delete_running_struct(rp); 1166 goto start_loop_3; 1167 } else { 1168 subtree_target = rp_prev; 1169 rp_prev = &rp->next; 1170 } 1171 } else { 1172 rp_prev = &rp->next; 1173 } 1174 } 1175 } 1176 /* 1177 * If still nothing found to build, we either have a deadlock 1178 * or a subtree with a dependency conflict with something waiting 1179 * to build. 1180 */ 1181 if (quiescent) { 1182 if (subtree_target == NULL) { 1183 fatal(catgets(catd, 1, 126, "Internal error: deadlock detected in process_next")); 1184 } else { 1185 rp = *subtree_target; 1186 if (debug_level > 0) { 1187 warning(catgets(catd, 1, 127, "Conditional macro conflict encountered for %s between %s and %s"), 1188 subtree_conflict2->string_mb, 1189 rp->target->string_mb, 1190 subtree_conflict->string_mb); 1191 } 1192 *subtree_target = (*subtree_target)->next; 1193 if (rp->next == NULL) { 1194 running_tail = subtree_target; 1195 } 1196 recursion_level = rp->recursion_level; 1197 doname_subtree(rp->target, rp->do_get, rp->implicit); 1198 #ifdef DISTRIBUTED 1199 just_did_subtree = true; 1200 #endif 1201 delete_running_struct(rp); 1202 } 1203 } 1204 } 1205 1206 /* 1207 * set_conditionals(cnt, targets) 1208 * 1209 * Sets the conditional macros for the targets given in the array of 1210 * targets. The old macro values are returned in an array of 1211 * Properties for later resetting. 1212 * 1213 * Return value: 1214 * Array of conditional macro settings 1215 * 1216 * Parameters: 1217 * cnt Number of targets 1218 * targets Array of targets 1219 */ 1220 static Property * 1221 set_conditionals(int cnt, Name *targets) 1222 { 1223 Property *locals, *lp; 1224 Name *tp; 1225 1226 locals = (Property *) getmem(cnt * sizeof(Property)); 1227 for (lp = locals, tp = targets; 1228 cnt > 0; 1229 cnt--, lp++, tp++) { 1230 *lp = (Property) getmem((*tp)->conditional_cnt * 1231 sizeof(struct _Property)); 1232 set_locals(*tp, *lp); 1233 } 1234 return locals; 1235 } 1236 1237 /* 1238 * reset_conditionals(cnt, targets, locals) 1239 * 1240 * Resets the conditional macros as saved in the given array of 1241 * Properties. The resets are done in reverse order. Afterwards the 1242 * data structures are freed. 1243 * 1244 * Parameters: 1245 * cnt Number of targets 1246 * targets Array of targets 1247 * locals Array of dependency macro settings 1248 */ 1249 static void 1250 reset_conditionals(int cnt, Name *targets, Property *locals) 1251 { 1252 Name *tp; 1253 Property *lp; 1254 1255 for (tp = targets + (cnt - 1), lp = locals + (cnt - 1); 1256 cnt > 0; 1257 cnt--, tp--, lp--) { 1258 reset_locals(*tp, 1259 *lp, 1260 get_prop((*tp)->prop, conditional_prop), 1261 0); 1262 retmem_mb((caddr_t) *lp); 1263 } 1264 retmem_mb((caddr_t) locals); 1265 } 1266 1267 /* 1268 * dependency_conflict(target) 1269 * 1270 * Returns true if there is an intersection between 1271 * the subtree of the target and any dependents of the pending targets. 1272 * 1273 * Return value: 1274 * True if conflict found 1275 * 1276 * Parameters: 1277 * target Subtree target to check 1278 * 1279 * Static variables used: 1280 * subtree_conflict Target conflict found 1281 * subtree_conflict2 Second conflict found 1282 * 1283 * Global variables used: 1284 * running_list List of running processes 1285 * wait_name .WAIT, not a real dependency 1286 */ 1287 static Boolean 1288 dependency_conflict(Name target) 1289 { 1290 Property line; 1291 Property pending_line; 1292 Dependency dp; 1293 Dependency pending_dp; 1294 Running rp; 1295 1296 /* Return if we are already checking this target */ 1297 if (target->checking_subtree) { 1298 return false; 1299 } 1300 target->checking_subtree = true; 1301 line = get_prop(target->prop, line_prop); 1302 if (line == NULL) { 1303 target->checking_subtree = false; 1304 return false; 1305 } 1306 /* Check each dependency of the target for conflicts */ 1307 for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) { 1308 /* Ignore .WAIT dependency */ 1309 if (dp->name == wait_name) { 1310 continue; 1311 } 1312 /* 1313 * For each pending target, look for a dependency which 1314 * is the same as a dependency of the subtree target. Since 1315 * we can't build the subtree until all pending targets have 1316 * finished which depend on the same dependency, this is 1317 * a conflict. 1318 */ 1319 for (rp = running_list; rp != NULL; rp = rp->next) { 1320 if (rp->state == build_pending) { 1321 pending_line = get_prop(rp->target->prop, 1322 line_prop); 1323 if (pending_line == NULL) { 1324 continue; 1325 } 1326 for(pending_dp = pending_line-> 1327 body.line.dependencies; 1328 pending_dp != NULL; 1329 pending_dp = pending_dp->next) { 1330 if (dp->name == pending_dp->name) { 1331 target->checking_subtree 1332 = false; 1333 subtree_conflict = rp->target; 1334 subtree_conflict2 = dp->name; 1335 return true; 1336 } 1337 } 1338 } 1339 } 1340 if (dependency_conflict(dp->name)) { 1341 target->checking_subtree = false; 1342 return true; 1343 } 1344 } 1345 target->checking_subtree = false; 1346 return false; 1347 } 1348 1349 /* 1350 * await_parallel(waitflg) 1351 * 1352 * Waits for parallel children to exit and finishes their processing. 1353 * If waitflg is false, the function returns after update_delay. 1354 * 1355 * Parameters: 1356 * waitflg dwight 1357 */ 1358 void 1359 await_parallel(Boolean waitflg) 1360 { 1361 #ifdef _CHECK_UPDATE_H 1362 static int number_of_unknown_children = 0; 1363 #endif /* _CHECK_UPDATE_H */ 1364 Boolean nohang; 1365 pid_t pid; 1366 int status; 1367 Running rp; 1368 int waiterr; 1369 1370 nohang = false; 1371 for ( ; ; ) { 1372 if (!nohang) { 1373 (void) alarm((int) update_delay); 1374 } 1375 pid = waitpid((pid_t)-1, 1376 &status, 1377 nohang ? WNOHANG : 0); 1378 waiterr = errno; 1379 if (!nohang) { 1380 (void) alarm(0); 1381 } 1382 if (pid <= 0) { 1383 if (waiterr == EINTR) { 1384 if (waitflg) { 1385 continue; 1386 } else { 1387 return; 1388 } 1389 } else { 1390 return; 1391 } 1392 } 1393 for (rp = running_list; 1394 (rp != NULL) && (rp->pid != pid); 1395 rp = rp->next) { 1396 ; 1397 } 1398 if (rp == NULL) { 1399 #ifdef _CHECK_UPDATE_H 1400 /* Ignore first child - it is check_update */ 1401 if (number_of_unknown_children <= 0) { 1402 number_of_unknown_children = 1; 1403 return; 1404 } 1405 #endif /* _CHECK_UPDATE_H */ 1406 if (send_mtool_msgs) { 1407 continue; 1408 } else { 1409 fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list")); 1410 } 1411 } else { 1412 rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed; 1413 } 1414 nohang = true; 1415 parallel_process_cnt--; 1416 1417 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000) 1418 if (job_adjust_mode == ADJUST_M2) { 1419 if (m2_release_job()) { 1420 job_adjust_error(); 1421 } 1422 } 1423 #endif 1424 } 1425 } 1426 1427 /* 1428 * finish_children(docheck) 1429 * 1430 * Finishes the processing for all targets which were running 1431 * and have now completed. 1432 * 1433 * Parameters: 1434 * docheck Completely check the finished target 1435 * 1436 * Static variables used: 1437 * running_tail The tail of the running list 1438 * 1439 * Global variables used: 1440 * continue_after_error -k flag 1441 * fatal_in_progress True if we are finishing up after fatal err 1442 * running_list List of running processes 1443 */ 1444 void 1445 finish_children(Boolean docheck) 1446 { 1447 int cmds_length; 1448 Property line; 1449 Property line2; 1450 struct stat out_buf; 1451 Running rp; 1452 Running *rp_prev; 1453 Cmd_line rule; 1454 Boolean silent_flag; 1455 1456 for (rp_prev = &running_list, rp = running_list; 1457 rp != NULL; 1458 rp = rp->next) { 1459 bypass_for_loop_inc_4: 1460 /* 1461 * If the state is ok or failed, then this target has 1462 * finished building. 1463 * In parallel_mode, output the accumulated stdout/stderr. 1464 * Read the auto dependency stuff, handle a failed build, 1465 * update the target, then finish the doname process for 1466 * that target. 1467 */ 1468 if (rp->state == build_ok || rp->state == build_failed) { 1469 *rp_prev = rp->next; 1470 if (rp->next == NULL) { 1471 running_tail = rp_prev; 1472 } 1473 if ((line2 = rp->command) == NULL) { 1474 line2 = get_prop(rp->target->prop, line_prop); 1475 } 1476 if (dmake_mode_type == distributed_mode) { 1477 if (rp->make_refd) { 1478 maybe_reread_make_state(); 1479 } 1480 } else { 1481 /* 1482 * Send an Avo_MToolJobResultMsg to maketool. 1483 */ 1484 #ifdef DISTRIBUTED 1485 if (send_mtool_msgs) { 1486 send_job_result_msg(rp); 1487 } 1488 #endif 1489 /* 1490 * Check if there were any job output 1491 * from the parallel build. 1492 */ 1493 if (rp->stdout_file != NULL) { 1494 if (stat(rp->stdout_file, &out_buf) < 0) { 1495 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"), 1496 rp->stdout_file, 1497 errmsg(errno)); 1498 } 1499 if ((line2 != NULL) && 1500 (out_buf.st_size > 0)) { 1501 cmds_length = 0; 1502 for (rule = line2->body.line.command_used, 1503 silent_flag = silent; 1504 rule != NULL; 1505 rule = rule->next) { 1506 cmds_length += rule->command_line->hash.length + 1; 1507 silent_flag = BOOLEAN(silent_flag || rule->silent); 1508 } 1509 if (out_buf.st_size != cmds_length || silent_flag || 1510 output_mode == txt2_mode) { 1511 dump_out_file(rp->stdout_file, false); 1512 } 1513 } 1514 (void) unlink(rp->stdout_file); 1515 retmem_mb(rp->stdout_file); 1516 rp->stdout_file = NULL; 1517 } 1518 #if defined(REDIRECT_ERR) 1519 if (!out_err_same && (rp->stderr_file != NULL)) { 1520 if (stat(rp->stderr_file, &out_buf) < 0) { 1521 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"), 1522 rp->stderr_file, 1523 errmsg(errno)); 1524 } 1525 if ((line2 != NULL) && 1526 (out_buf.st_size > 0)) { 1527 dump_out_file(rp->stderr_file, true); 1528 } 1529 (void) unlink(rp->stderr_file); 1530 retmem_mb(rp->stderr_file); 1531 rp->stderr_file = NULL; 1532 } 1533 #endif 1534 } 1535 check_state(rp->temp_file); 1536 if (rp->temp_file != NULL) { 1537 free_name(rp->temp_file); 1538 } 1539 rp->temp_file = NULL; 1540 if (rp->state == build_failed) { 1541 line = get_prop(rp->target->prop, line_prop); 1542 if (line != NULL) { 1543 line->body.line.command_used = NULL; 1544 } 1545 if (continue_after_error || 1546 fatal_in_progress || 1547 !docheck) { 1548 warning(catgets(catd, 1, 256, "Command failed for target `%s'"), 1549 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb); 1550 build_failed_seen = true; 1551 } else { 1552 /* 1553 * XXX??? - DMake needs to exit(), 1554 * but shouldn't call fatal(). 1555 */ 1556 #ifdef PRINT_EXIT_STATUS 1557 warning(NOCATGETS("I'm in finish_children. rp->state == build_failed.")); 1558 #endif 1559 1560 fatal(catgets(catd, 1, 258, "Command failed for target `%s'"), 1561 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb); 1562 } 1563 } 1564 if (!docheck) { 1565 delete_running_struct(rp); 1566 rp = *rp_prev; 1567 if (rp == NULL) { 1568 break; 1569 } else { 1570 goto bypass_for_loop_inc_4; 1571 } 1572 } 1573 update_target(get_prop(rp->target->prop, line_prop), 1574 rp->state); 1575 finish_doname(rp); 1576 delete_running_struct(rp); 1577 rp = *rp_prev; 1578 if (rp == NULL) { 1579 break; 1580 } else { 1581 goto bypass_for_loop_inc_4; 1582 } 1583 } else { 1584 rp_prev = &rp->next; 1585 } 1586 } 1587 } 1588 1589 /* 1590 * dump_out_file(filename, err) 1591 * 1592 * Write the contents of the file to stdout, then unlink the file. 1593 * 1594 * Parameters: 1595 * filename Name of temp file containing output 1596 * 1597 * Global variables used: 1598 */ 1599 static void 1600 dump_out_file(char *filename, Boolean err) 1601 { 1602 int chars_read; 1603 char copybuf[BUFSIZ]; 1604 int fd; 1605 int out_fd = (err ? 2 : 1); 1606 1607 if ((fd = open(filename, O_RDONLY)) < 0) { 1608 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"), 1609 filename, 1610 errmsg(errno)); 1611 } 1612 if (!silent && output_mode != txt2_mode) { 1613 (void) fprintf(err ? stderr : stdout, 1614 err ? 1615 catgets(catd, 1, 338, "%s --> Job errors\n") : 1616 catgets(catd, 1, 259, "%s --> Job output\n"), 1617 local_host); 1618 (void) fflush(err ? stderr : stdout); 1619 } 1620 for (chars_read = read(fd, copybuf, BUFSIZ); 1621 chars_read > 0; 1622 chars_read = read(fd, copybuf, BUFSIZ)) { 1623 /* 1624 * Read buffers from the source file until end or error. 1625 */ 1626 if (write(out_fd, copybuf, chars_read) < 0) { 1627 fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"), 1628 filename, 1629 errmsg(errno)); 1630 } 1631 } 1632 (void) close(fd); 1633 (void) unlink(filename); 1634 } 1635 1636 /* 1637 * finish_doname(rp) 1638 * 1639 * Completes the processing for a target which was left running. 1640 * 1641 * Parameters: 1642 * rp Running list entry for target 1643 * 1644 * Global variables used: 1645 * debug_level Debug flag 1646 * recursion_level Indentation for debug output 1647 */ 1648 static void 1649 finish_doname(Running rp) 1650 { 1651 int auto_count = rp->auto_count; 1652 Name *automatics = rp->automatics; 1653 Doname result = rp->state; 1654 Name target = rp->target; 1655 Name true_target = rp->true_target; 1656 Property *conditionals; 1657 1658 recursion_level = rp->recursion_level; 1659 if (result == build_ok) { 1660 if (true_target == NULL) { 1661 (void) printf(NOCATGETS("Target = %s\n"), target->string_mb); 1662 (void) printf(NOCATGETS(" State = %d\n"), result); 1663 fatal(NOCATGETS("Internal error: NULL true_target in finish_doname")); 1664 } 1665 /* If all went OK, set a nice timestamp */ 1666 if (true_target->stat.time == file_doesnt_exist) { 1667 true_target->stat.time = file_max_time; 1668 } 1669 } 1670 target->state = result; 1671 if (target->is_member) { 1672 Property member; 1673 1674 /* Propagate the timestamp from the member file to the member */ 1675 if ((target->stat.time != file_max_time) && 1676 ((member = get_prop(target->prop, member_prop)) != NULL) && 1677 (exists(member->body.member.member) > file_doesnt_exist)) { 1678 target->stat.time = 1679 /* 1680 exists(member->body.member.member); 1681 */ 1682 member->body.member.member->stat.time; 1683 } 1684 } 1685 /* 1686 * Check if we found any new auto dependencies when we 1687 * built the target. 1688 */ 1689 if ((result == build_ok) && check_auto_dependencies(target, 1690 auto_count, 1691 automatics)) { 1692 if (debug_level > 0) { 1693 (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"), 1694 recursion_level, 1695 "", 1696 true_target->string_mb); 1697 } 1698 target->rechecking_target = true; 1699 target->state = build_running; 1700 1701 /* [tolik, Tue Mar 25 1997] 1702 * Fix for bug 4038824: 1703 * command line options set by conditional macros get dropped 1704 * rp->conditional_cnt and rp->conditional_targets must be copied 1705 * to new 'rp' during add_pending(). Set_conditionals() stores 1706 * rp->conditional_targets to the global variable 'conditional_targets' 1707 * Add_pending() will use this variable to set up 'rp'. 1708 */ 1709 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets); 1710 add_pending(target, 1711 recursion_level, 1712 rp->do_get, 1713 rp->implicit, 1714 true); 1715 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals); 1716 } 1717 } 1718 1719 /* 1720 * new_running_struct() 1721 * 1722 * Constructor for Running struct. Creates a structure and initializes 1723 * its fields. 1724 * 1725 */ 1726 static Running new_running_struct() 1727 { 1728 Running rp; 1729 1730 rp = ALLOC(Running); 1731 rp->target = NULL; 1732 rp->true_target = NULL; 1733 rp->command = NULL; 1734 rp->sprodep_value = NULL; 1735 rp->sprodep_env = NULL; 1736 rp->auto_count = 0; 1737 rp->automatics = NULL; 1738 rp->pid = -1; 1739 rp->job_msg_id = -1; 1740 rp->stdout_file = NULL; 1741 rp->stderr_file = NULL; 1742 rp->temp_file = NULL; 1743 rp->next = NULL; 1744 return rp; 1745 } 1746 1747 /* 1748 * add_running(target, true_target, command, recursion_level, auto_count, 1749 * automatics, do_get, implicit) 1750 * 1751 * Adds a record on the running list for this target, which 1752 * was just spawned and is running. 1753 * 1754 * Parameters: 1755 * target Target being built 1756 * true_target True target for target 1757 * command Running command. 1758 * recursion_level Debug indentation level 1759 * auto_count Count of automatic dependencies 1760 * automatics List of automatic dependencies 1761 * do_get Sccs get flag 1762 * implicit Implicit flag 1763 * 1764 * Static variables used: 1765 * running_tail Tail of running list 1766 * process_running PID of process 1767 * 1768 * Global variables used: 1769 * current_line Current line for target 1770 * current_target Current target being built 1771 * stderr_file Temporary file for stdout 1772 * stdout_file Temporary file for stdout 1773 * temp_file_name Temporary file for auto dependencies 1774 */ 1775 void 1776 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit) 1777 { 1778 Running rp; 1779 Name *p; 1780 1781 rp = new_running_struct(); 1782 rp->state = build_running; 1783 rp->target = target; 1784 rp->true_target = true_target; 1785 rp->command = command; 1786 Property spro_val = get_prop(sunpro_dependencies->prop, macro_prop); 1787 if(spro_val) { 1788 rp->sprodep_value = spro_val->body.macro.value; 1789 spro_val->body.macro.value = NULL; 1790 spro_val = get_prop(sunpro_dependencies->prop, env_mem_prop); 1791 if(spro_val) { 1792 rp->sprodep_env = spro_val->body.env_mem.value; 1793 spro_val->body.env_mem.value = NULL; 1794 } 1795 } 1796 rp->recursion_level = recursion_level; 1797 rp->do_get = do_get; 1798 rp->implicit = implicit; 1799 rp->auto_count = auto_count; 1800 if (auto_count > 0) { 1801 rp->automatics = (Name *) getmem(auto_count * sizeof (Name)); 1802 for (p = rp->automatics; auto_count > 0; auto_count--) { 1803 *p++ = *automatics++; 1804 } 1805 } else { 1806 rp->automatics = NULL; 1807 } 1808 #ifdef DISTRIBUTED 1809 if (dmake_mode_type == distributed_mode) { 1810 rp->make_refd = called_make; 1811 called_make = false; 1812 } else 1813 #endif 1814 { 1815 rp->pid = process_running; 1816 process_running = -1; 1817 childPid = -1; 1818 } 1819 rp->job_msg_id = job_msg_id; 1820 rp->stdout_file = stdout_file; 1821 rp->stderr_file = stderr_file; 1822 rp->temp_file = temp_file_name; 1823 rp->redo = false; 1824 rp->next = NULL; 1825 store_conditionals(rp); 1826 stdout_file = NULL; 1827 stderr_file = NULL; 1828 temp_file_name = NULL; 1829 current_target = NULL; 1830 current_line = NULL; 1831 *running_tail = rp; 1832 running_tail = &rp->next; 1833 } 1834 1835 /* 1836 * add_pending(target, recursion_level, do_get, implicit, redo) 1837 * 1838 * Adds a record on the running list for a pending target 1839 * (waiting for its dependents to finish running). 1840 * 1841 * Parameters: 1842 * target Target being built 1843 * recursion_level Debug indentation level 1844 * do_get Sccs get flag 1845 * implicit Implicit flag 1846 * redo True if this target is being redone 1847 * 1848 * Static variables used: 1849 * running_tail Tail of running list 1850 */ 1851 void 1852 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo) 1853 { 1854 Running rp; 1855 rp = new_running_struct(); 1856 rp->state = build_pending; 1857 rp->target = target; 1858 rp->recursion_level = recursion_level; 1859 rp->do_get = do_get; 1860 rp->implicit = implicit; 1861 rp->redo = redo; 1862 store_conditionals(rp); 1863 *running_tail = rp; 1864 running_tail = &rp->next; 1865 } 1866 1867 /* 1868 * add_serial(target, recursion_level, do_get, implicit) 1869 * 1870 * Adds a record on the running list for a target which must be 1871 * executed in serial after others have finished. 1872 * 1873 * Parameters: 1874 * target Target being built 1875 * recursion_level Debug indentation level 1876 * do_get Sccs get flag 1877 * implicit Implicit flag 1878 * 1879 * Static variables used: 1880 * running_tail Tail of running list 1881 */ 1882 void 1883 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit) 1884 { 1885 Running rp; 1886 1887 rp = new_running_struct(); 1888 rp->target = target; 1889 rp->recursion_level = recursion_level; 1890 rp->do_get = do_get; 1891 rp->implicit = implicit; 1892 rp->state = build_serial; 1893 rp->redo = false; 1894 store_conditionals(rp); 1895 *running_tail = rp; 1896 running_tail = &rp->next; 1897 } 1898 1899 /* 1900 * add_subtree(target, recursion_level, do_get, implicit) 1901 * 1902 * Adds a record on the running list for a target which must be 1903 * executed in isolation after others have finished. 1904 * 1905 * Parameters: 1906 * target Target being built 1907 * recursion_level Debug indentation level 1908 * do_get Sccs get flag 1909 * implicit Implicit flag 1910 * 1911 * Static variables used: 1912 * running_tail Tail of running list 1913 */ 1914 void 1915 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit) 1916 { 1917 Running rp; 1918 1919 rp = new_running_struct(); 1920 rp->target = target; 1921 rp->recursion_level = recursion_level; 1922 rp->do_get = do_get; 1923 rp->implicit = implicit; 1924 rp->state = build_subtree; 1925 rp->redo = false; 1926 store_conditionals(rp); 1927 *running_tail = rp; 1928 running_tail = &rp->next; 1929 } 1930 1931 /* 1932 * store_conditionals(rp) 1933 * 1934 * Creates an array of the currently active targets with conditional 1935 * macros (found in the chain conditional_targets) and puts that 1936 * array in the Running struct. 1937 * 1938 * Parameters: 1939 * rp Running struct for storing chain 1940 * 1941 * Global variables used: 1942 * conditional_targets Chain of current dynamic conditionals 1943 */ 1944 static void 1945 store_conditionals(Running rp) 1946 { 1947 int cnt; 1948 Chain cond_name; 1949 1950 if (conditional_targets == NULL) { 1951 rp->conditional_cnt = 0; 1952 rp->conditional_targets = NULL; 1953 return; 1954 } 1955 cnt = 0; 1956 for (cond_name = conditional_targets; 1957 cond_name != NULL; 1958 cond_name = cond_name->next) { 1959 cnt++; 1960 } 1961 rp->conditional_cnt = cnt; 1962 rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name)); 1963 for (cond_name = conditional_targets; 1964 cond_name != NULL; 1965 cond_name = cond_name->next) { 1966 rp->conditional_targets[--cnt] = cond_name->name; 1967 } 1968 } 1969 1970 /* 1971 * parallel_ok(target, line_prop_must_exists) 1972 * 1973 * Returns true if the target can be run in parallel 1974 * 1975 * Return value: 1976 * True if can run in parallel 1977 * 1978 * Parameters: 1979 * target Target being tested 1980 * 1981 * Global variables used: 1982 * all_parallel True if all targets default to parallel 1983 * only_parallel True if no targets default to parallel 1984 */ 1985 Boolean 1986 parallel_ok(Name target, Boolean line_prop_must_exists) 1987 { 1988 Boolean assign; 1989 Boolean make_refd; 1990 Property line; 1991 Cmd_line rule; 1992 1993 assign = make_refd = false; 1994 if (((line = get_prop(target->prop, line_prop)) == NULL) && 1995 line_prop_must_exists) { 1996 return false; 1997 } 1998 if (line != NULL) { 1999 for (rule = line->body.line.command_used; 2000 rule != NULL; 2001 rule = rule->next) { 2002 if (rule->assign) { 2003 assign = true; 2004 } else if (rule->make_refd) { 2005 make_refd = true; 2006 } 2007 } 2008 } 2009 if (assign) { 2010 return false; 2011 } else if (target->parallel) { 2012 return true; 2013 } else if (target->no_parallel) { 2014 return false; 2015 } else if (all_parallel) { 2016 return true; 2017 } else if (only_parallel) { 2018 return false; 2019 } else if (make_refd) { 2020 return false; 2021 } else { 2022 return true; 2023 } 2024 } 2025 2026 /* 2027 * is_running(target) 2028 * 2029 * Returns true if the target is running. 2030 * 2031 * Return value: 2032 * True if target is running 2033 * 2034 * Parameters: 2035 * target Target to check 2036 * 2037 * Global variables used: 2038 * running_list List of running processes 2039 */ 2040 Boolean 2041 is_running(Name target) 2042 { 2043 Running rp; 2044 2045 if (target->state != build_running) { 2046 return false; 2047 } 2048 for (rp = running_list; 2049 rp != NULL && target != rp->target; 2050 rp = rp->next); 2051 if (rp == NULL) { 2052 return false; 2053 } else { 2054 return (rp->state == build_running) ? true : false; 2055 } 2056 } 2057 2058 /* 2059 * This function replaces the makesh binary. 2060 */ 2061 2062 #ifdef SGE_SUPPORT 2063 #define DO_CHECK(f) if (f <= 0) { \ 2064 fprintf(stderr, \ 2065 catgets(catd, 1, 347, "Could not write to file: %s: %s\n"), \ 2066 script_file, errmsg(errno)); \ 2067 _exit(1); \ 2068 } 2069 #endif /* SGE_SUPPORT */ 2070 2071 static pid_t 2072 run_rule_commands(char *host, char **commands) 2073 { 2074 Boolean always_exec; 2075 Name command; 2076 Boolean ignore; 2077 int length; 2078 Doname result; 2079 Boolean silent_flag; 2080 #ifdef SGE_SUPPORT 2081 wchar_t *wcmd, *tmp_wcs_buffer = NULL; 2082 char *cmd, *tmp_mbs_buffer = NULL; 2083 FILE *scrfp; 2084 Name shell = getvar(shell_name); 2085 #else 2086 wchar_t *tmp_wcs_buffer; 2087 #endif /* SGE_SUPPORT */ 2088 2089 childPid = fork(); 2090 switch (childPid) { 2091 case -1: /* Error */ 2092 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"), 2093 errmsg(errno)); 2094 break; 2095 case 0: /* Child */ 2096 /* To control the processed targets list is not the child's business */ 2097 running_list = NULL; 2098 #if defined(REDIRECT_ERR) 2099 if(out_err_same) { 2100 redirect_io(stdout_file, (char*)NULL); 2101 } else { 2102 redirect_io(stdout_file, stderr_file); 2103 } 2104 #else 2105 redirect_io(stdout_file, (char*)NULL); 2106 #endif 2107 #ifdef SGE_SUPPORT 2108 if (grid) { 2109 int fdes = mkstemp(script_file); 2110 if ((fdes < 0) || (scrfp = fdopen(fdes, "w")) == NULL) { 2111 fprintf(stderr, 2112 catgets(catd, 1, 341, "Could not create file: %s: %s\n"), 2113 script_file, errmsg(errno)); 2114 _exit(1); 2115 } 2116 if (IS_EQUAL(shell->string_mb, "")) { 2117 shell = shell_name; 2118 } 2119 } 2120 #endif /* SGE_SUPPORT */ 2121 for (commands = commands; 2122 (*commands != (char *)NULL); 2123 commands++) { 2124 silent_flag = silent; 2125 ignore = false; 2126 always_exec = false; 2127 while ((**commands == (int) at_char) || 2128 (**commands == (int) hyphen_char) || 2129 (**commands == (int) plus_char)) { 2130 if (**commands == (int) at_char) { 2131 silent_flag = true; 2132 } 2133 if (**commands == (int) hyphen_char) { 2134 ignore = true; 2135 } 2136 if (**commands == (int) plus_char) { 2137 always_exec = true; 2138 } 2139 (*commands)++; 2140 } 2141 #ifdef SGE_SUPPORT 2142 if (grid) { 2143 if ((length = strlen(*commands)) >= MAXPATHLEN / 2) { 2144 wcmd = tmp_wcs_buffer = ALLOC_WC(length * 2 + 1); 2145 (void) mbstowcs(tmp_wcs_buffer, *commands, length * 2 + 1); 2146 } else { 2147 MBSTOWCS(wcs_buffer, *commands); 2148 wcmd = wcs_buffer; 2149 cmd = mbs_buffer; 2150 } 2151 wchar_t *from = wcmd + wslen(wcmd); 2152 wchar_t *to = from + (from - wcmd); 2153 *to = (int) nul_char; 2154 while (from > wcmd) { 2155 *--to = *--from; 2156 if (*from == (int) newline_char) { // newline symbols are already quoted 2157 *--to = *--from; 2158 } else if (wschr(char_semantics_char, *from)) { 2159 *--to = (int) backslash_char; 2160 } 2161 } 2162 if (length >= MAXPATHLEN*MB_LEN_MAX/2) { // sizeof(mbs_buffer) / 2 2163 cmd = tmp_mbs_buffer = getmem((length * MB_LEN_MAX * 2) + 1); 2164 (void) wcstombs(tmp_mbs_buffer, to, (length * MB_LEN_MAX * 2) + 1); 2165 } else { 2166 WCSTOMBS(mbs_buffer, to); 2167 cmd = mbs_buffer; 2168 } 2169 char *mbst, *mbend; 2170 if ((length > 0) && 2171 !silent_flag) { 2172 for (mbst = cmd; (mbend = strstr(mbst, "\\\n")) != NULL; mbst = mbend + 2) { 2173 *mbend = '\0'; 2174 DO_CHECK(fprintf(scrfp, NOCATGETS("/usr/bin/printf '%%s\\n' %s\\\\\n"), mbst)); 2175 *mbend = '\\'; 2176 } 2177 DO_CHECK(fprintf(scrfp, NOCATGETS("/usr/bin/printf '%%s\\n' %s\n"), mbst)); 2178 } 2179 if (!do_not_exec_rule || 2180 !working_on_targets || 2181 always_exec) { 2182 #if defined(linux) 2183 if (0 != strcmp(shell->string_mb, (char*)NOCATGETS("/bin/sh"))) { 2184 DO_CHECK(fprintf(scrfp, NOCATGETS("%s -c %s\n"), shell->string_mb, cmd)); 2185 } else 2186 #endif 2187 DO_CHECK(fprintf(scrfp, NOCATGETS("%s -ce %s\n"), shell->string_mb, cmd)); 2188 DO_CHECK(fputs(NOCATGETS("__DMAKECMDEXITSTAT=$?\nif [ ${__DMAKECMDEXITSTAT} -ne 0 ]; then\n"), scrfp)); 2189 if (ignore) { 2190 DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s ${__DMAKECMDEXITSTAT} %s\n"), 2191 catgets(catd, 1, 343, "\"*** Error code"), 2192 catgets(catd, 1, 344, "(ignored)\""))); 2193 } else { 2194 DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s ${__DMAKECMDEXITSTAT}\n"), 2195 catgets(catd, 1, 342, "\"*** Error code\""))); 2196 } 2197 if (silent_flag) { 2198 DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s\n"), 2199 catgets(catd, 1, 345, "The following command caused the error:"))); 2200 for (mbst = cmd; (mbend = strstr(mbst, "\\\n")) != NULL; mbst = mbend + 2) { 2201 *mbend = '\0'; 2202 DO_CHECK(fprintf(scrfp, NOCATGETS("\t/usr/bin/printf '%%s\\n' %s\\\\\n"), mbst)); 2203 *mbend = '\\'; 2204 } 2205 DO_CHECK(fprintf(scrfp, NOCATGETS("\t/usr/bin/printf '%%s\\n' %s\n"), mbst)); 2206 } 2207 if (!ignore) { 2208 DO_CHECK(fputs(NOCATGETS("\texit ${__DMAKECMDEXITSTAT}\n"), scrfp)); 2209 } 2210 DO_CHECK(fputs(NOCATGETS("fi\n"), scrfp)); 2211 } 2212 if (tmp_wcs_buffer) { 2213 retmem_mb(tmp_mbs_buffer); 2214 tmp_mbs_buffer = NULL; 2215 } 2216 if (tmp_wcs_buffer) { 2217 retmem(tmp_wcs_buffer); 2218 tmp_wcs_buffer = NULL; 2219 } 2220 continue; 2221 } 2222 #endif /* SGE_SUPPORT */ 2223 if ((length = strlen(*commands)) >= MAXPATHLEN) { 2224 tmp_wcs_buffer = ALLOC_WC(length + 1); 2225 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1); 2226 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH); 2227 retmem(tmp_wcs_buffer); 2228 } else { 2229 MBSTOWCS(wcs_buffer, *commands); 2230 command = GETNAME(wcs_buffer, FIND_LENGTH); 2231 } 2232 if ((command->hash.length > 0) && 2233 !silent_flag) { 2234 (void) printf("%s\n", command->string_mb); 2235 } 2236 result = dosys(command, 2237 ignore, 2238 false, 2239 false, /* bugs #4085164 & #4990057 */ 2240 /* BOOLEAN(silent_flag && ignore), */ 2241 always_exec, 2242 (Name) NULL, 2243 false); 2244 if (result == build_failed) { 2245 if (silent_flag) { 2246 (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb); 2247 } 2248 if (!ignore) { 2249 _exit(1); 2250 } 2251 } 2252 } 2253 #ifndef SGE_SUPPORT 2254 _exit(0); 2255 #else 2256 if (!grid) { 2257 _exit(0); 2258 } 2259 DO_CHECK(fputs(NOCATGETS("exit 0\n"), scrfp)); 2260 if (fclose(scrfp) != 0) { 2261 fprintf(stderr, 2262 catgets(catd, 1, 346, "Could not close file: %s: %s\n"), 2263 script_file, errmsg(errno)); 2264 _exit(1); 2265 } 2266 { 2267 2268 #define DEFAULT_QRSH_TRIES_NUMBER 1 2269 #define DEFAULT_QRSH_TIMEOUT 0 2270 2271 static char *sge_env_var = NULL; 2272 static int qrsh_tries_number = DEFAULT_QRSH_TRIES_NUMBER; 2273 static int qrsh_timeout = DEFAULT_QRSH_TIMEOUT; 2274 #define SGE_DEBUG 2275 #ifdef SGE_DEBUG 2276 static Boolean do_not_remove = false; 2277 #endif /* SGE_DEBUG */ 2278 if (sge_env_var == NULL) { 2279 sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_TRIES")); 2280 if (sge_env_var != NULL) { 2281 qrsh_tries_number = atoi(sge_env_var); 2282 if (qrsh_tries_number < 1 || qrsh_tries_number > 9) { 2283 qrsh_tries_number = DEFAULT_QRSH_TRIES_NUMBER; 2284 } 2285 } 2286 sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_TIMEOUT")); 2287 if (sge_env_var != NULL) { 2288 qrsh_timeout = atoi(sge_env_var); 2289 if (qrsh_timeout <= 0) { 2290 qrsh_timeout = DEFAULT_QRSH_TIMEOUT; 2291 } 2292 } else { 2293 sge_env_var = ""; 2294 } 2295 #ifdef SGE_DEBUG 2296 sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_DEBUG")); 2297 if (sge_env_var == NULL) { 2298 sge_env_var = ""; 2299 } 2300 if (strstr(sge_env_var, NOCATGETS("noqrsh")) != NULL) 2301 qrsh_tries_number = 0; 2302 if (strstr(sge_env_var, NOCATGETS("donotremove")) != NULL) 2303 do_not_remove = true; 2304 #endif /* SGE_DEBUG */ 2305 } 2306 for (int i = qrsh_tries_number; ; i--) 2307 if ((childPid = fork()) < 0) { 2308 fatal(catgets(catd, 1, 348, "Could not fork child process for qrsh job: %s"), 2309 errmsg(errno)); 2310 _exit(1); 2311 } else if (childPid == 0) { 2312 enable_interrupt((void (*) (int))SIG_DFL); 2313 if (i > 0) { 2314 static char qrsh_cmd[50+MAXPATHLEN] = NOCATGETS("qrsh -cwd -V -noshell -nostdin /bin/sh "); 2315 static char *fname_ptr = NULL; 2316 static char *argv[] = { NOCATGETS("sh"), 2317 NOCATGETS("-fce"), 2318 qrsh_cmd, 2319 NULL}; 2320 if (fname_ptr == NULL) { 2321 fname_ptr = qrsh_cmd + strlen(qrsh_cmd); 2322 } 2323 strcpy(fname_ptr, script_file); 2324 (void) execve(NOCATGETS("/bin/sh"), argv, environ); 2325 } else { 2326 static char *argv[] = { NOCATGETS("sh"), 2327 script_file, 2328 NULL}; 2329 (void) execve(NOCATGETS("/bin/sh"), argv, environ); 2330 } 2331 fprintf(stderr, 2332 catgets(catd, 1, 349, "Could not load `qrsh': %s\n"), 2333 errmsg(errno)); 2334 _exit(1); 2335 } else { 2336 #if defined (HP_UX) || defined (linux) || defined (SUN5_0) 2337 int status; 2338 #else 2339 union wait status; 2340 #endif 2341 pid_t pid; 2342 while ((pid = wait(&status)) != childPid) { 2343 if (pid == -1) { 2344 fprintf(stderr, 2345 catgets(catd, 1, 350, "wait() failed: %s\n"), 2346 errmsg(errno)); 2347 _exit(1); 2348 } 2349 } 2350 if (status != 0 && i > 0) { 2351 if (i > 1) { 2352 sleep(qrsh_timeout); 2353 } 2354 continue; 2355 } 2356 #ifdef SGE_DEBUG 2357 if (do_not_remove) { 2358 if (status) { 2359 fprintf(stderr, 2360 NOCATGETS("SGE script failed: %s\n"), 2361 script_file); 2362 } 2363 _exit(status ? 1 : 0); 2364 } 2365 #endif /* SGE_DEBUG */ 2366 (void) unlink(script_file); 2367 _exit(status ? 1 : 0); 2368 } 2369 } 2370 #endif /* SGE_SUPPORT */ 2371 break; 2372 default: 2373 break; 2374 } 2375 return childPid; 2376 } 2377 2378 static void 2379 maybe_reread_make_state(void) 2380 { 2381 /* Copying dosys()... */ 2382 if (report_dependencies_level == 0) { 2383 make_state->stat.time = file_no_time; 2384 (void) exists(make_state); 2385 if (make_state_before == make_state->stat.time) { 2386 return; 2387 } 2388 makefile_type = reading_statefile; 2389 if (read_trace_level > 1) { 2390 trace_reader = true; 2391 } 2392 temp_file_number++; 2393 (void) read_simple_file(make_state, 2394 false, 2395 false, 2396 false, 2397 false, 2398 false, 2399 true); 2400 trace_reader = false; 2401 } 2402 } 2403 2404 #ifdef DISTRIBUTED 2405 /* 2406 * Create and send an Avo_MToolJobResultMsg. 2407 */ 2408 static void 2409 send_job_result_msg(Running rp) 2410 { 2411 Avo_MToolJobResultMsg *msg; 2412 RWCollectable *xdr_msg; 2413 2414 msg = new Avo_MToolJobResultMsg(); 2415 msg->setResult(rp->job_msg_id, 2416 (rp->state == build_ok) ? 0 : 1, 2417 DONE); 2418 append_job_result_msg(msg, 2419 rp->stdout_file, 2420 rp->stderr_file); 2421 2422 xdr_msg = (RWCollectable *)msg; 2423 xdr(get_xdrs_ptr(), xdr_msg); 2424 (void) fflush(get_mtool_msgs_fp()); 2425 2426 delete msg; 2427 } 2428 2429 /* 2430 * Append the stdout/err to Avo_MToolJobResultMsg. 2431 */ 2432 static void 2433 append_job_result_msg(Avo_MToolJobResultMsg *msg, char *outFn, char *errFn) 2434 { 2435 FILE *fp; 2436 char line[MAXPATHLEN]; 2437 2438 fp = fopen(outFn, "r"); 2439 if (fp == NULL) { 2440 /* Hmmm... what should we do here? */ 2441 return; 2442 } 2443 while (fgets(line, MAXPATHLEN, fp) != NULL) { 2444 if (line[strlen(line) - 1] == '\n') { 2445 line[strlen(line) - 1] = '\0'; 2446 } 2447 msg->appendOutput(AVO_STRDUP(line)); 2448 } 2449 (void) fclose(fp); 2450 } 2451 #endif 2452 2453 static void 2454 delete_running_struct(Running rp) 2455 { 2456 if ((rp->conditional_cnt > 0) && 2457 (rp->conditional_targets != NULL)) { 2458 retmem_mb((char *) rp->conditional_targets); 2459 } 2460 /**/ 2461 if ((rp->auto_count > 0) && 2462 (rp->automatics != NULL)) { 2463 retmem_mb((char *) rp->automatics); 2464 } 2465 /**/ 2466 if(rp->sprodep_value) { 2467 free_name(rp->sprodep_value); 2468 } 2469 if(rp->sprodep_env) { 2470 retmem_mb(rp->sprodep_env); 2471 } 2472 retmem_mb((char *) rp); 2473 2474 } 2475 2476 #endif 2477