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