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