Blame src/pmi/simple/simple_pmi.c

Packit Service c5cf8c
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 *  (C) 2001 by Argonne National Laboratory.
Packit Service c5cf8c
 *      See COPYRIGHT in top-level directory.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
/*********************** PMI implementation ********************************/
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * This file implements the client-side of the PMI interface.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * Note that the PMI client code must not print error messages (except
Packit Service c5cf8c
 * when an abort is required) because MPI error handling is based on
Packit Service c5cf8c
 * reporting error codes to which messages are attached.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * In v2, we should require a PMI client interface to use MPI error codes
Packit Service c5cf8c
 * to provide better integration with MPICH.
Packit Service c5cf8c
 */
Packit Service c5cf8c
/***************************************************************************/
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpichconf.h"
Packit Service c5cf8c
Packit Service c5cf8c
#define PMI_VERSION    1
Packit Service c5cf8c
#define PMI_SUBVERSION 1
Packit Service c5cf8c
Packit Service c5cf8c
#include <stdio.h>
Packit Service c5cf8c
#ifdef HAVE_UNISTD_H
Packit Service c5cf8c
#include <unistd.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#ifdef HAVE_STDLIB_H
Packit Service c5cf8c
#include <stdlib.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#ifdef HAVE_STRING_H
Packit Service c5cf8c
#include <string.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#ifdef HAVE_STRINGS_H
Packit Service c5cf8c
#include <strings.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#ifdef USE_PMI_PORT
Packit Service c5cf8c
#ifndef MAXHOSTNAME
Packit Service c5cf8c
#define MAXHOSTNAME 256
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#endif
Packit Service c5cf8c
/* This should be moved to pmiu for shutdown */
Packit Service c5cf8c
#if defined(HAVE_SYS_SOCKET_H)
Packit Service c5cf8c
#include <sys/socket.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
#include "mpl.h"        /* Get ATTRIBUTE, some base functions */
Packit Service c5cf8c
/* mpimem includes the definitions for MPL_malloc and MPL_free */
Packit Service c5cf8c
#include "mpir_mem.h"
Packit Service c5cf8c
Packit Service c5cf8c
/* Temporary debug definitions */
Packit Service c5cf8c
/* #define DBG_PRINTF(args) printf args ; fflush(stdout) */
Packit Service c5cf8c
#define DBG_PRINTF(args)
Packit Service c5cf8c
Packit Service c5cf8c
#include "pmi.h"
Packit Service c5cf8c
#include "simple_pmiutil.h"
Packit Service c5cf8c
#include "mpi.h"        /* to get MPI_MAX_PORT_NAME */
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
   These are global variable used *ONLY* in this file, and are hence
Packit Service c5cf8c
   declared static.
Packit Service c5cf8c
 */
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
static int PMI_fd = -1;
Packit Service c5cf8c
static int PMI_size = 1;
Packit Service c5cf8c
static int PMI_rank = 0;
Packit Service c5cf8c
Packit Service c5cf8c
/* Set PMI_initialized to 1 for singleton init but no process manager
Packit Service c5cf8c
   to help.  Initialized to 2 for normal initialization.  Initialized
Packit Service c5cf8c
   to values higher than 2 when singleton_init by a process manager.
Packit Service c5cf8c
   All values higher than 1 invlove a PM in some way.
Packit Service c5cf8c
*/
Packit Service c5cf8c
typedef enum { PMI_UNINITIALIZED = 0,
Packit Service c5cf8c
    SINGLETON_INIT_BUT_NO_PM = 1,
Packit Service c5cf8c
    NORMAL_INIT_WITH_PM,
Packit Service c5cf8c
    SINGLETON_INIT_WITH_PM
Packit Service c5cf8c
} PMIState;
Packit Service c5cf8c
static PMIState PMI_initialized = PMI_UNINITIALIZED;
Packit Service c5cf8c
Packit Service c5cf8c
/* ALL GLOBAL VARIABLES MUST BE INITIALIZED TO AVOID POLLUTING THE
Packit Service c5cf8c
   LIBRARY WITH COMMON SYMBOLS */
Packit Service c5cf8c
static int PMI_kvsname_max = 0;
Packit Service c5cf8c
static int PMI_keylen_max = 0;
Packit Service c5cf8c
static int PMI_vallen_max = 0;
Packit Service c5cf8c
Packit Service c5cf8c
static int PMI_debug = 0;
Packit Service c5cf8c
static int PMI_debug_init = 0;  /* Set this to true to debug the init
Packit Service c5cf8c
                                 * handshakes */
Packit Service c5cf8c
static int PMI_spawned = 0;
Packit Service c5cf8c
Packit Service c5cf8c
/* Function prototypes for internal routines */
Packit Service c5cf8c
static int PMII_getmaxes(int *kvsname_max, int *keylen_max, int *vallen_max);
Packit Service c5cf8c
static int PMII_Set_from_port(int, int);
Packit Service c5cf8c
static int PMII_Connect_to_pm(char *, int);
Packit Service c5cf8c
Packit Service c5cf8c
static int GetResponse(const char[], const char[], int);
Packit Service c5cf8c
static int getPMIFD(int *);
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef USE_PMI_PORT
Packit Service c5cf8c
static int PMII_singinit(void);
Packit Service c5cf8c
static int PMI_totalview = 0;
Packit Service c5cf8c
#endif
Packit Service c5cf8c
static int PMIi_InitIfSingleton(void);
Packit Service c5cf8c
static int accept_one_connection(int);
Packit Service c5cf8c
static int cached_singinit_inuse = 0;
Packit Service c5cf8c
static char cached_singinit_key[PMIU_MAXLINE];
Packit Service c5cf8c
static char cached_singinit_val[PMIU_MAXLINE];
Packit Service c5cf8c
static char singinit_kvsname[256];
Packit Service c5cf8c
Packit Service c5cf8c
/******************************** Group functions *************************/
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Init(int *spawned)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char *p;
Packit Service c5cf8c
    int notset = 1;
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
Packit Service c5cf8c
    PMI_initialized = PMI_UNINITIALIZED;
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME: Why is setvbuf commented out? */
Packit Service c5cf8c
    /* FIXME: What if the output should be fully buffered (directed to file)?
Packit Service c5cf8c
     * unbuffered (user explicitly set?) */
Packit Service c5cf8c
    /* setvbuf(stdout,0,_IONBF,0); */
Packit Service c5cf8c
    setbuf(stdout, NULL);
Packit Service c5cf8c
    /* PMIU_printf(1, "PMI_INIT\n"); */
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get the value of PMI_DEBUG from the environment if possible, since
Packit Service c5cf8c
     * we may have set it to help debug the setup process */
Packit Service c5cf8c
    p = getenv("PMI_DEBUG");
Packit Service c5cf8c
    if (p)
Packit Service c5cf8c
        PMI_debug = atoi(p);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Get the fd for PMI commands; if none, we're a singleton */
Packit Service c5cf8c
    rc = getPMIFD(&notset);
