xref: /illumos-gate/usr/src/cmd/make/bin/parallel.cc (revision ae389aa9)
110d63b7dSRichard Lowe /*
210d63b7dSRichard Lowe  * CDDL HEADER START
310d63b7dSRichard Lowe  *
410d63b7dSRichard Lowe  * The contents of this file are subject to the terms of the
510d63b7dSRichard Lowe  * Common Development and Distribution License (the "License").
610d63b7dSRichard Lowe  * You may not use this file except in compliance with the License.
710d63b7dSRichard Lowe  *
810d63b7dSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910d63b7dSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
1010d63b7dSRichard Lowe  * See the License for the specific language governing permissions
1110d63b7dSRichard Lowe  * and limitations under the License.
1210d63b7dSRichard Lowe  *
1310d63b7dSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
1410d63b7dSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510d63b7dSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
1610d63b7dSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
1710d63b7dSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
1810d63b7dSRichard Lowe  *
1910d63b7dSRichard Lowe  * CDDL HEADER END
2010d63b7dSRichard Lowe  */
2110d63b7dSRichard Lowe /*
2210d63b7dSRichard Lowe  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
2310d63b7dSRichard Lowe  * Use is subject to license terms.
2410d63b7dSRichard Lowe  */
2510d63b7dSRichard Lowe 
2610d63b7dSRichard Lowe 
2710d63b7dSRichard Lowe /*
2810d63b7dSRichard Lowe  *	parallel.cc
2910d63b7dSRichard Lowe  *
3010d63b7dSRichard Lowe  *	Deal with the parallel processing
3110d63b7dSRichard Lowe  */
3210d63b7dSRichard Lowe 
3310d63b7dSRichard Lowe /*
3410d63b7dSRichard Lowe  * Included files
3510d63b7dSRichard Lowe  */
3610d63b7dSRichard Lowe #include <errno.h>		/* errno */
3710d63b7dSRichard Lowe #include <fcntl.h>
3810d63b7dSRichard Lowe #include <mk/defs.h>
3910d63b7dSRichard Lowe #include <mksh/dosys.h>		/* redirect_io() */
4010d63b7dSRichard Lowe #include <mksh/macro.h>		/* expand_value() */
4110d63b7dSRichard Lowe #include <mksh/misc.h>		/* getmem() */
4210d63b7dSRichard Lowe #include <sys/signal.h>
4310d63b7dSRichard Lowe #include <sys/stat.h>
4410d63b7dSRichard Lowe #include <sys/types.h>
4510d63b7dSRichard Lowe #include <sys/utsname.h>
4610d63b7dSRichard Lowe #include <sys/wait.h>
4710d63b7dSRichard Lowe #include <unistd.h>
4810d63b7dSRichard Lowe #include <netdb.h>
4910d63b7dSRichard Lowe #include <libintl.h>
5010d63b7dSRichard Lowe 
5110d63b7dSRichard Lowe 
5210d63b7dSRichard Lowe 
5310d63b7dSRichard Lowe /*
5410d63b7dSRichard Lowe  * Defined macros
5510d63b7dSRichard Lowe  */
5610d63b7dSRichard Lowe #define MAXRULES		100
5710d63b7dSRichard Lowe 
5810d63b7dSRichard Lowe /*
5910d63b7dSRichard Lowe  * This const should be in avo_dms/include/AvoDmakeCommand.h
6010d63b7dSRichard Lowe  */
6110d63b7dSRichard Lowe const int local_host_mask = 0x20;
6210d63b7dSRichard Lowe 
6310d63b7dSRichard Lowe 
6410d63b7dSRichard Lowe /*
6510d63b7dSRichard Lowe  * typedefs & structs
6610d63b7dSRichard Lowe  */
6710d63b7dSRichard Lowe 
6810d63b7dSRichard Lowe 
6910d63b7dSRichard Lowe /*
7010d63b7dSRichard Lowe  * Static variables
7110d63b7dSRichard Lowe  */
7210d63b7dSRichard Lowe static	Boolean		just_did_subtree = false;
7310d63b7dSRichard Lowe static	char		local_host[MAXNAMELEN] = "";
7410d63b7dSRichard Lowe static	char		user_name[MAXNAMELEN] = "";
7510d63b7dSRichard Lowe static	int		pmake_max_jobs = 0;
7610d63b7dSRichard Lowe static	pid_t		process_running = -1;
7710d63b7dSRichard Lowe static	Running		*running_tail = &running_list;
7810d63b7dSRichard Lowe static	Name		subtree_conflict;
7910d63b7dSRichard Lowe static	Name		subtree_conflict2;
8010d63b7dSRichard Lowe 
8110d63b7dSRichard Lowe 
8210d63b7dSRichard Lowe /*
8310d63b7dSRichard Lowe  * File table of contents
8410d63b7dSRichard Lowe  */
8510d63b7dSRichard Lowe static	void		delete_running_struct(Running rp);
8610d63b7dSRichard Lowe static	Boolean		dependency_conflict(Name target);
8710d63b7dSRichard Lowe static	Doname		distribute_process(char **commands, Property line);
8810d63b7dSRichard Lowe static	void		doname_subtree(Name target, Boolean do_get, Boolean implicit);
8910d63b7dSRichard Lowe static	void		dump_out_file(char *filename, Boolean err);
9010d63b7dSRichard Lowe static	void		finish_doname(Running rp);
9110d63b7dSRichard Lowe static	void		maybe_reread_make_state(void);
9210d63b7dSRichard Lowe static	void		process_next(void);
9310d63b7dSRichard Lowe static	void		reset_conditionals(int cnt, Name *targets, Property *locals);
9410d63b7dSRichard Lowe static	pid_t           run_rule_commands(char *host, char **commands);
9510d63b7dSRichard Lowe static	Property	*set_conditionals(int cnt, Name *targets);
9610d63b7dSRichard Lowe static	void		store_conditionals(Running rp);
9710d63b7dSRichard Lowe 
9810d63b7dSRichard Lowe 
9910d63b7dSRichard Lowe /*
10010d63b7dSRichard Lowe  *	execute_parallel(line, waitflg)
10110d63b7dSRichard Lowe  *
10210d63b7dSRichard Lowe  *	DMake 2.x:
10310d63b7dSRichard Lowe  *	parallel mode: spawns a parallel process to execute the command group.
10410d63b7dSRichard Lowe  *
10510d63b7dSRichard Lowe  *	Return value:
10610d63b7dSRichard Lowe  *				The result of the execution
10710d63b7dSRichard Lowe  *
10810d63b7dSRichard Lowe  *	Parameters:
10910d63b7dSRichard Lowe  *		line		The command group to execute
11010d63b7dSRichard Lowe  */
11110d63b7dSRichard Lowe Doname
execute_parallel(Property line,Boolean waitflg,Boolean local)11210d63b7dSRichard Lowe execute_parallel(Property line, Boolean waitflg, Boolean local)
11310d63b7dSRichard Lowe {
11410d63b7dSRichard Lowe 	int			argcnt;
11510d63b7dSRichard Lowe 	int			cmd_options = 0;
11610d63b7dSRichard Lowe 	char			*commands[MAXRULES + 5];
11710d63b7dSRichard Lowe 	char			*cp;
11810d63b7dSRichard Lowe 	Name			dmake_name;
11910d63b7dSRichard Lowe 	Name			dmake_value;
12010d63b7dSRichard Lowe 	int			ignore;
12110d63b7dSRichard Lowe 	Name			make_machines_name;
12210d63b7dSRichard Lowe 	char			**p;
12310d63b7dSRichard Lowe 	Property		prop;
12410d63b7dSRichard Lowe 	Doname			result = build_ok;
12510d63b7dSRichard Lowe 	Cmd_line		rule;
12610d63b7dSRichard Lowe 	Boolean			silent_flag;
12710d63b7dSRichard Lowe 	Name			target = line->body.line.target;
12810d63b7dSRichard Lowe 	Boolean			wrote_state_file = false;
12910d63b7dSRichard Lowe 
13010d63b7dSRichard Lowe 	if ((pmake_max_jobs == 0) &&
13110d63b7dSRichard Lowe 	    (dmake_mode_type == parallel_mode)) {
13210d63b7dSRichard Lowe 		if (local_host[0] == '\0') {
13310d63b7dSRichard Lowe 			(void) gethostname(local_host, MAXNAMELEN);
13410d63b7dSRichard Lowe 		}
13510d63b7dSRichard Lowe 		MBSTOWCS(wcs_buffer, "DMAKE_MAX_JOBS");
13610d63b7dSRichard Lowe 		dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
13710d63b7dSRichard Lowe 		if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
13810d63b7dSRichard Lowe 		    ((dmake_value = prop->body.macro.value) != NULL)) {
13910d63b7dSRichard Lowe 			pmake_max_jobs = atoi(dmake_value->string_mb);
14010d63b7dSRichard Lowe 			if (pmake_max_jobs <= 0) {
14110d63b7dSRichard Lowe 				warning(gettext("DMAKE_MAX_JOBS cannot be less than or equal to zero."));
14210d63b7dSRichard Lowe 				warning(gettext("setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
14310d63b7dSRichard Lowe 				pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
14410d63b7dSRichard Lowe 			}
14510d63b7dSRichard Lowe 		} else {
14610d63b7dSRichard Lowe 			/*
14710d63b7dSRichard Lowe 			 * For backwards compatibility w/ PMake 1.x, when
14810d63b7dSRichard Lowe 			 * DMake 2.x is being run in parallel mode, DMake
14910d63b7dSRichard Lowe 			 * should parse the PMake startup file
15010d63b7dSRichard Lowe 			 * $(HOME)/.make.machines to get the pmake_max_jobs.
15110d63b7dSRichard Lowe 			 */
15210d63b7dSRichard Lowe 			MBSTOWCS(wcs_buffer, "PMAKE_MACHINESFILE");
15310d63b7dSRichard Lowe 			dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
15410d63b7dSRichard Lowe 			if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
15510d63b7dSRichard Lowe 			    ((dmake_value = prop->body.macro.value) != NULL)) {
15610d63b7dSRichard Lowe 				make_machines_name = dmake_value;
15710d63b7dSRichard Lowe 			} else {
15810d63b7dSRichard Lowe 				make_machines_name = NULL;
15910d63b7dSRichard Lowe 			}
16010d63b7dSRichard Lowe 			if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
16110d63b7dSRichard Lowe 				pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
16210d63b7dSRichard Lowe 			}
16310d63b7dSRichard Lowe 		}
16410d63b7dSRichard Lowe 	}
16510d63b7dSRichard Lowe 
16610d63b7dSRichard Lowe 	if ((dmake_mode_type == serial_mode) ||
16710d63b7dSRichard Lowe 	    ((dmake_mode_type == parallel_mode) && (waitflg))) {
16810d63b7dSRichard Lowe 		return (execute_serial(line));
16910d63b7dSRichard Lowe 	}
17010d63b7dSRichard Lowe 
17110d63b7dSRichard Lowe 	{
17210d63b7dSRichard Lowe 		p = commands;
17310d63b7dSRichard Lowe 	}
17410d63b7dSRichard Lowe 
17510d63b7dSRichard Lowe 	argcnt = 0;
17610d63b7dSRichard Lowe 	for (rule = line->body.line.command_used;
17710d63b7dSRichard Lowe 	     rule != NULL;
17810d63b7dSRichard Lowe 	     rule = rule->next) {
17910d63b7dSRichard Lowe 		if (posix && (touch || quest) && !rule->always_exec) {
18010d63b7dSRichard Lowe 			continue;
18110d63b7dSRichard Lowe 		}
18210d63b7dSRichard Lowe 		if (vpath_defined) {
18310d63b7dSRichard Lowe 			rule->command_line =
18410d63b7dSRichard Lowe 			  vpath_translation(rule->command_line);
18510d63b7dSRichard Lowe 		}
186*ae389aa9SAndy Fiddaman 
18710d63b7dSRichard Lowe 		silent_flag = false;
18810d63b7dSRichard Lowe 		ignore = 0;
18910d63b7dSRichard Lowe 
19010d63b7dSRichard Lowe 		if (rule->command_line->hash.length > 0) {
19110d63b7dSRichard Lowe 			if (++argcnt == MAXRULES) {
19210d63b7dSRichard Lowe 				return build_serial;
19310d63b7dSRichard Lowe 			}
19410d63b7dSRichard Lowe 			{
19510d63b7dSRichard Lowe 				if (rule->silent && !silent) {
19610d63b7dSRichard Lowe 					silent_flag = true;
19710d63b7dSRichard Lowe 				}
19810d63b7dSRichard Lowe 				if (rule->ignore_error) {
19910d63b7dSRichard Lowe 					ignore++;
20010d63b7dSRichard Lowe 				}
20110d63b7dSRichard Lowe 				/* XXX - need to add support for + prefix */
20210d63b7dSRichard Lowe 				if (silent_flag || ignore) {
20310d63b7dSRichard Lowe 					*p = getmem((silent_flag ? 1 : 0) +
20410d63b7dSRichard Lowe 						    ignore +
20510d63b7dSRichard Lowe 						    (strlen(rule->
20610d63b7dSRichard Lowe 						           command_line->
20710d63b7dSRichard Lowe 						           string_mb)) +
20810d63b7dSRichard Lowe 						    1);
20910d63b7dSRichard Lowe 					cp = *p++;
21010d63b7dSRichard Lowe 					if (silent_flag) {
21110d63b7dSRichard Lowe 						*cp++ = (int) at_char;
21210d63b7dSRichard Lowe 					}
21310d63b7dSRichard Lowe 					if (ignore) {
21410d63b7dSRichard Lowe 						*cp++ = (int) hyphen_char;
21510d63b7dSRichard Lowe 					}
21610d63b7dSRichard Lowe 					(void) strcpy(cp, rule->command_line->string_mb);
21710d63b7dSRichard Lowe 				} else {
21810d63b7dSRichard Lowe 					*p++ = rule->command_line->string_mb;
21910d63b7dSRichard Lowe 				}
22010d63b7dSRichard Lowe 			}
22110d63b7dSRichard Lowe 		}
22210d63b7dSRichard Lowe 	}
22310d63b7dSRichard Lowe 	if ((argcnt == 0) ||
22410d63b7dSRichard Lowe 	    (report_dependencies_level > 0)) {
22510d63b7dSRichard Lowe 		return build_ok;
22610d63b7dSRichard Lowe 	}
22710d63b7dSRichard Lowe 	{
22810d63b7dSRichard Lowe 		*p = NULL;
22910d63b7dSRichard Lowe 
23010d63b7dSRichard Lowe 		Doname res = distribute_process(commands, line);
23110d63b7dSRichard Lowe 		if (res == build_running) {
23210d63b7dSRichard Lowe 			parallel_process_cnt++;
23310d63b7dSRichard Lowe 		}
23410d63b7dSRichard Lowe 
23510d63b7dSRichard Lowe 		/*
23610d63b7dSRichard Lowe 		 * Return only those memory that were specially allocated
23710d63b7dSRichard Lowe 		 * for part of commands.
23810d63b7dSRichard Lowe 		 */
23910d63b7dSRichard Lowe 		for (int i = 0; commands[i] != NULL; i++) {
24010d63b7dSRichard Lowe 			if ((commands[i][0] == (int) at_char) ||
24110d63b7dSRichard Lowe 			    (commands[i][0] == (int) hyphen_char)) {
24210d63b7dSRichard Lowe 				retmem_mb(commands[i]);
24310d63b7dSRichard Lowe 			}
24410d63b7dSRichard Lowe 		}
24510d63b7dSRichard Lowe 		return res;
24610d63b7dSRichard Lowe 	}
24710d63b7dSRichard Lowe }
24810d63b7dSRichard Lowe 
24910d63b7dSRichard Lowe 
25010d63b7dSRichard Lowe 
25110d63b7dSRichard Lowe #include <unistd.h>	/* sysconf(_SC_NPROCESSORS_ONLN) */
25210d63b7dSRichard Lowe #include <sys/ipc.h>		/* ftok() */
25310d63b7dSRichard Lowe #include <sys/shm.h>		/* shmget(), shmat(), shmdt(), shmctl() */
25410d63b7dSRichard Lowe #include <semaphore.h>		/* sem_init(), sem_trywait(), sem_post(), sem_destroy() */
25510d63b7dSRichard Lowe #include <sys/loadavg.h>	/* getloadavg() */
25610d63b7dSRichard Lowe 
25710d63b7dSRichard Lowe /*
25810d63b7dSRichard Lowe  *	adjust_pmake_max_jobs (int pmake_max_jobs)
25910d63b7dSRichard Lowe  *
26010d63b7dSRichard Lowe  *	Parameters:
261*ae389aa9SAndy Fiddaman  *		pmake_max_jobs	- max jobs limit set by user
26210d63b7dSRichard Lowe  *
26310d63b7dSRichard Lowe  *	External functions used:
26410d63b7dSRichard Lowe  *		sysconf()
265*ae389aa9SAndy Fiddaman  *		getloadavg()
26610d63b7dSRichard Lowe  */
26710d63b7dSRichard Lowe static int
adjust_pmake_max_jobs(int pmake_max_jobs)26810d63b7dSRichard Lowe adjust_pmake_max_jobs (int pmake_max_jobs)
26910d63b7dSRichard Lowe {
27010d63b7dSRichard Lowe 	static int	ncpu = 0;
27110d63b7dSRichard Lowe 	double		loadavg[3];
27210d63b7dSRichard Lowe 	int		adjustment;
27310d63b7dSRichard Lowe 	int		adjusted_max_jobs;
27410d63b7dSRichard Lowe 
27510d63b7dSRichard Lowe 	if (ncpu <= 0) {
27610d63b7dSRichard Lowe 		if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) {
27710d63b7dSRichard Lowe 			ncpu = 1;
27810d63b7dSRichard Lowe 		}
27910d63b7dSRichard Lowe 	}
28010d63b7dSRichard Lowe 	if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs);
28110d63b7dSRichard Lowe 	adjustment = ((int)loadavg[LOADAVG_1MIN]);
28210d63b7dSRichard Lowe 	if (adjustment < 2) return(pmake_max_jobs);
28310d63b7dSRichard Lowe 	if (ncpu > 1) {
28410d63b7dSRichard Lowe 		adjustment = adjustment / ncpu;
28510d63b7dSRichard Lowe 	}
28610d63b7dSRichard Lowe 	adjusted_max_jobs = pmake_max_jobs - adjustment;
28710d63b7dSRichard Lowe 	if (adjusted_max_jobs < 1) adjusted_max_jobs = 1;
28810d63b7dSRichard Lowe 	return(adjusted_max_jobs);
28910d63b7dSRichard Lowe }
29010d63b7dSRichard Lowe 
29110d63b7dSRichard Lowe /*
29210d63b7dSRichard Lowe  *  M2 adjust mode data and functions
29310d63b7dSRichard Lowe  *
29410d63b7dSRichard Lowe  *  m2_init()		- initializes M2 shared semaphore
29510d63b7dSRichard Lowe  *  m2_acquire_job()	- decrements M2 semaphore counter
29610d63b7dSRichard Lowe  *  m2_release_job()	- increments M2 semaphore counter
29710d63b7dSRichard Lowe  *  m2_fini()		- destroys M2 semaphore and shared memory*
29810d63b7dSRichard Lowe  *
29910d63b7dSRichard Lowe  *  Environment variables:
30010d63b7dSRichard Lowe  *	__DMAKE_M2_FILE__
30110d63b7dSRichard Lowe  *
30210d63b7dSRichard Lowe  *  External functions:
30310d63b7dSRichard Lowe  *	ftok(), shmget(), shmat(), shmdt(), shmctl()
30410d63b7dSRichard Lowe  *	sem_init(), sem_trywait(), sem_post(), sem_destroy()
30510d63b7dSRichard Lowe  *	creat(), close(), unlink()
30610d63b7dSRichard Lowe  *	getenv(), putenv()
30710d63b7dSRichard Lowe  *
30810d63b7dSRichard Lowe  *  Static variables:
30910d63b7dSRichard Lowe  *	m2_file		- tmp file name to create ipc key for shared memory
31010d63b7dSRichard Lowe  *	m2_shm_id	- shared memory id
31110d63b7dSRichard Lowe  *	m2_shm_sem	- shared memory semaphore
31210d63b7dSRichard Lowe  */
31310d63b7dSRichard Lowe 
31410d63b7dSRichard Lowe static char	m2_file[MAXPATHLEN];
31510d63b7dSRichard Lowe static int	m2_shm_id = -1;
31610d63b7dSRichard Lowe static sem_t*	m2_shm_sem = 0;
31710d63b7dSRichard Lowe 
31810d63b7dSRichard Lowe static int
m2_init()31910d63b7dSRichard Lowe m2_init() {
32010d63b7dSRichard Lowe 	char	*var;
32110d63b7dSRichard Lowe 	key_t	key;
32210d63b7dSRichard Lowe 
32310d63b7dSRichard Lowe 	if ((var = getenv("__DMAKE_M2_FILE__")) == 0) {
32410d63b7dSRichard Lowe 		/* compose tmp file name */
32510d63b7dSRichard Lowe 		sprintf(m2_file, "%s/dmake.m2.%d.XXXXXX", tmpdir, getpid());
32610d63b7dSRichard Lowe 
32710d63b7dSRichard Lowe 		/* create tmp file */
32810d63b7dSRichard Lowe 		int fd = mkstemp(m2_file);
32910d63b7dSRichard Lowe 		if (fd < 0) {
33010d63b7dSRichard Lowe 			return -1;
33110d63b7dSRichard Lowe 		} else {
33210d63b7dSRichard Lowe 			close(fd);
33310d63b7dSRichard Lowe 		}
33410d63b7dSRichard Lowe 	} else {
33510d63b7dSRichard Lowe 		/* using existing semaphore */
33610d63b7dSRichard Lowe 		strcpy(m2_file, var);
33710d63b7dSRichard Lowe 	}
33810d63b7dSRichard Lowe 
33910d63b7dSRichard Lowe 	/* combine IPC key */
34010d63b7dSRichard Lowe 	if ((key = ftok(m2_file, 38)) == (key_t) -1) {
34110d63b7dSRichard Lowe 		return -1;
34210d63b7dSRichard Lowe 	}
34310d63b7dSRichard Lowe 
34410d63b7dSRichard Lowe 	/* create shared memory */
34510d63b7dSRichard Lowe 	if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {
34610d63b7dSRichard Lowe 		return -1;
34710d63b7dSRichard Lowe 	}
34810d63b7dSRichard Lowe 
34910d63b7dSRichard Lowe 	/* attach shared memory */
35010d63b7dSRichard Lowe 	if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
35110d63b7dSRichard Lowe 		return -1;
35210d63b7dSRichard Lowe 	}
35310d63b7dSRichard Lowe 
35410d63b7dSRichard Lowe 	/* root process */
35510d63b7dSRichard Lowe 	if (var == 0) {
35610d63b7dSRichard Lowe 		/* initialize semaphore */
35710d63b7dSRichard Lowe 		if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
35810d63b7dSRichard Lowe 			return -1;
35910d63b7dSRichard Lowe 		}
36010d63b7dSRichard Lowe 
36110d63b7dSRichard Lowe 		/* alloc memory for env variable */
36210d63b7dSRichard Lowe 		if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
36310d63b7dSRichard Lowe 			return -1;
36410d63b7dSRichard Lowe 		}
36510d63b7dSRichard Lowe 
36610d63b7dSRichard Lowe 		/* put key to env */
36710d63b7dSRichard Lowe 		sprintf(var, "__DMAKE_M2_FILE__=%s", m2_file);
36810d63b7dSRichard Lowe 		if (putenv(var)) {
36910d63b7dSRichard Lowe 			return -1;
37010d63b7dSRichard Lowe 		}
37110d63b7dSRichard Lowe 	}
37210d63b7dSRichard Lowe 	return 0;
37310d63b7dSRichard Lowe }
37410d63b7dSRichard Lowe 
37510d63b7dSRichard Lowe static void
m2_fini()37610d63b7dSRichard Lowe m2_fini() {
37710d63b7dSRichard Lowe 	if (m2_shm_id >= 0) {
37810d63b7dSRichard Lowe 		struct shmid_ds stat;
37910d63b7dSRichard Lowe 
38010d63b7dSRichard Lowe 		/* determine the number of attached processes */
38110d63b7dSRichard Lowe 		if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
38210d63b7dSRichard Lowe 			if (stat.shm_nattch <= 1) {
38310d63b7dSRichard Lowe 				/* destroy semaphore */
38410d63b7dSRichard Lowe 				if (m2_shm_sem != 0) {
38510d63b7dSRichard Lowe 					(void) sem_destroy(m2_shm_sem);
38610d63b7dSRichard Lowe 				}
38710d63b7dSRichard Lowe 
38810d63b7dSRichard Lowe 				/* destroy shared memory */
38910d63b7dSRichard Lowe 				(void) shmctl(m2_shm_id, IPC_RMID, &stat);
39010d63b7dSRichard Lowe 
39110d63b7dSRichard Lowe 				/* remove tmp file created for the key */
39210d63b7dSRichard Lowe 				(void) unlink(m2_file);
39310d63b7dSRichard Lowe 			} else {
39410d63b7dSRichard Lowe 				/* detach shared memory */
39510d63b7dSRichard Lowe 				if (m2_shm_sem != 0) {
39610d63b7dSRichard Lowe 					(void) shmdt((char*) m2_shm_sem);
39710d63b7dSRichard Lowe 				}
39810d63b7dSRichard Lowe 			}
39910d63b7dSRichard Lowe 		}
40010d63b7dSRichard Lowe 
40110d63b7dSRichard Lowe 		m2_shm_id = -1;
40210d63b7dSRichard Lowe 		m2_shm_sem = 0;
40310d63b7dSRichard Lowe 	}
40410d63b7dSRichard Lowe }
40510d63b7dSRichard Lowe 
40610d63b7dSRichard Lowe static int
m2_acquire_job()40710d63b7dSRichard Lowe m2_acquire_job() {
40810d63b7dSRichard Lowe 	if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
40910d63b7dSRichard Lowe 		if (sem_trywait(m2_shm_sem) == 0) {
41010d63b7dSRichard Lowe 			return 1;
41110d63b7dSRichard Lowe 		}
41210d63b7dSRichard Lowe 		if (errno == EAGAIN) {
41310d63b7dSRichard Lowe 			return 0;
41410d63b7dSRichard Lowe 		}
41510d63b7dSRichard Lowe 	}
41610d63b7dSRichard Lowe 	return -1;
41710d63b7dSRichard Lowe }
41810d63b7dSRichard Lowe 
41910d63b7dSRichard Lowe static int
m2_release_job()42010d63b7dSRichard Lowe m2_release_job() {
42110d63b7dSRichard Lowe 	if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
42210d63b7dSRichard Lowe 		if (sem_post(m2_shm_sem) == 0) {
42310d63b7dSRichard Lowe 			return 0;
42410d63b7dSRichard Lowe 		}
42510d63b7dSRichard Lowe 	}
42610d63b7dSRichard Lowe 	return -1;
42710d63b7dSRichard Lowe }
42810d63b7dSRichard Lowe 
42910d63b7dSRichard Lowe /*
43010d63b7dSRichard Lowe  *  job adjust mode
43110d63b7dSRichard Lowe  *
43210d63b7dSRichard Lowe  *  Possible values:
43310d63b7dSRichard Lowe  *    ADJUST_M1		- adjustment by system load (default)
43410d63b7dSRichard Lowe  *    ADJUST_M2		- fixed limit of jobs for the group of nested dmakes
43510d63b7dSRichard Lowe  *    ADJUST_NONE	- no adjustment - fixed limit of jobs for the current dmake
43610d63b7dSRichard Lowe  */
43710d63b7dSRichard Lowe static enum {
43810d63b7dSRichard Lowe 	ADJUST_UNKNOWN,
43910d63b7dSRichard Lowe 	ADJUST_M1,
44010d63b7dSRichard Lowe 	ADJUST_M2,
44110d63b7dSRichard Lowe 	ADJUST_NONE
44210d63b7dSRichard Lowe } job_adjust_mode = ADJUST_UNKNOWN;
44310d63b7dSRichard Lowe 
44410d63b7dSRichard Lowe /*
44510d63b7dSRichard Lowe  *  void job_adjust_fini()
44610d63b7dSRichard Lowe  *
44710d63b7dSRichard Lowe  *  Description:
44810d63b7dSRichard Lowe  *	Cleans up job adjust data.
44910d63b7dSRichard Lowe  *
45010d63b7dSRichard Lowe  *  Static variables:
45110d63b7dSRichard Lowe  *	job_adjust_mode	Current job adjust mode
45210d63b7dSRichard Lowe  */
45310d63b7dSRichard Lowe void
job_adjust_fini()45410d63b7dSRichard Lowe job_adjust_fini() {
45510d63b7dSRichard Lowe 	if (job_adjust_mode == ADJUST_M2) {
45610d63b7dSRichard Lowe 		m2_fini();
45710d63b7dSRichard Lowe 	}
45810d63b7dSRichard Lowe }
45910d63b7dSRichard Lowe 
46010d63b7dSRichard Lowe /*
46110d63b7dSRichard Lowe  *  void job_adjust_error()
46210d63b7dSRichard Lowe  *
46310d63b7dSRichard Lowe  *  Description:
46410d63b7dSRichard Lowe  *	Prints warning message, cleans up job adjust data, and disables job adjustment
46510d63b7dSRichard Lowe  *
46610d63b7dSRichard Lowe  *  Environment:
46710d63b7dSRichard Lowe  *	DMAKE_ADJUST_MAX_JOBS
46810d63b7dSRichard Lowe  *
46910d63b7dSRichard Lowe  *  External functions:
47010d63b7dSRichard Lowe  *	putenv()
47110d63b7dSRichard Lowe  *
47210d63b7dSRichard Lowe  *  Static variables:
47310d63b7dSRichard Lowe  *	job_adjust_mode	Current job adjust mode
47410d63b7dSRichard Lowe  */
47510d63b7dSRichard Lowe static void
job_adjust_error()47610d63b7dSRichard Lowe job_adjust_error() {
47710d63b7dSRichard Lowe 	if (job_adjust_mode != ADJUST_NONE) {
47810d63b7dSRichard Lowe 		/* cleanup internals */
47910d63b7dSRichard Lowe 		job_adjust_fini();
48010d63b7dSRichard Lowe 
48110d63b7dSRichard Lowe 		/* warning message for the user */
48210d63b7dSRichard Lowe 		warning(gettext("Encountered max jobs auto adjustment error - disabling auto adjustment."));
48310d63b7dSRichard Lowe 
48410d63b7dSRichard Lowe 		/* switch off job adjustment for the children */
48510d63b7dSRichard Lowe 		putenv(strdup("DMAKE_ADJUST_MAX_JOBS=NO"));
48610d63b7dSRichard Lowe 
48710d63b7dSRichard Lowe 		/* and for this dmake */
48810d63b7dSRichard Lowe 		job_adjust_mode = ADJUST_NONE;
48910d63b7dSRichard Lowe 	}
49010d63b7dSRichard Lowe }
49110d63b7dSRichard Lowe 
49210d63b7dSRichard Lowe /*
49310d63b7dSRichard Lowe  *  void job_adjust_init()
49410d63b7dSRichard Lowe  *
49510d63b7dSRichard Lowe  *  Description:
49610d63b7dSRichard Lowe  *	Parses DMAKE_ADJUST_MAX_JOBS env variable
49710d63b7dSRichard Lowe  *	and performs appropriate initializations.
49810d63b7dSRichard Lowe  *
49910d63b7dSRichard Lowe  *  Environment:
50010d63b7dSRichard Lowe  *	DMAKE_ADJUST_MAX_JOBS
50110d63b7dSRichard Lowe  *	  DMAKE_ADJUST_MAX_JOBS == "NO"	- no adjustment
50210d63b7dSRichard Lowe  *	  DMAKE_ADJUST_MAX_JOBS == "M2"	- M2 adjust mode
50310d63b7dSRichard Lowe  *	  other				- M1 adjust mode
50410d63b7dSRichard Lowe  *
50510d63b7dSRichard Lowe  *  External functions:
50610d63b7dSRichard Lowe  *	getenv()
50710d63b7dSRichard Lowe  *
50810d63b7dSRichard Lowe  *  Static variables:
50910d63b7dSRichard Lowe  *	job_adjust_mode	Current job adjust mode
51010d63b7dSRichard Lowe  */
51110d63b7dSRichard Lowe static void
job_adjust_init()51210d63b7dSRichard Lowe job_adjust_init() {
51310d63b7dSRichard Lowe 	if (job_adjust_mode == ADJUST_UNKNOWN) {
51410d63b7dSRichard Lowe 		/* default mode */
51510d63b7dSRichard Lowe 		job_adjust_mode = ADJUST_M1;
51610d63b7dSRichard Lowe 
51710d63b7dSRichard Lowe 		/* determine adjust mode */
51810d63b7dSRichard Lowe 		if (char *var = getenv("DMAKE_ADJUST_MAX_JOBS")) {
51910d63b7dSRichard Lowe 			if (strcasecmp(var, "NO") == 0) {
52010d63b7dSRichard Lowe 				job_adjust_mode = ADJUST_NONE;
52110d63b7dSRichard Lowe 			} else if (strcasecmp(var, "M2") == 0) {
52210d63b7dSRichard Lowe 				job_adjust_mode = ADJUST_M2;
52310d63b7dSRichard Lowe 			}
52410d63b7dSRichard Lowe 		}
52510d63b7dSRichard Lowe 
52610d63b7dSRichard Lowe 		/* M2 specific initialization */
52710d63b7dSRichard Lowe 		if (job_adjust_mode == ADJUST_M2) {
52810d63b7dSRichard Lowe 			if (m2_init()) {
52910d63b7dSRichard Lowe 				job_adjust_error();
53010d63b7dSRichard Lowe 			}
53110d63b7dSRichard Lowe 		}
53210d63b7dSRichard Lowe 	}
53310d63b7dSRichard Lowe }
53410d63b7dSRichard Lowe 
53510d63b7dSRichard Lowe 
53610d63b7dSRichard Lowe /*
53710d63b7dSRichard Lowe  *	distribute_process(char **commands, Property line)
53810d63b7dSRichard Lowe  *
53910d63b7dSRichard Lowe  *	Parameters:
54010d63b7dSRichard Lowe  *		commands	argv vector of commands to execute
54110d63b7dSRichard Lowe  *
54210d63b7dSRichard Lowe  *	Return value:
54310d63b7dSRichard Lowe  *				The result of the execution
54410d63b7dSRichard Lowe  *
54510d63b7dSRichard Lowe  *	Static variables used:
54610d63b7dSRichard Lowe  *		process_running	Set to the pid of the process set running
54710d63b7dSRichard Lowe  *		job_adjust_mode	Current job adjust mode
54810d63b7dSRichard Lowe  */
54910d63b7dSRichard Lowe static Doname
distribute_process(char ** commands,Property line)55010d63b7dSRichard Lowe distribute_process(char **commands, Property line)
55110d63b7dSRichard Lowe {
55210d63b7dSRichard Lowe 	static unsigned	file_number = 0;
55310d63b7dSRichard Lowe 	wchar_t		string[MAXPATHLEN];
55410d63b7dSRichard Lowe 	char		mbstring[MAXPATHLEN];
55510d63b7dSRichard Lowe 	int		filed;
55610d63b7dSRichard Lowe 	int		res;
55710d63b7dSRichard Lowe 	int		tmp_index;
55810d63b7dSRichard Lowe 	char		*tmp_index_str_ptr;
55910d63b7dSRichard Lowe 
56010d63b7dSRichard Lowe 	/* initialize adjust mode, if not initialized */
56110d63b7dSRichard Lowe 	if (job_adjust_mode == ADJUST_UNKNOWN) {
56210d63b7dSRichard Lowe 		job_adjust_init();
56310d63b7dSRichard Lowe 	}
56410d63b7dSRichard Lowe 
56510d63b7dSRichard Lowe 	/* actions depend on adjust mode */
56610d63b7dSRichard Lowe 	switch (job_adjust_mode) {
56710d63b7dSRichard Lowe 	case ADJUST_M1:
56810d63b7dSRichard Lowe 		while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) {
56910d63b7dSRichard Lowe 			await_parallel(false);
57010d63b7dSRichard Lowe 			finish_children(true);
57110d63b7dSRichard Lowe 		}
57210d63b7dSRichard Lowe 		break;
57310d63b7dSRichard Lowe 	case ADJUST_M2:
57410d63b7dSRichard Lowe 		if ((res = m2_acquire_job()) == 0) {
57510d63b7dSRichard Lowe 			if (parallel_process_cnt > 0) {
57610d63b7dSRichard Lowe 				await_parallel(false);
57710d63b7dSRichard Lowe 				finish_children(true);
57810d63b7dSRichard Lowe 
57910d63b7dSRichard Lowe 				if ((res = m2_acquire_job()) == 0) {
58010d63b7dSRichard Lowe 					return build_serial;
58110d63b7dSRichard Lowe 				}
58210d63b7dSRichard Lowe 			} else {
58310d63b7dSRichard Lowe 				return build_serial;
58410d63b7dSRichard Lowe 			}
58510d63b7dSRichard Lowe 		}
58610d63b7dSRichard Lowe 		if (res < 0) {
58710d63b7dSRichard Lowe 			/* job adjustment error */
58810d63b7dSRichard Lowe 			job_adjust_error();
58910d63b7dSRichard Lowe 
59010d63b7dSRichard Lowe 			/* no adjustment */
59110d63b7dSRichard Lowe 			while (parallel_process_cnt >= pmake_max_jobs) {
59210d63b7dSRichard Lowe 				await_parallel(false);
59310d63b7dSRichard Lowe 				finish_children(true);
59410d63b7dSRichard Lowe 			}
59510d63b7dSRichard Lowe 		}
59610d63b7dSRichard Lowe 		break;
59710d63b7dSRichard Lowe 	default:
59810d63b7dSRichard Lowe 		while (parallel_process_cnt >= pmake_max_jobs) {
59910d63b7dSRichard Lowe 			await_parallel(false);
60010d63b7dSRichard Lowe 			finish_children(true);
60110d63b7dSRichard Lowe 		}
60210d63b7dSRichard Lowe 	}
60310d63b7dSRichard Lowe 
60410d63b7dSRichard Lowe 	setvar_envvar();
60510d63b7dSRichard Lowe 	/*
60610d63b7dSRichard Lowe 	 * Tell the user what DMake is doing.
60710d63b7dSRichard Lowe 	 */
60810d63b7dSRichard Lowe 	if (!silent && output_mode != txt2_mode) {
60910d63b7dSRichard Lowe 		/*
61010d63b7dSRichard Lowe 		 * Print local_host --> x job(s).
61110d63b7dSRichard Lowe 		 */
61210d63b7dSRichard Lowe 		(void) fprintf(stdout,
61310d63b7dSRichard Lowe 		               gettext("%s --> %d %s\n"),
61410d63b7dSRichard Lowe 		               local_host,
61510d63b7dSRichard Lowe 		               parallel_process_cnt + 1,
61610d63b7dSRichard Lowe 		               (parallel_process_cnt == 0) ? gettext("job") : gettext("jobs"));
61710d63b7dSRichard Lowe 
61810d63b7dSRichard Lowe 		/* Print command line(s). */
61910d63b7dSRichard Lowe 		tmp_index = 0;
62010d63b7dSRichard Lowe 		while (commands[tmp_index] != NULL) {
62110d63b7dSRichard Lowe 		    /* No @ char. */
62210d63b7dSRichard Lowe 		    /* XXX - need to add [2] when + prefix is added */
62310d63b7dSRichard Lowe 		    if ((commands[tmp_index][0] != (int) at_char) &&
62410d63b7dSRichard Lowe 		        (commands[tmp_index][1] != (int) at_char)) {
62510d63b7dSRichard Lowe 			tmp_index_str_ptr = commands[tmp_index];
62610d63b7dSRichard Lowe 			if (*tmp_index_str_ptr == (int) hyphen_char) {
62710d63b7dSRichard Lowe 				tmp_index_str_ptr++;
62810d63b7dSRichard Lowe 			}
62910d63b7dSRichard Lowe                         (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
63010d63b7dSRichard Lowe 		    }
63110d63b7dSRichard Lowe 		    tmp_index++;
63210d63b7dSRichard Lowe 		}
63310d63b7dSRichard Lowe 		(void) fflush(stdout);
63410d63b7dSRichard Lowe 	}
63510d63b7dSRichard Lowe 
63610d63b7dSRichard Lowe 	(void) sprintf(mbstring,
63710d63b7dSRichard Lowe 		        "%s/dmake.stdout.%d.%d.XXXXXX",
63810d63b7dSRichard Lowe 			tmpdir,
63910d63b7dSRichard Lowe 		        getpid(),
64010d63b7dSRichard Lowe 	                file_number++);
64110d63b7dSRichard Lowe 
64210d63b7dSRichard Lowe 	mktemp(mbstring);
64310d63b7dSRichard Lowe 
64410d63b7dSRichard Lowe 	stdout_file = strdup(mbstring);
64510d63b7dSRichard Lowe 	stderr_file = NULL;
64610d63b7dSRichard Lowe 
64710d63b7dSRichard Lowe 	if (!out_err_same) {
64810d63b7dSRichard Lowe 		(void) sprintf(mbstring,
64910d63b7dSRichard Lowe 			        "%s/dmake.stderr.%d.%d.XXXXXX",
65010d63b7dSRichard Lowe 				tmpdir,
65110d63b7dSRichard Lowe 			        getpid(),
65210d63b7dSRichard Lowe 		                file_number++);
65310d63b7dSRichard Lowe 
65410d63b7dSRichard Lowe 		mktemp(mbstring);
65510d63b7dSRichard Lowe 
65610d63b7dSRichard Lowe 		stderr_file = strdup(mbstring);
65710d63b7dSRichard Lowe 	}
65810d63b7dSRichard Lowe 
65910d63b7dSRichard Lowe 	process_running = run_rule_commands(local_host, commands);
66010d63b7dSRichard Lowe 
66110d63b7dSRichard Lowe 	return build_running;
66210d63b7dSRichard Lowe }
66310d63b7dSRichard Lowe 
66410d63b7dSRichard Lowe /*
66510d63b7dSRichard Lowe  *	doname_parallel(target, do_get, implicit)
66610d63b7dSRichard Lowe  *
66710d63b7dSRichard Lowe  *	Processes the given target and finishes up any parallel
66810d63b7dSRichard Lowe  *	processes left running.
66910d63b7dSRichard Lowe  *
67010d63b7dSRichard Lowe  *	Return value:
67110d63b7dSRichard Lowe  *				Result of target build
67210d63b7dSRichard Lowe  *
67310d63b7dSRichard Lowe  *	Parameters:
67410d63b7dSRichard Lowe  *		target		Target to build
67510d63b7dSRichard Lowe  *		do_get		True if sccs get to be done
67610d63b7dSRichard Lowe  *		implicit	True if this is an implicit target
67710d63b7dSRichard Lowe  */
67810d63b7dSRichard Lowe Doname
doname_parallel(Name target,Boolean do_get,Boolean implicit)67910d63b7dSRichard Lowe doname_parallel(Name target, Boolean do_get, Boolean implicit)
68010d63b7dSRichard Lowe {
68110d63b7dSRichard Lowe 	Doname		result;
68210d63b7dSRichard Lowe 
68310d63b7dSRichard Lowe 	result = doname_check(target, do_get, implicit, false);
68410d63b7dSRichard Lowe 	if (result == build_ok || result == build_failed) {
68510d63b7dSRichard Lowe 		return result;
68610d63b7dSRichard Lowe 	}
68710d63b7dSRichard Lowe 	finish_running();
68810d63b7dSRichard Lowe 	return (Doname) target->state;
68910d63b7dSRichard Lowe }
69010d63b7dSRichard Lowe 
69110d63b7dSRichard Lowe /*
69210d63b7dSRichard Lowe  *	doname_subtree(target, do_get, implicit)
69310d63b7dSRichard Lowe  *
69410d63b7dSRichard Lowe  *	Completely computes an object and its dependents for a
69510d63b7dSRichard Lowe  *	serial subtree build.
69610d63b7dSRichard Lowe  *
69710d63b7dSRichard Lowe  *	Parameters:
69810d63b7dSRichard Lowe  *		target		Target to build
69910d63b7dSRichard Lowe  *		do_get		True if sccs get to be done
70010d63b7dSRichard Lowe  *		implicit	True if this is an implicit target
70110d63b7dSRichard Lowe  *
70210d63b7dSRichard Lowe  *	Static variables used:
70310d63b7dSRichard Lowe  *		running_tail	Tail of the list of running processes
70410d63b7dSRichard Lowe  *
70510d63b7dSRichard Lowe  *	Global variables used:
70610d63b7dSRichard Lowe  *		running_list	The list of running processes
70710d63b7dSRichard Lowe  */
70810d63b7dSRichard Lowe static void
doname_subtree(Name target,Boolean do_get,Boolean implicit)70910d63b7dSRichard Lowe doname_subtree(Name target, Boolean do_get, Boolean implicit)
71010d63b7dSRichard Lowe {
71110d63b7dSRichard Lowe 	Running		save_running_list;
71210d63b7dSRichard Lowe 	Running		*save_running_tail;
71310d63b7dSRichard Lowe 
71410d63b7dSRichard Lowe 	save_running_list = running_list;
71510d63b7dSRichard Lowe 	save_running_tail = running_tail;
71610d63b7dSRichard Lowe 	running_list = NULL;
71710d63b7dSRichard Lowe 	running_tail = &running_list;
71810d63b7dSRichard Lowe 	target->state = build_subtree;
71910d63b7dSRichard Lowe 	target->checking_subtree = true;
72010d63b7dSRichard Lowe 	while(doname_check(target, do_get, implicit, false) == build_running) {
72110d63b7dSRichard Lowe 		target->checking_subtree = false;
72210d63b7dSRichard Lowe 		finish_running();
72310d63b7dSRichard Lowe 		target->state = build_subtree;
72410d63b7dSRichard Lowe 	}
72510d63b7dSRichard Lowe 	target->checking_subtree = false;
72610d63b7dSRichard Lowe 	running_list = save_running_list;
72710d63b7dSRichard Lowe 	running_tail = save_running_tail;
72810d63b7dSRichard Lowe }
72910d63b7dSRichard Lowe 
73010d63b7dSRichard Lowe /*
73110d63b7dSRichard Lowe  *	finish_running()
73210d63b7dSRichard Lowe  *
73310d63b7dSRichard Lowe  *	Keeps processing until the running_list is emptied out.
73410d63b7dSRichard Lowe  *
73510d63b7dSRichard Lowe  *	Parameters:
73610d63b7dSRichard Lowe  *
73710d63b7dSRichard Lowe  *	Global variables used:
73810d63b7dSRichard Lowe  *		running_list	The list of running processes
73910d63b7dSRichard Lowe  */
74010d63b7dSRichard Lowe void
finish_running(void)74110d63b7dSRichard Lowe finish_running(void)
74210d63b7dSRichard Lowe {
74310d63b7dSRichard Lowe 	while (running_list != NULL) {
74410d63b7dSRichard Lowe 		{
74510d63b7dSRichard Lowe 			await_parallel(false);
74610d63b7dSRichard Lowe 			finish_children(true);
74710d63b7dSRichard Lowe 		}
74810d63b7dSRichard Lowe 		if (running_list != NULL) {
74910d63b7dSRichard Lowe 			process_next();
75010d63b7dSRichard Lowe 		}
75110d63b7dSRichard Lowe 	}
75210d63b7dSRichard Lowe }
75310d63b7dSRichard Lowe 
75410d63b7dSRichard Lowe /*
75510d63b7dSRichard Lowe  *	process_next()
75610d63b7dSRichard Lowe  *
75710d63b7dSRichard Lowe  *	Searches the running list for any targets which can start processing.
75810d63b7dSRichard Lowe  *	This can be a pending target, a serial target, or a subtree target.
75910d63b7dSRichard Lowe  *
76010d63b7dSRichard Lowe  *	Parameters:
76110d63b7dSRichard Lowe  *
76210d63b7dSRichard Lowe  *	Static variables used:
76310d63b7dSRichard Lowe  *		running_tail		The end of the list of running procs
76410d63b7dSRichard Lowe  *		subtree_conflict	A target which conflicts with a subtree
76510d63b7dSRichard Lowe  *		subtree_conflict2	The other target which conflicts
76610d63b7dSRichard Lowe  *
76710d63b7dSRichard Lowe  *	Global variables used:
76810d63b7dSRichard Lowe  *		commands_done		True if commands executed
76910d63b7dSRichard Lowe  *		debug_level		Controls debug output
77010d63b7dSRichard Lowe  *		parallel_process_cnt	Number of parallel process running
77110d63b7dSRichard Lowe  *		recursion_level		Indentation for debug output
77210d63b7dSRichard Lowe  *		running_list		List of running processes
77310d63b7dSRichard Lowe  */
77410d63b7dSRichard Lowe static void
process_next(void)77510d63b7dSRichard Lowe process_next(void)
77610d63b7dSRichard Lowe {
77710d63b7dSRichard Lowe 	Running		rp;
77810d63b7dSRichard Lowe 	Running		*rp_prev;
77910d63b7dSRichard Lowe 	Property	line;
78010d63b7dSRichard Lowe 	Chain		target_group;
78110d63b7dSRichard Lowe 	Dependency	dep;
78210d63b7dSRichard Lowe 	Boolean		quiescent = true;
78310d63b7dSRichard Lowe 	Running		*subtree_target;
78410d63b7dSRichard Lowe 	Boolean		saved_commands_done;
78510d63b7dSRichard Lowe 	Property	*conditionals;
78610d63b7dSRichard Lowe 
78710d63b7dSRichard Lowe 	subtree_target = NULL;
78810d63b7dSRichard Lowe 	subtree_conflict = NULL;
78910d63b7dSRichard Lowe 	subtree_conflict2 = NULL;
79010d63b7dSRichard Lowe 	/*
79110d63b7dSRichard Lowe 	 * If nothing currently running, build a serial target, if any.
79210d63b7dSRichard Lowe 	 */
79310d63b7dSRichard Lowe start_loop_1:
79410d63b7dSRichard Lowe 	for (rp_prev = &running_list, rp = running_list;
79510d63b7dSRichard Lowe 	     rp != NULL && parallel_process_cnt == 0;
79610d63b7dSRichard Lowe 	     rp = rp->next) {
79710d63b7dSRichard Lowe 		if (rp->state == build_serial) {
79810d63b7dSRichard Lowe 			*rp_prev = rp->next;
79910d63b7dSRichard Lowe 			if (rp->next == NULL) {
80010d63b7dSRichard Lowe 				running_tail = rp_prev;
80110d63b7dSRichard Lowe 			}
80210d63b7dSRichard Lowe 			recursion_level = rp->recursion_level;
80310d63b7dSRichard Lowe 			rp->target->state = build_pending;
80410d63b7dSRichard Lowe 			(void) doname_check(rp->target,
80510d63b7dSRichard Lowe 					    rp->do_get,
80610d63b7dSRichard Lowe 					    rp->implicit,
80710d63b7dSRichard Lowe 					    false);
80810d63b7dSRichard Lowe 			quiescent = false;
80910d63b7dSRichard Lowe 			delete_running_struct(rp);
81010d63b7dSRichard Lowe 			goto start_loop_1;
81110d63b7dSRichard Lowe 		} else {
81210d63b7dSRichard Lowe 			rp_prev = &rp->next;
81310d63b7dSRichard Lowe 		}
81410d63b7dSRichard Lowe 	}
81510d63b7dSRichard Lowe 	/*
81610d63b7dSRichard Lowe 	 * Find a target to build.  The target must be pending, have all
81710d63b7dSRichard Lowe 	 * its dependencies built, and not be in a target group with a target
81810d63b7dSRichard Lowe 	 * currently building.
81910d63b7dSRichard Lowe 	 */
82010d63b7dSRichard Lowe start_loop_2:
82110d63b7dSRichard Lowe 	for (rp_prev = &running_list, rp = running_list;
82210d63b7dSRichard Lowe 	     rp != NULL;
82310d63b7dSRichard Lowe 	     rp = rp->next) {
82410d63b7dSRichard Lowe 		if (!(rp->state == build_pending ||
82510d63b7dSRichard Lowe 		      rp->state == build_subtree)) {
82610d63b7dSRichard Lowe 			quiescent = false;
82710d63b7dSRichard Lowe 			rp_prev = &rp->next;
82810d63b7dSRichard Lowe 		} else if (rp->state == build_pending) {
82910d63b7dSRichard Lowe 			line = get_prop(rp->target->prop, line_prop);
83010d63b7dSRichard Lowe 			for (dep = line->body.line.dependencies;
83110d63b7dSRichard Lowe 			     dep != NULL;
83210d63b7dSRichard Lowe 			     dep = dep->next) {
83310d63b7dSRichard Lowe 				if (dep->name->state == build_running ||
83410d63b7dSRichard Lowe 				    dep->name->state == build_pending ||
83510d63b7dSRichard Lowe 				    dep->name->state == build_serial) {
83610d63b7dSRichard Lowe 					break;
83710d63b7dSRichard Lowe 				}
83810d63b7dSRichard Lowe 			}
83910d63b7dSRichard Lowe 			if (dep == NULL) {
84010d63b7dSRichard Lowe 				for (target_group = line->body.line.target_group;
84110d63b7dSRichard Lowe 				     target_group != NULL;
84210d63b7dSRichard Lowe 				     target_group = target_group->next) {
84310d63b7dSRichard Lowe 					if (is_running(target_group->name)) {
84410d63b7dSRichard Lowe 						break;
84510d63b7dSRichard Lowe 					}
84610d63b7dSRichard Lowe 				}
84710d63b7dSRichard Lowe 				if (target_group == NULL) {
84810d63b7dSRichard Lowe 					*rp_prev = rp->next;
84910d63b7dSRichard Lowe 					if (rp->next == NULL) {
85010d63b7dSRichard Lowe 						running_tail = rp_prev;
85110d63b7dSRichard Lowe 					}
85210d63b7dSRichard Lowe 					recursion_level = rp->recursion_level;
85310d63b7dSRichard Lowe 					rp->target->state = rp->redo ?
85410d63b7dSRichard Lowe 					  build_dont_know : build_pending;
85510d63b7dSRichard Lowe 					saved_commands_done = commands_done;
85610d63b7dSRichard Lowe 					conditionals =
85710d63b7dSRichard Lowe 						set_conditionals
85810d63b7dSRichard Lowe 						    (rp->conditional_cnt,
85910d63b7dSRichard Lowe 						     rp->conditional_targets);
86010d63b7dSRichard Lowe 					rp->target->dont_activate_cond_values = true;
86110d63b7dSRichard Lowe 					if ((doname_check(rp->target,
86210d63b7dSRichard Lowe 							  rp->do_get,
86310d63b7dSRichard Lowe 							  rp->implicit,
86410d63b7dSRichard Lowe 							  rp->target->has_target_prop ? true : false) !=
86510d63b7dSRichard Lowe 					     build_running) &&
86610d63b7dSRichard Lowe 					    !commands_done) {
86710d63b7dSRichard Lowe 						commands_done =
86810d63b7dSRichard Lowe 						  saved_commands_done;
86910d63b7dSRichard Lowe 					}
87010d63b7dSRichard Lowe 					rp->target->dont_activate_cond_values = false;
87110d63b7dSRichard Lowe 					reset_conditionals
87210d63b7dSRichard Lowe 						(rp->conditional_cnt,
87310d63b7dSRichard Lowe 						 rp->conditional_targets,
87410d63b7dSRichard Lowe 						 conditionals);
87510d63b7dSRichard Lowe 					quiescent = false;
87610d63b7dSRichard Lowe 					delete_running_struct(rp);
87710d63b7dSRichard Lowe 					goto start_loop_2;
87810d63b7dSRichard Lowe 				} else {
87910d63b7dSRichard Lowe 					rp_prev = &rp->next;
88010d63b7dSRichard Lowe 				}
88110d63b7dSRichard Lowe 			} else {
88210d63b7dSRichard Lowe 				rp_prev = &rp->next;
88310d63b7dSRichard Lowe 			}
88410d63b7dSRichard Lowe 		} else {
88510d63b7dSRichard Lowe 			rp_prev = &rp->next;
88610d63b7dSRichard Lowe 		}
88710d63b7dSRichard Lowe 	}
88810d63b7dSRichard Lowe 	/*
88910d63b7dSRichard Lowe 	 * If nothing has been found to build and there exists a subtree
89010d63b7dSRichard Lowe 	 * target with no dependency conflicts, build it.
89110d63b7dSRichard Lowe 	 */
89210d63b7dSRichard Lowe 	if (quiescent) {
89310d63b7dSRichard Lowe start_loop_3:
89410d63b7dSRichard Lowe 		for (rp_prev = &running_list, rp = running_list;
89510d63b7dSRichard Lowe 		     rp != NULL;
89610d63b7dSRichard Lowe 		     rp = rp->next) {
89710d63b7dSRichard Lowe 			if (rp->state == build_subtree) {
89810d63b7dSRichard Lowe 				if (!dependency_conflict(rp->target)) {
89910d63b7dSRichard Lowe 					*rp_prev = rp->next;
90010d63b7dSRichard Lowe 					if (rp->next == NULL) {
90110d63b7dSRichard Lowe 						running_tail = rp_prev;
90210d63b7dSRichard Lowe 					}
90310d63b7dSRichard Lowe 					recursion_level = rp->recursion_level;
90410d63b7dSRichard Lowe 					doname_subtree(rp->target,
90510d63b7dSRichard Lowe 						       rp->do_get,
90610d63b7dSRichard Lowe 						       rp->implicit);
90710d63b7dSRichard Lowe 					quiescent = false;
90810d63b7dSRichard Lowe 					delete_running_struct(rp);
90910d63b7dSRichard Lowe 					goto start_loop_3;
91010d63b7dSRichard Lowe 				} else {
91110d63b7dSRichard Lowe 					subtree_target = rp_prev;
91210d63b7dSRichard Lowe 					rp_prev = &rp->next;
91310d63b7dSRichard Lowe 				}
91410d63b7dSRichard Lowe 			} else {
91510d63b7dSRichard Lowe 				rp_prev = &rp->next;
91610d63b7dSRichard Lowe 			}
91710d63b7dSRichard Lowe 		}
91810d63b7dSRichard Lowe 	}
91910d63b7dSRichard Lowe 	/*
92010d63b7dSRichard Lowe 	 * If still nothing found to build, we either have a deadlock
92110d63b7dSRichard Lowe 	 * or a subtree with a dependency conflict with something waiting
92210d63b7dSRichard Lowe 	 * to build.
92310d63b7dSRichard Lowe 	 */
92410d63b7dSRichard Lowe 	if (quiescent) {
92510d63b7dSRichard Lowe 		if (subtree_target == NULL) {
92610d63b7dSRichard Lowe 			fatal(gettext("Internal error: deadlock detected in process_next"));
92710d63b7dSRichard Lowe 		} else {
92810d63b7dSRichard Lowe 			rp = *subtree_target;
92910d63b7dSRichard Lowe 			if (debug_level > 0) {
93010d63b7dSRichard Lowe 				warning(gettext("Conditional macro conflict encountered for %s between %s and %s"),
93110d63b7dSRichard Lowe 					subtree_conflict2->string_mb,
93210d63b7dSRichard Lowe 					rp->target->string_mb,
93310d63b7dSRichard Lowe 					subtree_conflict->string_mb);
93410d63b7dSRichard Lowe 			}
93510d63b7dSRichard Lowe 			*subtree_target = (*subtree_target)->next;
93610d63b7dSRichard Lowe 			if (rp->next == NULL) {
93710d63b7dSRichard Lowe 				running_tail = subtree_target;
93810d63b7dSRichard Lowe 			}
93910d63b7dSRichard Lowe 			recursion_level = rp->recursion_level;
94010d63b7dSRichard Lowe 			doname_subtree(rp->target, rp->do_get, rp->implicit);
94110d63b7dSRichard Lowe 			delete_running_struct(rp);
94210d63b7dSRichard Lowe 		}
94310d63b7dSRichard Lowe 	}
94410d63b7dSRichard Lowe }
94510d63b7dSRichard Lowe 
94610d63b7dSRichard Lowe /*
94710d63b7dSRichard Lowe  *	set_conditionals(cnt, targets)
94810d63b7dSRichard Lowe  *
94910d63b7dSRichard Lowe  *	Sets the conditional macros for the targets given in the array of
95010d63b7dSRichard Lowe  *	targets.  The old macro values are returned in an array of
95110d63b7dSRichard Lowe  *	Properties for later resetting.
95210d63b7dSRichard Lowe  *
95310d63b7dSRichard Lowe  *	Return value:
95410d63b7dSRichard Lowe  *					Array of conditional macro settings
95510d63b7dSRichard Lowe  *
95610d63b7dSRichard Lowe  *	Parameters:
95710d63b7dSRichard Lowe  *		cnt			Number of targets
95810d63b7dSRichard Lowe  *		targets			Array of targets
95910d63b7dSRichard Lowe  */
96010d63b7dSRichard Lowe static Property *
set_conditionals(int cnt,Name * targets)96110d63b7dSRichard Lowe set_conditionals(int cnt, Name *targets)
96210d63b7dSRichard Lowe {
96310d63b7dSRichard Lowe 	Property	*locals, *lp;
96410d63b7dSRichard Lowe 	Name		*tp;
96510d63b7dSRichard Lowe 
96610d63b7dSRichard Lowe 	locals = (Property *) getmem(cnt * sizeof(Property));
96710d63b7dSRichard Lowe 	for (lp = locals, tp = targets;
96810d63b7dSRichard Lowe 	     cnt > 0;
96910d63b7dSRichard Lowe 	     cnt--, lp++, tp++) {
97010d63b7dSRichard Lowe 		*lp = (Property) getmem((*tp)->conditional_cnt *
97110d63b7dSRichard Lowe 					sizeof(struct _Property));
97210d63b7dSRichard Lowe 		set_locals(*tp, *lp);
97310d63b7dSRichard Lowe 	}
97410d63b7dSRichard Lowe 	return locals;
97510d63b7dSRichard Lowe }
97610d63b7dSRichard Lowe 
97710d63b7dSRichard Lowe /*
97810d63b7dSRichard Lowe  *	reset_conditionals(cnt, targets, locals)
97910d63b7dSRichard Lowe  *
98010d63b7dSRichard Lowe  *	Resets the conditional macros as saved in the given array of
98110d63b7dSRichard Lowe  *	Properties.  The resets are done in reverse order.  Afterwards the
98210d63b7dSRichard Lowe  *	data structures are freed.
98310d63b7dSRichard Lowe  *
98410d63b7dSRichard Lowe  *	Parameters:
98510d63b7dSRichard Lowe  *		cnt			Number of targets
98610d63b7dSRichard Lowe  *		targets			Array of targets
98710d63b7dSRichard Lowe  *		locals			Array of dependency macro settings
98810d63b7dSRichard Lowe  */
98910d63b7dSRichard Lowe static void
reset_conditionals(int cnt,Name * targets,Property * locals)99010d63b7dSRichard Lowe reset_conditionals(int cnt, Name *targets, Property *locals)
99110d63b7dSRichard Lowe {
99210d63b7dSRichard Lowe 	Name		*tp;
99310d63b7dSRichard Lowe 	Property	*lp;
99410d63b7dSRichard Lowe 
99510d63b7dSRichard Lowe 	for (tp = targets + (cnt - 1), lp = locals + (cnt - 1);
99610d63b7dSRichard Lowe 	     cnt > 0;
99710d63b7dSRichard Lowe 	     cnt--, tp--, lp--) {
99810d63b7dSRichard Lowe 		reset_locals(*tp,
99910d63b7dSRichard Lowe 			     *lp,
100010d63b7dSRichard Lowe 			     get_prop((*tp)->prop, conditional_prop),
100110d63b7dSRichard Lowe 			     0);
100210d63b7dSRichard Lowe 		retmem_mb((caddr_t) *lp);
100310d63b7dSRichard Lowe 	}
100410d63b7dSRichard Lowe 	retmem_mb((caddr_t) locals);
100510d63b7dSRichard Lowe }
100610d63b7dSRichard Lowe 
100710d63b7dSRichard Lowe /*
100810d63b7dSRichard Lowe  *	dependency_conflict(target)
100910d63b7dSRichard Lowe  *
101010d63b7dSRichard Lowe  *	Returns true if there is an intersection between
101110d63b7dSRichard Lowe  *	the subtree of the target and any dependents of the pending targets.
101210d63b7dSRichard Lowe  *
101310d63b7dSRichard Lowe  *	Return value:
101410d63b7dSRichard Lowe  *					True if conflict found
101510d63b7dSRichard Lowe  *
101610d63b7dSRichard Lowe  *	Parameters:
101710d63b7dSRichard Lowe  *		target			Subtree target to check
101810d63b7dSRichard Lowe  *
101910d63b7dSRichard Lowe  *	Static variables used:
102010d63b7dSRichard Lowe  *		subtree_conflict	Target conflict found
102110d63b7dSRichard Lowe  *		subtree_conflict2	Second conflict found
102210d63b7dSRichard Lowe  *
102310d63b7dSRichard Lowe  *	Global variables used:
102410d63b7dSRichard Lowe  *		running_list		List of running processes
102510d63b7dSRichard Lowe  *		wait_name		.WAIT, not a real dependency
102610d63b7dSRichard Lowe  */
102710d63b7dSRichard Lowe static Boolean
dependency_conflict(Name target)102810d63b7dSRichard Lowe dependency_conflict(Name target)
102910d63b7dSRichard Lowe {
103010d63b7dSRichard Lowe 	Property	line;
103110d63b7dSRichard Lowe 	Property	pending_line;
103210d63b7dSRichard Lowe 	Dependency	dp;
103310d63b7dSRichard Lowe 	Dependency	pending_dp;
103410d63b7dSRichard Lowe 	Running		rp;
103510d63b7dSRichard Lowe 
103610d63b7dSRichard Lowe 	/* Return if we are already checking this target */
103710d63b7dSRichard Lowe 	if (target->checking_subtree) {
103810d63b7dSRichard Lowe 		return false;
103910d63b7dSRichard Lowe 	}
104010d63b7dSRichard Lowe 	target->checking_subtree = true;
104110d63b7dSRichard Lowe 	line = get_prop(target->prop, line_prop);
104210d63b7dSRichard Lowe 	if (line == NULL) {
104310d63b7dSRichard Lowe 		target->checking_subtree = false;
104410d63b7dSRichard Lowe 		return false;
104510d63b7dSRichard Lowe 	}
104610d63b7dSRichard Lowe 	/* Check each dependency of the target for conflicts */
104710d63b7dSRichard Lowe 	for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
104810d63b7dSRichard Lowe 		/* Ignore .WAIT dependency */
104910d63b7dSRichard Lowe 		if (dp->name == wait_name) {
105010d63b7dSRichard Lowe 			continue;
105110d63b7dSRichard Lowe 		}
105210d63b7dSRichard Lowe 		/*
105310d63b7dSRichard Lowe 		 * For each pending target, look for a dependency which
105410d63b7dSRichard Lowe 		 * is the same as a dependency of the subtree target.  Since
105510d63b7dSRichard Lowe 		 * we can't build the subtree until all pending targets have
105610d63b7dSRichard Lowe 		 * finished which depend on the same dependency, this is
105710d63b7dSRichard Lowe 		 * a conflict.
105810d63b7dSRichard Lowe 		 */
105910d63b7dSRichard Lowe 		for (rp = running_list; rp != NULL; rp = rp->next) {
106010d63b7dSRichard Lowe 			if (rp->state == build_pending) {
106110d63b7dSRichard Lowe 				pending_line = get_prop(rp->target->prop,
106210d63b7dSRichard Lowe 							line_prop);
106310d63b7dSRichard Lowe 				if (pending_line == NULL) {
106410d63b7dSRichard Lowe 					continue;
106510d63b7dSRichard Lowe 				}
106610d63b7dSRichard Lowe 				for(pending_dp = pending_line->
1067*ae389aa9SAndy Fiddaman 							body.line.dependencies;
106810d63b7dSRichard Lowe 				    pending_dp != NULL;
106910d63b7dSRichard Lowe 				    pending_dp = pending_dp->next) {
107010d63b7dSRichard Lowe 					if (dp->name == pending_dp->name) {
107110d63b7dSRichard Lowe 						target->checking_subtree
1072*ae389aa9SAndy Fiddaman 								= false;
107310d63b7dSRichard Lowe 						subtree_conflict = rp->target;
107410d63b7dSRichard Lowe 						subtree_conflict2 = dp->name;
107510d63b7dSRichard Lowe 						return true;
107610d63b7dSRichard Lowe 					}
107710d63b7dSRichard Lowe 				}
107810d63b7dSRichard Lowe 			}
107910d63b7dSRichard Lowe 		}
108010d63b7dSRichard Lowe 		if (dependency_conflict(dp->name)) {
108110d63b7dSRichard Lowe 			target->checking_subtree = false;
108210d63b7dSRichard Lowe 			return true;
108310d63b7dSRichard Lowe 		}
108410d63b7dSRichard Lowe 	}
108510d63b7dSRichard Lowe 	target->checking_subtree = false;
108610d63b7dSRichard Lowe 	return false;
108710d63b7dSRichard Lowe }
108810d63b7dSRichard Lowe 
108910d63b7dSRichard Lowe /*
109010d63b7dSRichard Lowe  *	await_parallel(waitflg)
109110d63b7dSRichard Lowe  *
109210d63b7dSRichard Lowe  *	Waits for parallel children to exit and finishes their processing.
109310d63b7dSRichard Lowe  *	If waitflg is false, the function returns after update_delay.
109410d63b7dSRichard Lowe  *
109510d63b7dSRichard Lowe  *	Parameters:
109610d63b7dSRichard Lowe  *		waitflg		dwight
109710d63b7dSRichard Lowe  */
109810d63b7dSRichard Lowe void
await_parallel(Boolean waitflg)109910d63b7dSRichard Lowe await_parallel(Boolean waitflg)
110010d63b7dSRichard Lowe {
110110d63b7dSRichard Lowe 	Boolean		nohang;
110210d63b7dSRichard Lowe 	pid_t		pid;
110310d63b7dSRichard Lowe 	int		status;
110410d63b7dSRichard Lowe 	Running		rp;
110510d63b7dSRichard Lowe 	int		waiterr;
110610d63b7dSRichard Lowe 
110710d63b7dSRichard Lowe 	nohang = false;
110810d63b7dSRichard Lowe 	for ( ; ; ) {
110910d63b7dSRichard Lowe 		if (!nohang) {
111010d63b7dSRichard Lowe 			(void) alarm((int) update_delay);
111110d63b7dSRichard Lowe 		}
111210d63b7dSRichard Lowe 		pid = waitpid((pid_t)-1,
111310d63b7dSRichard Lowe 			      &status,
111410d63b7dSRichard Lowe 			      nohang ? WNOHANG : 0);
111510d63b7dSRichard Lowe 		waiterr = errno;
111610d63b7dSRichard Lowe 		if (!nohang) {
111710d63b7dSRichard Lowe 			(void) alarm(0);
111810d63b7dSRichard Lowe 		}
111910d63b7dSRichard Lowe 		if (pid <= 0) {
112010d63b7dSRichard Lowe 			if (waiterr == EINTR) {
112110d63b7dSRichard Lowe 				if (waitflg) {
112210d63b7dSRichard Lowe 					continue;
112310d63b7dSRichard Lowe 				} else {
112410d63b7dSRichard Lowe 					return;
112510d63b7dSRichard Lowe 				}
112610d63b7dSRichard Lowe 			} else {
112710d63b7dSRichard Lowe 				return;
112810d63b7dSRichard Lowe 			}
112910d63b7dSRichard Lowe 		}
113010d63b7dSRichard Lowe 		for (rp = running_list;
113110d63b7dSRichard Lowe 		     (rp != NULL) && (rp->pid != pid);
113210d63b7dSRichard Lowe 		     rp = rp->next) {
113310d63b7dSRichard Lowe 			;
113410d63b7dSRichard Lowe 		}
113510d63b7dSRichard Lowe 		if (rp == NULL) {
113610d63b7dSRichard Lowe 			fatal(gettext("Internal error: returned child pid not in running_list"));
113710d63b7dSRichard Lowe 		} else {
113810d63b7dSRichard Lowe 			rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
113910d63b7dSRichard Lowe 		}
114010d63b7dSRichard Lowe 		nohang = true;
114110d63b7dSRichard Lowe 		parallel_process_cnt--;
114210d63b7dSRichard Lowe 
114310d63b7dSRichard Lowe 		if (job_adjust_mode == ADJUST_M2) {
114410d63b7dSRichard Lowe 			if (m2_release_job()) {
114510d63b7dSRichard Lowe 				job_adjust_error();
114610d63b7dSRichard Lowe 			}
114710d63b7dSRichard Lowe 		}
114810d63b7dSRichard Lowe 	}
114910d63b7dSRichard Lowe }
115010d63b7dSRichard Lowe 
115110d63b7dSRichard Lowe /*
115210d63b7dSRichard Lowe  *	finish_children(docheck)
115310d63b7dSRichard Lowe  *
115410d63b7dSRichard Lowe  *	Finishes the processing for all targets which were running
115510d63b7dSRichard Lowe  *	and have now completed.
115610d63b7dSRichard Lowe  *
115710d63b7dSRichard Lowe  *	Parameters:
115810d63b7dSRichard Lowe  *		docheck		Completely check the finished target
115910d63b7dSRichard Lowe  *
116010d63b7dSRichard Lowe  *	Static variables used:
116110d63b7dSRichard Lowe  *		running_tail	The tail of the running list
116210d63b7dSRichard Lowe  *
116310d63b7dSRichard Lowe  *	Global variables used:
116410d63b7dSRichard Lowe  *		continue_after_error  -k flag
116510d63b7dSRichard Lowe  *		fatal_in_progress  True if we are finishing up after fatal err
116610d63b7dSRichard Lowe  *		running_list	List of running processes
116710d63b7dSRichard Lowe  */
116810d63b7dSRichard Lowe void
finish_children(Boolean docheck)116910d63b7dSRichard Lowe finish_children(Boolean docheck)
117010d63b7dSRichard Lowe {
117110d63b7dSRichard Lowe 	int		cmds_length;
117210d63b7dSRichard Lowe 	Property	line;
117310d63b7dSRichard Lowe 	Property	line2;
117410d63b7dSRichard Lowe 	struct stat	out_buf;
117510d63b7dSRichard Lowe 	Running		rp;
117610d63b7dSRichard Lowe 	Running		*rp_prev;
117710d63b7dSRichard Lowe 	Cmd_line	rule;
117810d63b7dSRichard Lowe 	Boolean		silent_flag;
117910d63b7dSRichard Lowe 
118010d63b7dSRichard Lowe 	for (rp_prev = &running_list, rp = running_list;
118110d63b7dSRichard Lowe 	     rp != NULL;
118210d63b7dSRichard Lowe 	     rp = rp->next) {
118310d63b7dSRichard Lowe bypass_for_loop_inc_4:
118410d63b7dSRichard Lowe 		/*
118510d63b7dSRichard Lowe 		 * If the state is ok or failed, then this target has
118610d63b7dSRichard Lowe 		 * finished building.
118710d63b7dSRichard Lowe 		 * In parallel_mode, output the accumulated stdout/stderr.
118810d63b7dSRichard Lowe 		 * Read the auto dependency stuff, handle a failed build,
118910d63b7dSRichard Lowe 		 * update the target, then finish the doname process for
119010d63b7dSRichard Lowe 		 * that target.
119110d63b7dSRichard Lowe 		 */
119210d63b7dSRichard Lowe 		if (rp->state == build_ok || rp->state == build_failed) {
119310d63b7dSRichard Lowe 			*rp_prev = rp->next;
119410d63b7dSRichard Lowe 			if (rp->next == NULL) {
119510d63b7dSRichard Lowe 				running_tail = rp_prev;
119610d63b7dSRichard Lowe 			}
119710d63b7dSRichard Lowe 			if ((line2 = rp->command) == NULL) {
119810d63b7dSRichard Lowe 				line2 = get_prop(rp->target->prop, line_prop);
119910d63b7dSRichard Lowe 			}
120010d63b7dSRichard Lowe 
120110d63b7dSRichard Lowe 
120210d63b7dSRichard Lowe 			/*
120310d63b7dSRichard Lowe 			 * Check if there were any job output
120410d63b7dSRichard Lowe 			 * from the parallel build.
120510d63b7dSRichard Lowe 			 */
120610d63b7dSRichard Lowe 			if (rp->stdout_file != NULL) {
120710d63b7dSRichard Lowe 				if (stat(rp->stdout_file, &out_buf) < 0) {
120810d63b7dSRichard Lowe 					fatal(gettext("stat of %s failed: %s"),
120910d63b7dSRichard Lowe 					    rp->stdout_file,
121010d63b7dSRichard Lowe 					    errmsg(errno));
121110d63b7dSRichard Lowe 				}
121210d63b7dSRichard Lowe 
121310d63b7dSRichard Lowe 				if ((line2 != NULL) &&
121410d63b7dSRichard Lowe 				    (out_buf.st_size > 0)) {
121510d63b7dSRichard Lowe 					cmds_length = 0;
121610d63b7dSRichard Lowe 					for (rule = line2->body.line.command_used,
121710d63b7dSRichard Lowe 						 silent_flag = silent;
121810d63b7dSRichard Lowe 					     rule != NULL;
121910d63b7dSRichard Lowe 					     rule = rule->next) {
122010d63b7dSRichard Lowe 						cmds_length += rule->command_line->hash.length + 1;
122110d63b7dSRichard Lowe 						silent_flag = BOOLEAN(silent_flag || rule->silent);
122210d63b7dSRichard Lowe 					}
122310d63b7dSRichard Lowe 					if (out_buf.st_size != cmds_length || silent_flag ||
122410d63b7dSRichard Lowe 					    output_mode == txt2_mode) {
122510d63b7dSRichard Lowe 						dump_out_file(rp->stdout_file, false);
122610d63b7dSRichard Lowe 					}
122710d63b7dSRichard Lowe 				}
122810d63b7dSRichard Lowe 				(void) unlink(rp->stdout_file);
122910d63b7dSRichard Lowe 				retmem_mb(rp->stdout_file);
123010d63b7dSRichard Lowe 				rp->stdout_file = NULL;
123110d63b7dSRichard Lowe 			}
123210d63b7dSRichard Lowe 
123310d63b7dSRichard Lowe 			if (!out_err_same && (rp->stderr_file != NULL)) {
123410d63b7dSRichard Lowe 				if (stat(rp->stderr_file, &out_buf) < 0) {
123510d63b7dSRichard Lowe 					fatal(gettext("stat of %s failed: %s"),
123610d63b7dSRichard Lowe 					    rp->stderr_file,
123710d63b7dSRichard Lowe 					    errmsg(errno));
123810d63b7dSRichard Lowe 				}
123910d63b7dSRichard Lowe 				if ((line2 != NULL) &&
124010d63b7dSRichard Lowe 				    (out_buf.st_size > 0)) {
124110d63b7dSRichard Lowe 					dump_out_file(rp->stderr_file, true);
124210d63b7dSRichard Lowe 				}
124310d63b7dSRichard Lowe 				(void) unlink(rp->stderr_file);
124410d63b7dSRichard Lowe 				retmem_mb(rp->stderr_file);
124510d63b7dSRichard Lowe 				rp->stderr_file = NULL;
124610d63b7dSRichard Lowe 			}
1247*ae389aa9SAndy Fiddaman 
124810d63b7dSRichard Lowe 			check_state(rp->temp_file);
124910d63b7dSRichard Lowe 			if (rp->temp_file != NULL) {
125010d63b7dSRichard Lowe 				free_name(rp->temp_file);
125110d63b7dSRichard Lowe 			}
125210d63b7dSRichard Lowe 			rp->temp_file = NULL;
125310d63b7dSRichard Lowe 			if (rp->state == build_failed) {
125410d63b7dSRichard Lowe 				line = get_prop(rp->target->prop, line_prop);
125510d63b7dSRichard Lowe 				if (line != NULL) {
125610d63b7dSRichard Lowe 					line->body.line.command_used = NULL;
125710d63b7dSRichard Lowe 				}
125810d63b7dSRichard Lowe 				if (continue_after_error ||
125910d63b7dSRichard Lowe 				    fatal_in_progress ||
126010d63b7dSRichard Lowe 				    !docheck) {
126110d63b7dSRichard Lowe 					warning(gettext("Command failed for target `%s'"),
126210d63b7dSRichard Lowe 						rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
126310d63b7dSRichard Lowe 					build_failed_seen = true;
126410d63b7dSRichard Lowe 				} else {
126510d63b7dSRichard Lowe 					/*
126610d63b7dSRichard Lowe 					 * XXX??? - DMake needs to exit(),
126710d63b7dSRichard Lowe 					 * but shouldn't call fatal().
126810d63b7dSRichard Lowe 					 */
126910d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS
127010d63b7dSRichard Lowe 					warning("I'm in finish_children. rp->state == build_failed.");
127110d63b7dSRichard Lowe #endif
127210d63b7dSRichard Lowe 
127310d63b7dSRichard Lowe 					fatal(gettext("Command failed for target `%s'"),
127410d63b7dSRichard Lowe 						rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
127510d63b7dSRichard Lowe 				}
127610d63b7dSRichard Lowe 			}
127710d63b7dSRichard Lowe 			if (!docheck) {
127810d63b7dSRichard Lowe 				delete_running_struct(rp);
127910d63b7dSRichard Lowe 				rp = *rp_prev;
128010d63b7dSRichard Lowe 				if (rp == NULL) {
128110d63b7dSRichard Lowe 					break;
128210d63b7dSRichard Lowe 				} else {
128310d63b7dSRichard Lowe 					goto bypass_for_loop_inc_4;
128410d63b7dSRichard Lowe 				}
128510d63b7dSRichard Lowe 			}
128610d63b7dSRichard Lowe 			update_target(get_prop(rp->target->prop, line_prop),
128710d63b7dSRichard Lowe 				      rp->state);
128810d63b7dSRichard Lowe 			finish_doname(rp);
128910d63b7dSRichard Lowe 			delete_running_struct(rp);
129010d63b7dSRichard Lowe 			rp = *rp_prev;
129110d63b7dSRichard Lowe 			if (rp == NULL) {
129210d63b7dSRichard Lowe 				break;
129310d63b7dSRichard Lowe 			} else {
129410d63b7dSRichard Lowe 				goto bypass_for_loop_inc_4;
129510d63b7dSRichard Lowe 			}
129610d63b7dSRichard Lowe 		} else {
129710d63b7dSRichard Lowe 			rp_prev = &rp->next;
129810d63b7dSRichard Lowe 		}
129910d63b7dSRichard Lowe 	}
130010d63b7dSRichard Lowe }
130110d63b7dSRichard Lowe 
130210d63b7dSRichard Lowe /*
130310d63b7dSRichard Lowe  *	dump_out_file(filename, err)
130410d63b7dSRichard Lowe  *
130510d63b7dSRichard Lowe  *	Write the contents of the file to stdout, then unlink the file.
130610d63b7dSRichard Lowe  *
130710d63b7dSRichard Lowe  *	Parameters:
130810d63b7dSRichard Lowe  *		filename	Name of temp file containing output
130910d63b7dSRichard Lowe  *
131010d63b7dSRichard Lowe  *	Global variables used:
131110d63b7dSRichard Lowe  */
131210d63b7dSRichard Lowe static void
dump_out_file(char * filename,Boolean err)131310d63b7dSRichard Lowe dump_out_file(char *filename, Boolean err)
131410d63b7dSRichard Lowe {
131510d63b7dSRichard Lowe 	int		chars_read;
131610d63b7dSRichard Lowe 	char		copybuf[BUFSIZ];
131710d63b7dSRichard Lowe 	int		fd;
131810d63b7dSRichard Lowe 	int		out_fd = (err ? 2 : 1);
131910d63b7dSRichard Lowe 
132010d63b7dSRichard Lowe 	if ((fd = open(filename, O_RDONLY)) < 0) {
132110d63b7dSRichard Lowe 		fatal(gettext("open failed for output file %s: %s"),
132210d63b7dSRichard Lowe 		      filename,
132310d63b7dSRichard Lowe 		      errmsg(errno));
132410d63b7dSRichard Lowe 	}
132510d63b7dSRichard Lowe 	if (!silent && output_mode != txt2_mode) {
132610d63b7dSRichard Lowe 		(void) fprintf(err ? stderr : stdout,
132710d63b7dSRichard Lowe 		               err ?
132810d63b7dSRichard Lowe 				gettext("%s --> Job errors\n") :
132910d63b7dSRichard Lowe 				gettext("%s --> Job output\n"),
133010d63b7dSRichard Lowe 		               local_host);
133110d63b7dSRichard Lowe 		(void) fflush(err ? stderr : stdout);
133210d63b7dSRichard Lowe 	}
133310d63b7dSRichard Lowe 	for (chars_read = read(fd, copybuf, BUFSIZ);
133410d63b7dSRichard Lowe 	     chars_read > 0;
133510d63b7dSRichard Lowe 	     chars_read = read(fd, copybuf, BUFSIZ)) {
133610d63b7dSRichard Lowe 		/*
133710d63b7dSRichard Lowe 		 * Read buffers from the source file until end or error.
133810d63b7dSRichard Lowe 		 */
133910d63b7dSRichard Lowe 		if (write(out_fd, copybuf, chars_read) < 0) {
134010d63b7dSRichard Lowe 			fatal(gettext("write failed for output file %s: %s"),
134110d63b7dSRichard Lowe 			      filename,
134210d63b7dSRichard Lowe 			      errmsg(errno));
134310d63b7dSRichard Lowe 		}
134410d63b7dSRichard Lowe 	}
134510d63b7dSRichard Lowe 	(void) close(fd);
134610d63b7dSRichard Lowe 	(void) unlink(filename);
134710d63b7dSRichard Lowe }
134810d63b7dSRichard Lowe 
134910d63b7dSRichard Lowe /*
135010d63b7dSRichard Lowe  *	finish_doname(rp)
135110d63b7dSRichard Lowe  *
135210d63b7dSRichard Lowe  *	Completes the processing for a target which was left running.
135310d63b7dSRichard Lowe  *
135410d63b7dSRichard Lowe  *	Parameters:
135510d63b7dSRichard Lowe  *		rp		Running list entry for target
135610d63b7dSRichard Lowe  *
135710d63b7dSRichard Lowe  *	Global variables used:
135810d63b7dSRichard Lowe  *		debug_level	Debug flag
135910d63b7dSRichard Lowe  *		recursion_level	Indentation for debug output
136010d63b7dSRichard Lowe  */
136110d63b7dSRichard Lowe static void
finish_doname(Running rp)136210d63b7dSRichard Lowe finish_doname(Running rp)
136310d63b7dSRichard Lowe {
136410d63b7dSRichard Lowe 	int		auto_count = rp->auto_count;
136510d63b7dSRichard Lowe 	Name		*automatics = rp->automatics;
136610d63b7dSRichard Lowe 	Doname		result = rp->state;
136710d63b7dSRichard Lowe 	Name		target = rp->target;
136810d63b7dSRichard Lowe 	Name		true_target = rp->true_target;
136910d63b7dSRichard Lowe 	Property	*conditionals;
137010d63b7dSRichard Lowe 
137110d63b7dSRichard Lowe 	recursion_level = rp->recursion_level;
137210d63b7dSRichard Lowe 	if (result == build_ok) {
137310d63b7dSRichard Lowe 		if (true_target == NULL) {
137410d63b7dSRichard Lowe 			(void) printf("Target = %s\n", target->string_mb);
137510d63b7dSRichard Lowe 			(void) printf(" State = %d\n", result);
137610d63b7dSRichard Lowe 			fatal("Internal error: NULL true_target in finish_doname");
137710d63b7dSRichard Lowe 		}
137810d63b7dSRichard Lowe 		/* If all went OK, set a nice timestamp */
137910d63b7dSRichard Lowe 		if (true_target->stat.time == file_doesnt_exist) {
138010d63b7dSRichard Lowe 			true_target->stat.time = file_max_time;
138110d63b7dSRichard Lowe 		}
138210d63b7dSRichard Lowe 	}
138310d63b7dSRichard Lowe 	target->state = result;
138410d63b7dSRichard Lowe 	if (target->is_member) {
138510d63b7dSRichard Lowe 		Property member;
138610d63b7dSRichard Lowe 
138710d63b7dSRichard Lowe 		/* Propagate the timestamp from the member file to the member */
138810d63b7dSRichard Lowe 		if ((target->stat.time != file_max_time) &&
138910d63b7dSRichard Lowe 		    ((member = get_prop(target->prop, member_prop)) != NULL) &&
139010d63b7dSRichard Lowe 		    (exists(member->body.member.member) > file_doesnt_exist)) {
139110d63b7dSRichard Lowe 			target->stat.time =
139210d63b7dSRichard Lowe /*
139310d63b7dSRichard Lowe 			  exists(member->body.member.member);
139410d63b7dSRichard Lowe  */
139510d63b7dSRichard Lowe 			  member->body.member.member->stat.time;
139610d63b7dSRichard Lowe 		}
139710d63b7dSRichard Lowe 	}
139810d63b7dSRichard Lowe 	/*
139910d63b7dSRichard Lowe 	 * Check if we found any new auto dependencies when we
140010d63b7dSRichard Lowe 	 * built the target.
140110d63b7dSRichard Lowe 	 */
140210d63b7dSRichard Lowe 	if ((result == build_ok) && check_auto_dependencies(target,
140310d63b7dSRichard Lowe 							    auto_count,
140410d63b7dSRichard Lowe 							    automatics)) {
140510d63b7dSRichard Lowe 		if (debug_level > 0) {
140610d63b7dSRichard Lowe 			(void) printf(gettext("%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
140710d63b7dSRichard Lowe 				      recursion_level,
140810d63b7dSRichard Lowe 				      "",
140910d63b7dSRichard Lowe 				      true_target->string_mb);
141010d63b7dSRichard Lowe 		}
141110d63b7dSRichard Lowe 		target->rechecking_target = true;
141210d63b7dSRichard Lowe 		target->state = build_running;
141310d63b7dSRichard Lowe 
141410d63b7dSRichard Lowe 		/* [tolik, Tue Mar 25 1997]
141510d63b7dSRichard Lowe 		 * Fix for bug 4038824:
141610d63b7dSRichard Lowe 		 *       command line options set by conditional macros get dropped
141710d63b7dSRichard Lowe 		 * rp->conditional_cnt and rp->conditional_targets must be copied
141810d63b7dSRichard Lowe 		 * to new 'rp' during add_pending(). Set_conditionals() stores
141910d63b7dSRichard Lowe 		 * rp->conditional_targets to the global variable 'conditional_targets'
142010d63b7dSRichard Lowe 		 * Add_pending() will use this variable to set up 'rp'.
142110d63b7dSRichard Lowe 		 */
142210d63b7dSRichard Lowe 		conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
142310d63b7dSRichard Lowe 		add_pending(target,
142410d63b7dSRichard Lowe 			    recursion_level,
142510d63b7dSRichard Lowe 			    rp->do_get,
142610d63b7dSRichard Lowe 			    rp->implicit,
142710d63b7dSRichard Lowe 			    true);
142810d63b7dSRichard Lowe 		reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
142910d63b7dSRichard Lowe 	}
143010d63b7dSRichard Lowe }
143110d63b7dSRichard Lowe 
143210d63b7dSRichard Lowe /*
143310d63b7dSRichard Lowe  *	new_running_struct()
143410d63b7dSRichard Lowe  *
143510d63b7dSRichard Lowe  *	Constructor for Running struct. Creates a structure and initializes
143610d63b7dSRichard Lowe  *      its fields.
143710d63b7dSRichard Lowe  *
143810d63b7dSRichard Lowe  */
new_running_struct()143910d63b7dSRichard Lowe static Running new_running_struct()
144010d63b7dSRichard Lowe {
144110d63b7dSRichard Lowe 	Running		rp;
144210d63b7dSRichard Lowe 
144310d63b7dSRichard Lowe 	rp = ALLOC(Running);
144410d63b7dSRichard Lowe 	rp->target = NULL;
144510d63b7dSRichard Lowe 	rp->true_target = NULL;
144610d63b7dSRichard Lowe 	rp->command = NULL;
144710d63b7dSRichard Lowe 	rp->sprodep_value = NULL;
144810d63b7dSRichard Lowe 	rp->sprodep_env = NULL;
144910d63b7dSRichard Lowe 	rp->auto_count = 0;
145010d63b7dSRichard Lowe 	rp->automatics = NULL;
145110d63b7dSRichard Lowe 	rp->pid = -1;
145210d63b7dSRichard Lowe 	rp->job_msg_id = -1;
145310d63b7dSRichard Lowe 	rp->stdout_file = NULL;
145410d63b7dSRichard Lowe 	rp->stderr_file = NULL;
145510d63b7dSRichard Lowe 	rp->temp_file = NULL;
145610d63b7dSRichard Lowe 	rp->next = NULL;
145710d63b7dSRichard Lowe 	return rp;
145810d63b7dSRichard Lowe }
145910d63b7dSRichard Lowe 
146010d63b7dSRichard Lowe /*
146110d63b7dSRichard Lowe  *	add_running(target, true_target, command, recursion_level, auto_count,
146210d63b7dSRichard Lowe  *					automatics, do_get, implicit)
146310d63b7dSRichard Lowe  *
146410d63b7dSRichard Lowe  *	Adds a record on the running list for this target, which
146510d63b7dSRichard Lowe  *	was just spawned and is running.
146610d63b7dSRichard Lowe  *
146710d63b7dSRichard Lowe  *	Parameters:
146810d63b7dSRichard Lowe  *		target		Target being built
146910d63b7dSRichard Lowe  *		true_target	True target for target
147010d63b7dSRichard Lowe  *		command		Running command.
147110d63b7dSRichard Lowe  *		recursion_level	Debug indentation level
147210d63b7dSRichard Lowe  *		auto_count	Count of automatic dependencies
147310d63b7dSRichard Lowe  *		automatics	List of automatic dependencies
147410d63b7dSRichard Lowe  *		do_get		Sccs get flag
147510d63b7dSRichard Lowe  *		implicit	Implicit flag
147610d63b7dSRichard Lowe  *
147710d63b7dSRichard Lowe  *	Static variables used:
147810d63b7dSRichard Lowe  *		running_tail	Tail of running list
147910d63b7dSRichard Lowe  *		process_running	PID of process
148010d63b7dSRichard Lowe  *
148110d63b7dSRichard Lowe  *	Global variables used:
148210d63b7dSRichard Lowe  *		current_line	Current line for target
148310d63b7dSRichard Lowe  *		current_target	Current target being built
148410d63b7dSRichard Lowe  *		stderr_file	Temporary file for stdout
148510d63b7dSRichard Lowe  *		stdout_file	Temporary file for stdout
148610d63b7dSRichard Lowe  *		temp_file_name	Temporary file for auto dependencies
148710d63b7dSRichard Lowe  */
148810d63b7dSRichard Lowe void
add_running(Name target,Name true_target,Property command,int recursion_level,int auto_count,Name * automatics,Boolean do_get,Boolean implicit)148910d63b7dSRichard Lowe add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
149010d63b7dSRichard Lowe {
149110d63b7dSRichard Lowe 	Running		rp;
149210d63b7dSRichard Lowe 	Name		*p;
149310d63b7dSRichard Lowe 
149410d63b7dSRichard Lowe 	rp = new_running_struct();
149510d63b7dSRichard Lowe 	rp->state = build_running;
149610d63b7dSRichard Lowe 	rp->target = target;
149710d63b7dSRichard Lowe 	rp->true_target = true_target;
149810d63b7dSRichard Lowe 	rp->command = command;
149910d63b7dSRichard Lowe 	rp->recursion_level = recursion_level;
150010d63b7dSRichard Lowe 	rp->do_get = do_get;
150110d63b7dSRichard Lowe 	rp->implicit = implicit;
150210d63b7dSRichard Lowe 	rp->auto_count = auto_count;
150310d63b7dSRichard Lowe 	if (auto_count > 0) {
150410d63b7dSRichard Lowe 		rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
150510d63b7dSRichard Lowe 		for (p = rp->automatics; auto_count > 0; auto_count--) {
150610d63b7dSRichard Lowe 			*p++ = *automatics++;
150710d63b7dSRichard Lowe 		}
150810d63b7dSRichard Lowe 	} else {
150910d63b7dSRichard Lowe 		rp->automatics = NULL;
151010d63b7dSRichard Lowe 	}
151110d63b7dSRichard Lowe 	{
151210d63b7dSRichard Lowe 		rp->pid = process_running;
151310d63b7dSRichard Lowe 		process_running = -1;
151410d63b7dSRichard Lowe 		childPid = -1;
151510d63b7dSRichard Lowe 	}
151610d63b7dSRichard Lowe 	rp->job_msg_id = job_msg_id;
151710d63b7dSRichard Lowe 	rp->stdout_file = stdout_file;
151810d63b7dSRichard Lowe 	rp->stderr_file = stderr_file;
151910d63b7dSRichard Lowe 	rp->temp_file = temp_file_name;
152010d63b7dSRichard Lowe 	rp->redo = false;
152110d63b7dSRichard Lowe 	rp->next = NULL;
152210d63b7dSRichard Lowe 	store_conditionals(rp);
152310d63b7dSRichard Lowe 	stdout_file = NULL;
152410d63b7dSRichard Lowe 	stderr_file = NULL;
152510d63b7dSRichard Lowe 	temp_file_name = NULL;
152610d63b7dSRichard Lowe 	current_target = NULL;
152710d63b7dSRichard Lowe 	current_line = NULL;
152810d63b7dSRichard Lowe 	*running_tail = rp;
152910d63b7dSRichard Lowe 	running_tail = &rp->next;
153010d63b7dSRichard Lowe }
153110d63b7dSRichard Lowe 
153210d63b7dSRichard Lowe /*
153310d63b7dSRichard Lowe  *	add_pending(target, recursion_level, do_get, implicit, redo)
153410d63b7dSRichard Lowe  *
153510d63b7dSRichard Lowe  *	Adds a record on the running list for a pending target
153610d63b7dSRichard Lowe  *	(waiting for its dependents to finish running).
153710d63b7dSRichard Lowe  *
153810d63b7dSRichard Lowe  *	Parameters:
153910d63b7dSRichard Lowe  *		target		Target being built
154010d63b7dSRichard Lowe  *		recursion_level	Debug indentation level
154110d63b7dSRichard Lowe  *		do_get		Sccs get flag
154210d63b7dSRichard Lowe  *		implicit	Implicit flag
154310d63b7dSRichard Lowe  *		redo		True if this target is being redone
154410d63b7dSRichard Lowe  *
154510d63b7dSRichard Lowe  *	Static variables used:
154610d63b7dSRichard Lowe  *		running_tail	Tail of running list
154710d63b7dSRichard Lowe  */
154810d63b7dSRichard Lowe void
add_pending(Name target,int recursion_level,Boolean do_get,Boolean implicit,Boolean redo)154910d63b7dSRichard Lowe add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
155010d63b7dSRichard Lowe {
155110d63b7dSRichard Lowe 	Running		rp;
155210d63b7dSRichard Lowe 	rp = new_running_struct();
155310d63b7dSRichard Lowe 	rp->state = build_pending;
155410d63b7dSRichard Lowe 	rp->target = target;
155510d63b7dSRichard Lowe 	rp->recursion_level = recursion_level;
155610d63b7dSRichard Lowe 	rp->do_get = do_get;
155710d63b7dSRichard Lowe 	rp->implicit = implicit;
155810d63b7dSRichard Lowe 	rp->redo = redo;
155910d63b7dSRichard Lowe 	store_conditionals(rp);
156010d63b7dSRichard Lowe 	*running_tail = rp;
156110d63b7dSRichard Lowe 	running_tail = &rp->next;
156210d63b7dSRichard Lowe }
156310d63b7dSRichard Lowe 
156410d63b7dSRichard Lowe /*
156510d63b7dSRichard Lowe  *	add_serial(target, recursion_level, do_get, implicit)
156610d63b7dSRichard Lowe  *
156710d63b7dSRichard Lowe  *	Adds a record on the running list for a target which must be
156810d63b7dSRichard Lowe  *	executed in serial after others have finished.
156910d63b7dSRichard Lowe  *
157010d63b7dSRichard Lowe  *	Parameters:
157110d63b7dSRichard Lowe  *		target		Target being built
157210d63b7dSRichard Lowe  *		recursion_level	Debug indentation level
157310d63b7dSRichard Lowe  *		do_get		Sccs get flag
157410d63b7dSRichard Lowe  *		implicit	Implicit flag
157510d63b7dSRichard Lowe  *
157610d63b7dSRichard Lowe  *	Static variables used:
157710d63b7dSRichard Lowe  *		running_tail	Tail of running list
157810d63b7dSRichard Lowe  */
157910d63b7dSRichard Lowe void
add_serial(Name target,int recursion_level,Boolean do_get,Boolean implicit)158010d63b7dSRichard Lowe add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
158110d63b7dSRichard Lowe {
158210d63b7dSRichard Lowe 	Running		rp;
158310d63b7dSRichard Lowe 
158410d63b7dSRichard Lowe 	rp = new_running_struct();
158510d63b7dSRichard Lowe 	rp->target = target;
158610d63b7dSRichard Lowe 	rp->recursion_level = recursion_level;
158710d63b7dSRichard Lowe 	rp->do_get = do_get;
158810d63b7dSRichard Lowe 	rp->implicit = implicit;
158910d63b7dSRichard Lowe 	rp->state = build_serial;
159010d63b7dSRichard Lowe 	rp->redo = false;
159110d63b7dSRichard Lowe 	store_conditionals(rp);
159210d63b7dSRichard Lowe 	*running_tail = rp;
159310d63b7dSRichard Lowe 	running_tail = &rp->next;
159410d63b7dSRichard Lowe }
159510d63b7dSRichard Lowe 
159610d63b7dSRichard Lowe /*
159710d63b7dSRichard Lowe  *	add_subtree(target, recursion_level, do_get, implicit)
159810d63b7dSRichard Lowe  *
159910d63b7dSRichard Lowe  *	Adds a record on the running list for a target which must be
160010d63b7dSRichard Lowe  *	executed in isolation after others have finished.
160110d63b7dSRichard Lowe  *
160210d63b7dSRichard Lowe  *	Parameters:
160310d63b7dSRichard Lowe  *		target		Target being built
160410d63b7dSRichard Lowe  *		recursion_level	Debug indentation level
160510d63b7dSRichard Lowe  *		do_get		Sccs get flag
160610d63b7dSRichard Lowe  *		implicit	Implicit flag
160710d63b7dSRichard Lowe  *
160810d63b7dSRichard Lowe  *	Static variables used:
160910d63b7dSRichard Lowe  *		running_tail	Tail of running list
161010d63b7dSRichard Lowe  */
161110d63b7dSRichard Lowe void
add_subtree(Name target,int recursion_level,Boolean do_get,Boolean implicit)161210d63b7dSRichard Lowe add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
161310d63b7dSRichard Lowe {
161410d63b7dSRichard Lowe 	Running		rp;
161510d63b7dSRichard Lowe 
161610d63b7dSRichard Lowe 	rp = new_running_struct();
161710d63b7dSRichard Lowe 	rp->target = target;
161810d63b7dSRichard Lowe 	rp->recursion_level = recursion_level;
161910d63b7dSRichard Lowe 	rp->do_get = do_get;
162010d63b7dSRichard Lowe 	rp->implicit = implicit;
162110d63b7dSRichard Lowe 	rp->state = build_subtree;
162210d63b7dSRichard Lowe 	rp->redo = false;
162310d63b7dSRichard Lowe 	store_conditionals(rp);
162410d63b7dSRichard Lowe 	*running_tail = rp;
162510d63b7dSRichard Lowe 	running_tail = &rp->next;
162610d63b7dSRichard Lowe }
162710d63b7dSRichard Lowe 
162810d63b7dSRichard Lowe /*
162910d63b7dSRichard Lowe  *	store_conditionals(rp)
163010d63b7dSRichard Lowe  *
163110d63b7dSRichard Lowe  *	Creates an array of the currently active targets with conditional
163210d63b7dSRichard Lowe  *	macros (found in the chain conditional_targets) and puts that
163310d63b7dSRichard Lowe  *	array in the Running struct.
163410d63b7dSRichard Lowe  *
163510d63b7dSRichard Lowe  *	Parameters:
163610d63b7dSRichard Lowe  *		rp		Running struct for storing chain
163710d63b7dSRichard Lowe  *
163810d63b7dSRichard Lowe  *	Global variables used:
163910d63b7dSRichard Lowe  *		conditional_targets  Chain of current dynamic conditionals
164010d63b7dSRichard Lowe  */
164110d63b7dSRichard Lowe static void
store_conditionals(Running rp)164210d63b7dSRichard Lowe store_conditionals(Running rp)
164310d63b7dSRichard Lowe {
164410d63b7dSRichard Lowe 	int		cnt;
164510d63b7dSRichard Lowe 	Chain		cond_name;
164610d63b7dSRichard Lowe 
164710d63b7dSRichard Lowe 	if (conditional_targets == NULL) {
164810d63b7dSRichard Lowe 		rp->conditional_cnt = 0;
164910d63b7dSRichard Lowe 		rp->conditional_targets = NULL;
165010d63b7dSRichard Lowe 		return;
165110d63b7dSRichard Lowe 	}
165210d63b7dSRichard Lowe 	cnt = 0;
165310d63b7dSRichard Lowe 	for (cond_name = conditional_targets;
165410d63b7dSRichard Lowe 	     cond_name != NULL;
165510d63b7dSRichard Lowe 	     cond_name = cond_name->next) {
165610d63b7dSRichard Lowe 		cnt++;
165710d63b7dSRichard Lowe 	}
165810d63b7dSRichard Lowe 	rp->conditional_cnt = cnt;
165910d63b7dSRichard Lowe 	rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
166010d63b7dSRichard Lowe 	for (cond_name = conditional_targets;
166110d63b7dSRichard Lowe 	     cond_name != NULL;
166210d63b7dSRichard Lowe 	     cond_name = cond_name->next) {
166310d63b7dSRichard Lowe 		rp->conditional_targets[--cnt] = cond_name->name;
166410d63b7dSRichard Lowe 	}
166510d63b7dSRichard Lowe }
166610d63b7dSRichard Lowe 
166710d63b7dSRichard Lowe /*
166810d63b7dSRichard Lowe  *	parallel_ok(target, line_prop_must_exists)
166910d63b7dSRichard Lowe  *
167010d63b7dSRichard Lowe  *	Returns true if the target can be run in parallel
167110d63b7dSRichard Lowe  *
167210d63b7dSRichard Lowe  *	Return value:
167310d63b7dSRichard Lowe  *				True if can run in parallel
167410d63b7dSRichard Lowe  *
167510d63b7dSRichard Lowe  *	Parameters:
167610d63b7dSRichard Lowe  *		target		Target being tested
167710d63b7dSRichard Lowe  *
167810d63b7dSRichard Lowe  *	Global variables used:
167910d63b7dSRichard Lowe  *		all_parallel	True if all targets default to parallel
168010d63b7dSRichard Lowe  *		only_parallel	True if no targets default to parallel
168110d63b7dSRichard Lowe  */
168210d63b7dSRichard Lowe Boolean
parallel_ok(Name target,Boolean line_prop_must_exists)168310d63b7dSRichard Lowe parallel_ok(Name target, Boolean line_prop_must_exists)
168410d63b7dSRichard Lowe {
168510d63b7dSRichard Lowe 	Boolean		assign;
168610d63b7dSRichard Lowe 	Boolean		make_refd;
168710d63b7dSRichard Lowe 	Property	line;
168810d63b7dSRichard Lowe 	Cmd_line	rule;
168910d63b7dSRichard Lowe 
169010d63b7dSRichard Lowe 	assign = make_refd = false;
169110d63b7dSRichard Lowe 	if (((line = get_prop(target->prop, line_prop)) == NULL) &&
169210d63b7dSRichard Lowe 	    line_prop_must_exists) {
169310d63b7dSRichard Lowe 		return false;
169410d63b7dSRichard Lowe 	}
169510d63b7dSRichard Lowe 	if (line != NULL) {
169610d63b7dSRichard Lowe 		for (rule = line->body.line.command_used;
169710d63b7dSRichard Lowe 		     rule != NULL;
169810d63b7dSRichard Lowe 		     rule = rule->next) {
169910d63b7dSRichard Lowe 			if (rule->assign) {
170010d63b7dSRichard Lowe 				assign = true;
170110d63b7dSRichard Lowe 			} else if (rule->make_refd) {
170210d63b7dSRichard Lowe 				make_refd = true;
170310d63b7dSRichard Lowe 			}
170410d63b7dSRichard Lowe 		}
170510d63b7dSRichard Lowe 	}
170610d63b7dSRichard Lowe 	if (assign) {
170710d63b7dSRichard Lowe 		return false;
170810d63b7dSRichard Lowe 	} else if (target->parallel) {
170910d63b7dSRichard Lowe 		return true;
171010d63b7dSRichard Lowe 	} else if (target->no_parallel) {
171110d63b7dSRichard Lowe 		return false;
171210d63b7dSRichard Lowe 	} else if (all_parallel) {
171310d63b7dSRichard Lowe 		return true;
171410d63b7dSRichard Lowe 	} else if (only_parallel) {
171510d63b7dSRichard Lowe 		return false;
171610d63b7dSRichard Lowe 	} else if (make_refd) {
171710d63b7dSRichard Lowe 		return false;
171810d63b7dSRichard Lowe 	} else {
171910d63b7dSRichard Lowe 		return true;
172010d63b7dSRichard Lowe 	}
172110d63b7dSRichard Lowe }
172210d63b7dSRichard Lowe 
172310d63b7dSRichard Lowe /*
172410d63b7dSRichard Lowe  *	is_running(target)
172510d63b7dSRichard Lowe  *
172610d63b7dSRichard Lowe  *	Returns true if the target is running.
172710d63b7dSRichard Lowe  *
172810d63b7dSRichard Lowe  *	Return value:
172910d63b7dSRichard Lowe  *				True if target is running
173010d63b7dSRichard Lowe  *
173110d63b7dSRichard Lowe  *	Parameters:
173210d63b7dSRichard Lowe  *		target		Target to check
173310d63b7dSRichard Lowe  *
173410d63b7dSRichard Lowe  *	Global variables used:
173510d63b7dSRichard Lowe  *		running_list	List of running processes
173610d63b7dSRichard Lowe  */
173710d63b7dSRichard Lowe Boolean
is_running(Name target)173810d63b7dSRichard Lowe is_running(Name target)
173910d63b7dSRichard Lowe {
174010d63b7dSRichard Lowe 	Running		rp;
174110d63b7dSRichard Lowe 
174210d63b7dSRichard Lowe 	if (target->state != build_running) {
174310d63b7dSRichard Lowe 		return false;
174410d63b7dSRichard Lowe 	}
174510d63b7dSRichard Lowe 	for (rp = running_list;
174610d63b7dSRichard Lowe 	     rp != NULL && target != rp->target;
174710d63b7dSRichard Lowe 	     rp = rp->next);
174810d63b7dSRichard Lowe 	if (rp == NULL) {
174910d63b7dSRichard Lowe 		return false;
175010d63b7dSRichard Lowe 	} else {
175110d63b7dSRichard Lowe 		return (rp->state == build_running) ? true : false;
175210d63b7dSRichard Lowe 	}
175310d63b7dSRichard Lowe }
175410d63b7dSRichard Lowe 
175510d63b7dSRichard Lowe /*
175610d63b7dSRichard Lowe  * This function replaces the makesh binary.
175710d63b7dSRichard Lowe  */
1758*ae389aa9SAndy Fiddaman 
175910d63b7dSRichard Lowe 
176010d63b7dSRichard Lowe static pid_t
run_rule_commands(char * host,char ** commands)176110d63b7dSRichard Lowe run_rule_commands(char *host, char **commands)
176210d63b7dSRichard Lowe {
176310d63b7dSRichard Lowe 	Boolean		always_exec;
176410d63b7dSRichard Lowe 	Name		command;
176510d63b7dSRichard Lowe 	Boolean		ignore;
176610d63b7dSRichard Lowe 	int		length;
176710d63b7dSRichard Lowe 	Doname		result;
176810d63b7dSRichard Lowe 	Boolean		silent_flag;
176910d63b7dSRichard Lowe 	wchar_t		*tmp_wcs_buffer;
177010d63b7dSRichard Lowe 
177110d63b7dSRichard Lowe 	childPid = fork();
177210d63b7dSRichard Lowe 	switch (childPid) {
177310d63b7dSRichard Lowe 	case -1:	/* Error */
177410d63b7dSRichard Lowe 		fatal(gettext("Could not fork child process for dmake job: %s"),
177510d63b7dSRichard Lowe 		      errmsg(errno));
177610d63b7dSRichard Lowe 		break;
177710d63b7dSRichard Lowe 	case 0:		/* Child */
177810d63b7dSRichard Lowe 		/* To control the processed targets list is not the child's business */
177910d63b7dSRichard Lowe 		running_list = NULL;
178010d63b7dSRichard Lowe 		if(out_err_same) {
178110d63b7dSRichard Lowe 			redirect_io(stdout_file, (char*)NULL);
178210d63b7dSRichard Lowe 		} else {
178310d63b7dSRichard Lowe 			redirect_io(stdout_file, stderr_file);
178410d63b7dSRichard Lowe 		}
178510d63b7dSRichard Lowe 		for (commands = commands;
178610d63b7dSRichard Lowe 		     (*commands != (char *)NULL);
178710d63b7dSRichard Lowe 		     commands++) {
178810d63b7dSRichard Lowe 			silent_flag = silent;
178910d63b7dSRichard Lowe 			ignore = false;
179010d63b7dSRichard Lowe 			always_exec = false;
179110d63b7dSRichard Lowe 			while ((**commands == (int) at_char) ||
179210d63b7dSRichard Lowe 			       (**commands == (int) hyphen_char) ||
179310d63b7dSRichard Lowe 			       (**commands == (int) plus_char)) {
179410d63b7dSRichard Lowe 				if (**commands == (int) at_char) {
179510d63b7dSRichard Lowe 					silent_flag = true;
179610d63b7dSRichard Lowe 				}
179710d63b7dSRichard Lowe 				if (**commands == (int) hyphen_char) {
179810d63b7dSRichard Lowe 					ignore = true;
179910d63b7dSRichard Lowe 				}
180010d63b7dSRichard Lowe 				if (**commands == (int) plus_char) {
180110d63b7dSRichard Lowe 					always_exec = true;
180210d63b7dSRichard Lowe 				}
180310d63b7dSRichard Lowe 				(*commands)++;
180410d63b7dSRichard Lowe 			}
180510d63b7dSRichard Lowe 			if ((length = strlen(*commands)) >= MAXPATHLEN) {
180610d63b7dSRichard Lowe 				tmp_wcs_buffer = ALLOC_WC(length + 1);
180710d63b7dSRichard Lowe 				(void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
180810d63b7dSRichard Lowe 				command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
180910d63b7dSRichard Lowe 				retmem(tmp_wcs_buffer);
181010d63b7dSRichard Lowe 			} else {
181110d63b7dSRichard Lowe 				MBSTOWCS(wcs_buffer, *commands);
181210d63b7dSRichard Lowe 				command = GETNAME(wcs_buffer, FIND_LENGTH);
181310d63b7dSRichard Lowe 			}
181410d63b7dSRichard Lowe 			if ((command->hash.length > 0) &&
181510d63b7dSRichard Lowe 			    !silent_flag) {
181610d63b7dSRichard Lowe 				(void) printf("%s\n", command->string_mb);
181710d63b7dSRichard Lowe 			}
181810d63b7dSRichard Lowe 			result = dosys(command,
181910d63b7dSRichard Lowe 			               ignore,
182010d63b7dSRichard Lowe 			               false,
182110d63b7dSRichard Lowe 			               false, /* bugs #4085164 & #4990057 */
182210d63b7dSRichard Lowe 			               /* BOOLEAN(silent_flag && ignore), */
1823*ae389aa9SAndy Fiddaman 			               always_exec,
182410d63b7dSRichard Lowe 			               (Name) NULL);
182510d63b7dSRichard Lowe 			if (result == build_failed) {
182610d63b7dSRichard Lowe 				if (silent_flag) {
182710d63b7dSRichard Lowe 					(void) printf(gettext("The following command caused the error:\n%s\n"), command->string_mb);
182810d63b7dSRichard Lowe 				}
182910d63b7dSRichard Lowe 				if (!ignore) {
183010d63b7dSRichard Lowe 					_exit(1);
183110d63b7dSRichard Lowe 				}
183210d63b7dSRichard Lowe 			}
183310d63b7dSRichard Lowe 		}
183410d63b7dSRichard Lowe 		_exit(0);
183510d63b7dSRichard Lowe 		break;
183610d63b7dSRichard Lowe 	default:
183710d63b7dSRichard Lowe 		break;
183810d63b7dSRichard Lowe 	}
183910d63b7dSRichard Lowe 	return childPid;
184010d63b7dSRichard Lowe }
184110d63b7dSRichard Lowe 
184210d63b7dSRichard Lowe static void
maybe_reread_make_state(void)184310d63b7dSRichard Lowe maybe_reread_make_state(void)
184410d63b7dSRichard Lowe {
184510d63b7dSRichard Lowe 	/* Copying dosys()... */
184610d63b7dSRichard Lowe 	if (report_dependencies_level == 0) {
184710d63b7dSRichard Lowe 		make_state->stat.time = file_no_time;
184810d63b7dSRichard Lowe 		(void) exists(make_state);
184910d63b7dSRichard Lowe 		if (make_state_before == make_state->stat.time) {
185010d63b7dSRichard Lowe 			return;
185110d63b7dSRichard Lowe 		}
185210d63b7dSRichard Lowe 		makefile_type = reading_statefile;
185310d63b7dSRichard Lowe 		if (read_trace_level > 1) {
185410d63b7dSRichard Lowe 			trace_reader = true;
185510d63b7dSRichard Lowe 		}
185610d63b7dSRichard Lowe 		temp_file_number++;
185710d63b7dSRichard Lowe 		(void) read_simple_file(make_state,
185810d63b7dSRichard Lowe 					false,
185910d63b7dSRichard Lowe 					false,
186010d63b7dSRichard Lowe 					false,
186110d63b7dSRichard Lowe 					false,
186210d63b7dSRichard Lowe 					false,
186310d63b7dSRichard Lowe 					true);
186410d63b7dSRichard Lowe 		trace_reader = false;
186510d63b7dSRichard Lowe 	}
186610d63b7dSRichard Lowe }
186710d63b7dSRichard Lowe 
186810d63b7dSRichard Lowe 
186910d63b7dSRichard Lowe static void
delete_running_struct(Running rp)187010d63b7dSRichard Lowe delete_running_struct(Running rp)
187110d63b7dSRichard Lowe {
187210d63b7dSRichard Lowe 	if ((rp->conditional_cnt > 0) &&
187310d63b7dSRichard Lowe 	    (rp->conditional_targets != NULL)) {
187410d63b7dSRichard Lowe 		retmem_mb((char *) rp->conditional_targets);
187510d63b7dSRichard Lowe 	}
187610d63b7dSRichard Lowe /**/
187710d63b7dSRichard Lowe 	if ((rp->auto_count > 0) &&
187810d63b7dSRichard Lowe 	    (rp->automatics != NULL)) {
187910d63b7dSRichard Lowe 		retmem_mb((char *) rp->automatics);
188010d63b7dSRichard Lowe 	}
188110d63b7dSRichard Lowe /**/
188210d63b7dSRichard Lowe 	if(rp->sprodep_value) {
188310d63b7dSRichard Lowe 		free_name(rp->sprodep_value);
188410d63b7dSRichard Lowe 	}
188510d63b7dSRichard Lowe 	if(rp->sprodep_env) {
188610d63b7dSRichard Lowe 		retmem_mb(rp->sprodep_env);
188710d63b7dSRichard Lowe 	}
188810d63b7dSRichard Lowe 	retmem_mb((char *) rp);
188910d63b7dSRichard Lowe 
189010d63b7dSRichard Lowe }
189110d63b7dSRichard Lowe 
189210d63b7dSRichard Lowe 
1893