xref: /titanic_44/usr/src/cmd/make/bin/parallel.cc (revision 10d63b7db37a83b39c7f511cf9426c9d03ea0760)
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