Packit Service c5cf8c
    if (rc) {
Packit Service c5cf8c
        return rc;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_fd == -1) {
Packit Service c5cf8c
        /* Singleton init: Process not started with mpiexec,
Packit Service c5cf8c
         * so set size to 1, rank to 0 */
Packit Service c5cf8c
        PMI_size = 1;
Packit Service c5cf8c
        PMI_rank = 0;
Packit Service c5cf8c
        *spawned = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        PMI_initialized = SINGLETON_INIT_BUT_NO_PM;
Packit Service c5cf8c
        /* 256 is picked as the minimum allowed length by the PMI servers */
Packit Service c5cf8c
        PMI_kvsname_max = 256;
Packit Service c5cf8c
        PMI_keylen_max = 256;
Packit Service c5cf8c
        PMI_vallen_max = 256;
Packit Service c5cf8c
Packit Service c5cf8c
        return PMI_SUCCESS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* If size, rank, and debug are not set from a communication port,
Packit Service c5cf8c
     * use the environment */
Packit Service c5cf8c
    if (notset) {
Packit Service c5cf8c
        if ((p = getenv("PMI_SIZE")))
Packit Service c5cf8c
            PMI_size = atoi(p);
Packit Service c5cf8c
        else
Packit Service c5cf8c
            PMI_size = 1;
Packit Service c5cf8c
Packit Service c5cf8c
        if ((p = getenv("PMI_RANK"))) {
Packit Service c5cf8c
            PMI_rank = atoi(p);
Packit Service c5cf8c
            /* Let the util routine know the rank of this process for
Packit Service c5cf8c
             * any messages (usually debugging or error) */
Packit Service c5cf8c
            PMIU_Set_rank(PMI_rank);
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            PMI_rank = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        if ((p = getenv("PMI_DEBUG")))
Packit Service c5cf8c
            PMI_debug = atoi(p);
Packit Service c5cf8c
        else
Packit Service c5cf8c
            PMI_debug = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Leave unchanged otherwise, which indicates that no value
Packit Service c5cf8c
         * was set */
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
/* FIXME: Why does this depend on their being a port??? */
Packit Service c5cf8c
/* FIXME: What is this for? */
Packit Service c5cf8c
#ifdef USE_PMI_PORT
Packit Service c5cf8c
    if ((p = getenv("PMI_TOTALVIEW")))
Packit Service c5cf8c
        PMI_totalview = atoi(p);
Packit Service c5cf8c
    if (PMI_totalview) {
Packit Service c5cf8c
        char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
        /* FIXME: This should use a cmd/response rather than a expecting the
Packit Service c5cf8c
         * server to set a value in this and only this case */
Packit Service c5cf8c
        /* FIXME: And it most ceratainly should not happen *before* the
Packit Service c5cf8c
         * initialization handshake */
Packit Service c5cf8c
        PMIU_readline(PMI_fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
        PMIU_parse_keyvals(buf);
Packit Service c5cf8c
        PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
        if (strncmp(cmd, "tv_ready", PMIU_MAXLINE) != 0) {
Packit Service c5cf8c
            PMIU_printf(1, "expecting cmd=tv_ready, got %s\n", buf);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
    PMII_getmaxes(&PMI_kvsname_max, &PMI_keylen_max, &PMI_vallen_max);
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME: This is something that the PM should tell the process,
Packit Service c5cf8c
     * rather than deliver it through the environment */
Packit Service c5cf8c
    if ((p = getenv("PMI_SPAWNED")))
Packit Service c5cf8c
        PMI_spawned = atoi(p);
Packit Service c5cf8c
    else
Packit Service c5cf8c
        PMI_spawned = 0;
Packit Service c5cf8c
    if (PMI_spawned)
Packit Service c5cf8c
        *spawned = 1;
Packit Service c5cf8c
    else
Packit Service c5cf8c
        *spawned = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    if (!PMI_initialized)
Packit Service c5cf8c
        PMI_initialized = NORMAL_INIT_WITH_PM;
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Initialized(int *initialized)
Packit Service c5cf8c
{
Packit Service c5cf8c
    /* Turn this into a logical value (1 or 0) .  This allows us
Packit Service c5cf8c
     * to use PMI_initialized to distinguish between initialized with
Packit Service c5cf8c
     * an PMI service (e.g., via mpiexec) and the singleton init,
Packit Service c5cf8c
     * which has no PMI service */
Packit Service c5cf8c
    *initialized = (PMI_initialized != 0);
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Get_size(int *size)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (PMI_initialized)
Packit Service c5cf8c
        *size = PMI_size;
Packit Service c5cf8c
    else
Packit Service c5cf8c
        *size = 1;
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Get_rank(int *rank)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (PMI_initialized)
Packit Service c5cf8c
        *rank = PMI_rank;
Packit Service c5cf8c
    else
Packit Service c5cf8c
        *rank = 0;
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Get_universe_size is one of the routines that needs to communicate
Packit Service c5cf8c
 * with the process manager.  If we started as a singleton init, then
Packit Service c5cf8c
 * we first need to connect to the process manager and acquire the
Packit Service c5cf8c
 * needed information.
Packit Service c5cf8c
 */
Packit Service c5cf8c
int PMI_Get_universe_size(int *size)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int err;
Packit Service c5cf8c
    char size_c[PMIU_MAXLINE];
Packit Service c5cf8c
Packit Service c5cf8c
    /* Connect to the PM if we haven't already */
Packit Service c5cf8c
    if (PMIi_InitIfSingleton() != 0)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        err = GetResponse("cmd=get_universe_size\n", "universe_size", 0);
Packit Service c5cf8c
        if (err == PMI_SUCCESS) {
Packit Service c5cf8c
            PMIU_getval("size", size_c, PMIU_MAXLINE);
Packit Service c5cf8c
            *size = atoi(size_c);
Packit Service c5cf8c
            return PMI_SUCCESS;
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            return err;
Packit Service c5cf8c
    } else
Packit Service c5cf8c
        *size = 1;
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Get_appnum(int *appnum)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int err;
Packit Service c5cf8c
    char appnum_c[PMIU_MAXLINE];
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        err = GetResponse("cmd=get_appnum\n", "appnum", 0);
Packit Service c5cf8c
        if (err == PMI_SUCCESS) {
Packit Service c5cf8c
            PMIU_getval("appnum", appnum_c, PMIU_MAXLINE);
Packit Service c5cf8c
            *appnum = atoi(appnum_c);
Packit Service c5cf8c
            return PMI_SUCCESS;
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            return err;
Packit Service c5cf8c
Packit Service c5cf8c
    } else
Packit Service c5cf8c
        *appnum = -1;
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Barrier(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int err = PMI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        err = GetResponse("cmd=barrier_in\n", "barrier_out", 0);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Inform the process manager that we're in finalize */
Packit Service c5cf8c
int PMI_Finalize(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int err = PMI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        err = GetResponse("cmd=finalize\n", "finalize_ack", 0);
Packit Service c5cf8c
        shutdown(PMI_fd, SHUT_RDWR);
Packit Service c5cf8c
        close(PMI_fd);
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Abort(int exit_code, const char error_msg[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE];
Packit Service c5cf8c
Packit Service c5cf8c
    /* include exit_code in the abort command */
Packit Service c5cf8c
    MPL_snprintf(buf, PMIU_MAXLINE, "cmd=abort exitcode=%d\n", exit_code);
Packit Service c5cf8c
Packit Service c5cf8c
    PMIU_printf(PMI_debug, "aborting job:\n%s\n", error_msg);
Packit Service c5cf8c
    GetResponse(buf, "", 0);
Packit Service c5cf8c
Packit Service c5cf8c
    /* the above command should not return */
Packit Service c5cf8c
    return PMI_FAIL;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/************************************* Keymap functions **********************/
Packit Service c5cf8c
Packit Service c5cf8c
/*FIXME: need to return an error if the value of the kvs name returned is
Packit Service c5cf8c
  truncated because it is larger than length */
Packit Service c5cf8c
/* FIXME: My name should be cached rather than re-acquired, as it is
Packit Service c5cf8c
   unchanging (after singleton init) */
Packit Service c5cf8c
int PMI_KVS_Get_my_name(char kvsname[], int length)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int err;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        /* Return a dummy name */
Packit Service c5cf8c
        /* FIXME: We need to support a distinct kvsname for each
Packit Service c5cf8c
         * process group */
Packit Service c5cf8c
        MPL_snprintf(kvsname, length, "singinit_kvs_%d_0", (int) getpid());
Packit Service c5cf8c
        return PMI_SUCCESS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    err = GetResponse("cmd=get_my_kvsname\n", "my_kvsname", 0);
Packit Service c5cf8c
    if (err == PMI_SUCCESS) {
Packit Service c5cf8c
        PMIU_getval("kvsname", kvsname, length);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_KVS_Get_name_length_max(int *maxlen)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (maxlen == NULL)
Packit Service c5cf8c
        return PMI_ERR_INVALID_ARG;
Packit Service c5cf8c
    *maxlen = PMI_kvsname_max;
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_KVS_Get_key_length_max(int *maxlen)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (maxlen == NULL)
Packit Service c5cf8c
        return PMI_ERR_INVALID_ARG;
Packit Service c5cf8c
    *maxlen = PMI_keylen_max;
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_KVS_Get_value_length_max(int *maxlen)
Packit Service c5cf8c
{
Packit Service c5cf8c
    if (maxlen == NULL)
Packit Service c5cf8c
        return PMI_ERR_INVALID_ARG;
Packit Service c5cf8c
    *maxlen = PMI_vallen_max;
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_KVS_Put(const char kvsname[], const char key[], const char value[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE];
Packit Service c5cf8c
    int err = PMI_SUCCESS;
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
Packit Service c5cf8c
    /* This is a special hack to support singleton initialization */
Packit Service c5cf8c
    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        if (cached_singinit_inuse)
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        rc = MPL_strncpy(cached_singinit_key, key, PMI_keylen_max);
Packit Service c5cf8c
        if (rc != 0)
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        rc = MPL_strncpy(cached_singinit_val, value, PMI_vallen_max);
Packit Service c5cf8c
        if (rc != 0)
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        cached_singinit_inuse = 1;
Packit Service c5cf8c
        return PMI_SUCCESS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    rc = MPL_snprintf(buf, PMIU_MAXLINE,
Packit Service c5cf8c
                      "cmd=put kvsname=%s key=%s value=%s\n", kvsname, key, value);
Packit Service c5cf8c
    if (rc < 0)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    err = GetResponse(buf, "put_result", 1);
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_KVS_Commit(const char kvsname[]ATTRIBUTE((unused)))
Packit Service c5cf8c
{
Packit Service c5cf8c
    /* no-op in this implementation */
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*FIXME: need to return an error if the value returned is truncated
Packit Service c5cf8c
  because it is larger than length */
Packit Service c5cf8c
int PMI_KVS_Get(const char kvsname[], const char key[], char value[], int length)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE];
Packit Service c5cf8c
    int err = PMI_SUCCESS;
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Connect to the PM if we haven't already.  This is needed in case
Packit Service c5cf8c
     * we're doing an MPI_Comm_join or MPI_Comm_connect/accept from
Packit Service c5cf8c
     * the singleton init case.  This test is here because, in the way in
Packit Service c5cf8c
     * which MPICH uses PMI, this is where the test needs to be. */
Packit Service c5cf8c
    if (PMIi_InitIfSingleton() != 0)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
    rc = MPL_snprintf(buf, PMIU_MAXLINE, "cmd=get kvsname=%s key=%s\n", kvsname, key);
Packit Service c5cf8c
    if (rc < 0)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
    err = GetResponse(buf, "get_result", 0);
Packit Service c5cf8c
    if (err == PMI_SUCCESS) {
Packit Service c5cf8c
        PMIU_getval("rc", buf, PMIU_MAXLINE);
Packit Service c5cf8c
        rc = atoi(buf);
Packit Service c5cf8c
        if (rc == 0) {
Packit Service c5cf8c
            PMIU_getval("value", value, length);
Packit Service c5cf8c
            return PMI_SUCCESS;
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/*************************** Name Publishing functions **********************/
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Publish_name(const char service_name[], const char port[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
    int err;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        MPL_snprintf(cmd, PMIU_MAXLINE,
Packit Service c5cf8c
                     "cmd=publish_name service=%s port=%s\n", service_name, port);
Packit Service c5cf8c
        err = GetResponse(cmd, "publish_result", 0);
Packit Service c5cf8c
        if (err == PMI_SUCCESS) {
Packit Service c5cf8c
            PMIU_getval("rc", buf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (strcmp(buf, "0") != 0) {
Packit Service c5cf8c
                PMIU_getval("msg", buf, PMIU_MAXLINE);
Packit Service c5cf8c
                PMIU_printf(PMI_debug, "publish failed; reason = %s\n", buf);
Packit Service c5cf8c
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        PMIU_printf(1, "PMI_Publish_name called before init\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Unpublish_name(const char service_name[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
    int err = PMI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        MPL_snprintf(cmd, PMIU_MAXLINE, "cmd=unpublish_name service=%s\n", service_name);
Packit Service c5cf8c
        err = GetResponse(cmd, "unpublish_result", 0);
Packit Service c5cf8c
        if (err == PMI_SUCCESS) {
Packit Service c5cf8c
            PMIU_getval("rc", buf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (strcmp(buf, "0") != 0) {
Packit Service c5cf8c
                PMIU_getval("msg", buf, PMIU_MAXLINE);
Packit Service c5cf8c
                PMIU_printf(PMI_debug, "unpublish failed; reason = %s\n", buf);
Packit Service c5cf8c
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        PMIU_printf(1, "PMI_Unpublish_name called before init\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Lookup_name(const char service_name[], char port[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
    int err;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
Packit Service c5cf8c
        MPL_snprintf(cmd, PMIU_MAXLINE, "cmd=lookup_name service=%s\n", service_name);
Packit Service c5cf8c
        err = GetResponse(cmd, "lookup_result", 0);
Packit Service c5cf8c
        if (err == PMI_SUCCESS) {
Packit Service c5cf8c
            PMIU_getval("rc", buf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (strcmp(buf, "0") != 0) {
Packit Service c5cf8c
                PMIU_getval("msg", buf, PMIU_MAXLINE);
Packit Service c5cf8c
                PMIU_printf(PMI_debug, "lookup failed; reason = %s\n", buf);
Packit Service c5cf8c
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            PMIU_getval("port", port, MPI_MAX_PORT_NAME);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        PMIU_printf(1, "PMI_Lookup_name called before init\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
/************************** Process Creation functions **********************/
Packit Service c5cf8c
Packit Service c5cf8c
int PMI_Spawn_multiple(int count,
Packit Service c5cf8c
                       const char *cmds[],
Packit Service c5cf8c
                       const char **argvs[],
Packit Service c5cf8c
                       const int maxprocs[],
Packit Service c5cf8c
                       const int info_keyval_sizes[],
Packit Service c5cf8c
                       const PMI_keyval_t * info_keyval_vectors[],
Packit Service c5cf8c
                       int preput_keyval_size,
Packit Service c5cf8c
                       const PMI_keyval_t preput_keyval_vector[], int errors[])
Packit Service c5cf8c
{
Packit Service c5cf8c
    int i, rc, argcnt, spawncnt, total_num_processes, num_errcodes_found;
Packit Service c5cf8c
    char buf[PMIU_MAXLINE], tempbuf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
    char *lead, *lag;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Connect to the PM if we haven't already */
Packit Service c5cf8c
    if (PMIi_InitIfSingleton() != 0)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
    total_num_processes = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    for (spawncnt = 0; spawncnt < count; spawncnt++) {
Packit Service c5cf8c
        total_num_processes += maxprocs[spawncnt];
Packit Service c5cf8c
Packit Service c5cf8c
        rc = MPL_snprintf(buf, PMIU_MAXLINE,
Packit Service c5cf8c
                          "mcmd=spawn\nnprocs=%d\nexecname=%s\n",
Packit Service c5cf8c
                          maxprocs[spawncnt], cmds[spawncnt]);
Packit Service c5cf8c
        if (rc < 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        rc = MPL_snprintf(tempbuf, PMIU_MAXLINE,
Packit Service c5cf8c
                          "totspawns=%d\nspawnssofar=%d\n", count, spawncnt + 1);
Packit Service c5cf8c
Packit Service c5cf8c
        if (rc < 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        argcnt = 0;
Packit Service c5cf8c
        if ((argvs != NULL) && (argvs[spawncnt] != NULL)) {
Packit Service c5cf8c
            for (i = 0; argvs[spawncnt][i] != NULL; i++) {
Packit Service c5cf8c
                /* FIXME (protocol design flaw): command line arguments
Packit Service c5cf8c
                 * may contain both = and <space> (and even tab!).
Packit Service c5cf8c
                 */
Packit Service c5cf8c
                /* Note that part of this fixme was really a design error -
Packit Service c5cf8c
                 * because this uses the mcmd form, the data can be
Packit Service c5cf8c
                 * sent in multiple writelines.  This code now takes
Packit Service c5cf8c
                 * advantage of that.  Note also that a correct parser
Packit Service c5cf8c
                 * of the commands will permit any character other than a
Packit Service c5cf8c
                 * new line in the argument, since the form is
Packit Service c5cf8c
                 * argn=<any nonnewline><newline> */
Packit Service c5cf8c
                rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "arg%d=%s\n", i + 1, argvs[spawncnt][i]);
Packit Service c5cf8c
                if (rc < 0) {
Packit Service c5cf8c
                    return PMI_FAIL;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
                if (rc != 0) {
Packit Service c5cf8c
                    return PMI_FAIL;
Packit Service c5cf8c
                }
Packit Service c5cf8c
                argcnt++;
Packit Service c5cf8c
                rc = PMIU_writeline(PMI_fd, buf);
Packit Service c5cf8c
                if (rc)
Packit Service c5cf8c
                    return PMI_FAIL;
Packit Service c5cf8c
                buf[0] = 0;
Packit Service c5cf8c
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "argcnt=%d\n", argcnt);
Packit Service c5cf8c
        if (rc < 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "preput_num=%d\n", preput_keyval_size);
Packit Service c5cf8c
        if (rc < 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        for (i = 0; i < preput_keyval_size; i++) {
Packit Service c5cf8c
            rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "preput_key_%d=%s\n",
Packit Service c5cf8c
                              i, preput_keyval_vector[i].key);
Packit Service c5cf8c
            if (rc < 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (rc != 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "preput_val_%d=%s\n",
Packit Service c5cf8c
                              i, preput_keyval_vector[i].val);
Packit Service c5cf8c
            if (rc < 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (rc != 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
        rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "info_num=%d\n", info_keyval_sizes[spawncnt]);
Packit Service c5cf8c
        if (rc < 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        for (i = 0; i < info_keyval_sizes[spawncnt]; i++) {
Packit Service c5cf8c
            rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "info_key_%d=%s\n",
Packit Service c5cf8c
                              i, info_keyval_vectors[spawncnt][i].key);
Packit Service c5cf8c
            if (rc < 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (rc != 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            rc = MPL_snprintf(tempbuf, PMIU_MAXLINE, "info_val_%d=%s\n",
Packit Service c5cf8c
                              i, info_keyval_vectors[spawncnt][i].val);
Packit Service c5cf8c
            if (rc < 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
            rc = MPL_strnapp(buf, tempbuf, PMIU_MAXLINE);
Packit Service c5cf8c
            if (rc != 0) {
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        rc = MPL_strnapp(buf, "endcmd\n", PMIU_MAXLINE);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        rc = PMIU_writeline(PMI_fd, buf);
Packit Service c5cf8c
        if (rc) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    PMIU_readline(PMI_fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
    PMIU_parse_keyvals(buf);
Packit Service c5cf8c
    PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    if (strncmp(cmd, "spawn_result", PMIU_MAXLINE) != 0) {
Packit Service c5cf8c
        PMIU_printf(1, "got unexpected response to spawn :%s:\n", buf);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        PMIU_getval("rc", buf, PMIU_MAXLINE);
Packit Service c5cf8c
        rc = atoi(buf);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            /* PMIU_getval("status", tempbuf, PMIU_MAXLINE); */
Packit Service c5cf8c
            /* PMIU_printf(1, "pmi_spawn_mult failed; status: %s\n",tempbuf); */
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    PMIU_Assert(errors != NULL);
Packit Service c5cf8c
    if (PMIU_getval("errcodes", tempbuf, PMIU_MAXLINE)) {
Packit Service c5cf8c
        num_errcodes_found = 0;
Packit Service c5cf8c
        lag = &tempbuf[0];
Packit Service c5cf8c
        do {
Packit Service c5cf8c
            lead = strchr(lag, ',');
Packit Service c5cf8c
            if (lead)
Packit Service c5cf8c
                *lead = '\0';
Packit Service c5cf8c
            errors[num_errcodes_found++] = atoi(lag);
Packit Service c5cf8c
            lag = lead + 1;     /* move past the null char */
Packit Service c5cf8c
            PMIU_Assert(num_errcodes_found <= total_num_processes);
Packit Service c5cf8c
        } while (lead != NULL);
Packit Service c5cf8c
        PMIU_Assert(num_errcodes_found == total_num_processes);
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        /* gforker doesn't return errcodes, so we'll just pretend that means
Packit Service c5cf8c
         * that it was going to send all `0's. */
Packit Service c5cf8c
        for (i = 0; i < total_num_processes; ++i) {
Packit Service c5cf8c
            errors[i] = 0;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/***************** Internal routines not part of PMI interface ***************/
Packit Service c5cf8c
Packit Service c5cf8c
/* to get all maxes in one message */
Packit Service c5cf8c
/* FIXME: This mixes init with get maxes */
Packit Service c5cf8c
static int PMII_getmaxes(int *kvsname_max, int *keylen_max, int *vallen_max)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
    int err, rc;
Packit Service c5cf8c
Packit Service c5cf8c
    rc = MPL_snprintf(buf, PMIU_MAXLINE,
Packit Service c5cf8c
                      "cmd=init pmi_version=%d pmi_subversion=%d\n", PMI_VERSION, PMI_SUBVERSION);
Packit Service c5cf8c
    if (rc < 0) {
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    rc = PMIU_writeline(PMI_fd, buf);
Packit Service c5cf8c
    if (rc != 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Unable to write to PMI_fd\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    buf[0] = 0; /* Ensure buffer is empty if read fails */
Packit Service c5cf8c
    err = PMIU_readline(PMI_fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
    if (err < 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Error reading initack on %d\n", PMI_fd);
Packit Service c5cf8c
        perror("Error on readline:");
Packit Service c5cf8c
        PMI_Abort(-1, "Above error when reading after init");
Packit Service c5cf8c
    }
Packit Service c5cf8c
    PMIU_parse_keyvals(buf);
Packit Service c5cf8c
    cmd[0] = 0;
Packit Service c5cf8c
    PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
Packit Service c5cf8c
    if (strncmp(cmd, "response_to_init", PMIU_MAXLINE) != 0) {
Packit Service c5cf8c
        char errmsg[PMIU_MAXLINE * 2 + 100];
Packit Service c5cf8c
        MPL_snprintf(errmsg, sizeof(errmsg),
Packit Service c5cf8c
                     "got unexpected response to init :%s: (full line = %s)", cmd, buf);
Packit Service c5cf8c
        PMI_Abort(-1, errmsg);
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        char buf1[PMIU_MAXLINE];
Packit Service c5cf8c
        PMIU_getval("rc", buf, PMIU_MAXLINE);
Packit Service c5cf8c
        if (strncmp(buf, "0", PMIU_MAXLINE) != 0) {
Packit Service c5cf8c
            PMIU_getval("pmi_version", buf, PMIU_MAXLINE);
Packit Service c5cf8c
            PMIU_getval("pmi_subversion", buf1, PMIU_MAXLINE);
Packit Service c5cf8c
Packit Service c5cf8c
            char errmsg[PMIU_MAXLINE * 2 + 100];
Packit Service c5cf8c
            MPL_snprintf(errmsg, sizeof(errmsg),
Packit Service c5cf8c
                         "pmi_version mismatch; client=%d.%d mgr=%s.%s",
Packit Service c5cf8c
                         PMI_VERSION, PMI_SUBVERSION, buf, buf1);
Packit Service c5cf8c
            PMI_Abort(-1, errmsg);
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
    err = GetResponse("cmd=get_maxes\n", "maxes", 0);
Packit Service c5cf8c
    if (err == PMI_SUCCESS) {
Packit Service c5cf8c
        PMIU_getval("kvsname_max", buf, PMIU_MAXLINE);
Packit Service c5cf8c
        *kvsname_max = atoi(buf);
Packit Service c5cf8c
        PMIU_getval("keylen_max", buf, PMIU_MAXLINE);
Packit Service c5cf8c
        *keylen_max = atoi(buf);
Packit Service c5cf8c
        PMIU_getval("vallen_max", buf, PMIU_MAXLINE);
Packit Service c5cf8c
        *vallen_max = atoi(buf);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* ----------------------------------------------------------------------- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * This function is used to request information from the server and check
Packit Service c5cf8c
 * that the response uses the expected command name.  On a successful
Packit Service c5cf8c
 * return from this routine, additional PMIU_getval calls may be used
Packit Service c5cf8c
 * to access information about the returned value.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * If checkRc is true, this routine also checks that the rc value returned
Packit Service c5cf8c
 * was 0.  If not, it uses the "msg" value to report on the reason for
Packit Service c5cf8c
 * the failure.
Packit Service c5cf8c
 */
Packit Service c5cf8c
static int GetResponse(const char request[], const char expectedCmd[], int checkRc)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int err, n;
Packit Service c5cf8c
    char *p;
Packit Service c5cf8c
    char recvbuf[PMIU_MAXLINE];
Packit Service c5cf8c
    char cmdName[PMIU_MAXLINE];
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME: This is an example of an incorrect fix - writeline can change
Packit Service c5cf8c
     * the second argument in some cases, and that will break the const'ness
Packit Service c5cf8c
     * of request.  Instead, writeline should take a const item and return
Packit Service c5cf8c
     * an error in the case in which it currently truncates the data. */
Packit Service c5cf8c
    err = PMIU_writeline(PMI_fd, (char *) request);
Packit Service c5cf8c
    if (err) {
Packit Service c5cf8c
        return err;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    n = PMIU_readline(PMI_fd, recvbuf, sizeof(recvbuf));
Packit Service c5cf8c
    if (n <= 0) {
Packit Service c5cf8c
        PMIU_printf(1, "readline failed\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    err = PMIU_parse_keyvals(recvbuf);
Packit Service c5cf8c
    if (err) {
Packit Service c5cf8c
        PMIU_printf(1, "parse_kevals failed %d\n", err);
Packit Service c5cf8c
        return err;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    p = PMIU_getval("cmd", cmdName, sizeof(cmdName));
Packit Service c5cf8c
    if (!p) {
Packit Service c5cf8c
        PMIU_printf(1, "getval cmd failed\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (strcmp(expectedCmd, cmdName) != 0) {
Packit Service c5cf8c
        PMIU_printf(1, "expecting cmd=%s, got %s\n", expectedCmd, cmdName);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    if (checkRc) {
Packit Service c5cf8c
        p = PMIU_getval("rc", cmdName, PMIU_MAXLINE);
Packit Service c5cf8c
        if (p && strcmp(cmdName, "0") != 0) {
Packit Service c5cf8c
            PMIU_getval("msg", cmdName, PMIU_MAXLINE);
Packit Service c5cf8c
            PMIU_printf(1, "Command %s failed, reason='%s'\n", request, cmdName);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return err;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* ----------------------------------------------------------------------- */
Packit Service c5cf8c
Packit Service c5cf8c
Packit Service c5cf8c
#ifdef USE_PMI_PORT
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * This code allows a program to contact a host/port for the PMI socket.
Packit Service c5cf8c
 */
Packit Service c5cf8c
#include <errno.h>
Packit Service c5cf8c
#if defined(HAVE_SYS_TYPES_H)
Packit Service c5cf8c
#include <sys/types.h>
Packit Service c5cf8c
#endif
Packit Service c5cf8c
#include <sys/param.h>
Packit Service c5cf8c
#include <sys/socket.h>
Packit Service c5cf8c
Packit Service c5cf8c
/* sockaddr_in (Internet) */
Packit Service c5cf8c
#include <netinet/in.h>
Packit Service c5cf8c
/* TCP_NODELAY */
Packit Service c5cf8c
#include <netinet/tcp.h>
Packit Service c5cf8c
Packit Service c5cf8c
/* sockaddr_un (Unix) */
Packit Service c5cf8c
#include <sys/un.h>
Packit Service c5cf8c
Packit Service c5cf8c
/* defs of gethostbyname */
Packit Service c5cf8c
#include <netdb.h>
Packit Service c5cf8c
Packit Service c5cf8c
/* fcntl, F_GET/SETFL */
Packit Service c5cf8c
#include <fcntl.h>
Packit Service c5cf8c
Packit Service c5cf8c
/* This is really IP!? */
Packit Service c5cf8c
#ifndef TCP
Packit Service c5cf8c
#define TCP 0
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
/* stub for connecting to a specified host/port instead of using a
Packit Service c5cf8c
   specified fd inherited from a parent process */
Packit Service c5cf8c
static int PMII_Connect_to_pm(char *hostname, int portnum)
Packit Service c5cf8c
{
Packit Service c5cf8c
    MPL_sockaddr_t addr;
Packit Service c5cf8c
    int ret;
Packit Service c5cf8c
    int fd;
Packit Service c5cf8c
    int optval = 1;
Packit Service c5cf8c
    int q_wait = 1;
Packit Service c5cf8c
Packit Service c5cf8c
    ret = MPL_get_sockaddr(hostname, &addr);
Packit Service a56745
    if (ret) {
Packit Service c5cf8c
        PMIU_printf(1, "Unable to get host entry for %s\n", hostname);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    fd = MPL_socket();
Packit Service c5cf8c
    if (fd < 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Unable to get AF_INET socket\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *) &optval, sizeof(optval))) {
Packit Service c5cf8c
        perror("Error calling setsockopt:");
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* We wait here for the connection to succeed */
Packit Service c5cf8c
    ret = MPL_connect(fd, &addr, portnum);
Packit Service c5cf8c
    if (ret < 0) {
Packit Service c5cf8c
        switch (errno) {
Packit Service c5cf8c
            case ECONNREFUSED:
Packit Service c5cf8c
                PMIU_printf(1, "connect failed with connection refused\n");
Packit Service c5cf8c
                /* (close socket, get new socket, try again) */
Packit Service c5cf8c
                if (q_wait)
Packit Service c5cf8c
                    close(fd);
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
            case EINPROGRESS:  /*  (nonblocking) - select for writing. */
Packit Service c5cf8c
                break;
Packit Service c5cf8c
Packit Service c5cf8c
            case EISCONN:      /*  (already connected) */
Packit Service c5cf8c
                break;
Packit Service c5cf8c
Packit Service c5cf8c
            case ETIMEDOUT:    /* timed out */
Packit Service c5cf8c
                PMIU_printf(1, "connect failed with timeout\n");
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
Packit Service c5cf8c
            default:
Packit Service c5cf8c
                PMIU_printf(1, "connect failed with errno %d\n", errno);
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return fd;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static int PMII_Set_from_port(int fd, int id)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
    int err, rc;
Packit Service c5cf8c
Packit Service c5cf8c
    /* We start by sending a startup message to the server */
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_debug) {
Packit Service c5cf8c
        PMIU_printf(1, "Writing initack to destination fd %d\n", fd);
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* Handshake and initialize from a port */
Packit Service c5cf8c
Packit Service c5cf8c
    rc = MPL_snprintf(buf, PMIU_MAXLINE, "cmd=initack pmiid=%d\n", id);
Packit Service c5cf8c
    if (rc < 0) {
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    PMIU_printf(PMI_debug, "writing on fd %d line :%s:\n", fd, buf);
Packit Service c5cf8c
    err = PMIU_writeline(fd, buf);
Packit Service c5cf8c
    if (err) {
Packit Service c5cf8c
        PMIU_printf(1, "Error in writeline initack\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* cmd=initack */
Packit Service c5cf8c
    buf[0] = 0;
Packit Service c5cf8c
    PMIU_printf(PMI_debug, "reading initack\n");
Packit Service c5cf8c
    err = PMIU_readline(fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
    if (err < 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Error reading initack on %d\n", fd);
Packit Service c5cf8c
        perror("Error on readline:");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    PMIU_parse_keyvals(buf);
Packit Service c5cf8c
    PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    if (strcmp(cmd, "initack")) {
Packit Service c5cf8c
        PMIU_printf(1, "got unexpected input %s\n", buf);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    /* Read, in order, size, rank, and debug.  Eventually, we'll want
Packit Service c5cf8c
     * the handshake to include a version number */
Packit Service c5cf8c
Packit Service c5cf8c
    /* size */
Packit Service c5cf8c
    PMIU_printf(PMI_debug, "reading size\n");
Packit Service c5cf8c
    err = PMIU_readline(fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
    if (err < 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Error reading size on %d\n", fd);
Packit Service c5cf8c
        perror("Error on readline:");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    PMIU_parse_keyvals(buf);
Packit Service c5cf8c
    PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    if (strcmp(cmd, "set")) {
Packit Service c5cf8c
        PMIU_printf(1, "got unexpected command %s in %s\n", cmd, buf);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* cmd=set size=n */
Packit Service c5cf8c
    PMIU_getval("size", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    PMI_size = atoi(cmd);
Packit Service c5cf8c
Packit Service c5cf8c
    /* rank */
Packit Service c5cf8c
    PMIU_printf(PMI_debug, "reading rank\n");
Packit Service c5cf8c
    err = PMIU_readline(fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
    if (err < 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Error reading rank on %d\n", fd);
Packit Service c5cf8c
        perror("Error on readline:");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    PMIU_parse_keyvals(buf);
Packit Service c5cf8c
    PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    if (strcmp(cmd, "set")) {
Packit Service c5cf8c
        PMIU_printf(1, "got unexpected command %s in %s\n", cmd, buf);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* cmd=set rank=n */
Packit Service c5cf8c
    PMIU_getval("rank", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    PMI_rank = atoi(cmd);
Packit Service c5cf8c
    PMIU_Set_rank(PMI_rank);
Packit Service c5cf8c
Packit Service c5cf8c
    /* debug flag */
Packit Service c5cf8c
    err = PMIU_readline(fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
    if (err < 0) {
Packit Service c5cf8c
        PMIU_printf(1, "Error reading debug on %d\n", fd);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    PMIU_parse_keyvals(buf);
Packit Service c5cf8c
    PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    if (strcmp(cmd, "set")) {
Packit Service c5cf8c
        PMIU_printf(1, "got unexpected command %s in %s\n", cmd, buf);
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    /* cmd=set debug=n */
Packit Service c5cf8c
    PMIU_getval("debug", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
    PMI_debug = atoi(cmd);
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_debug) {
Packit Service c5cf8c
        DBG_PRINTF(("end of handshake, rank = %d, size = %d\n", PMI_rank, PMI_size));
Packit Service c5cf8c
        DBG_PRINTF(("Completed init\n"));
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
/*
Packit Service c5cf8c
 * Singleton Init.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * MPI-2 allows processes to become MPI processes and then make MPI calls,
Packit Service c5cf8c
 * such as MPI_Comm_spawn, that require a process manager (this is different
Packit Service c5cf8c
 * than the much simpler case of allowing MPI programs to run with an
Packit Service c5cf8c
 * MPI_COMM_WORLD of size 1 without an mpiexec or process manager).
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * The process starts when either the client or the process manager contacts
Packit Service c5cf8c
 * the other.  If the client starts, it sends a singinit command and
Packit Service c5cf8c
 * waits for the server to respond with its own singinit command.
Packit Service c5cf8c
 * If the server start, it send a singinit command and waits for the
Packit Service c5cf8c
 * client to respond with its own singinit command
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * client sends singinit with these required values
Packit Service c5cf8c
 *   pmi_version=<value of PMI_VERSION>
Packit Service c5cf8c
 *   pmi_subversion=<value of PMI_SUBVERSION>
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * and these optional values
Packit Service c5cf8c
 *   stdio=[yes|no]
Packit Service c5cf8c
 *   authtype=[none|shared|<other-to-be-defined>]
Packit Service c5cf8c
 *   authstring=<string>
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * server sends singinit with the same required and optional values as
Packit Service c5cf8c
 * above.
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * At this point, the protocol is now the same in both cases, and has the
Packit Service c5cf8c
 * following components:
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * server sends singinit_info with these required fields
Packit Service c5cf8c
 *   versionok=[yes|no]
Packit Service c5cf8c
 *   stdio=[yes|no]
Packit Service c5cf8c
 *   kvsname=<string>
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * The client then issues the init command (see PMII_getmaxes)
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * cmd=init pmi_version=<val> pmi_subversion=<val>
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * and expects to receive a
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * cmd=response_to_init rc=0 pmi_version=<val> pmi_subversion=<val>
Packit Service c5cf8c
 *
Packit Service c5cf8c
 * (This is the usual init sequence).
Packit Service c5cf8c
 *
Packit Service c5cf8c
 */
Packit Service c5cf8c
/* ------------------------------------------------------------------------- */
Packit Service c5cf8c
/* This is a special routine used to re-initialize PMI when it is in
Packit Service c5cf8c
   the singleton init case.  That is, the executable was started without
Packit Service c5cf8c
   mpiexec, and PMI_Init returned as if there was only one process.
Packit Service c5cf8c
Packit Service c5cf8c
   Note that PMI routines should not call PMII_singinit; they should
Packit Service c5cf8c
   call PMIi_InitIfSingleton(), which both connects to the process mangager
Packit Service c5cf8c
   and sets up the initial KVS connection entry.
Packit Service c5cf8c
*/
Packit Service c5cf8c
Packit Service c5cf8c
static int PMII_singinit(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int pid, rc;
Packit Service c5cf8c
    int singinit_listen_sock, stdin_sock, stdout_sock, stderr_sock;
Packit Service c5cf8c
    const char *newargv[8];
Packit Service c5cf8c
    char charpid[8], port_c[8];
Packit Service c5cf8c
    unsigned short port;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Create a socket on which to allow an mpiexec to connect back to
Packit Service c5cf8c
     * us */
Packit Service c5cf8c
    singinit_listen_sock = MPL_socket();
Packit Service c5cf8c
    if (singinit_listen_sock == -1) {
Packit Service c5cf8c
        perror("PMII_singinit: socket creation failed");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
Packit Service c5cf8c
    MPL_LISTEN_PUSH(0, 5);
Packit Service c5cf8c
    rc = MPL_listen_anyport(singinit_listen_sock, &port);
Packit Service c5cf8c
    MPL_LISTEN_POP;
Packit Service c5cf8c
    if (rc) {
Packit Service c5cf8c
        perror("PMII_singinit: listen failed");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    MPL_snprintf(port_c, sizeof(port_c), "%d", port);
Packit Service c5cf8c
Packit Service c5cf8c
    PMIU_printf(PMI_debug_init, "Starting mpiexec with %s\n", port_c);
Packit Service c5cf8c
Packit Service c5cf8c
    /* Launch the mpiexec process with the name of this port */
Packit Service c5cf8c
    pid = fork();
Packit Service c5cf8c
    if (pid < 0) {
Packit Service c5cf8c
        perror("PMII_singinit: fork failed");
Packit Service c5cf8c
        exit(-1);
Packit Service c5cf8c
    } else if (pid == 0) {
Packit Service c5cf8c
        newargv[0] = "mpiexec";
Packit Service c5cf8c
        newargv[1] = "-pmi_args";
Packit Service c5cf8c
        newargv[2] = port_c;
Packit Service c5cf8c
        /* FIXME: Use a valid hostname */
Packit Service c5cf8c
        newargv[3] = "default_interface";       /* default interface name, for now */
Packit Service c5cf8c
        newargv[4] = "default_key";     /* default authentication key, for now */
Packit Service c5cf8c
        MPL_snprintf(charpid, sizeof(charpid), "%d", getpid());
Packit Service c5cf8c
        newargv[5] = charpid;
Packit Service c5cf8c
        newargv[6] = NULL;
Packit Service c5cf8c
        rc = execvp(newargv[0], (char **) newargv);
Packit Service c5cf8c
        perror("PMII_singinit: execv failed");
Packit Service c5cf8c
        PMIU_printf(1, "  This singleton init program attempted to access some feature\n");
Packit Service c5cf8c
        PMIU_printf(1,
Packit Service c5cf8c
                    "  for which process manager support was required, e.g. spawn or universe_size.\n");
Packit Service c5cf8c
        PMIU_printf(1, "  But the necessary mpiexec is not in your path.\n");
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    } else {
Packit Service c5cf8c
        char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
Packit Service c5cf8c
        char *p;
Packit Service c5cf8c
        int connectStdio = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Allow one connection back from the created mpiexec program */
Packit Service c5cf8c
        PMI_fd = accept_one_connection(singinit_listen_sock);
Packit Service c5cf8c
        if (PMI_fd < 0) {
Packit Service c5cf8c
            PMIU_printf(1, "Failed to establish singleton init connection\n");
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* Execute the singleton init protocol */
Packit Service c5cf8c
        rc = PMIU_readline(PMI_fd, buf, PMIU_MAXLINE);
Packit Service c5cf8c
        PMIU_printf(PMI_debug_init, "Singinit: read %s\n", buf);
Packit Service c5cf8c
Packit Service c5cf8c
        PMIU_parse_keyvals(buf);
Packit Service c5cf8c
        PMIU_getval("cmd", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
        if (strcmp(cmd, "singinit") != 0) {
Packit Service c5cf8c
            PMIU_printf(1, "unexpected command from PM: %s\n", cmd);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        p = PMIU_getval("authtype", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
        if (p && strcmp(cmd, "none") != 0) {
Packit Service c5cf8c
            PMIU_printf(1, "unsupported authentication method %s\n", cmd);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        /* p = PMIU_getval("authstring", cmd, PMIU_MAXLINE); */
Packit Service c5cf8c
Packit Service c5cf8c
        /* If we're successful, send back our own singinit */
Packit Service c5cf8c
        rc = MPL_snprintf(buf, PMIU_MAXLINE,
Packit Service c5cf8c
                          "cmd=singinit pmi_version=%d pmi_subversion=%d stdio=yes authtype=none\n",
Packit Service c5cf8c
                          PMI_VERSION, PMI_SUBVERSION);
Packit Service c5cf8c
        if (rc < 0) {
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        PMIU_printf(PMI_debug_init, "GetResponse with %s\n", buf);
Packit Service c5cf8c
Packit Service c5cf8c
        rc = GetResponse(buf, "singinit_info", 0);
Packit Service c5cf8c
        if (rc != 0) {
Packit Service c5cf8c
            PMIU_printf(1, "GetResponse failed\n");
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        p = PMIU_getval("versionok", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
        if (p && strcmp(cmd, "yes") != 0) {
Packit Service c5cf8c
            PMIU_printf(1, "Process manager needs a different PMI version\n");
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        p = PMIU_getval("stdio", cmd, PMIU_MAXLINE);
Packit Service c5cf8c
        if (p && strcmp(cmd, "yes") == 0) {
Packit Service c5cf8c
            PMIU_printf(PMI_debug_init, "PM agreed to connect stdio\n");
Packit Service c5cf8c
            connectStdio = 1;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        p = PMIU_getval("kvsname", singinit_kvsname, sizeof(singinit_kvsname));
Packit Service c5cf8c
        PMIU_printf(PMI_debug_init, "kvsname to use is %s\n", singinit_kvsname);
Packit Service c5cf8c
Packit Service c5cf8c
        if (connectStdio) {
Packit Service c5cf8c
            PMIU_printf(PMI_debug_init, "Accepting three connections for stdin, out, err\n");
Packit Service c5cf8c
            stdin_sock = accept_one_connection(singinit_listen_sock);
Packit Service c5cf8c
            dup2(stdin_sock, 0);
Packit Service c5cf8c
            stdout_sock = accept_one_connection(singinit_listen_sock);
Packit Service c5cf8c
            dup2(stdout_sock, 1);
Packit Service c5cf8c
            stderr_sock = accept_one_connection(singinit_listen_sock);
Packit Service c5cf8c
            dup2(stderr_sock, 2);
Packit Service c5cf8c
        }
Packit Service c5cf8c
        PMIU_printf(PMI_debug_init, "Done with singinit handshake\n");
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
/* Promote PMI to a fully initialized version if it was started as
Packit Service c5cf8c
   a singleton init */
Packit Service c5cf8c
static int PMIi_InitIfSingleton(void)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int rc;
Packit Service c5cf8c
    static int firstcall = 1;
Packit Service c5cf8c
Packit Service c5cf8c
    if (PMI_initialized != SINGLETON_INIT_BUT_NO_PM || !firstcall)
Packit Service c5cf8c
        return PMI_SUCCESS;
Packit Service c5cf8c
Packit Service c5cf8c
    /* We only try to init as a singleton the first time */
Packit Service c5cf8c
    firstcall = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    /* First, start (if necessary) an mpiexec, connect to it,
Packit Service c5cf8c
     * and start the singleton init handshake */
Packit Service c5cf8c
    rc = PMII_singinit();
Packit Service c5cf8c
Packit Service c5cf8c
    if (rc < 0)
Packit Service c5cf8c
        return PMI_FAIL;
Packit Service c5cf8c
    PMI_initialized = SINGLETON_INIT_WITH_PM;   /* do this right away */
Packit Service c5cf8c
    PMI_size = 1;
Packit Service c5cf8c
    PMI_rank = 0;
Packit Service c5cf8c
    PMI_debug = 0;
Packit Service c5cf8c
    PMI_spawned = 0;
Packit Service c5cf8c
Packit Service c5cf8c
    PMII_getmaxes(&PMI_kvsname_max, &PMI_keylen_max, &PMI_vallen_max);
Packit Service c5cf8c
Packit Service c5cf8c
    /* FIXME: We need to support a distinct kvsname for each
Packit Service c5cf8c
     * process group */
Packit Service c5cf8c
    PMI_KVS_Put(singinit_kvsname, cached_singinit_key, cached_singinit_val);
Packit Service c5cf8c
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
static int accept_one_connection(int list_sock)
Packit Service c5cf8c
{
Packit Service c5cf8c
    int gotit, new_sock;
Packit Service c5cf8c
    MPL_sockaddr_t addr;
Packit Service c5cf8c
    socklen_t len;
Packit Service c5cf8c
Packit Service c5cf8c
    len = sizeof(addr);
Packit Service c5cf8c
    gotit = 0;
Packit Service c5cf8c
    while (!gotit) {
Packit Service c5cf8c
        new_sock = accept(list_sock, (struct sockaddr *) &addr, &len;;
Packit Service c5cf8c
        if (new_sock == -1) {
Packit Service c5cf8c
            if (errno == EINTR) /* interrupted? If so, try again */
Packit Service c5cf8c
                continue;
Packit Service c5cf8c
            else {
Packit Service c5cf8c
                PMIU_printf(1, "accept failed in accept_one_connection\n");
Packit Service c5cf8c
                exit(-1);
Packit Service c5cf8c
            }
Packit Service c5cf8c
        } else
Packit Service c5cf8c
            gotit = 1;
Packit Service c5cf8c
    }
Packit Service c5cf8c
    return (new_sock);
Packit Service c5cf8c
}
Packit Service c5cf8c
Packit Service c5cf8c
#endif
Packit Service c5cf8c
/* end USE_PMI_PORT */
Packit Service c5cf8c
Packit Service c5cf8c
/* Get the FD to use for PMI operations.  If a port is used, rather than
Packit Service c5cf8c
   a pre-established FD (i.e., via pipe), this routine will handle the
Packit Service c5cf8c
   initial handshake.
Packit Service c5cf8c
*/
Packit Service c5cf8c
static int getPMIFD(int *notset)
Packit Service c5cf8c
{
Packit Service c5cf8c
    char *p;
Packit Service c5cf8c
Packit Service c5cf8c
    /* Set the default */
Packit Service c5cf8c
    PMI_fd = -1;
Packit Service c5cf8c
Packit Service c5cf8c
    p = getenv("PMI_FD");
Packit Service c5cf8c
Packit Service c5cf8c
    if (p) {
Packit Service c5cf8c
        PMI_fd = atoi(p);
Packit Service c5cf8c
        return PMI_SUCCESS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
#ifdef USE_PMI_PORT
Packit Service c5cf8c
    p = getenv("PMI_PORT");
Packit Service c5cf8c
    if (p) {
Packit Service c5cf8c
        int portnum;
Packit Service c5cf8c
        char hostname[MAXHOSTNAME + 1];
Packit Service c5cf8c
        char *pn, *ph;
Packit Service c5cf8c
        int id = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        /* Connect to the indicated port (in format hostname:portnumber)
Packit Service c5cf8c
         * and get the fd for the socket */
Packit Service c5cf8c
Packit Service c5cf8c
        /* Split p into host and port */
Packit Service c5cf8c
        pn = p;
Packit Service c5cf8c
        ph = hostname;
Packit Service c5cf8c
        while (*pn && *pn != ':' && (ph - hostname) < MAXHOSTNAME) {
Packit Service c5cf8c
            *ph++ = *pn++;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        *ph = 0;
Packit Service c5cf8c
Packit Service c5cf8c
        if (PMI_debug) {
Packit Service c5cf8c
            DBG_PRINTF(("Connecting to %s\n", p));
Packit Service c5cf8c
        }
Packit Service c5cf8c
        if (*pn == ':') {
Packit Service c5cf8c
            portnum = atoi(pn + 1);
Packit Service c5cf8c
            /* FIXME: Check for valid integer after : */
Packit Service c5cf8c
            /* This routine only gets the fd to use to talk to
Packit Service c5cf8c
             * the process manager. The handshake below is used
Packit Service c5cf8c
             * to setup the initial values */
Packit Service c5cf8c
            PMI_fd = PMII_Connect_to_pm(hostname, portnum);
Packit Service c5cf8c
            if (PMI_fd < 0) {
Packit Service c5cf8c
                PMIU_printf(1, "Unable to connect to %s on %d\n", hostname, portnum);
Packit Service c5cf8c
                return PMI_FAIL;
Packit Service c5cf8c
            }
Packit Service c5cf8c
        } else {
Packit Service c5cf8c
            PMIU_printf(1, "unable to decode hostport from %s\n", p);
Packit Service c5cf8c
            return PMI_FAIL;
Packit Service c5cf8c
        }
Packit Service c5cf8c
Packit Service c5cf8c
        /* We should first handshake to get size, rank, debug. */
Packit Service c5cf8c
        p = getenv("PMI_ID");
Packit Service c5cf8c
        if (p) {
Packit Service c5cf8c
            id = atoi(p);
Packit Service c5cf8c
            /* PMII_Set_from_port sets up the values that are delivered
Packit Service c5cf8c
             * by enviroment variables when a separate port is not used */
Packit Service c5cf8c
            PMII_Set_from_port(PMI_fd, id);
Packit Service c5cf8c
            *notset = 0;
Packit Service c5cf8c
        }
Packit Service c5cf8c
        return PMI_SUCCESS;
Packit Service c5cf8c
    }
Packit Service c5cf8c
#endif
Packit Service c5cf8c
Packit Service c5cf8c
    /* Singleton init case - its ok to return success with no fd set */
Packit Service c5cf8c
    return PMI_SUCCESS;
Packit Service c5cf8c
}