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