summaryrefslogtreecommitdiff
path: root/usr/src/make_src/Make/bin/make/common/parallel.cc
diff options
context:
space:
mode:
authorIgor Pashev <igor.pashev@nexenta.com>2012-06-29 14:36:07 +0400
committerIgor Pashev <igor.pashev@nexenta.com>2012-06-29 14:36:07 +0400
commite0463df9c3d2ee6155221cc443c571d5da47098a (patch)
tree5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/parallel.cc
downloadsunmake-e0463df9c3d2ee6155221cc443c571d5da47098a.tar.gz
Initial import of DevPro make sourcesorig
Downloaded from http://dlc.sun.com/osol/devpro/downloads/current/ Licensed under CDDL http://www.opensource.org/licenses/CDDL-1.0
Diffstat (limited to 'usr/src/make_src/Make/bin/make/common/parallel.cc')
-rw-r--r--usr/src/make_src/Make/bin/make/common/parallel.cc2477
1 files changed, 2477 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/parallel.cc b/usr/src/make_src/Make/bin/make/common/parallel.cc
new file mode 100644
index 0000000..1831415
--- /dev/null
+++ b/usr/src/make_src/Make/bin/make/common/parallel.cc
@@ -0,0 +1,2477 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+/*
+ * @(#)parallel.cc 1.75 06/12/12
+ */
+
+#pragma ident "@(#)parallel.cc 1.75 06/12/12"
+
+#ifdef TEAMWARE_MAKE_CMN
+
+/*
+ * parallel.cc
+ *
+ * Deal with the parallel processing
+ */
+
+/*
+ * Included files
+ */
+#ifdef DISTRIBUTED
+#include <avo/strings.h> /* AVO_STRDUP() */
+#include <dm/Avo_DoJobMsg.h>
+#include <dm/Avo_MToolJobResultMsg.h>
+#endif
+#include <errno.h> /* errno */
+#include <fcntl.h>
+#include <avo/util.h> /* avo_get_user(), avo_hostname() */
+#include <mk/defs.h>
+#include <mksh/dosys.h> /* redirect_io() */
+#include <mksh/macro.h> /* expand_value() */
+#include <mksh/misc.h> /* getmem() */
+#include <sys/signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#ifdef SGE_SUPPORT
+#include <dmthread/Avo_PathNames.h>
+#endif
+
+
+/*
+ * Defined macros
+ */
+#define MAXRULES 100
+
+/*
+ * This const should be in avo_dms/include/AvoDmakeCommand.h
+ */
+const int local_host_mask = 0x20;
+
+
+/*
+ * typedefs & structs
+ */
+
+
+/*
+ * Static variables
+ */
+#ifdef TEAMWARE_MAKE_CMN
+static Boolean just_did_subtree = false;
+static char local_host[MAXNAMELEN] = "";
+static char user_name[MAXNAMELEN] = "";
+#endif
+static int pmake_max_jobs = 0;
+static pid_t process_running = -1;
+static Running *running_tail = &running_list;
+static Name subtree_conflict;
+static Name subtree_conflict2;
+
+
+/*
+ * File table of contents
+ */
+#ifdef DISTRIBUTED
+static void append_dmake_cmd(Avo_DoJobMsg *dmake_job_msg, char *orig_cmd_line, int cmd_options);
+static void append_job_result_msg(Avo_MToolJobResultMsg *msg, char *outFn, char *errFn);
+static void send_job_result_msg(Running rp);
+#endif
+static void delete_running_struct(Running rp);
+static Boolean dependency_conflict(Name target);
+static Doname distribute_process(char **commands, Property line);
+static void doname_subtree(Name target, Boolean do_get, Boolean implicit);
+static void dump_out_file(char *filename, Boolean err);
+static void finish_doname(Running rp);
+static void maybe_reread_make_state(void);
+static void process_next(void);
+static void reset_conditionals(int cnt, Name *targets, Property *locals);
+static pid_t run_rule_commands(char *host, char **commands);
+static Property *set_conditionals(int cnt, Name *targets);
+static void store_conditionals(Running rp);
+
+
+/*
+ * execute_parallel(line, waitflg)
+ *
+ * DMake 2.x:
+ * parallel mode: spawns a parallel process to execute the command group.
+ * distributed mode: sends the command group down the pipe to rxm.
+ *
+ * Return value:
+ * The result of the execution
+ *
+ * Parameters:
+ * line The command group to execute
+ */
+Doname
+execute_parallel(Property line, Boolean waitflg, Boolean local)
+{
+ int argcnt;
+ int cmd_options = 0;
+ char *commands[MAXRULES + 5];
+ char *cp;
+#ifdef DISTRIBUTED
+ Avo_DoJobMsg *dmake_job_msg = NULL;
+#endif
+ Name dmake_name;
+ Name dmake_value;
+ int ignore;
+ Name make_machines_name;
+ char **p;
+ Property prop;
+ Doname result = build_ok;
+ Cmd_line rule;
+ Boolean silent_flag;
+ Name target = line->body.line.target;
+ Boolean wrote_state_file = false;
+
+ if ((pmake_max_jobs == 0) &&
+ (dmake_mode_type == parallel_mode)) {
+ if (user_name[0] == '\0') {
+ avo_get_user(user_name, NULL);
+ }
+ if (local_host[0] == '\0') {
+ strcpy(local_host, avo_hostname());
+ }
+ MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MAX_JOBS"));
+ dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
+ if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
+ ((dmake_value = prop->body.macro.value) != NULL)) {
+ pmake_max_jobs = atoi(dmake_value->string_mb);
+ if (pmake_max_jobs <= 0) {
+ warning(catgets(catd, 1, 308, "DMAKE_MAX_JOBS cannot be less than or equal to zero."));
+ warning(catgets(catd, 1, 309, "setting DMAKE_MAX_JOBS to %d."), PMAKE_DEF_MAX_JOBS);
+ pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
+ }
+ } else {
+ /*
+ * For backwards compatibility w/ PMake 1.x, when
+ * DMake 2.x is being run in parallel mode, DMake
+ * should parse the PMake startup file
+ * $(HOME)/.make.machines to get the pmake_max_jobs.
+ */
+ MBSTOWCS(wcs_buffer, NOCATGETS("PMAKE_MACHINESFILE"));
+ dmake_name = GETNAME(wcs_buffer, FIND_LENGTH);
+ if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) &&
+ ((dmake_value = prop->body.macro.value) != NULL)) {
+ make_machines_name = dmake_value;
+ } else {
+ make_machines_name = NULL;
+ }
+ if ((pmake_max_jobs = read_make_machines(make_machines_name)) <= 0) {
+ pmake_max_jobs = PMAKE_DEF_MAX_JOBS;
+ }
+ }
+#ifdef DISTRIBUTED
+ if (send_mtool_msgs) {
+ send_rsrc_info_msg(pmake_max_jobs, local_host, user_name);
+ }
+#endif
+ }
+
+ if ((dmake_mode_type == serial_mode) ||
+ ((dmake_mode_type == parallel_mode) && (waitflg))) {
+ return (execute_serial(line));
+ }
+
+#ifdef DISTRIBUTED
+ if (dmake_mode_type == distributed_mode) {
+ if(local) {
+// return (execute_serial(line));
+ waitflg = true;
+ }
+ dmake_job_msg = new Avo_DoJobMsg();
+ dmake_job_msg->setJobId(++job_msg_id);
+ dmake_job_msg->setTarget(target->string_mb);
+ dmake_job_msg->setImmediateOutput(0);
+ called_make = false;
+ } else
+#endif
+ {
+ p = commands;
+ }
+
+ argcnt = 0;
+ for (rule = line->body.line.command_used;
+ rule != NULL;
+ rule = rule->next) {
+ if (posix && (touch || quest) && !rule->always_exec) {
+ continue;
+ }
+ if (vpath_defined) {
+ rule->command_line =
+ vpath_translation(rule->command_line);
+ }
+ if (dmake_mode_type == distributed_mode) {
+ cmd_options = 0;
+ if(local) {
+ cmd_options |= local_host_mask;
+ }
+ } else {
+ silent_flag = false;
+ ignore = 0;
+ }
+ if (rule->command_line->hash.length > 0) {
+ if (++argcnt == MAXRULES) {
+ if (dmake_mode_type == distributed_mode) {
+ /* XXX - tell rxm to execute on local host. */
+ /* I WAS HERE!!! */
+ } else {
+ /* Too many rules, run serially instead. */
+ return build_serial;
+ }
+ }
+#ifdef DISTRIBUTED
+ if (dmake_mode_type == distributed_mode) {
+ /*
+ * XXX - set assign_mask to tell rxm
+ * to do the following.
+ */
+/* From execute_serial():
+ if (rule->assign) {
+ result = build_ok;
+ do_assign(rule->command_line, target);
+ */
+ if (0) {
+ } else if (report_dependencies_level == 0) {
+ if (rule->ignore_error) {
+ cmd_options |= ignore_mask;
+ }
+ if (rule->silent) {
+ cmd_options |= silent_mask;
+ }
+ if (rule->command_line->meta) {
+ cmd_options |= meta_mask;
+ }
+ if (rule->make_refd) {
+ cmd_options |= make_refd_mask;
+ }
+ if (do_not_exec_rule) {
+ cmd_options |= do_not_exec_mask;
+ }
+ append_dmake_cmd(dmake_job_msg,
+ rule->command_line->string_mb,
+ cmd_options);
+ /* Copying dosys()... */
+ if (rule->make_refd) {
+ if (waitflg) {
+ dmake_job_msg->setImmediateOutput(1);
+ }
+ called_make = true;
+ if (command_changed &&
+ !wrote_state_file) {
+ write_state_file(0, false);
+ wrote_state_file = true;
+ }
+ }
+ }
+ } else
+#endif
+ {
+ if (rule->silent && !silent) {
+ silent_flag = true;
+ }
+ if (rule->ignore_error) {
+ ignore++;
+ }
+ /* XXX - need to add support for + prefix */
+ if (silent_flag || ignore) {
+ *p = getmem((silent_flag ? 1 : 0) +
+ ignore +
+ (strlen(rule->
+ command_line->
+ string_mb)) +
+ 1);
+ cp = *p++;
+ if (silent_flag) {
+ *cp++ = (int) at_char;
+ }
+ if (ignore) {
+ *cp++ = (int) hyphen_char;
+ }
+ (void) strcpy(cp, rule->command_line->string_mb);
+ } else {
+ *p++ = rule->command_line->string_mb;
+ }
+ }
+ }
+ }
+ if ((argcnt == 0) ||
+ (report_dependencies_level > 0)) {
+#ifdef DISTRIBUTED
+ if (dmake_job_msg) {
+ delete dmake_job_msg;
+ }
+#endif
+ return build_ok;
+ }
+#ifdef DISTRIBUTED
+ if (dmake_mode_type == distributed_mode) {
+ // Send a DoJob message to the rxm process.
+ distribute_rxm(dmake_job_msg);
+
+ // Wait for an acknowledgement.
+ Avo_AcknowledgeMsg *ackMsg = getAcknowledgeMsg();
+ if (ackMsg) {
+ delete ackMsg;
+ }
+
+ if (waitflg) {
+ // Wait for, and process a job result.
+ result = await_dist(waitflg);
+ if (called_make) {
+ maybe_reread_make_state();
+ }
+ check_state(temp_file_name);
+ if (result == build_failed) {
+ if (!continue_after_error) {
+
+#ifdef PRINT_EXIT_STATUS
+ warning(NOCATGETS("I'm in execute_parallel. await_dist() returned build_failed"));
+#endif
+
+ fatal(catgets(catd, 1, 252, "Command failed for target `%s'"),
+ target->string_mb);
+ }
+ /*
+ * Make sure a failing command is not
+ * saved in .make.state.
+ */
+ line->body.line.command_used = NULL;
+ }
+ if (temp_file_name != NULL) {
+ free_name(temp_file_name);
+ }
+ temp_file_name = NULL;
+ Property spro = get_prop(sunpro_dependencies->prop, macro_prop);
+ if(spro != NULL) {
+ Name val = spro->body.macro.value;
+ if(val != NULL) {
+ free_name(val);
+ spro->body.macro.value = NULL;
+ }
+ }
+ spro = get_prop(sunpro_dependencies->prop, env_mem_prop);
+ if(spro) {
+ char *val = spro->body.env_mem.value;
+ if(val != NULL) {
+ retmem_mb(val);
+ spro->body.env_mem.value = NULL;
+ }
+ }
+ return result;
+ } else {
+ parallel_process_cnt++;
+ return build_running;
+ }
+ } else
+#endif
+ {
+ *p = NULL;
+
+ Doname res = distribute_process(commands, line);
+ if (res == build_running) {
+ parallel_process_cnt++;
+ }
+
+ /*
+ * Return only those memory that were specially allocated
+ * for part of commands.
+ */
+ for (int i = 0; commands[i] != NULL; i++) {
+ if ((commands[i][0] == (int) at_char) ||
+ (commands[i][0] == (int) hyphen_char)) {
+ retmem_mb(commands[i]);
+ }
+ }
+ return res;
+ }
+}
+
+#ifdef DISTRIBUTED
+/*
+ * append_dmake_cmd()
+ *
+ * Replaces all escaped newline's (\<cr>)
+ * in the original command line with space's,
+ * then append the new command line to the DoJobMsg object.
+ */
+static void
+append_dmake_cmd(Avo_DoJobMsg *dmake_job_msg,
+ char *orig_cmd_line,
+ int cmd_options)
+{
+/*
+ Avo_DmakeCommand *tmp_dmake_command;
+
+ tmp_dmake_command = new Avo_DmakeCommand(orig_cmd_line, cmd_options);
+ dmake_job_msg->appendCmd(tmp_dmake_command);
+ delete tmp_dmake_command;
+ */
+ dmake_job_msg->appendCmd(new Avo_DmakeCommand(orig_cmd_line, cmd_options));
+}
+#endif
+
+#ifdef TEAMWARE_MAKE_CMN
+#define MAXJOBS_ADJUST_RFE4694000
+
+#ifdef MAXJOBS_ADJUST_RFE4694000
+
+#include <unistd.h> /* sysconf(_SC_NPROCESSORS_ONLN) */
+#include <sys/ipc.h> /* ftok() */
+#include <sys/shm.h> /* shmget(), shmat(), shmdt(), shmctl() */
+#include <semaphore.h> /* sem_init(), sem_trywait(), sem_post(), sem_destroy() */
+#if defined(linux)
+#define LOADAVG_1MIN 0
+#else
+#include <sys/loadavg.h> /* getloadavg() */
+#endif /* linux */
+
+/*
+ * adjust_pmake_max_jobs (int pmake_max_jobs)
+ *
+ * Parameters:
+ * pmake_max_jobs - max jobs limit set by user
+ *
+ * External functions used:
+ * sysconf()
+ * getloadavg()
+ */
+static int
+adjust_pmake_max_jobs (int pmake_max_jobs)
+{
+ static int ncpu = 0;
+ double loadavg[3];
+ int adjustment;
+ int adjusted_max_jobs;
+
+ if (ncpu <= 0) {
+ if ((ncpu = sysconf(_SC_NPROCESSORS_ONLN)) <= 0) {
+ ncpu = 1;
+ }
+ }
+ if (getloadavg(loadavg, 3) != 3) return(pmake_max_jobs);
+ adjustment = ((int)loadavg[LOADAVG_1MIN]);
+ if (adjustment < 2) return(pmake_max_jobs);
+ if (ncpu > 1) {
+ adjustment = adjustment / ncpu;
+ }
+ adjusted_max_jobs = pmake_max_jobs - adjustment;
+ if (adjusted_max_jobs < 1) adjusted_max_jobs = 1;
+ return(adjusted_max_jobs);
+}
+
+/*
+ * M2 adjust mode data and functions
+ *
+ * m2_init() - initializes M2 shared semaphore
+ * m2_acquire_job() - decrements M2 semaphore counter
+ * m2_release_job() - increments M2 semaphore counter
+ * m2_fini() - destroys M2 semaphore and shared memory*
+ *
+ * Environment variables:
+ * __DMAKE_M2_FILE__
+ *
+ * External functions:
+ * ftok(), shmget(), shmat(), shmdt(), shmctl()
+ * sem_init(), sem_trywait(), sem_post(), sem_destroy()
+ * creat(), close(), unlink()
+ * getenv(), putenv()
+ *
+ * Static variables:
+ * m2_file - tmp file name to create ipc key for shared memory
+ * m2_shm_id - shared memory id
+ * m2_shm_sem - shared memory semaphore
+ */
+
+static char m2_file[MAXPATHLEN];
+static int m2_shm_id = -1;
+static sem_t* m2_shm_sem = 0;
+
+static int
+m2_init() {
+ char *var;
+ key_t key;
+
+ if ((var = getenv(NOCATGETS("__DMAKE_M2_FILE__"))) == 0) {
+ /* compose tmp file name */
+ sprintf(m2_file, NOCATGETS("%s/dmake.m2.%d.XXXXXX"), tmpdir, getpid());
+
+ /* create tmp file */
+ int fd = mkstemp(m2_file);
+ if (fd < 0) {
+ return -1;
+ } else {
+ close(fd);
+ }
+ } else {
+ /* using existing semaphore */
+ strcpy(m2_file, var);
+ }
+
+ /* combine IPC key */
+ if ((key = ftok(m2_file, 38)) == (key_t) -1) {
+ return -1;
+ }
+
+ /* create shared memory */
+ if ((m2_shm_id = shmget(key, sizeof(*m2_shm_sem), 0666 | (var ? 0 : IPC_CREAT|IPC_EXCL))) == -1) {
+ return -1;
+ }
+
+ /* attach shared memory */
+ if ((m2_shm_sem = (sem_t*) shmat(m2_shm_id, 0, 0666)) == (sem_t*)-1) {
+ return -1;
+ }
+
+ /* root process */
+ if (var == 0) {
+ /* initialize semaphore */
+ if (sem_init(m2_shm_sem, 1, pmake_max_jobs)) {
+ return -1;
+ }
+
+ /* alloc memory for env variable */
+ if ((var = (char*) malloc(MAXPATHLEN)) == 0) {
+ return -1;
+ }
+
+ /* put key to env */
+ sprintf(var, NOCATGETS("__DMAKE_M2_FILE__=%s"), m2_file);
+ if (putenv(var)) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void
+m2_fini() {
+ if (m2_shm_id >= 0) {
+ struct shmid_ds stat;
+
+ /* determine the number of attached processes */
+ if (shmctl(m2_shm_id, IPC_STAT, &stat) == 0) {
+ if (stat.shm_nattch <= 1) {
+ /* destroy semaphore */
+ if (m2_shm_sem != 0) {
+ (void) sem_destroy(m2_shm_sem);
+ }
+
+ /* destroy shared memory */
+ (void) shmctl(m2_shm_id, IPC_RMID, &stat);
+
+ /* remove tmp file created for the key */
+ (void) unlink(m2_file);
+ } else {
+ /* detach shared memory */
+ if (m2_shm_sem != 0) {
+ (void) shmdt((char*) m2_shm_sem);
+ }
+ }
+ }
+
+ m2_shm_id = -1;
+ m2_shm_sem = 0;
+ }
+}
+
+static int
+m2_acquire_job() {
+ if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
+ if (sem_trywait(m2_shm_sem) == 0) {
+ return 1;
+ }
+ if (errno == EAGAIN) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+m2_release_job() {
+ if ((m2_shm_id >= 0) && (m2_shm_sem != 0)) {
+ if (sem_post(m2_shm_sem) == 0) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+/*
+ * job adjust mode
+ *
+ * Possible values:
+ * ADJUST_M1 - adjustment by system load (default)
+ * ADJUST_M2 - fixed limit of jobs for the group of nested dmakes
+ * ADJUST_NONE - no adjustment - fixed limit of jobs for the current dmake
+ */
+static enum {
+ ADJUST_UNKNOWN,
+ ADJUST_M1,
+ ADJUST_M2,
+ ADJUST_NONE
+} job_adjust_mode = ADJUST_UNKNOWN;
+
+/*
+ * void job_adjust_fini()
+ *
+ * Description:
+ * Cleans up job adjust data.
+ *
+ * Static variables:
+ * job_adjust_mode Current job adjust mode
+ */
+void
+job_adjust_fini() {
+ if (job_adjust_mode == ADJUST_M2) {
+ m2_fini();
+ }
+}
+
+/*
+ * void job_adjust_error()
+ *
+ * Description:
+ * Prints warning message, cleans up job adjust data, and disables job adjustment
+ *
+ * Environment:
+ * DMAKE_ADJUST_MAX_JOBS
+ *
+ * External functions:
+ * putenv()
+ *
+ * Static variables:
+ * job_adjust_mode Current job adjust mode
+ */
+static void
+job_adjust_error() {
+ if (job_adjust_mode != ADJUST_NONE) {
+ /* cleanup internals */
+ job_adjust_fini();
+
+ /* warning message for the user */
+ warning(catgets(catd, 1, 339, "Encountered max jobs auto adjustment error - disabling auto adjustment."));
+
+ /* switch off job adjustment for the children */
+ putenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS=NO"));
+
+ /* and for this dmake */
+ job_adjust_mode = ADJUST_NONE;
+ }
+}
+
+/*
+ * void job_adjust_init()
+ *
+ * Description:
+ * Parses DMAKE_ADJUST_MAX_JOBS env variable
+ * and performs appropriate initializations.
+ *
+ * Environment:
+ * DMAKE_ADJUST_MAX_JOBS
+ * DMAKE_ADJUST_MAX_JOBS == "NO" - no adjustment
+ * DMAKE_ADJUST_MAX_JOBS == "M2" - M2 adjust mode
+ * other - M1 adjust mode
+ *
+ * External functions:
+ * getenv()
+ *
+ * Static variables:
+ * job_adjust_mode Current job adjust mode
+ */
+static void
+job_adjust_init() {
+ if (job_adjust_mode == ADJUST_UNKNOWN) {
+ /* default mode */
+ job_adjust_mode = ADJUST_M1;
+
+ /* determine adjust mode */
+ if (char *var = getenv(NOCATGETS("DMAKE_ADJUST_MAX_JOBS"))) {
+ if (strcasecmp(var, NOCATGETS("NO")) == 0) {
+ job_adjust_mode = ADJUST_NONE;
+ } else if (strcasecmp(var, NOCATGETS("M2")) == 0) {
+ job_adjust_mode = ADJUST_M2;
+ }
+ }
+
+ /* M2 specific initialization */
+ if (job_adjust_mode == ADJUST_M2) {
+ if (m2_init()) {
+ job_adjust_error();
+ }
+ }
+ }
+}
+
+#endif /* MAXJOBS_ADJUST_RFE4694000 */
+#endif /* TEAMWARE_MAKE_CMN */
+
+/*
+ * distribute_process(char **commands, Property line)
+ *
+ * Parameters:
+ * commands argv vector of commands to execute
+ *
+ * Return value:
+ * The result of the execution
+ *
+ * Static variables used:
+ * process_running Set to the pid of the process set running
+ * #if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
+ * job_adjust_mode Current job adjust mode
+ * #endif
+ */
+static Doname
+distribute_process(char **commands, Property line)
+{
+ static unsigned file_number = 0;
+ wchar_t string[MAXPATHLEN];
+ char mbstring[MAXPATHLEN];
+ int filed;
+ int res;
+ int tmp_index;
+ char *tmp_index_str_ptr;
+
+#if !defined (TEAMWARE_MAKE_CMN) || !defined (MAXJOBS_ADJUST_RFE4694000)
+ while (parallel_process_cnt >= pmake_max_jobs) {
+ await_parallel(false);
+ finish_children(true);
+ }
+#else /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
+ /* initialize adjust mode, if not initialized */
+ if (job_adjust_mode == ADJUST_UNKNOWN) {
+ job_adjust_init();
+ }
+
+ /* actions depend on adjust mode */
+ switch (job_adjust_mode) {
+ case ADJUST_M1:
+ while (parallel_process_cnt >= adjust_pmake_max_jobs (pmake_max_jobs)) {
+ await_parallel(false);
+ finish_children(true);
+ }
+ break;
+ case ADJUST_M2:
+ if ((res = m2_acquire_job()) == 0) {
+ if (parallel_process_cnt > 0) {
+ await_parallel(false);
+ finish_children(true);
+
+ if ((res = m2_acquire_job()) == 0) {
+ return build_serial;
+ }
+ } else {
+ return build_serial;
+ }
+ }
+ if (res < 0) {
+ /* job adjustment error */
+ job_adjust_error();
+
+ /* no adjustment */
+ while (parallel_process_cnt >= pmake_max_jobs) {
+ await_parallel(false);
+ finish_children(true);
+ }
+ }
+ break;
+ default:
+ while (parallel_process_cnt >= pmake_max_jobs) {
+ await_parallel(false);
+ finish_children(true);
+ }
+ }
+#endif /* TEAMWARE_MAKE_CMN && MAXJOBS_ADJUST_RFE4694000 */
+#ifdef DISTRIBUTED
+ if (send_mtool_msgs) {
+ send_job_start_msg(line);
+ }
+#endif
+#ifdef DISTRIBUTED
+ setvar_envvar((Avo_DoJobMsg *)NULL);
+#else
+ setvar_envvar();
+#endif
+ /*
+ * Tell the user what DMake is doing.
+ */
+ if (!silent && output_mode != txt2_mode) {
+ /*
+ * Print local_host --> x job(s).
+ */
+ (void) fprintf(stdout,
+ catgets(catd, 1, 325, "%s --> %d %s\n"),
+ local_host,
+ parallel_process_cnt + 1,
+ (parallel_process_cnt == 0) ? catgets(catd, 1, 124, "job") : catgets(catd, 1, 125, "jobs"));
+
+ /* Print command line(s). */
+ tmp_index = 0;
+ while (commands[tmp_index] != NULL) {
+ /* No @ char. */
+ /* XXX - need to add [2] when + prefix is added */
+ if ((commands[tmp_index][0] != (int) at_char) &&
+ (commands[tmp_index][1] != (int) at_char)) {
+ tmp_index_str_ptr = commands[tmp_index];
+ if (*tmp_index_str_ptr == (int) hyphen_char) {
+ tmp_index_str_ptr++;
+ }
+ (void) fprintf(stdout, "%s\n", tmp_index_str_ptr);
+ }
+ tmp_index++;
+ }
+ (void) fflush(stdout);
+ }
+
+ (void) sprintf(mbstring,
+ NOCATGETS("%s/dmake.stdout.%d.%d.XXXXXX"),
+ tmpdir,
+ getpid(),
+ file_number++);
+
+ mktemp(mbstring);
+
+ stdout_file = strdup(mbstring);
+ stderr_file = NULL;
+#if defined (TEAMWARE_MAKE_CMN) && defined(REDIRECT_ERR)
+ if (!out_err_same) {
+ (void) sprintf(mbstring,
+ NOCATGETS("%s/dmake.stderr.%d.%d.XXXXXX"),
+ tmpdir,
+ getpid(),
+ file_number++);
+
+ mktemp(mbstring);
+
+ stderr_file = strdup(mbstring);
+ }
+#endif
+
+#ifdef SGE_SUPPORT
+ if (grid) {
+ static char *dir4gridscripts = NULL;
+ static char *hostName = NULL;
+ if (dir4gridscripts == NULL) {
+ Name dmakeOdir_name, dmakeOdir_value;
+ Property prop;
+ MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_ODIR"));
+ dmakeOdir_name = GETNAME(wcs_buffer, FIND_LENGTH);
+ if (((prop = get_prop(dmakeOdir_name->prop, macro_prop)) != NULL) &&
+ ((dmakeOdir_value = prop->body.macro.value) != NULL)) {
+ dir4gridscripts = dmakeOdir_value->string_mb;
+ }
+ dir4gridscripts = Avo_PathNames::pathname_output_directory(dir4gridscripts);
+ hostName = Avo_PathNames::pathname_local_host();
+ }
+ (void) sprintf(script_file,
+ NOCATGETS("%s/dmake.script.%s.%d.%d.XXXXXX"),
+ dir4gridscripts,
+ hostName,
+ getpid(),
+ file_number++);
+ }
+#endif /* SGE_SUPPORT */
+ process_running = run_rule_commands(local_host, commands);
+
+ return build_running;
+}
+
+/*
+ * doname_parallel(target, do_get, implicit)
+ *
+ * Processes the given target and finishes up any parallel
+ * processes left running.
+ *
+ * Return value:
+ * Result of target build
+ *
+ * Parameters:
+ * target Target to build
+ * do_get True if sccs get to be done
+ * implicit True if this is an implicit target
+ */
+Doname
+doname_parallel(Name target, Boolean do_get, Boolean implicit)
+{
+ Doname result;
+
+ result = doname_check(target, do_get, implicit, false);
+ if (result == build_ok || result == build_failed) {
+ return result;
+ }
+ finish_running();
+ return (Doname) target->state;
+}
+
+/*
+ * doname_subtree(target, do_get, implicit)
+ *
+ * Completely computes an object and its dependents for a
+ * serial subtree build.
+ *
+ * Parameters:
+ * target Target to build
+ * do_get True if sccs get to be done
+ * implicit True if this is an implicit target
+ *
+ * Static variables used:
+ * running_tail Tail of the list of running processes
+ *
+ * Global variables used:
+ * running_list The list of running processes
+ */
+static void
+doname_subtree(Name target, Boolean do_get, Boolean implicit)
+{
+ Running save_running_list;
+ Running *save_running_tail;
+
+ save_running_list = running_list;
+ save_running_tail = running_tail;
+ running_list = NULL;
+ running_tail = &running_list;
+ target->state = build_subtree;
+ target->checking_subtree = true;
+ while(doname_check(target, do_get, implicit, false) == build_running) {
+ target->checking_subtree = false;
+ finish_running();
+ target->state = build_subtree;
+ }
+ target->checking_subtree = false;
+ running_list = save_running_list;
+ running_tail = save_running_tail;
+}
+
+/*
+ * finish_running()
+ *
+ * Keeps processing until the running_list is emptied out.
+ *
+ * Parameters:
+ *
+ * Global variables used:
+ * running_list The list of running processes
+ */
+void
+finish_running(void)
+{
+ while (running_list != NULL) {
+#ifdef DISTRIBUTED
+ if (dmake_mode_type == distributed_mode) {
+ if ((just_did_subtree) ||
+ (parallel_process_cnt == 0)) {
+ just_did_subtree = false;
+ } else {
+ (void) await_dist(false);
+ finish_children(true);
+ }
+ } else
+#endif
+ {
+ await_parallel(false);
+ finish_children(true);
+ }
+ if (running_list != NULL) {
+ process_next();
+ }
+ }
+}
+
+/*
+ * process_next()
+ *
+ * Searches the running list for any targets which can start processing.
+ * This can be a pending target, a serial target, or a subtree target.
+ *
+ * Parameters:
+ *
+ * Static variables used:
+ * running_tail The end of the list of running procs
+ * subtree_conflict A target which conflicts with a subtree
+ * subtree_conflict2 The other target which conflicts
+ *
+ * Global variables used:
+ * commands_done True if commands executed
+ * debug_level Controls debug output
+ * parallel_process_cnt Number of parallel process running
+ * recursion_level Indentation for debug output
+ * running_list List of running processes
+ */
+static void
+process_next(void)
+{
+ Running rp;
+ Running *rp_prev;
+ Property line;
+ Chain target_group;
+ Dependency dep;
+ Boolean quiescent = true;
+ Running *subtree_target;
+ Boolean saved_commands_done;
+ Property *conditionals;
+
+ subtree_target = NULL;
+ subtree_conflict = NULL;
+ subtree_conflict2 = NULL;
+ /*
+ * If nothing currently running, build a serial target, if any.
+ */
+start_loop_1:
+ for (rp_prev = &running_list, rp = running_list;
+ rp != NULL && parallel_process_cnt == 0;
+ rp = rp->next) {
+ if (rp->state == build_serial) {
+ *rp_prev = rp->next;
+ if (rp->next == NULL) {
+ running_tail = rp_prev;
+ }
+ recursion_level = rp->recursion_level;
+ rp->target->state = build_pending;
+ (void) doname_check(rp->target,
+ rp->do_get,
+ rp->implicit,
+ false);
+ quiescent = false;
+ delete_running_struct(rp);
+ goto start_loop_1;
+ } else {
+ rp_prev = &rp->next;
+ }
+ }
+ /*
+ * Find a target to build. The target must be pending, have all
+ * its dependencies built, and not be in a target group with a target
+ * currently building.
+ */
+start_loop_2:
+ for (rp_prev = &running_list, rp = running_list;
+ rp != NULL;
+ rp = rp->next) {
+ if (!(rp->state == build_pending ||
+ rp->state == build_subtree)) {
+ quiescent = false;
+ rp_prev = &rp->next;
+ } else if (rp->state == build_pending) {
+ line = get_prop(rp->target->prop, line_prop);
+ for (dep = line->body.line.dependencies;
+ dep != NULL;
+ dep = dep->next) {
+ if (dep->name->state == build_running ||
+ dep->name->state == build_pending ||
+ dep->name->state == build_serial) {
+ break;
+ }
+ }
+ if (dep == NULL) {
+ for (target_group = line->body.line.target_group;
+ target_group != NULL;
+ target_group = target_group->next) {
+ if (is_running(target_group->name)) {
+ break;
+ }
+ }
+ if (target_group == NULL) {
+ *rp_prev = rp->next;
+ if (rp->next == NULL) {
+ running_tail = rp_prev;
+ }
+ recursion_level = rp->recursion_level;
+ rp->target->state = rp->redo ?
+ build_dont_know : build_pending;
+ saved_commands_done = commands_done;
+ conditionals =
+ set_conditionals
+ (rp->conditional_cnt,
+ rp->conditional_targets);
+ rp->target->dont_activate_cond_values = true;
+ if ((doname_check(rp->target,
+ rp->do_get,
+ rp->implicit,
+ rp->target->has_target_prop ? true : false) !=
+ build_running) &&
+ !commands_done) {
+ commands_done =
+ saved_commands_done;
+ }
+ rp->target->dont_activate_cond_values = false;
+ reset_conditionals
+ (rp->conditional_cnt,
+ rp->conditional_targets,
+ conditionals);
+ quiescent = false;
+ delete_running_struct(rp);
+ goto start_loop_2;
+ } else {
+ rp_prev = &rp->next;
+ }
+ } else {
+ rp_prev = &rp->next;
+ }
+ } else {
+ rp_prev = &rp->next;
+ }
+ }
+ /*
+ * If nothing has been found to build and there exists a subtree
+ * target with no dependency conflicts, build it.
+ */
+ if (quiescent) {
+start_loop_3:
+ for (rp_prev = &running_list, rp = running_list;
+ rp != NULL;
+ rp = rp->next) {
+ if (rp->state == build_subtree) {
+ if (!dependency_conflict(rp->target)) {
+ *rp_prev = rp->next;
+ if (rp->next == NULL) {
+ running_tail = rp_prev;
+ }
+ recursion_level = rp->recursion_level;
+ doname_subtree(rp->target,
+ rp->do_get,
+ rp->implicit);
+#ifdef DISTRIBUTED
+ just_did_subtree = true;
+#endif
+ quiescent = false;
+ delete_running_struct(rp);
+ goto start_loop_3;
+ } else {
+ subtree_target = rp_prev;
+ rp_prev = &rp->next;
+ }
+ } else {
+ rp_prev = &rp->next;
+ }
+ }
+ }
+ /*
+ * If still nothing found to build, we either have a deadlock
+ * or a subtree with a dependency conflict with something waiting
+ * to build.
+ */
+ if (quiescent) {
+ if (subtree_target == NULL) {
+ fatal(catgets(catd, 1, 126, "Internal error: deadlock detected in process_next"));
+ } else {
+ rp = *subtree_target;
+ if (debug_level > 0) {
+ warning(catgets(catd, 1, 127, "Conditional macro conflict encountered for %s between %s and %s"),
+ subtree_conflict2->string_mb,
+ rp->target->string_mb,
+ subtree_conflict->string_mb);
+ }
+ *subtree_target = (*subtree_target)->next;
+ if (rp->next == NULL) {
+ running_tail = subtree_target;
+ }
+ recursion_level = rp->recursion_level;
+ doname_subtree(rp->target, rp->do_get, rp->implicit);
+#ifdef DISTRIBUTED
+ just_did_subtree = true;
+#endif
+ delete_running_struct(rp);
+ }
+ }
+}
+
+/*
+ * set_conditionals(cnt, targets)
+ *
+ * Sets the conditional macros for the targets given in the array of
+ * targets. The old macro values are returned in an array of
+ * Properties for later resetting.
+ *
+ * Return value:
+ * Array of conditional macro settings
+ *
+ * Parameters:
+ * cnt Number of targets
+ * targets Array of targets
+ */
+static Property *
+set_conditionals(int cnt, Name *targets)
+{
+ Property *locals, *lp;
+ Name *tp;
+
+ locals = (Property *) getmem(cnt * sizeof(Property));
+ for (lp = locals, tp = targets;
+ cnt > 0;
+ cnt--, lp++, tp++) {
+ *lp = (Property) getmem((*tp)->conditional_cnt *
+ sizeof(struct _Property));
+ set_locals(*tp, *lp);
+ }
+ return locals;
+}
+
+/*
+ * reset_conditionals(cnt, targets, locals)
+ *
+ * Resets the conditional macros as saved in the given array of
+ * Properties. The resets are done in reverse order. Afterwards the
+ * data structures are freed.
+ *
+ * Parameters:
+ * cnt Number of targets
+ * targets Array of targets
+ * locals Array of dependency macro settings
+ */
+static void
+reset_conditionals(int cnt, Name *targets, Property *locals)
+{
+ Name *tp;
+ Property *lp;
+
+ for (tp = targets + (cnt - 1), lp = locals + (cnt - 1);
+ cnt > 0;
+ cnt--, tp--, lp--) {
+ reset_locals(*tp,
+ *lp,
+ get_prop((*tp)->prop, conditional_prop),
+ 0);
+ retmem_mb((caddr_t) *lp);
+ }
+ retmem_mb((caddr_t) locals);
+}
+
+/*
+ * dependency_conflict(target)
+ *
+ * Returns true if there is an intersection between
+ * the subtree of the target and any dependents of the pending targets.
+ *
+ * Return value:
+ * True if conflict found
+ *
+ * Parameters:
+ * target Subtree target to check
+ *
+ * Static variables used:
+ * subtree_conflict Target conflict found
+ * subtree_conflict2 Second conflict found
+ *
+ * Global variables used:
+ * running_list List of running processes
+ * wait_name .WAIT, not a real dependency
+ */
+static Boolean
+dependency_conflict(Name target)
+{
+ Property line;
+ Property pending_line;
+ Dependency dp;
+ Dependency pending_dp;
+ Running rp;
+
+ /* Return if we are already checking this target */
+ if (target->checking_subtree) {
+ return false;
+ }
+ target->checking_subtree = true;
+ line = get_prop(target->prop, line_prop);
+ if (line == NULL) {
+ target->checking_subtree = false;
+ return false;
+ }
+ /* Check each dependency of the target for conflicts */
+ for (dp = line->body.line.dependencies; dp != NULL; dp = dp->next) {
+ /* Ignore .WAIT dependency */
+ if (dp->name == wait_name) {
+ continue;
+ }
+ /*
+ * For each pending target, look for a dependency which
+ * is the same as a dependency of the subtree target. Since
+ * we can't build the subtree until all pending targets have
+ * finished which depend on the same dependency, this is
+ * a conflict.
+ */
+ for (rp = running_list; rp != NULL; rp = rp->next) {
+ if (rp->state == build_pending) {
+ pending_line = get_prop(rp->target->prop,
+ line_prop);
+ if (pending_line == NULL) {
+ continue;
+ }
+ for(pending_dp = pending_line->
+ body.line.dependencies;
+ pending_dp != NULL;
+ pending_dp = pending_dp->next) {
+ if (dp->name == pending_dp->name) {
+ target->checking_subtree
+ = false;
+ subtree_conflict = rp->target;
+ subtree_conflict2 = dp->name;
+ return true;
+ }
+ }
+ }
+ }
+ if (dependency_conflict(dp->name)) {
+ target->checking_subtree = false;
+ return true;
+ }
+ }
+ target->checking_subtree = false;
+ return false;
+}
+
+/*
+ * await_parallel(waitflg)
+ *
+ * Waits for parallel children to exit and finishes their processing.
+ * If waitflg is false, the function returns after update_delay.
+ *
+ * Parameters:
+ * waitflg dwight
+ */
+void
+await_parallel(Boolean waitflg)
+{
+#ifdef _CHECK_UPDATE_H
+ static int number_of_unknown_children = 0;
+#endif /* _CHECK_UPDATE_H */
+ Boolean nohang;
+ pid_t pid;
+ int status;
+ Running rp;
+ int waiterr;
+
+ nohang = false;
+ for ( ; ; ) {
+ if (!nohang) {
+ (void) alarm((int) update_delay);
+ }
+ pid = waitpid((pid_t)-1,
+ &status,
+ nohang ? WNOHANG : 0);
+ waiterr = errno;
+ if (!nohang) {
+ (void) alarm(0);
+ }
+ if (pid <= 0) {
+ if (waiterr == EINTR) {
+ if (waitflg) {
+ continue;
+ } else {
+ return;
+ }
+ } else {
+ return;
+ }
+ }
+ for (rp = running_list;
+ (rp != NULL) && (rp->pid != pid);
+ rp = rp->next) {
+ ;
+ }
+ if (rp == NULL) {
+#ifdef _CHECK_UPDATE_H
+ /* Ignore first child - it is check_update */
+ if (number_of_unknown_children <= 0) {
+ number_of_unknown_children = 1;
+ return;
+ }
+#endif /* _CHECK_UPDATE_H */
+ if (send_mtool_msgs) {
+ continue;
+ } else {
+ fatal(catgets(catd, 1, 128, "Internal error: returned child pid not in running_list"));
+ }
+ } else {
+ rp->state = (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? build_ok : build_failed;
+ }
+ nohang = true;
+ parallel_process_cnt--;
+
+#if defined (TEAMWARE_MAKE_CMN) && defined (MAXJOBS_ADJUST_RFE4694000)
+ if (job_adjust_mode == ADJUST_M2) {
+ if (m2_release_job()) {
+ job_adjust_error();
+ }
+ }
+#endif
+ }
+}
+
+/*
+ * finish_children(docheck)
+ *
+ * Finishes the processing for all targets which were running
+ * and have now completed.
+ *
+ * Parameters:
+ * docheck Completely check the finished target
+ *
+ * Static variables used:
+ * running_tail The tail of the running list
+ *
+ * Global variables used:
+ * continue_after_error -k flag
+ * fatal_in_progress True if we are finishing up after fatal err
+ * running_list List of running processes
+ */
+void
+finish_children(Boolean docheck)
+{
+ int cmds_length;
+ Property line;
+ Property line2;
+ struct stat out_buf;
+ Running rp;
+ Running *rp_prev;
+ Cmd_line rule;
+ Boolean silent_flag;
+
+ for (rp_prev = &running_list, rp = running_list;
+ rp != NULL;
+ rp = rp->next) {
+bypass_for_loop_inc_4:
+ /*
+ * If the state is ok or failed, then this target has
+ * finished building.
+ * In parallel_mode, output the accumulated stdout/stderr.
+ * Read the auto dependency stuff, handle a failed build,
+ * update the target, then finish the doname process for
+ * that target.
+ */
+ if (rp->state == build_ok || rp->state == build_failed) {
+ *rp_prev = rp->next;
+ if (rp->next == NULL) {
+ running_tail = rp_prev;
+ }
+ if ((line2 = rp->command) == NULL) {
+ line2 = get_prop(rp->target->prop, line_prop);
+ }
+ if (dmake_mode_type == distributed_mode) {
+ if (rp->make_refd) {
+ maybe_reread_make_state();
+ }
+ } else {
+ /*
+ * Send an Avo_MToolJobResultMsg to maketool.
+ */
+#ifdef DISTRIBUTED
+ if (send_mtool_msgs) {
+ send_job_result_msg(rp);
+ }
+#endif
+ /*
+ * Check if there were any job output
+ * from the parallel build.
+ */
+ if (rp->stdout_file != NULL) {
+ if (stat(rp->stdout_file, &out_buf) < 0) {
+ fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
+ rp->stdout_file,
+ errmsg(errno));
+ }
+ if ((line2 != NULL) &&
+ (out_buf.st_size > 0)) {
+ cmds_length = 0;
+ for (rule = line2->body.line.command_used,
+ silent_flag = silent;
+ rule != NULL;
+ rule = rule->next) {
+ cmds_length += rule->command_line->hash.length + 1;
+ silent_flag = BOOLEAN(silent_flag || rule->silent);
+ }
+ if (out_buf.st_size != cmds_length || silent_flag ||
+ output_mode == txt2_mode) {
+ dump_out_file(rp->stdout_file, false);
+ }
+ }
+ (void) unlink(rp->stdout_file);
+ retmem_mb(rp->stdout_file);
+ rp->stdout_file = NULL;
+ }
+#if defined(REDIRECT_ERR)
+ if (!out_err_same && (rp->stderr_file != NULL)) {
+ if (stat(rp->stderr_file, &out_buf) < 0) {
+ fatal(catgets(catd, 1, 130, "stat of %s failed: %s"),
+ rp->stderr_file,
+ errmsg(errno));
+ }
+ if ((line2 != NULL) &&
+ (out_buf.st_size > 0)) {
+ dump_out_file(rp->stderr_file, true);
+ }
+ (void) unlink(rp->stderr_file);
+ retmem_mb(rp->stderr_file);
+ rp->stderr_file = NULL;
+ }
+#endif
+ }
+ check_state(rp->temp_file);
+ if (rp->temp_file != NULL) {
+ free_name(rp->temp_file);
+ }
+ rp->temp_file = NULL;
+ if (rp->state == build_failed) {
+ line = get_prop(rp->target->prop, line_prop);
+ if (line != NULL) {
+ line->body.line.command_used = NULL;
+ }
+ if (continue_after_error ||
+ fatal_in_progress ||
+ !docheck) {
+ warning(catgets(catd, 1, 256, "Command failed for target `%s'"),
+ rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
+ build_failed_seen = true;
+ } else {
+ /*
+ * XXX??? - DMake needs to exit(),
+ * but shouldn't call fatal().
+ */
+#ifdef PRINT_EXIT_STATUS
+ warning(NOCATGETS("I'm in finish_children. rp->state == build_failed."));
+#endif
+
+ fatal(catgets(catd, 1, 258, "Command failed for target `%s'"),
+ rp->command ? line2->body.line.target->string_mb : rp->target->string_mb);
+ }
+ }
+ if (!docheck) {
+ delete_running_struct(rp);
+ rp = *rp_prev;
+ if (rp == NULL) {
+ break;
+ } else {
+ goto bypass_for_loop_inc_4;
+ }
+ }
+ update_target(get_prop(rp->target->prop, line_prop),
+ rp->state);
+ finish_doname(rp);
+ delete_running_struct(rp);
+ rp = *rp_prev;
+ if (rp == NULL) {
+ break;
+ } else {
+ goto bypass_for_loop_inc_4;
+ }
+ } else {
+ rp_prev = &rp->next;
+ }
+ }
+}
+
+/*
+ * dump_out_file(filename, err)
+ *
+ * Write the contents of the file to stdout, then unlink the file.
+ *
+ * Parameters:
+ * filename Name of temp file containing output
+ *
+ * Global variables used:
+ */
+static void
+dump_out_file(char *filename, Boolean err)
+{
+ int chars_read;
+ char copybuf[BUFSIZ];
+ int fd;
+ int out_fd = (err ? 2 : 1);
+
+ if ((fd = open(filename, O_RDONLY)) < 0) {
+ fatal(catgets(catd, 1, 141, "open failed for output file %s: %s"),
+ filename,
+ errmsg(errno));
+ }
+ if (!silent && output_mode != txt2_mode) {
+ (void) fprintf(err ? stderr : stdout,
+ err ?
+ catgets(catd, 1, 338, "%s --> Job errors\n") :
+ catgets(catd, 1, 259, "%s --> Job output\n"),
+ local_host);
+ (void) fflush(err ? stderr : stdout);
+ }
+ for (chars_read = read(fd, copybuf, BUFSIZ);
+ chars_read > 0;
+ chars_read = read(fd, copybuf, BUFSIZ)) {
+ /*
+ * Read buffers from the source file until end or error.
+ */
+ if (write(out_fd, copybuf, chars_read) < 0) {
+ fatal(catgets(catd, 1, 260, "write failed for output file %s: %s"),
+ filename,
+ errmsg(errno));
+ }
+ }
+ (void) close(fd);
+ (void) unlink(filename);
+}
+
+/*
+ * finish_doname(rp)
+ *
+ * Completes the processing for a target which was left running.
+ *
+ * Parameters:
+ * rp Running list entry for target
+ *
+ * Global variables used:
+ * debug_level Debug flag
+ * recursion_level Indentation for debug output
+ */
+static void
+finish_doname(Running rp)
+{
+ int auto_count = rp->auto_count;
+ Name *automatics = rp->automatics;
+ Doname result = rp->state;
+ Name target = rp->target;
+ Name true_target = rp->true_target;
+ Property *conditionals;
+
+ recursion_level = rp->recursion_level;
+ if (result == build_ok) {
+ if (true_target == NULL) {
+ (void) printf(NOCATGETS("Target = %s\n"), target->string_mb);
+ (void) printf(NOCATGETS(" State = %d\n"), result);
+ fatal(NOCATGETS("Internal error: NULL true_target in finish_doname"));
+ }
+ /* If all went OK, set a nice timestamp */
+ if (true_target->stat.time == file_doesnt_exist) {
+ true_target->stat.time = file_max_time;
+ }
+ }
+ target->state = result;
+ if (target->is_member) {
+ Property member;
+
+ /* Propagate the timestamp from the member file to the member */
+ if ((target->stat.time != file_max_time) &&
+ ((member = get_prop(target->prop, member_prop)) != NULL) &&
+ (exists(member->body.member.member) > file_doesnt_exist)) {
+ target->stat.time =
+/*
+ exists(member->body.member.member);
+ */
+ member->body.member.member->stat.time;
+ }
+ }
+ /*
+ * Check if we found any new auto dependencies when we
+ * built the target.
+ */
+ if ((result == build_ok) && check_auto_dependencies(target,
+ auto_count,
+ automatics)) {
+ if (debug_level > 0) {
+ (void) printf(catgets(catd, 1, 261, "%*sTarget `%s' acquired new dependencies from build, checking all dependencies\n"),
+ recursion_level,
+ "",
+ true_target->string_mb);
+ }
+ target->rechecking_target = true;
+ target->state = build_running;
+
+ /* [tolik, Tue Mar 25 1997]
+ * Fix for bug 4038824:
+ * command line options set by conditional macros get dropped
+ * rp->conditional_cnt and rp->conditional_targets must be copied
+ * to new 'rp' during add_pending(). Set_conditionals() stores
+ * rp->conditional_targets to the global variable 'conditional_targets'
+ * Add_pending() will use this variable to set up 'rp'.
+ */
+ conditionals = set_conditionals(rp->conditional_cnt, rp->conditional_targets);
+ add_pending(target,
+ recursion_level,
+ rp->do_get,
+ rp->implicit,
+ true);
+ reset_conditionals(rp->conditional_cnt, rp->conditional_targets, conditionals);
+ }
+}
+
+/*
+ * new_running_struct()
+ *
+ * Constructor for Running struct. Creates a structure and initializes
+ * its fields.
+ *
+ */
+static Running new_running_struct()
+{
+ Running rp;
+
+ rp = ALLOC(Running);
+ rp->target = NULL;
+ rp->true_target = NULL;
+ rp->command = NULL;
+ rp->sprodep_value = NULL;
+ rp->sprodep_env = NULL;
+ rp->auto_count = 0;
+ rp->automatics = NULL;
+ rp->pid = -1;
+ rp->job_msg_id = -1;
+ rp->stdout_file = NULL;
+ rp->stderr_file = NULL;
+ rp->temp_file = NULL;
+ rp->next = NULL;
+ return rp;
+}
+
+/*
+ * add_running(target, true_target, command, recursion_level, auto_count,
+ * automatics, do_get, implicit)
+ *
+ * Adds a record on the running list for this target, which
+ * was just spawned and is running.
+ *
+ * Parameters:
+ * target Target being built
+ * true_target True target for target
+ * command Running command.
+ * recursion_level Debug indentation level
+ * auto_count Count of automatic dependencies
+ * automatics List of automatic dependencies
+ * do_get Sccs get flag
+ * implicit Implicit flag
+ *
+ * Static variables used:
+ * running_tail Tail of running list
+ * process_running PID of process
+ *
+ * Global variables used:
+ * current_line Current line for target
+ * current_target Current target being built
+ * stderr_file Temporary file for stdout
+ * stdout_file Temporary file for stdout
+ * temp_file_name Temporary file for auto dependencies
+ */
+void
+add_running(Name target, Name true_target, Property command, int recursion_level, int auto_count, Name *automatics, Boolean do_get, Boolean implicit)
+{
+ Running rp;
+ Name *p;
+
+ rp = new_running_struct();
+ rp->state = build_running;
+ rp->target = target;
+ rp->true_target = true_target;
+ rp->command = command;
+ Property spro_val = get_prop(sunpro_dependencies->prop, macro_prop);
+ if(spro_val) {
+ rp->sprodep_value = spro_val->body.macro.value;
+ spro_val->body.macro.value = NULL;
+ spro_val = get_prop(sunpro_dependencies->prop, env_mem_prop);
+ if(spro_val) {
+ rp->sprodep_env = spro_val->body.env_mem.value;
+ spro_val->body.env_mem.value = NULL;
+ }
+ }
+ rp->recursion_level = recursion_level;
+ rp->do_get = do_get;
+ rp->implicit = implicit;
+ rp->auto_count = auto_count;
+ if (auto_count > 0) {
+ rp->automatics = (Name *) getmem(auto_count * sizeof (Name));
+ for (p = rp->automatics; auto_count > 0; auto_count--) {
+ *p++ = *automatics++;
+ }
+ } else {
+ rp->automatics = NULL;
+ }
+#ifdef DISTRIBUTED
+ if (dmake_mode_type == distributed_mode) {
+ rp->make_refd = called_make;
+ called_make = false;
+ } else
+#endif
+ {
+ rp->pid = process_running;
+ process_running = -1;
+ childPid = -1;
+ }
+ rp->job_msg_id = job_msg_id;
+ rp->stdout_file = stdout_file;
+ rp->stderr_file = stderr_file;
+ rp->temp_file = temp_file_name;
+ rp->redo = false;
+ rp->next = NULL;
+ store_conditionals(rp);
+ stdout_file = NULL;
+ stderr_file = NULL;
+ temp_file_name = NULL;
+ current_target = NULL;
+ current_line = NULL;
+ *running_tail = rp;
+ running_tail = &rp->next;
+}
+
+/*
+ * add_pending(target, recursion_level, do_get, implicit, redo)
+ *
+ * Adds a record on the running list for a pending target
+ * (waiting for its dependents to finish running).
+ *
+ * Parameters:
+ * target Target being built
+ * recursion_level Debug indentation level
+ * do_get Sccs get flag
+ * implicit Implicit flag
+ * redo True if this target is being redone
+ *
+ * Static variables used:
+ * running_tail Tail of running list
+ */
+void
+add_pending(Name target, int recursion_level, Boolean do_get, Boolean implicit, Boolean redo)
+{
+ Running rp;
+ rp = new_running_struct();
+ rp->state = build_pending;
+ rp->target = target;
+ rp->recursion_level = recursion_level;
+ rp->do_get = do_get;
+ rp->implicit = implicit;
+ rp->redo = redo;
+ store_conditionals(rp);
+ *running_tail = rp;
+ running_tail = &rp->next;
+}
+
+/*
+ * add_serial(target, recursion_level, do_get, implicit)
+ *
+ * Adds a record on the running list for a target which must be
+ * executed in serial after others have finished.
+ *
+ * Parameters:
+ * target Target being built
+ * recursion_level Debug indentation level
+ * do_get Sccs get flag
+ * implicit Implicit flag
+ *
+ * Static variables used:
+ * running_tail Tail of running list
+ */
+void
+add_serial(Name target, int recursion_level, Boolean do_get, Boolean implicit)
+{
+ Running rp;
+
+ rp = new_running_struct();
+ rp->target = target;
+ rp->recursion_level = recursion_level;
+ rp->do_get = do_get;
+ rp->implicit = implicit;
+ rp->state = build_serial;
+ rp->redo = false;
+ store_conditionals(rp);
+ *running_tail = rp;
+ running_tail = &rp->next;
+}
+
+/*
+ * add_subtree(target, recursion_level, do_get, implicit)
+ *
+ * Adds a record on the running list for a target which must be
+ * executed in isolation after others have finished.
+ *
+ * Parameters:
+ * target Target being built
+ * recursion_level Debug indentation level
+ * do_get Sccs get flag
+ * implicit Implicit flag
+ *
+ * Static variables used:
+ * running_tail Tail of running list
+ */
+void
+add_subtree(Name target, int recursion_level, Boolean do_get, Boolean implicit)
+{
+ Running rp;
+
+ rp = new_running_struct();
+ rp->target = target;
+ rp->recursion_level = recursion_level;
+ rp->do_get = do_get;
+ rp->implicit = implicit;
+ rp->state = build_subtree;
+ rp->redo = false;
+ store_conditionals(rp);
+ *running_tail = rp;
+ running_tail = &rp->next;
+}
+
+/*
+ * store_conditionals(rp)
+ *
+ * Creates an array of the currently active targets with conditional
+ * macros (found in the chain conditional_targets) and puts that
+ * array in the Running struct.
+ *
+ * Parameters:
+ * rp Running struct for storing chain
+ *
+ * Global variables used:
+ * conditional_targets Chain of current dynamic conditionals
+ */
+static void
+store_conditionals(Running rp)
+{
+ int cnt;
+ Chain cond_name;
+
+ if (conditional_targets == NULL) {
+ rp->conditional_cnt = 0;
+ rp->conditional_targets = NULL;
+ return;
+ }
+ cnt = 0;
+ for (cond_name = conditional_targets;
+ cond_name != NULL;
+ cond_name = cond_name->next) {
+ cnt++;
+ }
+ rp->conditional_cnt = cnt;
+ rp->conditional_targets = (Name *) getmem(cnt * sizeof(Name));
+ for (cond_name = conditional_targets;
+ cond_name != NULL;
+ cond_name = cond_name->next) {
+ rp->conditional_targets[--cnt] = cond_name->name;
+ }
+}
+
+/*
+ * parallel_ok(target, line_prop_must_exists)
+ *
+ * Returns true if the target can be run in parallel
+ *
+ * Return value:
+ * True if can run in parallel
+ *
+ * Parameters:
+ * target Target being tested
+ *
+ * Global variables used:
+ * all_parallel True if all targets default to parallel
+ * only_parallel True if no targets default to parallel
+ */
+Boolean
+parallel_ok(Name target, Boolean line_prop_must_exists)
+{
+ Boolean assign;
+ Boolean make_refd;
+ Property line;
+ Cmd_line rule;
+
+ assign = make_refd = false;
+ if (((line = get_prop(target->prop, line_prop)) == NULL) &&
+ line_prop_must_exists) {
+ return false;
+ }
+ if (line != NULL) {
+ for (rule = line->body.line.command_used;
+ rule != NULL;
+ rule = rule->next) {
+ if (rule->assign) {
+ assign = true;
+ } else if (rule->make_refd) {
+ make_refd = true;
+ }
+ }
+ }
+ if (assign) {
+ return false;
+ } else if (target->parallel) {
+ return true;
+ } else if (target->no_parallel) {
+ return false;
+ } else if (all_parallel) {
+ return true;
+ } else if (only_parallel) {
+ return false;
+ } else if (make_refd) {
+ return false;
+ } else {
+ return true;
+ }
+}
+
+/*
+ * is_running(target)
+ *
+ * Returns true if the target is running.
+ *
+ * Return value:
+ * True if target is running
+ *
+ * Parameters:
+ * target Target to check
+ *
+ * Global variables used:
+ * running_list List of running processes
+ */
+Boolean
+is_running(Name target)
+{
+ Running rp;
+
+ if (target->state != build_running) {
+ return false;
+ }
+ for (rp = running_list;
+ rp != NULL && target != rp->target;
+ rp = rp->next);
+ if (rp == NULL) {
+ return false;
+ } else {
+ return (rp->state == build_running) ? true : false;
+ }
+}
+
+/*
+ * This function replaces the makesh binary.
+ */
+
+#ifdef SGE_SUPPORT
+#define DO_CHECK(f) if (f <= 0) { \
+ fprintf(stderr, \
+ catgets(catd, 1, 347, "Could not write to file: %s: %s\n"), \
+ script_file, errmsg(errno)); \
+ _exit(1); \
+ }
+#endif /* SGE_SUPPORT */
+
+static pid_t
+run_rule_commands(char *host, char **commands)
+{
+ Boolean always_exec;
+ Name command;
+ Boolean ignore;
+ int length;
+ Doname result;
+ Boolean silent_flag;
+#ifdef SGE_SUPPORT
+ wchar_t *wcmd, *tmp_wcs_buffer = NULL;
+ char *cmd, *tmp_mbs_buffer = NULL;
+ FILE *scrfp;
+ Name shell = getvar(shell_name);
+#else
+ wchar_t *tmp_wcs_buffer;
+#endif /* SGE_SUPPORT */
+
+ childPid = fork();
+ switch (childPid) {
+ case -1: /* Error */
+ fatal(catgets(catd, 1, 337, "Could not fork child process for dmake job: %s"),
+ errmsg(errno));
+ break;
+ case 0: /* Child */
+ /* To control the processed targets list is not the child's business */
+ running_list = NULL;
+#if defined(REDIRECT_ERR)
+ if(out_err_same) {
+ redirect_io(stdout_file, (char*)NULL);
+ } else {
+ redirect_io(stdout_file, stderr_file);
+ }
+#else
+ redirect_io(stdout_file, (char*)NULL);
+#endif
+#ifdef SGE_SUPPORT
+ if (grid) {
+ int fdes = mkstemp(script_file);
+ if ((fdes < 0) || (scrfp = fdopen(fdes, "w")) == NULL) {
+ fprintf(stderr,
+ catgets(catd, 1, 341, "Could not create file: %s: %s\n"),
+ script_file, errmsg(errno));
+ _exit(1);
+ }
+ if (IS_EQUAL(shell->string_mb, "")) {
+ shell = shell_name;
+ }
+ }
+#endif /* SGE_SUPPORT */
+ for (commands = commands;
+ (*commands != (char *)NULL);
+ commands++) {
+ silent_flag = silent;
+ ignore = false;
+ always_exec = false;
+ while ((**commands == (int) at_char) ||
+ (**commands == (int) hyphen_char) ||
+ (**commands == (int) plus_char)) {
+ if (**commands == (int) at_char) {
+ silent_flag = true;
+ }
+ if (**commands == (int) hyphen_char) {
+ ignore = true;
+ }
+ if (**commands == (int) plus_char) {
+ always_exec = true;
+ }
+ (*commands)++;
+ }
+#ifdef SGE_SUPPORT
+ if (grid) {
+ if ((length = strlen(*commands)) >= MAXPATHLEN / 2) {
+ wcmd = tmp_wcs_buffer = ALLOC_WC(length * 2 + 1);
+ (void) mbstowcs(tmp_wcs_buffer, *commands, length * 2 + 1);
+ } else {
+ MBSTOWCS(wcs_buffer, *commands);
+ wcmd = wcs_buffer;
+ cmd = mbs_buffer;
+ }
+ wchar_t *from = wcmd + wslen(wcmd);
+ wchar_t *to = from + (from - wcmd);
+ *to = (int) nul_char;
+ while (from > wcmd) {
+ *--to = *--from;
+ if (*from == (int) newline_char) { // newline symbols are already quoted
+ *--to = *--from;
+ } else if (wschr(char_semantics_char, *from)) {
+ *--to = (int) backslash_char;
+ }
+ }
+ if (length >= MAXPATHLEN*MB_LEN_MAX/2) { // sizeof(mbs_buffer) / 2
+ cmd = tmp_mbs_buffer = getmem((length * MB_LEN_MAX * 2) + 1);
+ (void) wcstombs(tmp_mbs_buffer, to, (length * MB_LEN_MAX * 2) + 1);
+ } else {
+ WCSTOMBS(mbs_buffer, to);
+ cmd = mbs_buffer;
+ }
+ char *mbst, *mbend;
+ if ((length > 0) &&
+ !silent_flag) {
+ for (mbst = cmd; (mbend = strstr(mbst, "\\\n")) != NULL; mbst = mbend + 2) {
+ *mbend = '\0';
+ DO_CHECK(fprintf(scrfp, NOCATGETS("/usr/bin/printf '%%s\\n' %s\\\\\n"), mbst));
+ *mbend = '\\';
+ }
+ DO_CHECK(fprintf(scrfp, NOCATGETS("/usr/bin/printf '%%s\\n' %s\n"), mbst));
+ }
+ if (!do_not_exec_rule ||
+ !working_on_targets ||
+ always_exec) {
+#if defined(linux)
+ if (0 != strcmp(shell->string_mb, (char*)NOCATGETS("/bin/sh"))) {
+ DO_CHECK(fprintf(scrfp, NOCATGETS("%s -c %s\n"), shell->string_mb, cmd));
+ } else
+#endif
+ DO_CHECK(fprintf(scrfp, NOCATGETS("%s -ce %s\n"), shell->string_mb, cmd));
+ DO_CHECK(fputs(NOCATGETS("__DMAKECMDEXITSTAT=$?\nif [ ${__DMAKECMDEXITSTAT} -ne 0 ]; then\n"), scrfp));
+ if (ignore) {
+ DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s ${__DMAKECMDEXITSTAT} %s\n"),
+ catgets(catd, 1, 343, "\"*** Error code"),
+ catgets(catd, 1, 344, "(ignored)\"")));
+ } else {
+ DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s ${__DMAKECMDEXITSTAT}\n"),
+ catgets(catd, 1, 342, "\"*** Error code\"")));
+ }
+ if (silent_flag) {
+ DO_CHECK(fprintf(scrfp, NOCATGETS("\techo %s\n"),
+ catgets(catd, 1, 345, "The following command caused the error:")));
+ for (mbst = cmd; (mbend = strstr(mbst, "\\\n")) != NULL; mbst = mbend + 2) {
+ *mbend = '\0';
+ DO_CHECK(fprintf(scrfp, NOCATGETS("\t/usr/bin/printf '%%s\\n' %s\\\\\n"), mbst));
+ *mbend = '\\';
+ }
+ DO_CHECK(fprintf(scrfp, NOCATGETS("\t/usr/bin/printf '%%s\\n' %s\n"), mbst));
+ }
+ if (!ignore) {
+ DO_CHECK(fputs(NOCATGETS("\texit ${__DMAKECMDEXITSTAT}\n"), scrfp));
+ }
+ DO_CHECK(fputs(NOCATGETS("fi\n"), scrfp));
+ }
+ if (tmp_wcs_buffer) {
+ retmem_mb(tmp_mbs_buffer);
+ tmp_mbs_buffer = NULL;
+ }
+ if (tmp_wcs_buffer) {
+ retmem(tmp_wcs_buffer);
+ tmp_wcs_buffer = NULL;
+ }
+ continue;
+ }
+#endif /* SGE_SUPPORT */
+ if ((length = strlen(*commands)) >= MAXPATHLEN) {
+ tmp_wcs_buffer = ALLOC_WC(length + 1);
+ (void) mbstowcs(tmp_wcs_buffer, *commands, length + 1);
+ command = GETNAME(tmp_wcs_buffer, FIND_LENGTH);
+ retmem(tmp_wcs_buffer);
+ } else {
+ MBSTOWCS(wcs_buffer, *commands);
+ command = GETNAME(wcs_buffer, FIND_LENGTH);
+ }
+ if ((command->hash.length > 0) &&
+ !silent_flag) {
+ (void) printf("%s\n", command->string_mb);
+ }
+ result = dosys(command,
+ ignore,
+ false,
+ false, /* bugs #4085164 & #4990057 */
+ /* BOOLEAN(silent_flag && ignore), */
+ always_exec,
+ (Name) NULL,
+ false);
+ if (result == build_failed) {
+ if (silent_flag) {
+ (void) printf(catgets(catd, 1, 152, "The following command caused the error:\n%s\n"), command->string_mb);
+ }
+ if (!ignore) {
+ _exit(1);
+ }
+ }
+ }
+#ifndef SGE_SUPPORT
+ _exit(0);
+#else
+ if (!grid) {
+ _exit(0);
+ }
+ DO_CHECK(fputs(NOCATGETS("exit 0\n"), scrfp));
+ if (fclose(scrfp) != 0) {
+ fprintf(stderr,
+ catgets(catd, 1, 346, "Could not close file: %s: %s\n"),
+ script_file, errmsg(errno));
+ _exit(1);
+ }
+ {
+
+#define DEFAULT_QRSH_TRIES_NUMBER 1
+#define DEFAULT_QRSH_TIMEOUT 0
+
+ static char *sge_env_var = NULL;
+ static int qrsh_tries_number = DEFAULT_QRSH_TRIES_NUMBER;
+ static int qrsh_timeout = DEFAULT_QRSH_TIMEOUT;
+#define SGE_DEBUG
+#ifdef SGE_DEBUG
+ static Boolean do_not_remove = false;
+#endif /* SGE_DEBUG */
+ if (sge_env_var == NULL) {
+ sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_TRIES"));
+ if (sge_env_var != NULL) {
+ qrsh_tries_number = atoi(sge_env_var);
+ if (qrsh_tries_number < 1 || qrsh_tries_number > 9) {
+ qrsh_tries_number = DEFAULT_QRSH_TRIES_NUMBER;
+ }
+ }
+ sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_TIMEOUT"));
+ if (sge_env_var != NULL) {
+ qrsh_timeout = atoi(sge_env_var);
+ if (qrsh_timeout <= 0) {
+ qrsh_timeout = DEFAULT_QRSH_TIMEOUT;
+ }
+ } else {
+ sge_env_var = "";
+ }
+#ifdef SGE_DEBUG
+ sge_env_var = getenv(NOCATGETS("__SPRO_DMAKE_SGE_DEBUG"));
+ if (sge_env_var == NULL) {
+ sge_env_var = "";
+ }
+ if (strstr(sge_env_var, NOCATGETS("noqrsh")) != NULL)
+ qrsh_tries_number = 0;
+ if (strstr(sge_env_var, NOCATGETS("donotremove")) != NULL)
+ do_not_remove = true;
+#endif /* SGE_DEBUG */
+ }
+ for (int i = qrsh_tries_number; ; i--)
+ if ((childPid = fork()) < 0) {
+ fatal(catgets(catd, 1, 348, "Could not fork child process for qrsh job: %s"),
+ errmsg(errno));
+ _exit(1);
+ } else if (childPid == 0) {
+ enable_interrupt((void (*) (int))SIG_DFL);
+ if (i > 0) {
+ static char qrsh_cmd[50+MAXPATHLEN] = NOCATGETS("qrsh -cwd -V -noshell -nostdin /bin/sh ");
+ static char *fname_ptr = NULL;
+ static char *argv[] = { NOCATGETS("sh"),
+ NOCATGETS("-fce"),
+ qrsh_cmd,
+ NULL};
+ if (fname_ptr == NULL) {
+ fname_ptr = qrsh_cmd + strlen(qrsh_cmd);
+ }
+ strcpy(fname_ptr, script_file);
+ (void) execve(NOCATGETS("/bin/sh"), argv, environ);
+ } else {
+ static char *argv[] = { NOCATGETS("sh"),
+ script_file,
+ NULL};
+ (void) execve(NOCATGETS("/bin/sh"), argv, environ);
+ }
+ fprintf(stderr,
+ catgets(catd, 1, 349, "Could not load `qrsh': %s\n"),
+ errmsg(errno));
+ _exit(1);
+ } else {
+#if defined (HP_UX) || defined (linux) || defined (SUN5_0)
+ int status;
+#else
+ union wait status;
+#endif
+ pid_t pid;
+ while ((pid = wait(&status)) != childPid) {
+ if (pid == -1) {
+ fprintf(stderr,
+ catgets(catd, 1, 350, "wait() failed: %s\n"),
+ errmsg(errno));
+ _exit(1);
+ }
+ }
+ if (status != 0 && i > 0) {
+ if (i > 1) {
+ sleep(qrsh_timeout);
+ }
+ continue;
+ }
+#ifdef SGE_DEBUG
+ if (do_not_remove) {
+ if (status) {
+ fprintf(stderr,
+ NOCATGETS("SGE script failed: %s\n"),
+ script_file);
+ }
+ _exit(status ? 1 : 0);
+ }
+#endif /* SGE_DEBUG */
+ (void) unlink(script_file);
+ _exit(status ? 1 : 0);
+ }
+ }
+#endif /* SGE_SUPPORT */
+ break;
+ default:
+ break;
+ }
+ return childPid;
+}
+
+static void
+maybe_reread_make_state(void)
+{
+ /* Copying dosys()... */
+ if (report_dependencies_level == 0) {
+ make_state->stat.time = file_no_time;
+ (void) exists(make_state);
+ if (make_state_before == make_state->stat.time) {
+ return;
+ }
+ makefile_type = reading_statefile;
+ if (read_trace_level > 1) {
+ trace_reader = true;
+ }
+ temp_file_number++;
+ (void) read_simple_file(make_state,
+ false,
+ false,
+ false,
+ false,
+ false,
+ true);
+ trace_reader = false;
+ }
+}
+
+#ifdef DISTRIBUTED
+/*
+ * Create and send an Avo_MToolJobResultMsg.
+ */
+static void
+send_job_result_msg(Running rp)
+{
+ Avo_MToolJobResultMsg *msg;
+ RWCollectable *xdr_msg;
+
+ msg = new Avo_MToolJobResultMsg();
+ msg->setResult(rp->job_msg_id,
+ (rp->state == build_ok) ? 0 : 1,
+ DONE);
+ append_job_result_msg(msg,
+ rp->stdout_file,
+ rp->stderr_file);
+
+ xdr_msg = (RWCollectable *)msg;
+ xdr(get_xdrs_ptr(), xdr_msg);
+ (void) fflush(get_mtool_msgs_fp());
+
+ delete msg;
+}
+
+/*
+ * Append the stdout/err to Avo_MToolJobResultMsg.
+ */
+static void
+append_job_result_msg(Avo_MToolJobResultMsg *msg, char *outFn, char *errFn)
+{
+ FILE *fp;
+ char line[MAXPATHLEN];
+
+ fp = fopen(outFn, "r");
+ if (fp == NULL) {
+ /* Hmmm... what should we do here? */
+ return;
+ }
+ while (fgets(line, MAXPATHLEN, fp) != NULL) {
+ if (line[strlen(line) - 1] == '\n') {
+ line[strlen(line) - 1] = '\0';
+ }
+ msg->appendOutput(AVO_STRDUP(line));
+ }
+ (void) fclose(fp);
+}
+#endif
+
+static void
+delete_running_struct(Running rp)
+{
+ if ((rp->conditional_cnt > 0) &&
+ (rp->conditional_targets != NULL)) {
+ retmem_mb((char *) rp->conditional_targets);
+ }
+/**/
+ if ((rp->auto_count > 0) &&
+ (rp->automatics != NULL)) {
+ retmem_mb((char *) rp->automatics);
+ }
+/**/
+ if(rp->sprodep_value) {
+ free_name(rp->sprodep_value);
+ }
+ if(rp->sprodep_env) {
+ retmem_mb(rp->sprodep_env);
+ }
+ retmem_mb((char *) rp);
+
+}
+
+#endif
+