|
Packit Service |
c5cf8c |
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
|
|
Packit Service |
c5cf8c |
/*
|
|
Packit Service |
c5cf8c |
* (C) 2004 by Argonne National Laboratory.
|
|
Packit Service |
c5cf8c |
* See COPYRIGHT in top-level directory.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* OWNER=gropp */
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* An example mpiexec program that uses a remote shell program to create
|
|
Packit Service |
c5cf8c |
new processes on the selected hosts.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
This code also shows how to use the pmutil routines (in ../util)
|
|
Packit Service |
c5cf8c |
to provide many of the services required by mpiexec
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
Steps:
|
|
Packit Service |
c5cf8c |
1. Read and process that command line. Build a ProcessList. (A ProcessList
|
|
Packit Service |
c5cf8c |
may have one entry for a request to create n separate processes)
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
2. Convert the ProcessList into a ProcessTable. In the forker mpiexec,
|
|
Packit Service |
c5cf8c |
this simply expands the requested number of processes into an
|
|
Packit Service |
c5cf8c |
array with one entry per process. These entries contain information
|
|
Packit Service |
c5cf8c |
on both the setup of the processes and the file descriptors used for
|
|
Packit Service |
c5cf8c |
stdin,out,err, and for the PMI calls.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
3. (Optionally) allow the forked processes to use a host:port to
|
|
Packit Service |
c5cf8c |
contact this program, rather than just sharing a pipe. This allows the
|
|
Packit Service |
c5cf8c |
forker to start other programs, such as debuggers.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
4. Establish a signal handler for SIGCHLD. This will allow us to
|
|
Packit Service |
c5cf8c |
get information about process termination; in particular, the exit
|
|
Packit Service |
c5cf8c |
status.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
5. Start the programs.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
6. Process input from the programs; send stdin given to this process
|
|
Packit Service |
c5cf8c |
to the selected processes (usually rank 0 or everyone). Handle all
|
|
Packit Service |
c5cf8c |
PMI commands, including spawn. Another "input" is the expiration of the
|
|
Packit Service |
c5cf8c |
specified timelimit for the run, if any.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
7. Process rundown commands and handle any abnormal termination.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
8. Wait for any processes to exit; gather the exit status and reason
|
|
Packit Service |
c5cf8c |
for exit (if abnormal, such as signaled with SEGV or BUS)
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
9. Release all resources and compute the exit status for this program
|
|
Packit Service |
c5cf8c |
(using one of several approaches, such as taking the maximum of the
|
|
Packit Service |
c5cf8c |
exit statuses).
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
Special Case to support Singleton Init:
|
|
Packit Service |
c5cf8c |
To support a singleton init of a process that then wants to
|
|
Packit Service |
c5cf8c |
create processes with MPI_Comm_spawn(_multiple), a special form of
|
|
Packit Service |
c5cf8c |
mpiexec is supported:
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
mpiexec -pmi_args <port> <interfacename> <securitykey> <pid>
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
The singleton process (in a routine in simple_pmi.c) forks a process and
|
|
Packit Service |
c5cf8c |
execs mpiexe with these arguments, where port is the port to which
|
|
Packit Service |
c5cf8c |
mpiexec should connect, interfacename is the name of the network interface, securitykey
|
|
Packit Service |
c5cf8c |
is a place-holder for a key used by the singleton init process to verify
|
|
Packit Service |
c5cf8c |
that the process connecting on the port is the one that was intended, and
|
|
Packit Service |
c5cf8c |
pid is the pid of the singleton init process.
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
FIXME: The above has not been implemented yet.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#include "mpichconf.h"
|
|
Packit Service |
c5cf8c |
#include <stdio.h>
|
|
Packit Service |
c5cf8c |
#include <string.h>
|
|
Packit Service |
c5cf8c |
#ifdef HAVE_UNISTD_H
|
|
Packit Service |
c5cf8c |
#include <unistd.h>
|
|
Packit Service |
c5cf8c |
#endif
|
|
Packit Service |
c5cf8c |
#include <stdlib.h>
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#include "pmutil.h"
|
|
Packit Service |
c5cf8c |
#include "process.h"
|
|
Packit Service |
c5cf8c |
#include "cmnargs.h"
|
|
Packit Service |
c5cf8c |
#include "pmiserv.h"
|
|
Packit Service |
c5cf8c |
#include "ioloop.h"
|
|
Packit Service |
c5cf8c |
#include "labelout.h"
|
|
Packit Service |
c5cf8c |
#include "rm.h"
|
|
Packit Service |
c5cf8c |
#include "simple_pmiutil.h"
|
|
Packit Service |
c5cf8c |
#include "env.h" /* MPIE_Putenv */
|
|
Packit Service |
c5cf8c |
/* mpir_mem.h contains prototypes for MPL_strncpy etc. */
|
|
Packit Service |
c5cf8c |
/* We no longer can use these because they are MPI device specific */
|
|
Packit Service |
c5cf8c |
/* #include "mpir_mem.h" */
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
typedef struct {
|
|
Packit Service |
c5cf8c |
PMISetup pmiinfo;
|
|
Packit Service |
c5cf8c |
IOLabelSetup labelinfo;
|
|
Packit Service |
c5cf8c |
} SetupInfo;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Forward declarations */
|
|
Packit Service |
c5cf8c |
int mypreamble(void *, ProcessState *);
|
|
Packit Service |
c5cf8c |
int mypostfork(void *, void *, ProcessState *);
|
|
Packit Service |
c5cf8c |
int mypostamble(void *, void *, ProcessState *);
|
|
Packit Service |
c5cf8c |
int myspawn(ProcessWorld *, void *);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
static int AddEnvSetToCmdLine(const char *, const char *, const char **);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Set printFailure to 1 to get an explanation of the failure reason
|
|
Packit Service |
c5cf8c |
for each process when a process fails */
|
|
Packit Service |
c5cf8c |
static int printFailure = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#ifndef MAX_PORT_STRING
|
|
Packit Service |
c5cf8c |
#define MAX_PORT_STRING 1024
|
|
Packit Service |
c5cf8c |
#endif
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Note that envp is common but not standard */
|
|
Packit Service |
c5cf8c |
int main(int argc, char *argv[], char *envp[])
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
int rc;
|
|
Packit Service |
c5cf8c |
int erc = 0; /* Other (exceptional) return codes */
|
|
Packit Service |
c5cf8c |
int reason, signaled = 0;
|
|
Packit Service |
c5cf8c |
SetupInfo s;
|
|
Packit Service |
c5cf8c |
char portString[MAX_PORT_STRING];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* MPIE_ProcessInit initializes the global pUniv */
|
|
Packit Service |
c5cf8c |
MPIE_ProcessInit();
|
|
Packit Service |
c5cf8c |
/* Set a default for the universe size */
|
|
Packit Service |
c5cf8c |
pUniv.size = 64;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Set defaults for any arguments that are options. Also check the
|
|
Packit Service |
c5cf8c |
* environment for special options, such as debugging. Set
|
|
Packit Service |
c5cf8c |
* some defaults in pUniv */
|
|
Packit Service |
c5cf8c |
MPIE_CheckEnv(&pUniv, 0, 0);
|
|
Packit Service |
c5cf8c |
IOLabelCheckEnv();
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Handle the command line arguments. Use the routine from util/cmnargs.c
|
|
Packit Service |
c5cf8c |
* to fill in the universe */
|
|
Packit Service |
c5cf8c |
MPIE_Args(argc, argv, &pUniv, 0, 0);
|
|
Packit Service |
c5cf8c |
/* If there were any soft arguments, we need to handle them now */
|
|
Packit Service |
c5cf8c |
rc = MPIE_InitWorldWithSoft(&pUniv.worlds[0], pUniv.size);
|
|
Packit Service |
c5cf8c |
if (!rc) {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("Unable to process soft arguments\n");
|
|
Packit Service |
c5cf8c |
exit(1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (pUniv.fromSingleton) {
|
|
Packit Service |
c5cf8c |
/* The MPI process is already running. We create a simple entry
|
|
Packit Service |
c5cf8c |
* for a single process rather than creating the process */
|
|
Packit Service |
c5cf8c |
MPIE_SetupSingleton(&pUniv);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
rc = MPIE_ChooseHosts(&pUniv.worlds[0], MPIE_ReadMachines, 0);
|
|
Packit Service |
c5cf8c |
if (rc) {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("Unable to assign hosts to processes\n");
|
|
Packit Service |
c5cf8c |
exit(1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (MPIE_Debug)
|
|
Packit Service |
c5cf8c |
MPIE_PrintProcessUniverse(stdout, &pUniv);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
DBG_PRINTF(("timeout_seconds = %d\n", pUniv.timeout));
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Get the common port for creating PMI connections to the created
|
|
Packit Service |
c5cf8c |
* processes */
|
|
Packit Service |
c5cf8c |
rc = PMIServSetupPort(&pUniv, portString, sizeof(portString));
|
|
Packit Service |
c5cf8c |
if (rc) {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("Unable to setup port for listener\n");
|
|
Packit Service |
c5cf8c |
exit(1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
s.pmiinfo.portName = portString;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
#ifdef USE_MPI_STAGE_EXECUTABLES
|
|
Packit Service |
c5cf8c |
/* Hook for later use in staging executables */
|
|
Packit Service |
c5cf8c |
if (? stageExes) {
|
|
Packit Service |
c5cf8c |
rc = MPIE_StageExecutables(&pUniv.worlds[0]);
|
|
Packit Service |
c5cf8c |
if (!rc)
|
|
Packit Service |
c5cf8c |
...;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
#endif
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
PMIServInit(myspawn, &s);
|
|
Packit Service |
c5cf8c |
s.pmiinfo.pWorld = &pUniv.worlds[0];
|
|
Packit Service |
c5cf8c |
PMISetupNewGroup(pUniv.worlds[0].nProcess, 0);
|
|
Packit Service |
c5cf8c |
MPIE_ForwardCommonSignals();
|
|
Packit Service |
c5cf8c |
if (!pUniv.fromSingleton) {
|
|
Packit Service |
c5cf8c |
MPIE_ForkProcesses(&pUniv.worlds[0], envp, mypreamble, &s, mypostfork, 0, mypostamble, 0);
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
/* FIXME: The singleton code goes here */
|
|
Packit Service |
c5cf8c |
MPL_error_printf("Singleton init not supported\n");
|
|
Packit Service |
c5cf8c |
exit(1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
reason = MPIE_IOLoop(pUniv.timeout);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (reason == IOLOOP_TIMEOUT) {
|
|
Packit Service |
c5cf8c |
/* Exited due to timeout. Generate an error message and
|
|
Packit Service |
c5cf8c |
* terminate the children */
|
|
Packit Service |
c5cf8c |
if (pUniv.timeout > 60) {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("Timeout of %d minutes expired; job aborted\n", pUniv.timeout / 60);
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("Timeout of %d seconds expired; job aborted\n", pUniv.timeout);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
erc = 1;
|
|
Packit Service |
c5cf8c |
MPIE_KillUniverse(&pUniv);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Wait for all processes to exit and gather information on them.
|
|
Packit Service |
c5cf8c |
* We do this through the SIGCHLD handler. We also bound the length
|
|
Packit Service |
c5cf8c |
* of time that we wait to 2 seconds.
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
MPIE_WaitForProcesses(&pUniv, 2);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Compute the return code (max for now) */
|
|
Packit Service |
c5cf8c |
rc = MPIE_ProcessGetExitStatus(&signaled);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Optionally provide detailed information about failed processes */
|
|
Packit Service |
c5cf8c |
if ((rc && printFailure) || signaled)
|
|
Packit Service |
c5cf8c |
MPIE_PrintFailureReasons(stderr);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* If the processes exited normally (or were already gone) but we
|
|
Packit Service |
c5cf8c |
* had an exceptional exit, such as a timeout, use the erc value */
|
|
Packit Service |
c5cf8c |
if (!rc && erc)
|
|
Packit Service |
c5cf8c |
rc = erc;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
return (rc);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
void mpiexec_usage(const char *msg)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
if (msg) {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("%s", msg);
|
|
Packit Service |
c5cf8c |
if (msg[strlen(msg) - 1] != '\n') {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("\n");
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
MPL_usage_printf("Usage: mpiexec %s\n", MPIE_ArgDescription());
|
|
Packit Service |
c5cf8c |
exit(-1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Redirect stdout and stderr to a handler */
|
|
Packit Service |
c5cf8c |
int mypreamble(void *data, ProcessState * pState)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
SetupInfo *s = (SetupInfo *) data;
|
|
Packit Service |
c5cf8c |
int rc;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
IOLabelSetupFDs(&s->labelinfo);
|
|
Packit Service |
c5cf8c |
rc = PMISetupSockets(1, &s->pmiinfo);
|
|
Packit Service |
c5cf8c |
/* We must use communication over the socket, rather than the
|
|
Packit Service |
c5cf8c |
* environment, to pass initialization data */
|
|
Packit Service |
c5cf8c |
pState->initWithEnv = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
return rc;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Close one side of each pipe pair and replace stdout/err with the pipes */
|
|
Packit Service |
c5cf8c |
int mypostfork(void *predata, void *data, ProcessState * pState)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
SetupInfo *s = (SetupInfo *) predata;
|
|
Packit Service |
c5cf8c |
int curarg = 0;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
IOLabelSetupInClient(&s->labelinfo);
|
|
Packit Service |
c5cf8c |
PMISetupInClient(1, &s->pmiinfo);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Now, we *also* change the process state to insert the
|
|
Packit Service |
c5cf8c |
* interposed remote shell routine. This is probably not
|
|
Packit Service |
c5cf8c |
* where we want this in the final version (because MPIE_ExecProgram
|
|
Packit Service |
c5cf8c |
* does a lot under the assumption that the started program will
|
|
Packit Service |
c5cf8c |
* know what to do with new environment variables), but this
|
|
Packit Service |
c5cf8c |
* will allow us to start. */
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
ProcessApp *app = pState->app;
|
|
Packit Service |
c5cf8c |
const char **newargs = 0;
|
|
Packit Service |
c5cf8c |
char *pmiDebugStr = 0;
|
|
Packit Service |
c5cf8c |
int j;
|
|
Packit Service |
c5cf8c |
char rankStr[12];
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Insert into app->args */
|
|
Packit Service |
c5cf8c |
newargs = (const char **) MPL_malloc((app->nArgs + 14 + 1) * sizeof(char *), MPL_MEM_PM);
|
|
Packit Service |
c5cf8c |
if (!pState->hostname) {
|
|
Packit Service |
c5cf8c |
MPL_error_printf("No hostname avaliable for %s\n", app->exename);
|
|
Packit Service |
c5cf8c |
exit(1);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
snprintf(rankStr, sizeof(rankStr) - 1, "%d", pState->id);
|
|
Packit Service |
c5cf8c |
rankStr[12 - 1] = 0;
|
|
Packit Service |
c5cf8c |
curarg = 0;
|
|
Packit Service |
c5cf8c |
newargs[curarg++] = MPL_strdup("-Y");
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
newargs[curarg++] = pState->hostname;
|
|
Packit Service |
c5cf8c |
curarg += AddEnvSetToCmdLine("PMI_PORT", s->pmiinfo.portName, newargs + curarg);
|
|
Packit Service |
c5cf8c |
curarg += AddEnvSetToCmdLine("PMI_ID", rankStr, newargs + curarg);
|
|
Packit Service |
c5cf8c |
pmiDebugStr = getenv("PMI_DEBUG");
|
|
Packit Service |
c5cf8c |
if (pmiDebugStr) {
|
|
Packit Service |
c5cf8c |
/* Use this to help debug the connection process */
|
|
Packit Service |
c5cf8c |
curarg += AddEnvSetToCmdLine("PMI_DEBUG", pmiDebugStr, newargs + curarg);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
newargs[curarg++] = app->exename;
|
|
Packit Service |
c5cf8c |
for (j = 0; j < app->nArgs; j++) {
|
|
Packit Service |
c5cf8c |
newargs[j + curarg] = app->args[j];
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
newargs[j + curarg] = 0;
|
|
Packit Service |
c5cf8c |
app->exename = MPL_strdup("/usr/bin/ssh");
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
app->args = newargs;
|
|
Packit Service |
c5cf8c |
app->nArgs += curarg;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (MPIE_Debug) {
|
|
Packit Service |
c5cf8c |
printf("cmd = %s\n", app->exename);
|
|
Packit Service |
c5cf8c |
fflush(stdout);
|
|
Packit Service |
c5cf8c |
printf("Number of args = %d\n", app->nArgs);
|
|
Packit Service |
c5cf8c |
for (j = 0; j < app->nArgs; j++) {
|
|
Packit Service |
c5cf8c |
printf("argv[%d] = %s\n", j, app->args[j]);
|
|
Packit Service |
c5cf8c |
fflush(stdout);
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
return 0;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Close one side of the pipe pair and register a handler for the I/O */
|
|
Packit Service |
c5cf8c |
int mypostamble(void *predata, void *data, ProcessState * pState)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
SetupInfo *s = (SetupInfo *) predata;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
IOLabelSetupFinishInServer(&s->labelinfo, pState);
|
|
Packit Service |
c5cf8c |
PMISetupFinishInServer(1, &s->pmiinfo, pState);
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
return 0;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
int myspawn(ProcessWorld * pWorld, void *data)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
SetupInfo *s = (SetupInfo *) data;
|
|
Packit Service |
c5cf8c |
ProcessWorld *p, **pPtr;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
p = pUniv.worlds;
|
|
Packit Service |
c5cf8c |
pPtr = &(pUniv.worlds);
|
|
Packit Service |
c5cf8c |
while (p) {
|
|
Packit Service |
c5cf8c |
pPtr = &p->nextWorld;
|
|
Packit Service |
c5cf8c |
p = *pPtr;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
*pPtr = pWorld;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Fork Processes may call a routine that is passed s but not pWorld;
|
|
Packit Service |
c5cf8c |
* this makes sure that all routines can access the current world */
|
|
Packit Service |
c5cf8c |
s->pmiinfo.pWorld = pWorld;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* FIXME: This should be part of the PMI initialization in the clients */
|
|
Packit Service |
c5cf8c |
MPIE_Putenv(pWorld, "PMI_SPAWNED=1");
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
MPIE_ForkProcesses(pWorld, 0, mypreamble, s, mypostfork, 0, mypostamble, 0);
|
|
Packit Service |
c5cf8c |
return 0;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Temp test for the replacement for the simple "spawn == fork" */
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/*
|
|
Packit Service |
c5cf8c |
* Approach:
|
|
Packit Service |
c5cf8c |
* Processes are created using a remote shell program. This requires
|
|
Packit Service |
c5cf8c |
* changing the command line from
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* a.out args ...
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* to
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* remshell-program remshell-args /bin/sh -c PMI_PORT=string &&
|
|
Packit Service |
c5cf8c |
* export PMI_PORT && PMI_ID=rank-in-world && export PMI_ID &&
|
|
Packit Service |
c5cf8c |
* a.out args
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* (the export PMI_PORT=string syntax is not valid in all versions of sh)
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Using PMI_ID ensures that we correctly identify each process (this was
|
|
Packit Service |
c5cf8c |
* a major problem in the setup used by the p4 device in MPICH1).
|
|
Packit Service |
c5cf8c |
* Using environment variables instead of command line arguments keeps
|
|
Packit Service |
c5cf8c |
* the commaand line clean.
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Two alternatives should be considered
|
|
Packit Service |
c5cf8c |
* 1) Use an intermediate manager. This would allow us to set up the
|
|
Packit Service |
c5cf8c |
* environment as well:
|
|
Packit Service |
c5cf8c |
* remshell-program remshell-args manager -port string
|
|
Packit Service |
c5cf8c |
* 2) Use the secure server (even the same one as in MPICH1); then
|
|
Packit Service |
c5cf8c |
* there is no remote shell command.
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* We can handle the transformation of the command line by adding a
|
|
Packit Service |
c5cf8c |
* to the postfork routine; this is called after the fork but before the
|
|
Packit Service |
c5cf8c |
* exec, and it can change the command line by making a copy of the app
|
|
Packit Service |
c5cf8c |
* structure, changing the command line, and setting the pState structure
|
|
Packit Service |
c5cf8c |
* to point to this new app (after the fork, these changes are visable only
|
|
Packit Service |
c5cf8c |
* to the forked process).
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Enhancements:
|
|
Packit Service |
c5cf8c |
* Allow the code to avoid the remote shell if the process is being created
|
|
Packit Service |
c5cf8c |
* on the local host.
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Handle the user of -l username and -n options to remshell
|
|
Packit Service |
c5cf8c |
* (-n makes stdin /dev/null, necessary for backgrounding).
|
|
Packit Service |
c5cf8c |
* (-l username allows login to hosts where the user's username is
|
|
Packit Service |
c5cf8c |
* different)
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* Provide an option to add a backslash before any - to deal with the
|
|
Packit Service |
c5cf8c |
* serious bug in the GNU inetutils remote shell programs that process
|
|
Packit Service |
c5cf8c |
* *all* arguments on the remote shell command line, even those for the
|
|
Packit Service |
c5cf8c |
* *program*!
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
* To best support the errcodes return from MPI_Comm_spawn,
|
|
Packit Service |
c5cf8c |
* we need a way to communicate the array of error codes back to the
|
|
Packit Service |
c5cf8c |
* spawn and spawn multiple commands. Query: how is that done in
|
|
Packit Service |
c5cf8c |
* PMI?
|
|
Packit Service |
c5cf8c |
*
|
|
Packit Service |
c5cf8c |
*/
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
static int AddEnvSetToCmdLine(const char *envName, const char *envValue, const char **args)
|
|
Packit Service |
c5cf8c |
{
|
|
Packit Service |
c5cf8c |
int nArgs = 0;
|
|
Packit Service |
c5cf8c |
static int useCSHFormat = -1;
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
/* Determine the Shell type the first time */
|
|
Packit Service |
c5cf8c |
if (useCSHFormat == -1) {
|
|
Packit Service |
c5cf8c |
char *shell = getenv("SHELL"), *sname;
|
|
Packit Service |
c5cf8c |
if (shell) {
|
|
Packit Service |
c5cf8c |
/* printf("Shell is %s\n", shell); */
|
|
Packit Service |
c5cf8c |
sname = strrchr(shell, '/');
|
|
Packit Service |
c5cf8c |
if (!sname)
|
|
Packit Service |
c5cf8c |
sname = shell;
|
|
Packit Service |
c5cf8c |
else
|
|
Packit Service |
c5cf8c |
sname++;
|
|
Packit Service |
c5cf8c |
/* printf("Sname is %s\n", sname); */
|
|
Packit Service |
c5cf8c |
if (strcmp(sname, "bash") == 0 || strcmp(sname, "sh") || strcmp(sname, "ash") == 0)
|
|
Packit Service |
c5cf8c |
useCSHFormat = 0;
|
|
Packit Service |
c5cf8c |
else
|
|
Packit Service |
c5cf8c |
useCSHFormat = 1;
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
/* Default is to assume csh (setenv) format */
|
|
Packit Service |
c5cf8c |
useCSHFormat = 1;
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
|
|
Packit Service |
c5cf8c |
if (useCSHFormat) {
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup("setenv");
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup(envName);
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup(envValue);
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup(";");
|
|
Packit Service |
c5cf8c |
} else {
|
|
Packit Service |
c5cf8c |
char tmpBuf[1024];
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup("export");
|
|
Packit Service |
c5cf8c |
MPL_strncpy(tmpBuf, envName, sizeof(tmpBuf));
|
|
Packit Service |
c5cf8c |
MPL_strnapp(tmpBuf, "=", sizeof(tmpBuf));
|
|
Packit Service |
c5cf8c |
MPL_strnapp(tmpBuf, envValue, sizeof(tmpBuf));
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup(tmpBuf);
|
|
Packit Service |
c5cf8c |
args[nArgs++] = MPL_strdup(";");
|
|
Packit Service |
c5cf8c |
}
|
|
Packit Service |
c5cf8c |
return nArgs;
|
|
Packit Service |
c5cf8c |
}
|