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
27 /*
28 * parallel.cc
29 *
30 * Deal with the parallel processing
31 */
32
33 /*
34 * Included files
35 */
36 #include <errno.h> /* errno */
37 #include <fcntl.h>
38 #include <mk/defs.h>
39 #include <mksh/dosys.h> /* redirect_io() */
40 #include <mksh/macro.h> /* expand_value() */
41 #include <mksh/misc.h> /* getmem() */
42 #include <sys/signal.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <sys/utsname.h>
46 #include <sys/wait.h>
47 #include <unistd.h>
48 #include <netdb.h>
49
50
51
52 /*
53 * Defined macros
54 */
55 #define MAXRULES 100
56
57 /*
58 * This const should be in avo_dms/include/AvoDmakeCommand.h
59 */
60 const int local_host_mask = 0x20;
61
62
63 /*
64 * typedefs & structs
65 */
66
67
68 /*
69 * Static variables
70 */
71 static Boolean just_did_subtree = false;
72 static char local_host[MAXNAMELEN] = "";
73 static char user_name[MAXNAMELEN] = "";
74 static int pmake_max_jobs = 0;
75 static pid_t process_running = -1;
76 static Running *running_tail = &running_list;
77 static Name subtree_conflict;
78 static Name subtree_conflict2;
79
80
81 /*
82 * File table of contents
83 */
84 static void delete_running_struct(Running rp);
85 static Boolean dependency_conflict(Name target);
86 static Doname distribute_process(char **commands, Property line);
87 static void doname_subtree(Name target, Boolean do_get, Boolean implicit);
88 static void dump_out_file(char *filename, Boolean err);
89 static void finish_doname(Running rp);
90 static void maybe_reread_make_state(void);
91 static void process_next(void);
92 static void reset_conditionals(int cnt, Name *targets, Property *locals);
93 static pid_t run_rule_commands(char *host, char **commands);
94 static Property *set_conditionals(int cnt, Name *targets);
95 static void store_conditionals(Running rp);
96
97
98 /*
99 * execute_parallel(line, waitflg)
100 *
101 * DMake 2.x:
102 * parallel mode: spawns a parallel process to execute the command group.
103 *
104 * Return value:
105 * The result of the execution
106 *
107 * Parameters:
108 * line The command group to execute
109 */
110 Doname
111 execute_parallel(Property line, Boolean waitflg, Boolean local)
112 {
113 int argcnt;
114 int cmd_options = 0;
115 char *commands[MAXRULES + 5];
116 char *cp;
117 Name dmake_name;
118 Name dmake_value;
119 int ignore;
120 Name make_machines_name;
121 char **p;
122 Property prop;
123 Doname result = build_ok;
124 Cmd_line rule;
125 Boolean silent_flag;
126 Name target = line->body.line.target;
127 Boolean wrote_state_file = false;
128
129 if ((pmake_max_jobs == 0) &&
130 (dmake_mode_type == parallel_mode)) {
131 if (local_host[0] == '\0') {
132 (void) gethostname(local_host, MAXNAMELEN);
133 }
134 MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MAX_JOBS"));
135 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
136 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
137 ((dmake_value = prop->body.macro.value) != NULL)) {
138 pmake_max_jobs = atoi(dmake_value->string_mb);
139 if (pmake_max_jobs <= 0) {
140 warning(catgets(catd, 1, 308, "DMAKE_MAX_JOBS cannot be less than or equal to zero."));
141 warning(catgets(catd, 1, 309, "setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
142 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
143 }
144 } else {
145 /*
146 * For backwards compatibility w/ PMake 1.x, when
147 * DMake 2.x is being run in parallel mode, DMake
148 * should parse the PMake startup file
149 * $(HOME)/.make.machines to get the pmake_max_jobs.
150 */
151 MBSTOWCS(wcs_buffer, NOCATGETS("PMAKE_MACHINESFILE"));
152 dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
153 if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
154 ((dmake_value = prop->body.macro.value) != NULL)) {
155 make_machines_name = dmake_value;
156 } else {
157 make_machines_name = NULL;
158 }
159 if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
160 pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
161 }
162 }
163 }
164
165 if ((dmake_mode_type == serial_mode) ||
166 ((dmake_mode_type == parallel_mode) && (waitflg))) {
167 return (execute_serial(line));
168 }
169
170 {
171 p = commands;
172 }
173
174 argcnt = 0;
175 for (rule = line->body.line.command_used;
176 rule != NULL;
177 rule = rule->next) {
178 if (posix && (touch || quest) && !rule->always_exec) {
179 continue;
180 }
181 if (vpath_defined) {
182 rule->command_line =
183 vpath_translation(rule->command_line);
184 }
185
186 silent_flag = false;
187 ignore = 0;
188
189 if (rule->command_line->hash.length > 0) {
190 if (++argcnt == MAXRULES) {
191 return build_serial;
192 }
193 {
194 if (rule->silent && !silent) {
195 silent_flag = true;
196 }
197 if (rule->ignore_error) {
198 ignore++;
199 }
200 /* XXX - need to add support for + prefix */
201 if (silent_flag || ignore) {
202 *p = getmem((silent_flag ? 1 : 0) +
203 ignore +
204 (strlen(rule->
205 command_line->
206 string_mb)) +
207 1);
208 cp = *p++;
209 if (silent_flag) {
210 *cp++ = (int) at_char;
211 }
212 if (ignore) {
213 *cp++ = (int) hyphen_char;
214 }
215 (void) strcpy(cp, rule->command_line->string_mb);
216 } else {
217 *p++ = rule->command_line->string_mb;
218 }
219 }
220 }
221 }
222 if ((argcnt == 0) ||
223 (report_dependencies_level > 0)) {
224 return build_ok;
225 }
226 {
227 *p = NULL;
228
229 Doname res = distribute_process(commands, line);
230 if (res == build_running) {
231 parallel_process_cnt++;
232 }
233
234 /*
235 * Return only those memory that were specially allocated
236 * for part of commands.
237 */
238 for (int i = 0; commands[i] != NULL; i++) {
239 if ((commands[i][0] == (int) at_char) ||
240 (commands[i][0] == (int) hyphen_char)) {
241 retmem_mb(commands[i]);
242 }
243 }
244 return res;
245 }
246 }
247
248
249 #define MAXJOBS_ADJUST_RFE4694000
250
251 #ifdef MAXJOBS_ADJUST_RFE4694000
252
253 #include <unistd.h> /* sysconf(_SC_NPROCESSORS_ONLN) */
254 #include <sys/ipc.h> /* ftok() */
255 #include <sys/shm.h> /* shmget(), shmat(), shmdt(), shmctl() */
256 #include <semaphore.h> /* sem_init(), sem_trywait(), sem_post(), sem_destroy() */
257 #include <sys/loadavg.h> /* getloadavg() */
258
259 /*
260 * adjust_pmake_max_jobs (int pmake_max_jobs)
261 *
262 * Parameters:
263 * pmake_max_jobs - max jobs limit set by user
264 *
265 * External functions used:
266 * sysconf()
267 * getloadavg()
268 */
269 static int
270 adjust_pmake_max_jobs (int pmake_max_jobs)
271 {
272 static int ncpu = 0;
273 double loadavg[3];
274 int adjustment;
275 int adjusted_max_jobs;
276
277 if (ncpu <= 0) {
278 if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) {
279 ncpu = 1;
280 }
281 }
282 if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs);
283 adjustment = ((int)loadavg[LOADAVG_1MIN]);
284 if (adjustment < 2) return(pmake_max_jobs);
285 if (ncpu > 1) {
286 adjustment = adjustment / ncpu;
287 }
288 adjusted_max_jobs = pmake_max_jobs - adjustment;
289 if (adjusted_max_jobs < 1) adjusted_max_jobs = 1;
290 return(adjusted_max_jobs);
291 }
292
293 /*
294 * M2 adjust mode data and functions
295 *
296 * m2_init() - initializes M2 shared semaphore
297 * m2_acquire_job() - decrements M2 semaphore counter
298 * m2_release_job() - increments M2 semaphore counter
299 * m2_fini() - destroys M2 semaphore and shared memory*
300 *
301 * Environment variables:
302 * __DMAKE_M2_FILE__
303 *
304 * External functions:
305 * ftok(), shmget(), shmat(), shmdt(), shmctl()
306 * sem_init(), sem_trywait(), sem_post(), sem_destroy()
307 * creat(), close(), unlink()
308 * getenv(), putenv()
309 *
310 * Static variables:
311 * m2_file - tmp file name to create ipc key for shared memory
312 * m2_shm_id - shared memory id
313 * m2_shm_sem - shared memory semaphore
314 */
315
316 static char m2_file[MAXPATHLEN];
317 static int m2_shm_id = -1;
318 static sem_t* m2_shm_sem = 0;
319
320 static int
321 m2_init() {
322 char *var;
323 key_t key;
324
325 if ((var = getenv(NOCATGETS("__DMAKE_M2_FILE__"))) == 0) {
326 /* compose tmp file name */
327 sprintf(m2_file, NOCATGETS("%s/dmake.m2.%d.XXXXXX"), tmpdir, getpid());
328
329 /* create tmp file */
330 int fd = mkstemp(m2_file);
331 if (fd < 0) {
332 return -1;
333 } else {
334 close(fd);
335 }
336 } else {
337 /* using existing semaphore */
338 strcpy(m2_file, var);
339 }
340
341 /* combine IPC key */
342 if ((key = ftok(m2_file, 38)) == (key_t) -1) {
343 return -1;
344 }
345
346 /* create shared memory */
347 if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {
348 return -1;
349 }
350
351 /* attach shared memory */
352 if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
353 return -1;
354 }
355
356 /* root process */
357 if (var == 0) {
358 /* initialize semaphore */
359 if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
360 return -1;
361 }
362
363 /* alloc memory for env variable */
364 if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
365 return -1;
366 }
367
368 /* put key to env */
369 sprintf(var, NOCATGETS("__DMAKE_M2_FILE__=%s"), m2_file);
370 if (putenv(var)) {
371 return -1;
372 }
373 }
374 return 0;
375 }
376
377 static void
378 m2_fini() {
379 if (m2_shm_id >= 0) {
380 struct shmid_ds stat;
381
382 /* determine the number of attached processes */
383 if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
384 if (stat.shm_nattch <= 1) {
385 /* destroy semaphore */
386 if (m2_shm_sem != 0) {
387 (void) sem_destroy(m2_shm_sem);
388 }
389
390 /* destroy shared memory */
391 (void) shmctl(m2_shm_id, IPC_RMID, &stat);
392
393 /* remove tmp file created for the key */
394 (void) unlink(m2_file);
395 } else {
396 /* detach shared memory */
397 if (m2_shm_sem != 0) {
398 (void) shmdt((char*) m2_shm_sem);
399 }
400 }
401 }
402
403 m2_shm_id = -1;
404 m2_shm_sem = 0;
405 }
406 }
407
408 static int
409 m2_acquire_job() {
410 if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
411 if (sem_trywait(m2_shm_sem) == 0) {
412 return 1;
413 }
414 if (errno == EAGAIN) {
415 return 0;
416 }
417 }
418 return -1;
419 }
420
421 static int
422 m2_release_job() {
423 if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
424 if (sem_post(m2_shm_sem) == 0) {
425 return 0;
426 }
427 }
428 return -1;
429 }
430
431 /*
432 * job adjust mode
433 *
434 * Possible values:
435 * ADJUST_M1 - adjustment by system load (default)
436 * ADJUST_M2 - fixed limit of jobs for the group of nested dmakes
437 * ADJUST_NONE - no adjustment - fixed limit of jobs for the current dmake
438 */
439 static enum {
440 ADJUST_UNKNOWN,
441 ADJUST_M1,
442 ADJUST_M2,
443 ADJUST_NONE
444 } job_adjust_mode = ADJUST_UNKNOWN;
445
446 /*
447 * void job_adjust_fini()
448 *
449 * Description:
450 * Cleans up job adjust data.
451 *
452 * Static variables:
453 * job_adjust_mode Current job adjust mode
454 */
455 void
456 job_adjust_fini() {
457 if (job_adjust_mode == ADJUST_M2) {
458 m2_fini();
459 }
460 }
461
462 /*
463 * void job_adjust_error()
464 *
465 * Description:
466 * Prints warning message, cleans up job adjust data, and disables job adjustment
467 *
468 * Environment:
469 * DMAKE_ADJUST_MAX_JOBS
470 *
471 * External functions:
472 * putenv()
473 *
474 * Static variables:
475 * job_adjust_mode Current job adjust mode
476 */
477 static void
478 job_adjust_error() {
479 if (job_adjust_mode != ADJUST_NONE) {
480 /* cleanup internals */
481 job_adjust_fini();
482
483 /* warning message for the user */
484 warning(catgets(catd, 1, 339, "Encountered max jobs auto adjustment error - disabling auto adjustment."));
485
486 /* switch off job adjustment for the children */
487 putenv(strdup(NOCATGETS("DMAKE_ADJUST_MAX_JOBS=NO")));
488
489 /* and for this dmake */
490 job_adjust_mode = ADJUST_NONE;
491 }
492 }
493
494 /*
495 * void job_adjust_init()
496 *
497 * Description:
498 * Parses DMAKE_ADJUST_MAX_JOBS env variable
499 * and performs appropriate initializations.
500 *
501 * Environment:
502 * DMAKE_ADJUST_MAX_JOBS
503 * DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment
504 * DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode
505 * other - M1 adjust mode
506 *
507 * External functions:
508 * getenv()
509 *
510 * Static variables:
511 * job_adjust_mode Current job adjust mode
512 */
513 static void
514 job_adjust_init() {
515 if (job_adjust_mode == ADJUST_UNKNOWN) {
516 /* default mode */
517 job_adjust_mode = ADJUST_M1;
518
519 /* determine adjust mode */
520 if (char *var = getenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS"))) {
521 if (strcasecmp(var, NOCATGETS("NO")) == 0) {
522 job_adjust_mode = ADJUST_NONE;
523 } else if (strcasecmp(var, NOCATGETS("M2")) == 0) {
524 job_adjust_mode = ADJUST_M2;
525 }
526 }
527
528 /* M2 specific initialization */
529 if (job_adjust_mode == ADJUST_M2) {
530 if (m2_init()) {
531 job_adjust_error();
532 }
533 }
534 }
535 }
536
537 #endif /* MAXJOBS_ADJUST_RFE4694000 */
538
539 /*
540 * distribute_process(char **commands, Property line)
541 *
542 * Parameters:
543 * commands argv vector of commands to execute
544 *
545 * Return value:
546 * The result of the execution
547 *
548 * Static variables used:
549 * process_running Set to the pid of the process set running
550 * #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
551 * job_adjust_mode Current job adjust mode
552 * #endif
553 */
554 static Doname
555 distribute_process(char **commands, Property line)
556 {
557 static unsigned file_number = 0;
558 wchar_t string[MAXPATHLEN];
559 char mbstring[MAXPATHLEN];
560 int filed;
561 int res;
562 int tmp_index;
563 char *tmp_index_str_ptr;
564
565 #if !defined (TEAMWARE_MAKE_CMN) || !defined (MAXJOBS_ADJUST_RFE4694000)
566 while (parallel_process_cnt >= pmake_max_jobs) {
567 await_parallel(false);
568 finish_children(true);
569 }
570 #else /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
571 /* initialize adjust mode, if not initialized */
572 if (job_adjust_mode == ADJUST_UNKNOWN) {
573 job_adjust_init();
574 }
575
576 /* actions depend on adjust mode */
577 switch (job_adjust_mode) {
578 case ADJUST_M1:
579 while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) {
580 await_parallel(false);
581 finish_children(true);
582 }
583 break;
584 case ADJUST_M2:
585 if ((res = m2_acquire_job()) == 0) {
586 if (parallel_process_cnt > 0) {
587 await_parallel(false);
588 finish_children(true);
589
590 if ((res = m2_acquire_job()) == 0) {
591 return build_serial;
592 }
593 } else {
594 return build_serial;
595 }
596 }
597 if (res < 0) {
598 /* job adjustment error */
599 job_adjust_error();
600
601 /* no adjustment */
602 while (parallel_process_cnt >= pmake_max_jobs) {
603 await_parallel(false);
604 finish_children(true);
605 }
606 }
607 break;
608 default:
609 while (parallel_process_cnt >= pmake_max_jobs) {
610 await_parallel(false);
611 finish_children(true);
612 }
613 }
614 #endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
615 setvar_envvar();
616 /*
617 * Tell the user what DMake is doing.
618 */
619 if (!silent && output_mode != txt2_mode) {
620 /*
621 * Print local_host --> x job(s).
622 */
623 (void) fprintf(stdout,
624 catgets(catd, 1, 325, "%s --> %d %s\n"),
625 local_host,
626 parallel_process_cnt + 1,
627 (parallel_process_cnt == 0) ? catgets(catd, 1, 124, "job") : catgets(catd, 1, 125, "jobs"));
628
629 /* Print command line(s). */
630 tmp_index = 0;
631 while (commands[tmp_index] != NULL) {
632 /* No @ char. */
633 /* XXX - need to add [2] when + prefix is added */
634 if ((commands[tmp_index][0] != (int) at_char) &&
635 (commands[tmp_index][1] != (int) at_char)) {
636 tmp_index_str_ptr = commands[tmp_index];
637 if (*tmp_index_str_ptr == (int) hyphen_char) {
638 tmp_index_str_ptr++;
639 }
640 (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
641 }
642 tmp_index++;
643 }
644 (void) fflush(stdout);
645 }
646
647 (void) sprintf(mbstring,
648 NOCATGETS("%s/dmake.stdout.%d.%d.XXXXXX"),
649 tmpdir,
650 getpid(),
651 file_number++);
652
653 mktemp(mbstring);
654
655 stdout_file = strdup(mbstring);
656 stderr_file = NULL;
657
658 if (!out_err_same) {
659 (void) sprintf(mbstring,
660 NOCATGETS("%s/dmake.stderr.%d.%d.XXXXXX"),
661 tmpdir,
662 getpid(),
663 file_number++);
664
665 mktemp(mbstring);
666
667 stderr_file = strdup(mbstring);
668 }
669
670 process_running = run_rule_commands(local_host, commands);
671
672 return build_running;
673 }
674
675 /*
676 * doname_parallel(target, do_get, implicit)
677 *
678 * Processes the given target and finishes up any parallel
679 * processes left running.
680 *
681 * Return value:
682 * Result of target build
683 *
684 * Parameters:
685 * target Target to build
686 * do_get True if sccs get to be done
687 * implicit True if this is an implicit target
688 */
689 Doname
690 doname_parallel(Name target, Boolean do_get, Boolean implicit)
691 {
692 Doname result;
693
694 result = doname_check(target, do_get, implicit, false);
695 if (result == build_ok || result == build_failed) {
696 return result;
697 }
698 finish_running();
699 return (Doname) target->state;
700 }
701
702 /*
703 * doname_subtree(target, do_get, implicit)
704 *
705 * Completely computes an object and its dependents for a
706 * serial subtree build.
707 *
708 * Parameters:
709 * target Target to build
710 * do_get True if sccs get to be done
711 * implicit True if this is an implicit target
712 *
713 * Static variables used:
714 * running_tail Tail of the list of running processes
715 *
716 * Global variables used:
717 * running_list The list of running processes
718 */
719 static void
720 doname_subtree(Name target, Boolean do_get, Boolean implicit)
721 {
722 Running save_running_list;
723 Running *save_running_tail;
724
725 save_running_list = running_list;
726 save_running_tail = running_tail;
727 running_list = NULL;
728 running_tail = &running_list;
729 target->state = build_subtree;
730 target->checking_subtree = true;
731 while(doname_check(target, do_get, implicit, false) == build_running) {
732 target->checking_subtree = false;
733 finish_running();
734 target->state = build_subtree;
735 }
736 target->checking_subtree = false;
737 running_list = save_running_list;
738 running_tail = save_running_tail;
739 }
740
741 /*
742 * finish_running()
743 *
744 * Keeps processing until the running_list is emptied out.
745 *
746 * Parameters:
747 *
748 * Global variables used:
749 * running_list The list of running processes
750 */
751 void
752 finish_running(void)
753 {
754 while (running_list != NULL) {
755 {
756 await_parallel(false);
757 finish_children(true);
758 }
759 if (running_list != NULL) {
760 process_next();
761 }
762 }
763 }
764
765 /*
766 * process_next()
767 *
768 * Searches the running list for any targets which can start processing.
769 * This can be a pending target, a serial target, or a subtree target.
770 *
771 * Parameters:
772 *
773 * Static variables used:
774 * running_tail The end of the list of running procs
775 * subtree_conflict A target which conflicts with a subtree
776 * subtree_conflict2 The other target which conflicts
777 *
778 * Global variables used:
779 * commands_done True if commands executed
780 * debug_level Controls debug output
781 * parallel_process_cnt Number of parallel process running
782 * recursion_level Indentation for debug output
783 * running_list List of running processes
784 */
785 static void
786 process_next(void)
787 {
788 Running rp;
789 Running *rp_prev;
790 Property line;
791 Chain target_group;
792 Dependency dep;
793 Boolean quiescent = true;
794 Running *subtree_target;
795 Boolean saved_commands_done;
796 Property *conditionals;
797
798 subtree_target = NULL;
799 subtree_conflict = NULL;
800 subtree_conflict2 = NULL;
801 /*
802 * If nothing currently running, build a serial target, if any.
803 */
804 start_loop_1:
805 for (rp_prev = &running_list, rp = running_list;
806 rp != NULL && parallel_process_cnt == 0;
807 rp = rp->next) {
808 if (rp->state == build_serial) {
809 *rp_prev = rp->next;
810 if (rp->next == NULL) {
811 running_tail = rp_prev;
812 }
813 recursion_level = rp->recursion_level;
814 rp->target->state = build_pending;
815 (void) doname_check(rp->target,
816 rp->do_get,
817 rp->implicit,
818 false);
819 quiescent = false;
820 delete_running_struct(rp);
821 goto start_loop_1;
822 } else {
823 rp_prev = &rp->next;
824 }
825 }
826 /*
827 * Find a target to build. The target must be pending, have all
828 * its dependencies built, and not be in a target group with a target
829 * currently building.
830 */
831 start_loop_2:
832 for (rp_prev = &running_list, rp = running_list;
833 rp != NULL;
834 rp = rp->next) {
835 if (!(rp->state == build_pending ||
836 rp->state == build_subtree)) {
837 quiescent = false;
838 rp_prev = &rp->next;
839 } else if (rp->state == build_pending) {
840 line = get_prop(rp->target->prop, line_prop);
841 for (dep = line->body.line.dependencies;
842 dep != NULL;
843 dep = dep->next) {
844 if (dep->name->state == build_running ||
845 dep->name->state == build_pending ||
846 dep->name->state == build_serial) {
847 break;
848 }
849 }
850 if (dep == NULL) {
851 for (target_group = line->body.line.target_group;
852 target_group != NULL;
853 target_group = target_group->next) {
854 if (is_running(target_group->name)) {
855 break;
856 }
857 }
858 if (target_group == NULL) {
859 *rp_prev = rp->next;
860 if (rp->next == NULL) {
861 running_tail = rp_prev;
862 }
863 recursion_level = rp->recursion_level;
864 rp->target->state = rp->redo ?
865 build_dont_know : build_pending;
866 saved_commands_done = commands_done;
867 conditionals =
868 set_conditionals
869 (rp->conditional_cnt,
870 rp->conditional_targets);
871 rp->target->dont_activate_cond_values = true;
872 if ((doname_check(rp->target,
873 rp->do_get,
874 rp->implicit,
875 rp->target->has_target_prop ? true : false) !=
876 build_running) &&
877 !commands_done) {
878 commands_done =
879 saved_commands_done;
880 }
881 rp->target->dont_activate_cond_values = false;
882 reset_conditionals
883 (rp->conditional_cnt,
884 rp->conditional_targets,
885 conditionals);
886 quiescent = false;
887 delete_running_struct(rp);
888 goto start_loop_2;
889 } else {
890 rp_prev = &rp->next;
891 }
892 } else {
893 rp_prev = &rp->next;
894 }
895 } else {
896 rp_prev = &rp->next;
897 }
898 }
899 /*
900 * If nothing has been found to build and there exists a subtree
901 * target with no dependency conflicts, build it.
902 */
903 if (quiescent) {
904 start_loop_3:
905 for (rp_prev = &running_list, rp = running_list;
906 rp != NULL;
907 rp = rp->next) {
908 if (rp->state == build_subtree) {
909 if (!dependency_conflict(rp->target)) {
910 *rp_prev = rp->next;
911 if (rp->next == NULL) {
912 running_tail = rp_prev;
913 }
914 recursion_level = rp->recursion_level;
915 doname_subtree(rp->target,
916 rp->do_get,
917 rp->implicit);
918 quiescent = false;
919 delete_running_struct(rp);
920 goto start_loop_3;
921 } else {
922 subtree_target = rp_prev;
923 rp_prev = &rp->next;
924 }
925 } else {
926 rp_prev = &rp->next;
927 }
928 }
929 }
930 /*
931 * If still nothing found to build, we either have a deadlock
932 * or a subtree with a dependency conflict with something waiting
933 * to build.
934 */
935 if (quiescent) {
936 if (subtree_target == NULL) {
937 fatal(catgets(catd, 1, 126, "Internal error: deadlock detected in process_next"));
938 } else {
939 rp = *subtree_target;
940 if (debug_level > 0) {
941 warning(catgets(catd, 1, 127, "Conditional macro conflict encountered for %s between %s and %s"),
942 subtree_conflict2->string_mb,
943 rp->target->string_mb,
944 subtree_conflict->string_mb);
945 }
946 *subtree_target = (*subtree_target)->next;
947 if (rp->next == NULL) {
948 running_tail = subtree_target;
949 }
950 recursion_level = rp->recursion_level;
951 doname_subtree(rp->target, rp->do_get, rp->implicit);
952 delete_running_struct(rp);
953 }
954 }
955 }
956
957 /*
958 * set_conditionals(cnt, targets)
959 *
960 * Sets the conditional macros for the targets given in the array of
961 * targets. The old macro values are returned in an array of
962 * Properties for later resetting.
963 *
964 * Return value:
965 * Array of conditional macro settings
966 *
967 * Parameters:
968 * cnt Number of targets
969 * targets Array of targets
970 */
971 static Property *
972 set_conditionals(int cnt, Name *targets)
973 {
974 Property *locals, *lp;
975 Name *tp;
976
977 locals = (Property *) getmem(cnt * sizeof(Property));
978 for (lp = locals, tp = targets;
979 cnt > 0;
980 cnt--, lp++, tp++) {
981 *lp = (Property) getmem((*tp)->conditional_cnt *
982 sizeof(struct _Property));
983 set_locals(*tp, *lp);
984 }
985 return locals;
986 }
987
988 /*
989 * reset_conditionals(cnt, targets, locals)
990 *
991 * Resets the conditional macros as saved in the given array of
992 * Properties. The resets are done in reverse order. Afterwards the
993 * data structures are freed.
994 *
995 * Parameters:
996 * cnt Number of targets
997 * targets Array of targets
998 * locals Array of dependency macro settings
999 */
1000 static void
1001 reset_conditionals(int cnt, Name *targets, Property *locals)
1002 {
1003 Name *tp;
1004 Property *lp;
1005
1006 for (tp = targets + (cnt - 1), lp = locals + (cnt - 1);
1007 cnt > 0;
1008 cnt--, tp--, lp--) {
1009 reset_locals(*tp,
1010 *lp,
1011 get_prop((*tp)->prop, conditional_prop),
1012 0);
1013 retmem_mb((caddr_t) *lp);
1014 }
1015 retmem_mb((caddr_t) locals);
1016 }
1017
1018 /*
1019 * dependency_conflict(target)
1020 *
1021 * Returns true if there is an intersection between
1022 * the subtree of the target and any dependents of the pending targets.
1023 *
1024 * Return value:
1025 * True if conflict found
1026 *
1027 * Parameters:
1028 * target Subtree target to check
1029 *
1030 * Static variables used:
1031 * subtree_conflict Target conflict found
1032 * subtree_conflict2 Second conflict found
1033 *
1034 * Global variables used:
1035 * running_list List of running processes
1036 * wait_name .WAIT, not a real dependency
1037 */
1038 static Boolean
1039 dependency_conflict(Name target)
1040 {
1041 Property line;
1042 Property pending_line;
1043 Dependency dp;
1044 Dependency pending_dp;
1045 Running rp;
1046
1047 /* Return if we are already checking this target */
1048 if (target->checking_subtree) {
1049 return false;
1050 }
1051 target->checking_subtree = true;
1052 line = get_prop(target->prop, line_prop);
1053 if (line == NULL) {
1054 target->checking_subtree = false;
1055 return false;
1056 }
1057 /* Check each dependency of the target for conflicts */
1058 for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
1059 /* Ignore .WAIT dependency */
1060 if (dp->name == wait_name) {
1061 continue;
1062 }
1063 /*
1064 * For each pending target, look for a dependency which
1065 * is the same as a dependency of the subtree target. Since
1066 * we can't build the subtree until all pending targets have
1067 * finished which depend on the same dependency, this is
1068 * a conflict.
1069 */
1070 for (rp = running_list; rp != NULL; rp = rp->next) {
1071 if (rp->state == build_pending) {
1072 pending_line = get_prop(rp->target->prop,
1073 line_prop);
1074 if (pending_line == NULL) {
1075 continue;
1076 }
1077 for(pending_dp = pending_line->
1078 body.line.dependencies;
1079 pending_dp != NULL;
1080 pending_dp = pending_dp->next) {
1081 if (dp->name == pending_dp->name) {
1082 target->checking_subtree
1083 = false;
1084 subtree_conflict = rp->target;
1085 subtree_conflict2 = dp->name;
1086 return true;
1087 }
1088 }
1089 }
1090 }
1091 if (dependency_conflict(dp->name)) {
1092 target->checking_subtree = false;
1093 return true;
1094 }
1095 }
1096 target->checking_subtree = false;
1097 return false;
1098 }
1099
1100 /*
1101 * await_parallel(waitflg)
1102 *
1103 * Waits for parallel children to exit and finishes their processing.
1104 * If waitflg is false, the function returns after update_delay.
1105 *
1106 * Parameters:
1107 * waitflg dwight
1108 */
1109 void
1110 await_parallel(Boolean waitflg)
1111 {
1112 Boolean nohang;
1113 pid_t pid;
1114 int status;
1115 Running rp;
1116 int waiterr;
1117
1118 nohang = false;
1119 for ( ; ; ) {
1120 if (!nohang) {
1121 (void) alarm((int) update_delay);
1122 }
1123 pid = waitpid((pid_t)-1,
1124 &status,
1125 nohang ? WNOHANG : 0);
1126 waiterr = errno;
1127 if (!nohang) {
1128 (void) alarm(0);
1129 }
1130 if (pid <= 0) {
1131 if (waiterr == EINTR) {
1132 if (waitflg) {
1133 continue;
1134 } else {
1135 return;
1136 }
1137 } else {
1138 return;
1139 }
1140 }
1141 for (rp = running_list;
1142 (rp != NULL) && (rp->pid != pid);
1143 rp = rp->next) {
1144 ;
1145 }
1146 if (rp == NULL) {
1147 fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list"));
1148 } else {
1149 rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
1150 }
1151 nohang = true;
1152 parallel_process_cnt--;
1153
1154 #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
1155 if (job_adjust_mode == ADJUST_M2) {
1156 if (m2_release_job()) {
1157 job_adjust_error();
1158 }
1159 }
1160 #endif
1161 }
1162 }
1163
1164 /*
1165 * finish_children(docheck)
1166 *
1167 * Finishes the processing for all targets which were running
1168 * and have now completed.
1169 *
1170 * Parameters:
1171 * docheck Completely check the finished target
1172 *
1173 * Static variables used:
1174 * running_tail The tail of the running list
1175 *
1176 * Global variables used:
1177 * continue_after_error -k flag
1178 * fatal_in_progress True if we are finishing up after fatal err
1179 * running_list List of running processes
1180 */
1181 void
1182 finish_children(Boolean docheck)
1183 {
1184 int cmds_length;
1185 Property line;
1186 Property line2;
1187 struct stat out_buf;
1188 Running rp;
1189 Running *rp_prev;
1190 Cmd_line rule;
1191 Boolean silent_flag;
1192
1193 for (rp_prev = &running_list, rp = running_list;
1194 rp != NULL;
1195 rp = rp->next) {
1196 bypass_for_loop_inc_4:
1197 /*
1198 * If the state is ok or failed, then this target has
1199 * finished building.
1200 * In parallel_mode, output the accumulated stdout/stderr.
1201 * Read the auto dependency stuff, handle a failed build,
1202 * update the target, then finish the doname process for
1203 * that target.
1204 */
1205 if (rp->state == build_ok || rp->state == build_failed) {
1206 *rp_prev = rp->next;
1207 if (rp->next == NULL) {
1208 running_tail = rp_prev;
1209 }
1210 if ((line2 = rp->command) == NULL) {
1211 line2 = get_prop(rp->target->prop, line_prop);
1212 }
1213
1214
1215 /*
1216 * Check if there were any job output
1217 * from the parallel build.
1218 */
1219 if (rp->stdout_file != NULL) {
1220 if (stat(rp->stdout_file, &out_buf) < 0) {
1221 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1222 rp->stdout_file,
1223 errmsg(errno));
1224 }
1225
1226 if ((line2 != NULL) &&
1227 (out_buf.st_size > 0)) {
1228 cmds_length = 0;
1229 for (rule = line2->body.line.command_used,
1230 silent_flag = silent;
1231 rule != NULL;
1232 rule = rule->next) {
1233 cmds_length += rule->command_line->hash.length + 1;
1234 silent_flag = BOOLEAN(silent_flag || rule->silent);
1235 }
1236 if (out_buf.st_size != cmds_length || silent_flag ||
1237 output_mode == txt2_mode) {
1238 dump_out_file(rp->stdout_file, false);
1239 }
1240 }
1241 (void) unlink(rp->stdout_file);
1242 retmem_mb(rp->stdout_file);
1243 rp->stdout_file = NULL;
1244 }
1245
1246 if (!out_err_same && (rp->stderr_file != NULL)) {
1247 if (stat(rp->stderr_file, &out_buf) < 0) {
1248 fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
1249 rp->stderr_file,
1250 errmsg(errno));
1251 }
1252 if ((line2 != NULL) &&
1253 (out_buf.st_size > 0)) {
1254 dump_out_file(rp->stderr_file, true);
1255 }
1256 (void) unlink(rp->stderr_file);
1257 retmem_mb(rp->stderr_file);
1258 rp->stderr_file = NULL;
1259 }
1260
1261 check_state(rp->temp_file);
1262 if (rp->temp_file != NULL) {
1263 free_name(rp->temp_file);
1264 }
1265 rp->temp_file = NULL;
1266 if (rp->state == build_failed) {
1267 line = get_prop(rp->target->prop, line_prop);
1268 if (line != NULL) {
1269 line->body.line.command_used = NULL;
1270 }
1271 if (continue_after_error ||
1272 fatal_in_progress ||
1273 !docheck) {
1274 warning(catgets(catd, 1, 256, "Command failed for target `%s'"),
1275 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1276 build_failed_seen = true;
1277 } else {
1278 /*
1279 * XXX??? - DMake needs to exit(),
1280 * but shouldn't call fatal().
1281 */
1282 #ifdef PRINT_EXIT_STATUS
1283 warning(NOCATGETS("I'm in finish_children. rp->state == build_failed."));
1284 #endif
1285
1286 fatal(catgets(catd, 1, 258, "Command failed for target `%s'"),
1287 rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
1288 }
1289 }
1290 if (!docheck) {
1291 delete_running_struct(rp);
1292 rp = *rp_prev;
1293 if (rp == NULL) {
1294 break;
1295 } else {
1296 goto bypass_for_loop_inc_4;
1297 }
1298 }
1299 update_target(get_prop(rp->target->prop, line_prop),
1300 rp->state);
1301 finish_doname(rp);
1302 delete_running_struct(rp);
1303 rp = *rp_prev;
1304 if (rp == NULL) {
1305 break;
1306 } else {
1307 goto bypass_for_loop_inc_4;
1308 }
1309 } else {
1310 rp_prev = &rp->next;
1311 }
1312 }
1313 }
1314
1315 /*
1316 * dump_out_file(filename, err)
1317 *
1318 * Write the contents of the file to stdout, then unlink the file.
1319 *
1320 * Parameters:
1321 * filename Name of temp file containing output
1322 *
1323 * Global variables used:
1324 */
1325 static void
1326 dump_out_file(char *filename, Boolean err)
1327 {
1328 int chars_read;
1329 char copybuf[BUFSIZ];
1330 int fd;
1331 int out_fd = (err ? 2 : 1);
1332
1333 if ((fd = open(filename, O_RDONLY)) < 0) {
1334 fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"),
1335 filename,
1336 errmsg(errno));
1337 }
1338 if (!silent && output_mode != txt2_mode) {
1339 (void) fprintf(err ? stderr : stdout,
1340 err ?
1341 catgets(catd, 1, 338, "%s --> Job errors\n") :
1342 catgets(catd, 1, 259, "%s --> Job output\n"),
1343 local_host);
1344 (void) fflush(err ? stderr : stdout);
1345 }
1346 for (chars_read = read(fd, copybuf, BUFSIZ);
1347 chars_read > 0;
1348 chars_read = read(fd, copybuf, BUFSIZ)) {
1349 /*
1350 * Read buffers from the source file until end or error.
1351 */
1352 if (write(out_fd, copybuf, chars_read) < 0) {
1353 fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"),
1354 filename,
1355 errmsg(errno));
1356 }
1357 }
1358 (void) close(fd);
1359 (void) unlink(filename);
1360 }
1361
1362 /*
1363 * finish_doname(rp)
1364 *
1365 * Completes the processing for a target which was left running.
1366 *
1367 * Parameters:
1368 * rp Running list entry for target
1369 *
1370 * Global variables used:
1371 * debug_level Debug flag
1372 * recursion_level Indentation for debug output
1373 */
1374 static void
1375 finish_doname(Running rp)
1376 {
1377 int auto_count = rp->auto_count;
1378 Name *automatics = rp->automatics;
1379 Doname result = rp->state;
1380 Name target = rp->target;
1381 Name true_target = rp->true_target;
1382 Property *conditionals;
1383
1384 recursion_level = rp->recursion_level;
1385 if (result == build_ok) {
1386 if (true_target == NULL) {
1387 (void) printf(NOCATGETS("Target = %s\n"), target->string_mb);
1388 (void) printf(NOCATGETS(" State = %d\n"), result);
1389 fatal(NOCATGETS("Internal error: NULL true_target in finish_doname"));
1390 }
1391 /* If all went OK, set a nice timestamp */
1392 if (true_target->stat.time == file_doesnt_exist) {
1393 true_target->stat.time = file_max_time;
1394 }
1395 }
1396 target->state = result;
1397 if (target->is_member) {
1398 Property member;
1399
1400 /* Propagate the timestamp from the member file to the member */
1401 if ((target->stat.time != file_max_time) &&
1402 ((member = get_prop(target->prop, member_prop)) != NULL) &&
1403 (exists(member->body.member.member) > file_doesnt_exist)) {
1404 target->stat.time =
1405 /*
1406 exists(member->body.member.member);
1407 */
1408 member->body.member.member->stat.time;
1409 }
1410 }
1411 /*
1412 * Check if we found any new auto dependencies when we
1413 * built the target.
1414 */
1415 if ((result == build_ok) && check_auto_dependencies(target,
1416 auto_count,
1417 automatics)) {
1418 if (debug_level > 0) {
1419 (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
1420 recursion_level,
1421 "",
1422 true_target->string_mb);
1423 }
1424 target->rechecking_target = true;
1425 target->state = build_running;
1426
1427 /* [tolik, Tue Mar 25 1997]
1428 * Fix for bug 4038824:
1429 * command line options set by conditional macros get dropped
1430 * rp->conditional_cnt and rp->conditional_targets must be copied
1431 * to new 'rp' during add_pending(). Set_conditionals() stores
1432 * rp->conditional_targets to the global variable 'conditional_targets'
1433 * Add_pending() will use this variable to set up 'rp'.
1434 */
1435 conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
1436 add_pending(target,
1437 recursion_level,
1438 rp->do_get,
1439 rp->implicit,
1440 true);
1441 reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
1442 }
1443 }
1444
1445 /*
1446 * new_running_struct()
1447 *
1448 * Constructor for Running struct. Creates a structure and initializes
1449 * its fields.
1450 *
1451 */
1452 static Running new_running_struct()
1453 {
1454 Running rp;
1455
1456 rp = ALLOC(Running);
1457 rp->target = NULL;
1458 rp->true_target = NULL;
1459 rp->command = NULL;
1460 rp->sprodep_value = NULL;
1461 rp->sprodep_env = NULL;
1462 rp->auto_count = 0;
1463 rp->automatics = NULL;
1464 rp->pid = -1;
1465 rp->job_msg_id = -1;
1466 rp->stdout_file = NULL;
1467 rp->stderr_file = NULL;
1468 rp->temp_file = NULL;
1469 rp->next = NULL;
1470 return rp;
1471 }
1472
1473 /*
1474 * add_running(target, true_target, command, recursion_level, auto_count,
1475 * automatics, do_get, implicit)
1476 *
1477 * Adds a record on the running list for this target, which
1478 * was just spawned and is running.
1479 *
1480 * Parameters:
1481 * target Target being built
1482 * true_target True target for target
1483 * command Running command.
1484 * recursion_level Debug indentation level
1485 * auto_count Count of automatic dependencies
1486 * automatics List of automatic dependencies
1487 * do_get Sccs get flag
1488 * implicit Implicit flag
1489 *
1490 * Static variables used:
1491 * running_tail Tail of running list
1492 * process_running PID of process
1493 *
1494 * Global variables used:
1495 * current_line Current line for target
1496 * current_target Current target being built
1497 * stderr_file Temporary file for stdout
1498 * stdout_file Temporary file for stdout
1499 * temp_file_name Temporary file for auto dependencies
1500 */
1501 void
1502 add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
1503 {
1504 Running rp;
1505 Name *p;
1506
1507 rp = new_running_struct();
1508 rp->state = build_running;
1509 rp->target = target;
1510 rp->true_target = true_target;
1511 rp->command = command;
1512 rp->recursion_level = recursion_level;
1513 rp->do_get = do_get;
1514 rp->implicit = implicit;
1515 rp->auto_count = auto_count;
1516 if (auto_count > 0) {
1517 rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
1518 for (p = rp->automatics; auto_count > 0; auto_count--) {
1519 *p++ = *automatics++;
1520 }
1521 } else {
1522 rp->automatics = NULL;
1523 }
1524 {
1525 rp->pid = process_running;
1526 process_running = -1;
1527 childPid = -1;
1528 }
1529 rp->job_msg_id = job_msg_id;
1530 rp->stdout_file = stdout_file;
1531 rp->stderr_file = stderr_file;
1532 rp->temp_file = temp_file_name;
1533 rp->redo = false;
1534 rp->next = NULL;
1535 store_conditionals(rp);
1536 stdout_file = NULL;
1537 stderr_file = NULL;
1538 temp_file_name = NULL;
1539 current_target = NULL;
1540 current_line = NULL;
1541 *running_tail = rp;
1542 running_tail = &rp->next;
1543 }
1544
1545 /*
1546 * add_pending(target, recursion_level, do_get, implicit, redo)
1547 *
1548 * Adds a record on the running list for a pending target
1549 * (waiting for its dependents to finish running).
1550 *
1551 * Parameters:
1552 * target Target being built
1553 * recursion_level Debug indentation level
1554 * do_get Sccs get flag
1555 * implicit Implicit flag
1556 * redo True if this target is being redone
1557 *
1558 * Static variables used:
1559 * running_tail Tail of running list
1560 */
1561 void
1562 add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
1563 {
1564 Running rp;
1565 rp = new_running_struct();
1566 rp->state = build_pending;
1567 rp->target = target;
1568 rp->recursion_level = recursion_level;
1569 rp->do_get = do_get;
1570 rp->implicit = implicit;
1571 rp->redo = redo;
1572 store_conditionals(rp);
1573 *running_tail = rp;
1574 running_tail = &rp->next;
1575 }
1576
1577 /*
1578 * add_serial(target, recursion_level, do_get, implicit)
1579 *
1580 * Adds a record on the running list for a target which must be
1581 * executed in serial after others have finished.
1582 *
1583 * Parameters:
1584 * target Target being built
1585 * recursion_level Debug indentation level
1586 * do_get Sccs get flag
1587 * implicit Implicit flag
1588 *
1589 * Static variables used:
1590 * running_tail Tail of running list
1591 */
1592 void
1593 add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1594 {
1595 Running rp;
1596
1597 rp = new_running_struct();
1598 rp->target = target;
1599 rp->recursion_level = recursion_level;
1600 rp->do_get = do_get;
1601 rp->implicit = implicit;
1602 rp->state = build_serial;
1603 rp->redo = false;
1604 store_conditionals(rp);
1605 *running_tail = rp;
1606 running_tail = &rp->next;
1607 }
1608
1609 /*
1610 * add_subtree(target, recursion_level, do_get, implicit)
1611 *
1612 * Adds a record on the running list for a target which must be
1613 * executed in isolation after others have finished.
1614 *
1615 * Parameters:
1616 * target Target being built
1617 * recursion_level Debug indentation level
1618 * do_get Sccs get flag
1619 * implicit Implicit flag
1620 *
1621 * Static variables used:
1622 * running_tail Tail of running list
1623 */
1624 void
1625 add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
1626 {
1627 Running rp;
1628
1629 rp = new_running_struct();
1630 rp->target = target;
1631 rp->recursion_level = recursion_level;
1632 rp->do_get = do_get;
1633 rp->implicit = implicit;
1634 rp->state = build_subtree;
1635 rp->redo = false;
1636 store_conditionals(rp);
1637 *running_tail = rp;
1638 running_tail = &rp->next;
1639 }
1640
1641 /*
1642 * store_conditionals(rp)
1643 *
1644 * Creates an array of the currently active targets with conditional
1645 * macros (found in the chain conditional_targets) and puts that
1646 * array in the Running struct.
1647 *
1648 * Parameters:
1649 * rp Running struct for storing chain
1650 *
1651 * Global variables used:
1652 * conditional_targets Chain of current dynamic conditionals
1653 */
1654 static void
1655 store_conditionals(Running rp)
1656 {
1657 int cnt;
1658 Chain cond_name;
1659
1660 if (conditional_targets == NULL) {
1661 rp->conditional_cnt = 0;
1662 rp->conditional_targets = NULL;
1663 return;
1664 }
1665 cnt = 0;
1666 for (cond_name = conditional_targets;
1667 cond_name != NULL;
1668 cond_name = cond_name->next) {
1669 cnt++;
1670 }
1671 rp->conditional_cnt = cnt;
1672 rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
1673 for (cond_name = conditional_targets;
1674 cond_name != NULL;
1675 cond_name = cond_name->next) {
1676 rp->conditional_targets[--cnt] = cond_name->name;
1677 }
1678 }
1679
1680 /*
1681 * parallel_ok(target, line_prop_must_exists)
1682 *
1683 * Returns true if the target can be run in parallel
1684 *
1685 * Return value:
1686 * True if can run in parallel
1687 *
1688 * Parameters:
1689 * target Target being tested
1690 *
1691 * Global variables used:
1692 * all_parallel True if all targets default to parallel
1693 * only_parallel True if no targets default to parallel
1694 */
1695 Boolean
1696 parallel_ok(Name target, Boolean line_prop_must_exists)
1697 {
1698 Boolean assign;
1699 Boolean make_refd;
1700 Property line;
1701 Cmd_line rule;
1702
1703 assign = make_refd = false;
1704 if (((line = get_prop(target->prop, line_prop)) == NULL) &&
1705 line_prop_must_exists) {
1706 return false;
1707 }
1708 if (line != NULL) {
1709 for (rule = line->body.line.command_used;
1710 rule != NULL;
1711 rule = rule->next) {
1712 if (rule->assign) {
1713 assign = true;
1714 } else if (rule->make_refd) {
1715 make_refd = true;
1716 }
1717 }
1718 }
1719 if (assign) {
1720 return false;
1721 } else if (target->parallel) {
1722 return true;
1723 } else if (target->no_parallel) {
1724 return false;
1725 } else if (all_parallel) {
1726 return true;
1727 } else if (only_parallel) {
1728 return false;
1729 } else if (make_refd) {
1730 return false;
1731 } else {
1732 return true;
1733 }
1734 }
1735
1736 /*
1737 * is_running(target)
1738 *
1739 * Returns true if the target is running.
1740 *
1741 * Return value:
1742 * True if target is running
1743 *
1744 * Parameters:
1745 * target Target to check
1746 *
1747 * Global variables used:
1748 * running_list List of running processes
1749 */
1750 Boolean
1751 is_running(Name target)
1752 {
1753 Running rp;
1754
1755 if (target->state != build_running) {
1756 return false;
1757 }
1758 for (rp = running_list;
1759 rp != NULL && target != rp->target;
1760 rp = rp->next);
1761 if (rp == NULL) {
1762 return false;
1763 } else {
1764 return (rp->state == build_running) ? true : false;
1765 }
1766 }
1767
1768 /*
1769 * This function replaces the makesh binary.
1770 */
1771
1772
1773 static pid_t
1774 run_rule_commands(char *host, char **commands)
1775 {
1776 Boolean always_exec;
1777 Name command;
1778 Boolean ignore;
1779 int length;
1780 Doname result;
1781 Boolean silent_flag;
1782 wchar_t *tmp_wcs_buffer;
1783
1784 childPid = fork();
1785 switch (childPid) {
1786 case -1: /* Error */
1787 fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"),
1788 errmsg(errno));
1789 break;
1790 case 0: /* Child */
1791 /* To control the processed targets list is not the child's business */
1792 running_list = NULL;
1793 if(out_err_same) {
1794 redirect_io(stdout_file, (char*)NULL);
1795 } else {
1796 redirect_io(stdout_file, stderr_file);
1797 }
1798 for (commands = commands;
1799 (*commands != (char *)NULL);
1800 commands++) {
1801 silent_flag = silent;
1802 ignore = false;
1803 always_exec = false;
1804 while ((**commands == (int) at_char) ||
1805 (**commands == (int) hyphen_char) ||
1806 (**commands == (int) plus_char)) {
1807 if (**commands == (int) at_char) {
1808 silent_flag = true;
1809 }
1810 if (**commands == (int) hyphen_char) {
1811 ignore = true;
1812 }
1813 if (**commands == (int) plus_char) {
1814 always_exec = true;
1815 }
1816 (*commands)++;
1817 }
1818 if ((length = strlen(*commands)) >= MAXPATHLEN) {
1819 tmp_wcs_buffer = ALLOC_WC(length + 1);
1820 (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
1821 command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
1822 retmem(tmp_wcs_buffer);
1823 } else {
1824 MBSTOWCS(wcs_buffer, *commands);
1825 command = GETNAME(wcs_buffer, FIND_LENGTH);
1826 }
1827 if ((command->hash.length > 0) &&
1828 !silent_flag) {
1829 (void) printf("%s\n", command->string_mb);
1830 }
1831 result = dosys(command,
1832 ignore,
1833 false,
1834 false, /* bugs #4085164 & #4990057 */
1835 /* BOOLEAN(silent_flag && ignore), */
1836 always_exec,
1837 (Name) NULL);
1838 if (result == build_failed) {
1839 if (silent_flag) {
1840 (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb);
1841 }
1842 if (!ignore) {
1843 _exit(1);
1844 }
1845 }
1846 }
1847 _exit(0);
1848 break;
1849 default:
1850 break;
1851 }
1852 return childPid;
1853 }
1854
1855 static void
1856 maybe_reread_make_state(void)
1857 {
1858 /* Copying dosys()... */
1859 if (report_dependencies_level == 0) {
1860 make_state->stat.time = file_no_time;
1861 (void) exists(make_state);
1862 if (make_state_before == make_state->stat.time) {
1863 return;
1864 }
1865 makefile_type = reading_statefile;
1866 if (read_trace_level > 1) {
1867 trace_reader = true;
1868 }
1869 temp_file_number++;
1870 (void) read_simple_file(make_state,
1871 false,
1872 false,
1873 false,
1874 false,
1875 false,
1876 true);
1877 trace_reader = false;
1878 }
1879 }
1880
1881
1882 static void
1883 delete_running_struct(Running rp)
1884 {
1885 if ((rp->conditional_cnt > 0) &&
1886 (rp->conditional_targets != NULL)) {
1887 retmem_mb((char *) rp->conditional_targets);
1888 }
1889 /**/
1890 if ((rp->auto_count > 0) &&
1891 (rp->automatics != NULL)) {
1892 retmem_mb((char *) rp->automatics);
1893 }
1894 /**/
1895 if(rp->sprodep_value) {
1896 free_name(rp->sprodep_value);
1897 }
1898 if(rp->sprodep_env) {
1899 retmem_mb(rp->sprodep_env);
1900 }
1901 retmem_mb((char *) rp);
1902
1903 }
1904
1905