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