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