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