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