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