diff options
author | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
---|---|---|
committer | Igor Pashev <igor.pashev@nexenta.com> | 2012-06-29 14:36:07 +0400 |
commit | e0463df9c3d2ee6155221cc443c571d5da47098a (patch) | |
tree | 5c6b99e64c1b65d986e2722728c74f202a578be6 /usr/src/make_src/Make/bin/make/common/dist.cc | |
download | sunmake-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/dist.cc')
-rw-r--r-- | usr/src/make_src/Make/bin/make/common/dist.cc | 581 |
1 files changed, 581 insertions, 0 deletions
diff --git a/usr/src/make_src/Make/bin/make/common/dist.cc b/usr/src/make_src/Make/bin/make/common/dist.cc new file mode 100644 index 0000000..f825d43 --- /dev/null +++ b/usr/src/make_src/Make/bin/make/common/dist.cc @@ -0,0 +1,581 @@ +/* + * 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 2004 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ +/* + * @(#)dist.cc 1.35 06/12/12 + */ + +#pragma ident "@(#)dist.cc 1.25 96/03/12" + +#ifdef DISTRIBUTED +/* + * dist.cc + * + * Deal with the distributed processing + */ + +#include <avo/err.h> +#include <avo/find_dir.h> +#include <avo/util.h> +#include <dm/Avo_AcknowledgeMsg.h> +#include <dm/Avo_DoJobMsg.h> +#include <dm/Avo_JobResultMsg.h> +#include <mk/defs.h> +#include <mksh/misc.h> /* getmem() */ +#include <rw/pstream.h> +#include <rw/queuecol.h> +#include <rw/xdrstrea.h> +#include <signal.h> +#ifdef linux +#include <sstream> +using namespace std; +#else +#include <strstream.h> +#endif +#include <sys/stat.h> /* stat() */ +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <errno.h> + +/* + * Defined macros + */ + +#define AVO_BLOCK_INTERUPTS sigfillset(&newset) ; \ + sigprocmask(SIG_SETMASK, &newset, &oldset) + +#define AVO_UNBLOCK_INTERUPTS \ + sigprocmask(SIG_SETMASK, &oldset, &newset) + + +/* + * typedefs & structs + */ + +/* + * Static variables + */ +int dmake_ifd; +FILE* dmake_ifp; +XDR xdrs_in; + +int dmake_ofd; +FILE* dmake_ofp; +XDR xdrs_out; + +// These instances are required for the RWfactory. +static Avo_JobResultMsg dummyJobResultMsg; +static Avo_AcknowledgeMsg dummyAcknowledgeMsg; +static int firstAcknowledgeReceived = 0; + +int rxmPid = 0; + +/* + * File table of contents + */ +static void set_dmake_env_vars(void); + +/* + * void + * startup_rxm(void) + * + * When startup_rxm() is called, read_command_options() and + * read_files_and_state() have already been read, so DMake + * will now know what options to pass to rxm. + * + * rxm + * [ -k ] [ -n ] + * [ -c <dmake_rcfile> ] + * [ -g <dmake_group> ] + * [ -j <dmake_max_jobs> ] + * [ -m <dmake_mode> ] + * [ -o <dmake_odir> ] + * <read_fd> <write_fd> + * + * rxm will, among other things, read the rc file. + * + */ +void +startup_rxm(void) +{ + Name dmake_name; + Name dmake_value; + Avo_err *find_run_dir_err; + int pipe1[2], pipe2[2]; + Property prop; + char *run_dir; + char rxm_command[MAXPATHLEN]; + int rxm_debug = 0; + + int length; + char * env; + + firstAcknowledgeReceived = 0; + /* + * Create two pipes, one for dmake->rxm, and one for rxm->dmake. + * pipe1 is dmake->rxm, + * pipe2 is rxm->dmake. + */ + if ((pipe(pipe1) < 0) || (pipe(pipe2) < 0)) { + fatal(catgets(catd, 1, 245, "pipe() failed: %s"), errmsg(errno)); + } + + set_dmake_env_vars(); + + if ((rxmPid = fork()) < 0) { /* error */ + fatal(catgets(catd, 1, 246, "fork() failed: %s"), errmsg(errno)); + } else if (rxmPid > 0) { /* parent, dmake */ + dmake_ofd = pipe1[1]; // write side of pipe + if (!(dmake_ofp = fdopen(dmake_ofd, "a"))) { + fatal(catgets(catd, 1, 247, "fdopen() failed: %s"), errmsg(errno)); + } + xdrstdio_create(&xdrs_out, dmake_ofp, XDR_ENCODE); + + dmake_ifd = pipe2[0]; // read side of pipe + if (!(dmake_ifp = fdopen(dmake_ifd, "r"))) { + fatal(catgets(catd, 1, 248, "fdopen() failed: %s"), errmsg(errno)); + } + xdrstdio_create(&xdrs_in, dmake_ifp, XDR_DECODE); + + close(pipe1[0]); // read side + close(pipe2[1]); // write side + } else { /* child, rxm */ + close(pipe1[1]); // write side + close(pipe2[0]); // read side + + /* Find the run directory of dmake, for rxm. */ + find_run_dir_err = avo_find_run_dir(&run_dir); + if (find_run_dir_err) { + delete find_run_dir_err; + /* Use the path to find rxm. */ + (void) sprintf(rxm_command, NOCATGETS("rxm")); + } else { + /* Use the run dir of dmake for rxm. */ + (void) sprintf(rxm_command, NOCATGETS("%s/rxm"), run_dir); + } + + if (continue_after_error) { + (void) strcat(rxm_command, NOCATGETS(" -k")); + } + if (do_not_exec_rule) { + (void) strcat(rxm_command, NOCATGETS(" -n")); + } + if (rxm_debug) { + (void) strcat(rxm_command, NOCATGETS(" -S")); + } + if (send_mtool_msgs) { + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" -O %d"), + mtool_msgs_fd); + } + MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_RCFILE")); + dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); + if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && + ((dmake_value = prop->body.macro.value) != NULL)) { + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" -c %s"), + dmake_value->string_mb); + } else { + length = 2 + strlen(NOCATGETS("DMAKE_RCFILE")); + env = getmem(length); + (void) sprintf(env, + "%s=", + NOCATGETS("DMAKE_RCFILE")); + (void) putenv(env); + } + MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_GROUP")); + dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); + if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && + ((dmake_value = prop->body.macro.value) != NULL)) { + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" -g %s"), + dmake_value->string_mb); + } else { + length = 2 + strlen(NOCATGETS("DMAKE_GROUP")); + env = getmem(length); + (void) sprintf(env, + "%s=", + NOCATGETS("DMAKE_GROUP")); + (void) putenv(env); + } + 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)) { + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" -j %s"), + dmake_value->string_mb); + } else { + length = 2 + strlen(NOCATGETS("DMAKE_MAX_JOBS")); + env = getmem(length); + (void) sprintf(env, + "%s=", + NOCATGETS("DMAKE_MAX_JOBS")); + (void) putenv(env); + } + MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_MODE")); + dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); + if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && + ((dmake_value = prop->body.macro.value) != NULL)) { + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" -m %s"), + dmake_value->string_mb); + } else { + length = 2 + strlen(NOCATGETS("DMAKE_MODE")); + env = getmem(length); + (void) sprintf(env, + "%s=", + NOCATGETS("DMAKE_MODE")); + (void) putenv(env); + } + MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_ODIR")); + dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); + if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && + ((dmake_value = prop->body.macro.value) != NULL)) { + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" -o %s"), + dmake_value->string_mb); + } else { + length = 2 + strlen(NOCATGETS("DMAKE_ODIR")); + env = getmem(length); + (void) sprintf(env, + "%s=", + NOCATGETS("DMAKE_ODIR")); + (void) putenv(env); + } + + (void) sprintf(&rxm_command[strlen(rxm_command)], + NOCATGETS(" %d %d"), + pipe1[0], pipe2[1]); +#ifdef linux + execl(NOCATGETS("/bin/sh"), +#else + execl(NOCATGETS("/usr/bin/sh"), +#endif + NOCATGETS("sh"), + NOCATGETS("-c"), + rxm_command, + (char *)NULL); + _exit(127); + } +} + +/* + * static void + * set_dmake_env_vars() + * + * Sets the DMAKE_* environment variables for rxm and rxs. + * DMAKE_PWD + * DMAKE_NPWD + * DMAKE_UMASK + * DMAKE_SHELL + */ +static void +set_dmake_env_vars() +{ + char *current_netpath; + char *current_path; + static char *env; + int length; + char netpath[MAXPATHLEN]; + mode_t um; + char um_buf[MAXPATHLEN]; + Name dmake_name; + Name dmake_value; + Property prop; + +#ifdef REDIRECT_ERR + /* Set __DMAKE_REDIRECT_STDERR */ + length = 2 + strlen(NOCATGETS("__DMAKE_REDIRECT_STDERR")) + 1; + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("__DMAKE_REDIRECT_STDERR"), + out_err_same ? NOCATGETS("0") : NOCATGETS("1")); + (void) putenv(env); +#endif + + /* Set DMAKE_PWD to the current working directory */ + current_path = get_current_path(); + length = 2 + strlen(NOCATGETS("DMAKE_PWD")) + strlen(current_path); + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("DMAKE_PWD"), + current_path); + (void) putenv(env); + + /* Set DMAKE_NPWD to machine:pathname */ + if (avo_path_to_netpath(current_path, netpath)) { + current_netpath = netpath; + } else { + current_netpath = current_path; + } + length = 2 + strlen(NOCATGETS("DMAKE_NPWD")) + strlen(current_netpath); + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("DMAKE_NPWD"), + current_netpath); + (void) putenv(env); + + /* Set DMAKE_UMASK to the value of umask */ + um = umask(0); + umask(um); + (void) sprintf(um_buf, NOCATGETS("%ul"), um); + length = 2 + strlen(NOCATGETS("DMAKE_UMASK")) + strlen(um_buf); + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("DMAKE_UMASK"), + um_buf); + (void) putenv(env); + + if (((prop = get_prop(shell_name->prop, macro_prop)) != NULL) && + ((dmake_value = prop->body.macro.value) != NULL)) { + length = 2 + strlen(NOCATGETS("DMAKE_SHELL")) + + strlen(dmake_value->string_mb); + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("DMAKE_SHELL"), + dmake_value->string_mb); + (void) putenv(env); + } + MBSTOWCS(wcs_buffer, NOCATGETS("DMAKE_OUTPUT_MODE")); + dmake_name = GETNAME(wcs_buffer, FIND_LENGTH); + if (((prop = get_prop(dmake_name->prop, macro_prop)) != NULL) && + ((dmake_value = prop->body.macro.value) != NULL)) { + length = 2 + strlen(NOCATGETS("DMAKE_OUTPUT_MODE")) + + strlen(dmake_value->string_mb); + env = getmem(length); + (void) sprintf(env, + "%s=%s", + NOCATGETS("DMAKE_OUTPUT_MODE"), + dmake_value->string_mb); + (void) putenv(env); + } +} + +/* + * void + * distribute_rxm(Avo_DoJobMsg *dmake_job_msg) + * + * Write the DMake rule to be distributed down the pipe to rxm. + * + */ +void +distribute_rxm(Avo_DoJobMsg *dmake_job_msg) +{ + /* Add all dynamic env vars to the dmake_job_msg. */ + setvar_envvar(dmake_job_msg); + + /* + * Copying dosys()... + * Stat .make.state to see if we'll need to reread it later + */ + make_state->stat.time = file_no_time; + (void)exists(make_state); + make_state_before = make_state->stat.time; + + // Wait for the first Acknowledge message from the rxm process + // before sending the first message. + if (!firstAcknowledgeReceived) { + firstAcknowledgeReceived++; + Avo_AcknowledgeMsg *msg = getAcknowledgeMsg(); + if (msg) { + delete msg; + } + } + + RWCollectable *doJobMsg = (RWCollectable *)dmake_job_msg; + sigset_t newset; + sigset_t oldset; + + AVO_BLOCK_INTERUPTS; + int xdrResult = xdr(&xdrs_out, doJobMsg); + + if (xdrResult) { + fflush(dmake_ofp); + AVO_UNBLOCK_INTERUPTS; + } else { + AVO_UNBLOCK_INTERUPTS; + fatal(catgets(catd, 1, 249, "Couldn't send the job request to rxm")); + } + + delete dmake_job_msg; +} + +// Queue for JobResult messages. +static RWSlistCollectablesQueue jobResultQueue; + +// Queue for Acknowledge messages. +static RWSlistCollectablesQueue acknowledgeQueue; + +// Read a message from the rxm process, and put it into a queue, by +// message type. Return the message type. + +int +getRxmMessage(void) +{ + RWCollectable *msg = (RWCollectable *)0; + int msgType = 0; +// sigset_t newset; +// sigset_t oldset; + + // It seems unnecessarily to block interrupts here because + // any nonignored signal means exit for dmake in distributed mode. +// AVO_BLOCK_INTERUPTS; + int xdrResult = xdr(&xdrs_in, msg); +// AVO_UNBLOCK_INTERUPTS; + + if (xdrResult) { + switch(msg->isA()) { + case __AVO_ACKNOWLEDGEMSG: + acknowledgeQueue.append(msg); + msgType = __AVO_ACKNOWLEDGEMSG; + break; + case __AVO_JOBRESULTMSG: + jobResultQueue.append(msg); + msgType = __AVO_JOBRESULTMSG; + break; + default: + warning(catgets(catd, 1, 291, "Unknown message on rxm input fd")); + msgType = 0; + break; + } + } else { + if (errno == EINTR) { + fputs(NOCATGETS("dmake: Internal error: xdr() has been interrupted by a signal.\n"), stderr); + } + fatal(catgets(catd, 1, 250, "Couldn't receive message from rxm")); + } + + return msgType; +} + +// Get a JobResult message from it's queue, and +// if the queue is empty, call the getRxmMessage() function until +// a JobResult message shows. + +Avo_JobResultMsg * +getJobResultMsg(void) +{ + RWCollectable *msg = 0; + + if (!(msg = jobResultQueue.get())) { + while (getRxmMessage() != __AVO_JOBRESULTMSG); + msg = jobResultQueue.get(); + } + + return (Avo_JobResultMsg *)msg; +} + +// Get an Acknowledge message from it's queue, and +// if the queue is empty, call the getRxmMessage() function until +// a Acknowledge message shows. + +Avo_AcknowledgeMsg * +getAcknowledgeMsg(void) +{ + RWCollectable *msg = 0; + + if (!(msg = acknowledgeQueue.get())) { + while (getRxmMessage() != __AVO_ACKNOWLEDGEMSG); + msg = acknowledgeQueue.get(); + } + + return (Avo_AcknowledgeMsg *)msg; +} + + +/* + * Doname + * await_dist(Boolean waitflg) + * + * Waits for distributed children to exit and finishes their processing. + * Rxm will send a msg down the pipe when a child is done. + * + */ +Doname +await_dist(Boolean waitflg) +{ + Avo_JobResultMsg *dmake_result_msg; + int job_msg_id; + Doname result = build_ok; + int result_msg_cmd_status; + int result_msg_job_status; + Running rp; + + while (!(dmake_result_msg = getJobResultMsg())); + job_msg_id = dmake_result_msg->getId(); + result_msg_cmd_status = dmake_result_msg->getCmdStatus(); + result_msg_job_status = dmake_result_msg->getJobStatus(); + + if (waitflg) { + result = (result_msg_cmd_status == 0) ? build_ok : build_failed; + +#ifdef PRINT_EXIT_STATUS + if (result == build_ok) { + warning(NOCATGETS("I'm in await_dist(), waitflg is true, and result is build_ok.")); + } else { + warning(NOCATGETS("I'm in await_dist(), waitflg is true, and result is build_failed.")); + } +#endif + + } else { + for (rp = running_list; + (rp != NULL) && (job_msg_id != rp->job_msg_id); + rp = rp->next) { + } + if (rp == NULL) { + fatal(catgets(catd, 1, 251, "Internal error: returned child job_msg_id not in running_list")); + } else { + /* XXX - This may not be correct! */ + if (result_msg_job_status == RETURNED) { + rp->state = build_ok; + } else { + rp->state = (result_msg_cmd_status == 0) ? build_ok : build_failed; + } + result = rp->state; + +#ifdef PRINT_EXIT_STATUS + if (result == build_ok) { + warning(NOCATGETS("I'm in await_dist(), waitflg is false, and result is build_ok.")); + } else { + warning(NOCATGETS("I'm in await_dist(), waitflg is false, and result is build_failed.")); + } +#endif + + } + parallel_process_cnt--; + } + delete dmake_result_msg; + return result; +} + +#endif + + |