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