root/mpich2/trunk/src/pmi/simple/simple_pmi.c @ 4888

Revision 4888, 42.8 KB (checked in by buntinas, 5 months ago)

squashed more warnings

Line 
1/* -*- Mode: C; c-basic-offset:4 ; -*- */
2/* 
3 *  (C) 2001 by Argonne National Laboratory.
4 *      See COPYRIGHT in top-level directory.
5 */
6
7/*********************** PMI implementation ********************************/
8/*
9 * This file implements the client-side of the PMI interface.
10 *
11 * Note that the PMI client code must not print error messages (except
12 * when an abort is required) because MPI error handling is based on
13 * reporting error codes to which messages are attached. 
14 *
15 * In v2, we should require a PMI client interface to use MPI error codes
16 * to provide better integration with MPICH2. 
17 */
18/***************************************************************************/
19
20#include "pmiconf.h"
21
22#define PMI_VERSION    1
23#define PMI_SUBVERSION 1
24
25#include <stdio.h>
26#ifdef HAVE_UNISTD_H
27#include <unistd.h>
28#endif
29#ifdef HAVE_STDLIB_H
30#include <stdlib.h>
31#endif
32#ifdef HAVE_STRING_H
33#include <string.h>
34#endif
35#ifdef HAVE_STRINGS_H
36#include <strings.h>
37#endif
38#ifdef USE_PMI_PORT
39#ifndef MAXHOSTNAME
40#define MAXHOSTNAME 256
41#endif
42#endif
43/* This should be moved to pmiu for shutdown */
44#if defined(HAVE_SYS_SOCKET_H)
45#include <sys/socket.h>
46#endif
47
48#include "mpibase.h"            /* Get ATTRIBUTE, some base functions */
49/* mpimem includes the definitions for MPIU_Snprintf, MPIU_Malloc, and
50   MPIU_Free */
51#include "mpimem.h"
52
53/* Temporary debug definitions */
54#if 0
55#define DBG_PRINTF(args) printf args ; fflush(stdout)
56#else
57#define DBG_PRINTF(args)
58#endif
59
60#include "pmi.h"
61#include "simple_pmiutil.h"
62#include "mpi.h"                /* to get MPI_MAX_PORT_NAME */
63
64/*
65   These are global variable used *ONLY* in this file, and are hence
66   declared static.
67 */
68
69
70static int PMI_fd = -1;
71static int PMI_size = 1;
72static int PMI_rank = 0;
73
74/* Set PMI_initialized to 1 for singleton init but no process manager
75   to help.  Initialized to 2 for normal initialization.  Initialized
76   to values higher than 2 when singleton_init by a process manager.
77   All values higher than 1 invlove a PM in some way.
78*/
79typedef enum { PMI_UNINITIALIZED = 0, 
80               SINGLETON_INIT_BUT_NO_PM = 1,
81               NORMAL_INIT_WITH_PM,
82               SINGLETON_INIT_WITH_PM } PMIState;
83static PMIState PMI_initialized = PMI_UNINITIALIZED;
84
85/* ALL GLOBAL VARIABLES MUST BE INITIALIZED TO AVOID POLLUTING THE
86   LIBRARY WITH COMMON SYMBOLS */
87static int PMI_kvsname_max = 0;
88static int PMI_keylen_max = 0;
89static int PMI_vallen_max = 0;
90
91static int PMI_iter_next_idx = 0;
92static int PMI_debug = 0;
93static int PMI_debug_init = 0;    /* Set this to true to debug the init
94                                     handshakes */
95static int PMI_spawned = 0;
96
97/* Function prototypes for internal routines */
98static int PMII_getmaxes( int *kvsname_max, int *keylen_max, int *vallen_max );
99static int PMII_iter( const char *kvsname, const int idx, int *nextidx, 
100                      char *key, int key_len, char *val, int val_len );
101static int PMII_Set_from_port( int, int );
102static int PMII_Connect_to_pm( char *, int );
103
104static int GetResponse( const char [], const char [], int );
105static int getPMIFD( int * );
106
107#ifdef USE_PMI_PORT
108static int PMII_singinit(void);
109static int PMI_totalview = 0;
110#endif
111static int PMIi_InitIfSingleton(void);
112static int accept_one_connection(int);
113static char cached_singinit_key[PMIU_MAXLINE];
114static char cached_singinit_val[PMIU_MAXLINE];
115static char singinit_kvsname[256];
116
117/******************************** Group functions *************************/
118
119int PMI_Init( int *spawned )
120{
121    char *p;
122    int notset = 1;
123    int rc;
124
125    /* FIXME: Why is setvbuf commented out? */
126    /* FIXME: What if the output should be fully buffered (directed to file)?
127       unbuffered (user explicitly set?) */
128    /* setvbuf(stdout,0,_IONBF,0); */
129    setbuf(stdout,NULL);
130    /* PMIU_printf( 1, "PMI_INIT\n" ); */
131
132    /* Get the value of PMI_DEBUG from the environment if possible, since
133       we may have set it to help debug the setup process */
134    p = getenv( "PMI_DEBUG" );
135    if (p) PMI_debug = atoi( p );
136
137    /* Get the fd for PMI commands; if none, we're a singleton */
138    rc = getPMIFD(&notset);
139    if (rc) {
140        return rc;
141    }
142
143    if ( PMI_fd == -1 ) {
144        /* Singleton init: Process not started with mpiexec,
145           so set size to 1, rank to 0 */
146        PMI_size = 1;
147        PMI_rank = 0;
148        *spawned = 0;
149       
150        PMI_initialized = SINGLETON_INIT_BUT_NO_PM;
151        /* 256 is picked as the minimum allowed length by the PMI servers */
152        PMI_kvsname_max = 256;
153        PMI_keylen_max  = 256;
154        PMI_vallen_max  = 256;
155       
156        return( 0 );
157    }
158
159    /* If size, rank, and debug are not set from a communication port,
160       use the environment */
161    if (notset) {
162        if ( ( p = getenv( "PMI_SIZE" ) ) )
163            PMI_size = atoi( p );
164        else 
165            PMI_size = 1;
166       
167        if ( ( p = getenv( "PMI_RANK" ) ) ) {
168            PMI_rank = atoi( p );
169            /* Let the util routine know the rank of this process for
170               any messages (usually debugging or error) */
171            PMIU_Set_rank( PMI_rank );
172        }
173        else 
174            PMI_rank = 0;
175       
176        if ( ( p = getenv( "PMI_DEBUG" ) ) )
177            PMI_debug = atoi( p );
178        else 
179            PMI_debug = 0;
180
181        /* Leave unchanged otherwise, which indicates that no value
182           was set */
183    }
184
185/* FIXME: Why does this depend on their being a port??? */
186/* FIXME: What is this for? */
187#ifdef USE_PMI_PORT
188    if ( ( p = getenv( "PMI_TOTALVIEW" ) ) )
189        PMI_totalview = atoi( p );
190    if ( PMI_totalview ) {
191        char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
192        /* FIXME: This should use a cmd/response rather than a expecting the
193           server to set a value in this and only this case */
194        /* FIXME: And it most ceratainly should not happen *before* the
195           initialization handshake */
196        PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
197        PMIU_parse_keyvals( buf );
198        PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
199        if ( strncmp( cmd, "tv_ready", PMIU_MAXLINE ) != 0 ) {
200            PMIU_printf( 1, "expecting cmd=tv_ready, got %s\n", buf );
201            return( PMI_FAIL );
202        }
203    }
204#endif
205
206    PMII_getmaxes( &PMI_kvsname_max, &PMI_keylen_max, &PMI_vallen_max );
207
208    /* FIXME: This is something that the PM should tell the process,
209       rather than deliver it through the environment */
210    if ( ( p = getenv( "PMI_SPAWNED" ) ) )
211        PMI_spawned = atoi( p );
212    else
213        PMI_spawned = 0;
214    if (PMI_spawned)
215        *spawned = 1;
216    else
217        *spawned = 0;
218
219    if ( ! PMI_initialized )
220        PMI_initialized = NORMAL_INIT_WITH_PM;
221
222    return( 0 );
223}
224
225int PMI_Initialized( PMI_BOOL *initialized )
226{
227    /* Turn this into a logical value (1 or 0) .  This allows us
228       to use PMI_initialized to distinguish between initialized with
229       an PMI service (e.g., via mpiexec) and the singleton init,
230       which has no PMI service */
231    *initialized = PMI_initialized != 0 ? PMI_TRUE : PMI_FALSE;
232    return PMI_SUCCESS;
233}
234
235int PMI_Get_size( int *size )
236{
237    if ( PMI_initialized )
238        *size = PMI_size;
239    else
240        *size = 1;
241    return( 0 );
242}
243
244int PMI_Get_rank( int *rank )
245{
246    if ( PMI_initialized )
247        *rank = PMI_rank;
248    else
249        *rank = 0;
250    return( 0 );
251}
252
253/*
254 * Get_universe_size is one of the routines that needs to communicate
255 * with the process manager.  If we started as a singleton init, then
256 * we first need to connect to the process manager and acquire the
257 * needed information.
258 */
259int PMI_Get_universe_size( int *size)
260{
261    int  err;
262    char size_c[PMIU_MAXLINE];
263
264    /* Connect to the PM if we haven't already */
265    if (PMIi_InitIfSingleton() != 0) return -1;
266
267    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM)  {
268        err = GetResponse( "cmd=get_universe_size\n", "universe_size", 0 );
269        if (err == PMI_SUCCESS) {
270            PMIU_getval( "size", size_c, PMIU_MAXLINE );
271            *size = atoi(size_c);
272            return( PMI_SUCCESS );
273        }
274        else return err;
275    }
276    else
277        *size = 1;
278    return( PMI_SUCCESS );
279}
280
281int PMI_Get_appnum( int *appnum )
282{
283    int  err;
284    char appnum_c[PMIU_MAXLINE];
285
286    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
287        err = GetResponse( "cmd=get_appnum\n", "appnum", 0 );
288        if (err == PMI_SUCCESS) {
289            PMIU_getval( "appnum", appnum_c, PMIU_MAXLINE );
290            *appnum = atoi(appnum_c);
291            return( PMI_SUCCESS );
292        }
293        else return err;
294       
295    }
296    else
297        *appnum = -1;
298
299    return( PMI_SUCCESS );
300}
301
302int PMI_Barrier( void )
303{
304    int err = PMI_SUCCESS;
305
306    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
307        err = GetResponse( "cmd=barrier_in\n", "barrier_out", 0 );
308    }
309
310    return err;
311}
312
313/* */
314static int clique_size=-2, *clique_ranks =0;
315
316/* pmiPrivateLocalRanks_<r> gets the local ranks for this process */
317int PMI_Get_clique_size( int *size )
318{
319#if 1
320    char buf[PMIU_MAXLINE];
321    char pmi_kvsname[1024];
322    int i, rc, err;
323
324    /* As the server for the information on the */
325    if (clique_size == -2 && PMI_initialized > SINGLETON_INIT_BUT_NO_PM)  {
326        PMI_KVS_Get_my_name( pmi_kvsname, sizeof(pmi_kvsname) );
327        rc = MPIU_Snprintf( buf, PMIU_MAXLINE, 
328                            "cmd=get kvsname=%s key=pmiPrivateLocalRanks_%d\n", 
329                            pmi_kvsname, PMI_rank );
330        if (rc < 0) return PMI_FAIL;
331
332        err = GetResponse( buf, "get_result", 0 );
333        if (err == PMI_SUCCESS) {
334            PMIU_getval( "rc", buf, PMIU_MAXLINE );
335            rc = atoi( buf );
336            if ( rc == 0 ) {
337                char *p = buf, *p0;
338                /* Allocate clique_ranks and fill it in */
339                PMIU_getval( "value", buf, PMIU_MAXLINE );
340                /* Count the number of ranks and allocate the space for them */
341                clique_size = 1;
342                while (*p) {
343                    if (*p++ == ',') clique_size++;
344                }
345                clique_ranks = (int *)MPIU_Malloc( clique_size * sizeof(int) );
346                DBG_PRINTF( ("Clique_size = %d\n", clique_size) );
347                p0 = p = buf;
348                i  = 0;
349                while (*p) {
350                    while (*p && *p != ',') p++;
351                    if (*p == ',') *p++ = 0;
352                    clique_ranks[i++] = atoi(p0);
353                    p0 = p;
354                }
355            }
356            else {
357                /* Default case (PM did not understand request) */
358                clique_size = 1;
359            }
360        }
361    }
362    if (clique_size < 0) *size = 1;
363    else                 *size = clique_size;
364#else
365    *size = 1;
366#endif
367    return PMI_SUCCESS;
368}
369
370int PMI_Get_clique_ranks( int ranks[], int length )
371{
372#if 1
373    int i;
374    if (length < 1) 
375        return PMI_ERR_INVALID_ARG;
376
377    if (clique_size > 0 && clique_ranks) {
378        for (i=0; i<length && i<clique_size; i++) 
379            ranks[i] = clique_ranks[i];
380    }
381    else 
382        ranks[0] = PMI_rank;
383    return PMI_SUCCESS;
384#else
385    if ( length < 1 )
386        return PMI_ERR_INVALID_ARG;
387    else
388        return PMI_Get_rank( &ranks[0] );
389#endif
390}
391
392/* Inform the process manager that we're in finalize */
393int PMI_Finalize( void )
394{
395    int err = PMI_SUCCESS;
396
397    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
398        err = GetResponse( "cmd=finalize\n", "finalize_ack", 0 );
399        shutdown( PMI_fd, SHUT_RDWR );
400        close( PMI_fd );
401    }
402    /* Free any memory that we've allocated */
403    if (clique_ranks) MPIU_Free( clique_ranks );
404
405    return err;
406}
407
408int PMI_Abort(int exit_code, const char error_msg[])
409{
410    PMIU_printf(1, "aborting job:\n%s\n", error_msg);
411    MPIU_Exit(exit_code);
412    return -1;
413}
414
415/************************************* Keymap functions **********************/
416
417/*FIXME: need to return an error if the value of the kvs name returned is
418  truncated because it is larger than length */
419/* FIXME: My name should be cached rather than re-acquired, as it is
420   unchanging (after singleton init) */
421int PMI_KVS_Get_my_name( char kvsname[], int length )
422{
423    int err;
424
425    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
426        /* Return a dummy name */
427        /* FIXME: We need to support a distinct kvsname for each
428           process group */
429        /* FIXME: Should the length be length (from the arg list)
430           instead of PMIU_MAXLINE? */
431        MPIU_Snprintf( kvsname, PMIU_MAXLINE, "singinit_kvs_%d_0", 
432                       (int)getpid() );
433        return 0;
434    }
435    err = GetResponse( "cmd=get_my_kvsname\n", "my_kvsname", 0 );
436    if (err == PMI_SUCCESS) {
437        PMIU_getval( "kvsname", kvsname, length );
438    }
439    return err;
440}
441
442int PMI_KVS_Get_name_length_max( int *maxlen )
443{
444    if (maxlen == NULL)
445        return PMI_ERR_INVALID_ARG;
446    *maxlen = PMI_kvsname_max;
447    return PMI_SUCCESS;
448}
449
450int PMI_KVS_Get_key_length_max( int *maxlen )
451{
452    if (maxlen == NULL)
453        return PMI_ERR_INVALID_ARG;
454    *maxlen = PMI_keylen_max;
455    return PMI_SUCCESS;
456}
457
458int PMI_KVS_Get_value_length_max( int *maxlen )
459{
460    if (maxlen == NULL)
461        return PMI_ERR_INVALID_ARG;
462    *maxlen = PMI_vallen_max;
463    return PMI_SUCCESS;
464}
465
466/* We will use the default kvsname for both the kvs_domain_id and for the id */
467/* Hence the implementation of the following three functions */
468
469int PMI_Get_id_length_max( int *length )
470{
471    if (length == NULL)
472        return PMI_ERR_INVALID_ARG;
473    *length = PMI_kvsname_max;
474    return PMI_SUCCESS;
475}
476
477int PMI_Get_id( char id_str[], int length )
478{
479    int rc = PMI_KVS_Get_my_name( id_str, length );
480    return rc;
481}
482
483/* FIXME: What is this function?  How is it defined and used? */
484int PMI_Get_kvs_domain_id( char id_str[], int length )
485{
486    return PMI_KVS_Get_my_name( id_str, length );
487}
488
489/*FIXME: need to return an error if the value of the kvs name returned is
490  truncated  because it is larger than length */
491int PMI_KVS_Create( char kvsname[], int length )
492{
493    int err = PMI_SUCCESS;
494   
495    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
496        /* It is ok to pretend to *create* a kvs space */
497        return 0;
498    }
499
500    err = GetResponse( "cmd=create_kvs\n", "newkvs", 0 );
501    if (err == PMI_SUCCESS) {
502        PMIU_getval( "kvsname", kvsname, length );
503    }
504    return err;
505}
506
507int PMI_KVS_Destroy( const char kvsname[] )
508{
509    char buf[PMIU_MAXLINE];
510    int  err = PMI_SUCCESS;
511
512    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
513        return 0;
514    }
515
516    /* FIXME: Check for tempbuf too short */
517    MPIU_Snprintf( buf, PMIU_MAXLINE, "cmd=destroy_kvs kvsname=%s\n", 
518                   kvsname );
519    err = GetResponse( buf, "kvs_destroyed", 1 );
520    return err;
521
522}
523
524int PMI_KVS_Put( const char kvsname[], const char key[], const char value[] )
525{
526    char buf[PMIU_MAXLINE];
527    int  err = PMI_SUCCESS;
528    int  rc;
529
530    /* This is a special hack to support singleton initialization */
531    if (PMI_initialized == SINGLETON_INIT_BUT_NO_PM) {
532        rc = MPIU_Strncpy(cached_singinit_key,key,PMI_keylen_max);
533        if (rc != 0) return PMI_FAIL;
534        rc = MPIU_Strncpy(cached_singinit_val,value,PMI_vallen_max);
535        if (rc != 0) return PMI_FAIL;
536        return 0;
537    }
538   
539    rc = MPIU_Snprintf( buf, PMIU_MAXLINE, 
540                        "cmd=put kvsname=%s key=%s value=%s\n",
541                        kvsname, key, value);
542    if (rc < 0) return PMI_FAIL;
543    err = GetResponse( buf, "put_result", 1 );
544    return err;
545}
546
547int PMI_KVS_Commit( const char kvsname[] ATTRIBUTE((unused)))
548{
549    /* no-op in this implementation */
550    return( 0 );
551}
552
553/*FIXME: need to return an error if the value returned is truncated
554  because it is larger than length */
555int PMI_KVS_Get( const char kvsname[], const char key[], char value[], 
556                 int length)
557{
558    char buf[PMIU_MAXLINE];
559    int err = PMI_SUCCESS;
560    int  rc;
561
562    /* Connect to the PM if we haven't already.  This is needed in case
563       we're doing an MPI_Comm_join or MPI_Comm_connect/accept from
564       the singleton init case.  This test is here because, in the way in
565       which MPICH2 uses PMI, this is where the test needs to be. */
566    if (PMIi_InitIfSingleton() != 0) return -1;
567
568    rc = MPIU_Snprintf( buf, PMIU_MAXLINE, "cmd=get kvsname=%s key=%s\n", 
569                        kvsname, key );
570    if (rc < 0) return PMI_FAIL;
571
572    err = GetResponse( buf, "get_result", 0 );
573    if (err == PMI_SUCCESS) {
574        PMIU_getval( "rc", buf, PMIU_MAXLINE );
575        rc = atoi( buf );
576        if ( rc == 0 ) {
577            PMIU_getval( "value", value, length );
578            return( 0 );
579        }
580        else {
581            return( -1 );
582        }
583    }
584
585    return err;
586}
587
588int PMI_KVS_Iter_first(const char kvsname[], char key[], int key_len, 
589                       char val[], int val_len)
590{
591    int rc;
592
593    rc = PMII_iter( kvsname, 0, &PMI_iter_next_idx, key, key_len, val, val_len );
594    return( rc );
595}
596
597int PMI_KVS_Iter_next(const char kvsname[], char key[], int key_len, 
598                      char val[], int val_len)
599{
600    int rc;
601
602    rc = PMII_iter( kvsname, PMI_iter_next_idx, &PMI_iter_next_idx, 
603                    key, key_len, val, val_len );
604    if ( rc == -2 )
605        PMI_iter_next_idx = 0;
606    return( rc );
607}
608
609/*************************** Name Publishing functions **********************/
610
611int PMI_Publish_name( const char service_name[], const char port[] )
612{
613    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
614    int err;
615
616    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
617        MPIU_Snprintf( cmd, PMIU_MAXLINE, 
618                       "cmd=publish_name service=%s port=%s\n",
619                       service_name, port );
620        err = GetResponse( cmd, "publish_result", 0 );
621        /* FIXME: This should have used rc and msg */
622        if (err == PMI_SUCCESS) {
623            PMIU_getval( "info", buf, PMIU_MAXLINE );
624            if ( strcmp(buf,"ok") != 0 ) {
625                PMIU_printf( 1, "publish failed; reason = %s\n", buf );
626                return( PMI_FAIL );
627            }
628        }
629    }
630    else
631    {
632        PMIU_printf( 1, "PMI_Publish_name called before init\n" );
633        return( PMI_FAIL );
634    }
635
636    return( PMI_SUCCESS );
637}
638
639int PMI_Unpublish_name( const char service_name[] )
640{
641    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
642    int err = PMI_SUCCESS;
643
644    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
645        MPIU_Snprintf( cmd, PMIU_MAXLINE, "cmd=unpublish_name service=%s\n", 
646                       service_name );
647        err = GetResponse( cmd, "unpublish_result", 0 );
648        if (err == PMI_SUCCESS) {
649            PMIU_getval( "info", buf, PMIU_MAXLINE );
650            if ( strcmp(buf,"ok") != 0 ) {
651                /* FIXME: Do correct error reporting */
652                /*
653                PMIU_printf( 1, "unpublish failed; reason = %s\n", buf );
654                */
655                return( PMI_FAIL );
656            }
657        }
658    }
659    else
660    {
661        PMIU_printf( 1, "PMI_Unpublish_name called before init\n" );
662        return( PMI_FAIL );
663    }
664
665    return( PMI_SUCCESS );
666}
667
668int PMI_Lookup_name( const char service_name[], char port[] )
669{
670    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
671    int err;
672
673    if ( PMI_initialized > SINGLETON_INIT_BUT_NO_PM) {
674        MPIU_Snprintf( cmd, PMIU_MAXLINE, "cmd=lookup_name service=%s\n", 
675                       service_name );
676        err = GetResponse( cmd, "lookup_result", 0 );
677        if (err == PMI_SUCCESS) {
678            PMIU_getval( "info", buf, PMIU_MAXLINE );
679            if ( strcmp(buf,"ok") != 0 ) {
680                /* FIXME: Do correct error reporting */
681                /****
682                PMIU_printf( 1, "lookup failed; reason = %s\n", buf );
683                ****/
684                return( PMI_FAIL );
685            }
686            PMIU_getval( "port", port, MPI_MAX_PORT_NAME );
687        }
688    }
689    else
690    {
691        PMIU_printf( 1, "PMI_Lookup_name called before init\n" );
692        return( PMI_FAIL );
693    }
694
695    return( PMI_SUCCESS );
696}
697
698
699/************************** Process Creation functions **********************/
700
701int PMI_Spawn_multiple(int count,
702                       const char * cmds[],
703                       const char ** argvs[],
704                       const int maxprocs[],
705                       const int info_keyval_sizes[],
706                       const PMI_keyval_t * info_keyval_vectors[],
707                       int preput_keyval_size,
708                       const PMI_keyval_t preput_keyval_vector[],
709                       int errors[])
710{
711    int  i,rc,argcnt,spawncnt,total_num_processes,num_errcodes_found;
712    char buf[PMIU_MAXLINE], tempbuf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
713    char *lead, *lag;
714
715    /* Connect to the PM if we haven't already */
716    if (PMIi_InitIfSingleton() != 0) return -1;
717
718    total_num_processes = 0;
719
720    for (spawncnt=0; spawncnt < count; spawncnt++)
721    {
722        total_num_processes += maxprocs[spawncnt];
723
724        rc = MPIU_Snprintf(buf, PMIU_MAXLINE, 
725                           "mcmd=spawn\nnprocs=%d\nexecname=%s\n",
726                           maxprocs[spawncnt], cmds[spawncnt] );
727        if (rc < 0) {
728            return PMI_FAIL;
729        }
730
731        rc = MPIU_Snprintf(tempbuf, PMIU_MAXLINE,
732                           "totspawns=%d\nspawnssofar=%d\n",
733                           count, spawncnt+1);
734
735        if (rc < 0) { 
736            return PMI_FAIL;
737        }
738        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
739        if (rc != 0) {
740            return PMI_FAIL;
741        }
742
743        argcnt = 0;
744        if ((argvs != NULL) && (argvs[spawncnt] != NULL)) {
745            for (i=0; argvs[spawncnt][i] != NULL; i++)
746            {
747                /* FIXME (protocol design flaw): command line arguments
748                   may contain both = and <space> (and even tab!).
749                */
750                /* Note that part of this fixme was really a design error -
751                   because this uses the mcmd form, the data can be
752                   sent in multiple writelines.  This code now takes
753                   advantage of that.  Note also that a correct parser
754                   of the commands will permit any character other than a
755                   new line in the argument, since the form is
756                   argn=<any nonnewline><newline> */
757                rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"arg%d=%s\n",
758                                   i+1,argvs[spawncnt][i]);
759                if (rc < 0) {
760                    return PMI_FAIL;
761                }
762                rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
763                if (rc != 0) {
764                    return PMI_FAIL;
765                }
766                argcnt++;
767                rc = PMIU_writeline( PMI_fd, buf );
768                buf[0] = 0;
769
770            }
771        }
772        rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"argcnt=%d\n",argcnt);
773        if (rc < 0) {
774            return PMI_FAIL;
775        }
776        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
777        if (rc != 0) {
778            return PMI_FAIL;
779        }
780   
781        rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"preput_num=%d\n", 
782                           preput_keyval_size);
783        if (rc < 0) {
784            return PMI_FAIL;
785        }
786
787        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
788        if (rc != 0) {
789            return PMI_FAIL;
790        }
791        for (i=0; i < preput_keyval_size; i++) {
792            rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"preput_key_%d=%s\n",
793                               i,preput_keyval_vector[i].key);
794            if (rc < 0) {
795                return PMI_FAIL;
796            }
797            rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
798            if (rc != 0) {
799                return PMI_FAIL;
800            }
801            rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"preput_val_%d=%s\n",
802                               i,preput_keyval_vector[i].val);
803            if (rc < 0) {
804                return PMI_FAIL;
805            }
806            rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
807            if (rc != 0) {
808                return PMI_FAIL;
809            }
810        } 
811        rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"info_num=%d\n", 
812                           info_keyval_sizes[spawncnt]);
813        if (rc < 0) {
814            return PMI_FAIL;
815        }
816        rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE);
817        if (rc != 0) {
818            return PMI_FAIL;
819        }
820        for (i=0; i < info_keyval_sizes[spawncnt]; i++)
821        {
822            rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"info_key_%d=%s\n",
823                               i,info_keyval_vectors[spawncnt][i].key);
824            if (rc < 0) {
825                return PMI_FAIL;
826            }
827            rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
828            if (rc != 0) {
829                return PMI_FAIL;
830            }
831            rc = MPIU_Snprintf(tempbuf,PMIU_MAXLINE,"info_val_%d=%s\n",
832                               i,info_keyval_vectors[spawncnt][i].val);
833            if (rc < 0) {
834                return PMI_FAIL;
835            }
836            rc = MPIU_Strnapp(buf,tempbuf,PMIU_MAXLINE); 
837            if (rc != 0) {
838                return PMI_FAIL;
839            }
840        }
841
842        rc = MPIU_Strnapp(buf, "endcmd\n", PMIU_MAXLINE);
843        if (rc != 0) {
844            return PMI_FAIL;
845        }
846        PMIU_writeline( PMI_fd, buf );
847    }
848
849    PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
850    PMIU_parse_keyvals( buf ); 
851    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
852    if ( strncmp( cmd, "spawn_result", PMIU_MAXLINE ) != 0 ) {
853        PMIU_printf( 1, "got unexpected response to spawn :%s:\n", buf );
854        return( -1 );
855    }
856    else {
857        PMIU_getval( "rc", buf, PMIU_MAXLINE );
858        rc = atoi( buf );
859        if ( rc != 0 ) {
860            /****
861            PMIU_getval( "status", tempbuf, PMIU_MAXLINE );
862            PMIU_printf( 1, "pmi_spawn_mult failed; status: %s\n",tempbuf);
863            ****/
864            return( -1 );
865        }
866    }
867   
868    PMIU_Assert(errors != NULL);
869    if (PMIU_getval( "errcodes", tempbuf, PMIU_MAXLINE )) {
870        num_errcodes_found = 0;
871        lag = &tempbuf[0];
872        do {
873            lead = strchr(lag, ',');
874            if (lead) *lead = '\0';
875            errors[num_errcodes_found++] = atoi(lag);
876            lag = lead + 1; /* move past the null char */
877            PMIU_Assert(num_errcodes_found <= total_num_processes);
878        } while (lead != NULL);
879        PMIU_Assert(num_errcodes_found == total_num_processes);
880    }
881    else {
882        /* gforker doesn't return errcodes, so we'll just pretend that means
883           that it was going to send all `0's. */
884        for (i = 0; i < total_num_processes; ++i) {
885            errors[i] = 0;
886        }
887    }
888
889    return( 0 );
890}
891
892/***************** Internal routines not part of PMI interface ***************/
893
894/* get a keyval pair by specific index */
895
896static int PMII_iter( const char *kvsname, const int idx, int *next_idx, 
897                      char *key, int key_len, char *val, int val_len)
898{
899    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
900    int  rc, err;
901
902    /* FIXME: Check for tempbuf too short */
903    rc = MPIU_Snprintf( buf, PMIU_MAXLINE, "cmd=getbyidx kvsname=%s idx=%d\n", 
904                        kvsname, idx  );
905    if (rc < 0) {
906        return PMI_FAIL;
907    }
908    err = GetResponse( cmd, "getbyidx_results", 0 );
909    if (err == PMI_SUCCESS) {
910        PMIU_getval( "rc", buf, PMIU_MAXLINE );
911        rc = atoi( buf );
912        if ( rc == 0 ) {
913            PMIU_getval( "nextidx", buf, PMIU_MAXLINE );
914            *next_idx = atoi( buf );
915            PMIU_getval( "key", key, key_len );
916            PMIU_getval( "val", val, val_len );
917            return( PMI_SUCCESS );
918        }
919        else {
920            PMIU_getval( "reason", buf, PMIU_MAXLINE );
921            if ( strncmp( buf, "no_more_keyvals", PMIU_MAXLINE ) == 0 ) {
922                key[0] = '\0';
923                return( PMI_SUCCESS );
924            }
925            else {
926                PMIU_printf( 1, "iter failed; reason = %s\n", buf );
927                return( PMI_FAIL );
928            }
929        }
930    }
931    return err;
932}
933
934/* to get all maxes in one message */
935/* FIXME: This mixes init with get maxes */
936static int PMII_getmaxes( int *kvsname_max, int *keylen_max, int *vallen_max )
937{
938    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE], errmsg[PMIU_MAXLINE];
939    int err, rc;
940
941    rc = MPIU_Snprintf( buf, PMIU_MAXLINE, 
942                        "cmd=init pmi_version=%d pmi_subversion=%d\n",
943                        PMI_VERSION, PMI_SUBVERSION );
944    if (rc < 0) {
945        return PMI_FAIL;
946    }
947
948    rc = PMIU_writeline( PMI_fd, buf );
949    if (rc != 0) {
950        PMIU_printf( 1, "Unable to write to PMI_fd\n" );
951        return PMI_FAIL;
952    }
953    buf[0] = 0;   /* Ensure buffer is empty if read fails */
954    err = PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
955    if (err < 0) {
956        PMIU_printf( 1, "Error reading initack on %d\n", PMI_fd );
957        perror( "Error on readline:" );
958        PMI_Abort(-1, "Above error when reading after init" );
959    }
960    PMIU_parse_keyvals( buf );
961    cmd[0] = 0;
962    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
963    if ( strncmp( cmd, "response_to_init", PMIU_MAXLINE ) != 0 ) {
964        MPIU_Snprintf(errmsg, PMIU_MAXLINE, 
965                      "got unexpected response to init :%s: (full line = %s)",
966                      cmd, buf  );
967        PMI_Abort( -1, errmsg );
968    }
969    else {
970        char buf1[PMIU_MAXLINE];
971        PMIU_getval( "rc", buf, PMIU_MAXLINE );
972        if ( strncmp( buf, "0", PMIU_MAXLINE ) != 0 ) {
973            PMIU_getval( "pmi_version", buf, PMIU_MAXLINE );
974            PMIU_getval( "pmi_subversion", buf1, PMIU_MAXLINE );
975            MPIU_Snprintf(errmsg, PMIU_MAXLINE, 
976                          "pmi_version mismatch; client=%d.%d mgr=%s.%s",
977                          PMI_VERSION, PMI_SUBVERSION, buf, buf1 );
978            PMI_Abort( -1, errmsg );
979        }
980    }
981    err = GetResponse( "cmd=get_maxes\n", "maxes", 0 );
982    if (err == PMI_SUCCESS) {
983        PMIU_getval( "kvsname_max", buf, PMIU_MAXLINE );
984        *kvsname_max = atoi( buf );
985        PMIU_getval( "keylen_max", buf, PMIU_MAXLINE );
986        *keylen_max = atoi( buf );
987        PMIU_getval( "vallen_max", buf, PMIU_MAXLINE );
988        *vallen_max = atoi( buf );
989    }
990    return err;
991}
992
993/* ----------------------------------------------------------------------- */
994/*
995 * This function is used to request information from the server and check
996 * that the response uses the expected command name.  On a successful
997 * return from this routine, additional PMIU_getval calls may be used
998 * to access information about the returned value.
999 *
1000 * If checkRc is true, this routine also checks that the rc value returned
1001 * was 0.  If not, it uses the "msg" value to report on the reason for
1002 * the failure.
1003 */
1004static int GetResponse( const char request[], const char expectedCmd[],
1005                        int checkRc )
1006{
1007    int err, n;
1008    char *p;
1009    char recvbuf[PMIU_MAXLINE];
1010    char cmdName[PMIU_MAXLINE];
1011
1012    /* FIXME: This is an example of an incorrect fix - writeline can change
1013       the second argument in some cases, and that will break the const'ness
1014       of request.  Instead, writeline should take a const item and return
1015       an error in the case in which it currently truncates the data. */
1016    err = PMIU_writeline( PMI_fd, (char *)request );
1017    if (err) {
1018        return err;
1019    }
1020    n = PMIU_readline( PMI_fd, recvbuf, sizeof(recvbuf) );
1021    if (n <= 0) {
1022        PMIU_printf( 1, "readline failed\n" );
1023        return PMI_FAIL;
1024    }
1025    err = PMIU_parse_keyvals( recvbuf );
1026    if (err) {
1027        PMIU_printf( 1, "parse_kevals failed %d\n", err );
1028        return err;
1029    }
1030    p = PMIU_getval( "cmd", cmdName, sizeof(cmdName) );
1031    if (!p) {
1032        PMIU_printf( 1, "getval cmd failed\n" );
1033        return PMI_FAIL;
1034    }
1035    if (strcmp( expectedCmd, cmdName ) != 0) {
1036        PMIU_printf( 1, "expecting cmd=%s, got %s\n", expectedCmd, cmdName );
1037        return PMI_FAIL;
1038    }
1039    if (checkRc) {
1040        p = PMIU_getval( "rc", cmdName, PMIU_MAXLINE );
1041        if ( p && strcmp(cmdName,"0") != 0 ) {
1042            PMIU_getval( "msg", cmdName, PMIU_MAXLINE );
1043            PMIU_printf( 1, "Command %s failed, reason='%s'\n", 
1044                         request, cmdName );
1045            return PMI_FAIL;
1046        }
1047    }
1048
1049    return err;
1050}
1051/* ----------------------------------------------------------------------- */
1052
1053
1054#ifdef USE_PMI_PORT
1055/*
1056 * This code allows a program to contact a host/port for the PMI socket.
1057 */
1058#include <errno.h>
1059#if defined(HAVE_SYS_TYPES_H)
1060#include <sys/types.h>
1061#endif
1062#include <sys/param.h>
1063#include <sys/socket.h>
1064
1065/* sockaddr_in (Internet) */
1066#include <netinet/in.h>
1067/* TCP_NODELAY */
1068#include <netinet/tcp.h>
1069
1070/* sockaddr_un (Unix) */
1071#include <sys/un.h>
1072
1073/* defs of gethostbyname */
1074#include <netdb.h>
1075
1076/* fcntl, F_GET/SETFL */
1077#include <fcntl.h>
1078
1079/* This is really IP!? */
1080#ifndef TCP
1081#define TCP 0
1082#endif
1083
1084/* stub for connecting to a specified host/port instead of using a
1085   specified fd inherited from a parent process */
1086static int PMII_Connect_to_pm( char *hostname, int portnum )
1087{
1088    struct hostent     *hp;
1089    struct sockaddr_in sa;
1090    int                fd;
1091    int                optval = 1;
1092    int                q_wait = 1;
1093   
1094    hp = gethostbyname( hostname );
1095    if (!hp) {
1096        PMIU_printf( 1, "Unable to get host entry for %s\n", hostname );
1097        return -1;
1098    }
1099   
1100    memset( (void *)&sa, 0, sizeof(sa) );
1101    /* POSIX might define h_addr_list only and node define h_addr */
1102#ifdef HAVE_H_ADDR_LIST
1103    memcpy( (void *)&sa.sin_addr, (void *)hp->h_addr_list[0], hp->h_length);
1104#else
1105    memcpy( (void *)&sa.sin_addr, (void *)hp->h_addr, hp->h_length);
1106#endif
1107    sa.sin_family = hp->h_addrtype;
1108    sa.sin_port   = htons( (unsigned short) portnum );
1109   
1110    fd = socket( AF_INET, SOCK_STREAM, TCP );
1111    if (fd < 0) {
1112        PMIU_printf( 1, "Unable to get AF_INET socket\n" );
1113        return -1;
1114    }
1115   
1116    if (setsockopt( fd, IPPROTO_TCP, TCP_NODELAY, 
1117                    (char *)&optval, sizeof(optval) )) {
1118        perror( "Error calling setsockopt:" );
1119    }
1120
1121    /* We wait here for the connection to succeed */
1122    if (connect( fd, (struct sockaddr *)&sa, sizeof(sa) ) < 0) {
1123        switch (errno) {
1124        case ECONNREFUSED:
1125            PMIU_printf( 1, "connect failed with connection refused\n" );
1126            /* (close socket, get new socket, try again) */
1127            if (q_wait)
1128                close(fd);
1129            return -1;
1130           
1131        case EINPROGRESS: /*  (nonblocking) - select for writing. */
1132            break;
1133           
1134        case EISCONN: /*  (already connected) */
1135            break;
1136           
1137        case ETIMEDOUT: /* timed out */
1138            PMIU_printf( 1, "connect failed with timeout\n" );
1139            return -1;
1140
1141        default:
1142            PMIU_printf( 1, "connect failed with errno %d\n", errno );
1143            return -1;
1144        }
1145    }
1146
1147    return fd;
1148}
1149
1150static int PMII_Set_from_port( int fd, int id )
1151{
1152    char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
1153    int err, rc;
1154
1155    /* We start by sending a startup message to the server */
1156
1157    if (PMI_debug) {
1158        PMIU_printf( 1, "Writing initack to destination fd %d\n", fd );
1159    }
1160    /* Handshake and initialize from a port */
1161
1162    rc = MPIU_Snprintf( buf, PMIU_MAXLINE, "cmd=initack pmiid=%d\n", id );
1163    if (rc < 0) {
1164        return PMI_FAIL;
1165    }
1166    PMIU_printf( PMI_debug, "writing on fd %d line :%s:\n", fd, buf );
1167    err = PMIU_writeline( fd, buf );
1168    if (err) {
1169        PMIU_printf( 1, "Error in writeline initack\n" );
1170        return -1;
1171    }
1172
1173    /* cmd=initack */
1174    buf[0] = 0;
1175    PMIU_printf( PMI_debug, "reading initack\n" );
1176    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
1177    if (err < 0) {
1178        PMIU_printf( 1, "Error reading initack on %d\n", fd );
1179        perror( "Error on readline:" );
1180        return -1;
1181    }
1182    PMIU_parse_keyvals( buf );
1183    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
1184    if ( strcmp( cmd, "initack" ) ) {
1185        PMIU_printf( 1, "got unexpected input %s\n", buf );
1186        return -1;
1187    }
1188   
1189    /* Read, in order, size, rank, and debug.  Eventually, we'll want
1190       the handshake to include a version number */
1191
1192    /* size */
1193    PMIU_printf( PMI_debug, "reading size\n" );
1194    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
1195    if (err < 0) {
1196        PMIU_printf( 1, "Error reading size on %d\n", fd );
1197        perror( "Error on readline:" );
1198        return -1;
1199    }
1200    PMIU_parse_keyvals( buf );
1201    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
1202    if ( strcmp(cmd,"set")) {
1203        PMIU_printf( 1, "got unexpected command %s in %s\n", cmd, buf );
1204        return -1;
1205    }
1206    /* cmd=set size=n */
1207    PMIU_getval( "size", cmd, PMIU_MAXLINE );
1208    PMI_size = atoi(cmd);
1209
1210    /* rank */
1211    PMIU_printf( PMI_debug, "reading rank\n" );
1212    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
1213    if (err < 0) {
1214        PMIU_printf( 1, "Error reading rank on %d\n", fd );
1215        perror( "Error on readline:" );
1216        return -1;
1217    }
1218    PMIU_parse_keyvals( buf );
1219    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
1220    if ( strcmp(cmd,"set")) {
1221        PMIU_printf( 1, "got unexpected command %s in %s\n", cmd, buf );
1222        return -1;
1223    }
1224    /* cmd=set rank=n */
1225    PMIU_getval( "rank", cmd, PMIU_MAXLINE );
1226    PMI_rank = atoi(cmd);
1227    PMIU_Set_rank( PMI_rank );
1228
1229    /* debug flag */
1230    err = PMIU_readline( fd, buf, PMIU_MAXLINE );
1231    if (err < 0) {
1232        PMIU_printf( 1, "Error reading debug on %d\n", fd );
1233        return -1;
1234    }
1235    PMIU_parse_keyvals( buf );
1236    PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
1237    if ( strcmp(cmd,"set")) {
1238        PMIU_printf( 1, "got unexpected command %s in %s\n", cmd, buf );
1239        return -1;
1240    }
1241    /* cmd=set debug=n */
1242    PMIU_getval( "debug", cmd, PMIU_MAXLINE );
1243    PMI_debug = atoi(cmd);
1244
1245    if (PMI_debug) {
1246        DBG_PRINTF( ("end of handshake, rank = %d, size = %d\n", 
1247                    PMI_rank, PMI_size )); 
1248        DBG_PRINTF( ("Completed init\n" ) );
1249    }
1250
1251    return 0;
1252}
1253
1254/* ------------------------------------------------------------------------- */
1255/*
1256 * Singleton Init.
1257 *
1258 * MPI-2 allows processes to become MPI processes and then make MPI calls,
1259 * such as MPI_Comm_spawn, that require a process manager (this is different
1260 * than the much simpler case of allowing MPI programs to run with an
1261 * MPI_COMM_WORLD of size 1 without an mpiexec or process manager).
1262 *
1263 * The process starts when either the client or the process manager contacts
1264 * the other.  If the client starts, it sends a singinit command and
1265 * waits for the server to respond with its own singinit command.
1266 * If the server start, it send a singinit command and waits for the
1267 * client to respond with its own singinit command
1268 *
1269 * client sends singinit with these required values
1270 *   pmi_version=<value of PMI_VERSION>
1271 *   pmi_subversion=<value of PMI_SUBVERSION>
1272 *
1273 * and these optional values
1274 *   stdio=[yes|no]
1275 *   authtype=[none|shared|<other-to-be-defined>]
1276 *   authstring=<string>
1277 *
1278 * server sends singinit with the same required and optional values as
1279 * above.
1280 *
1281 * At this point, the protocol is now the same in both cases, and has the
1282 * following components:
1283 *
1284 * server sends singinit_info with these required fields
1285 *   versionok=[yes|no]
1286 *   stdio=[yes|no]
1287 *   kvsname=<string>
1288 *
1289 * The client then issues the init command (see PMII_getmaxes)
1290 *
1291 * cmd=init pmi_version=<val> pmi_subversion=<val>
1292 *
1293 * and expects to receive a
1294 *
1295 * cmd=response_to_init rc=0 pmi_version=<val> pmi_subversion=<val>
1296 *
1297 * (This is the usual init sequence).
1298 *
1299 */
1300/* ------------------------------------------------------------------------- */
1301/* This is a special routine used to re-initialize PMI when it is in
1302   the singleton init case.  That is, the executable was started without
1303   mpiexec, and PMI_Init returned as if there was only one process.
1304
1305   Note that PMI routines should not call PMII_singinit; they should
1306   call PMIi_InitIfSingleton(), which both connects to the process mangager
1307   and sets up the initial KVS connection entry.
1308*/
1309
1310static int PMII_singinit(void)
1311{
1312    int pid, rc;
1313    int singinit_listen_sock, stdin_sock, stdout_sock, stderr_sock;
1314    const char *newargv[8];
1315    char charpid[8], port_c[8];
1316    struct sockaddr_in sin;
1317    socklen_t len;
1318
1319    /* Create a socket on which to allow an mpiexec to connect back to
1320       us */
1321    sin.sin_family      = AF_INET;
1322    sin.sin_addr.s_addr = INADDR_ANY;
1323    sin.sin_port        = htons(0);    /* anonymous port */
1324    singinit_listen_sock = socket(AF_INET, SOCK_STREAM, 0);
1325    rc = bind(singinit_listen_sock, (struct sockaddr *)&sin ,sizeof(sin));
1326    len = sizeof(struct sockaddr_in);
1327    rc = getsockname( singinit_listen_sock, (struct sockaddr *) &sin, &len ); 
1328    MPIU_Snprintf(port_c, sizeof(port_c), "%d",ntohs(sin.sin_port));
1329    rc = listen(singinit_listen_sock, 5);
1330
1331    PMIU_printf( PMI_debug_init, "Starting mpiexec with %s\n", port_c );
1332
1333    /* Launch the mpiexec process with the name of this port */
1334    pid = fork();
1335    if (pid < 0) {
1336        perror("PMII_singinit: fork failed");
1337        exit(-1);
1338    }
1339    else if (pid == 0) {
1340        newargv[0] = "mpiexec";
1341        newargv[1] = "-pmi_args";
1342        newargv[2] = port_c;
1343        /* FIXME: Use a valid hostname */
1344        newargv[3] = "default_interface";  /* default interface name, for now */
1345        newargv[4] = "default_key";   /* default authentication key, for now */
1346        MPIU_Snprintf(charpid, sizeof(charpid), "%d",getpid());
1347        newargv[5] = charpid;
1348        newargv[6] = NULL;
1349        rc = execvp(newargv[0], (char **)newargv);
1350        perror("PMII_singinit: execv failed");
1351        PMIU_printf(1, "  This singleton init program attempted to access some feature\n");
1352        PMIU_printf(1, "  for which process manager support was required, e.g. spawn or universe_size.\n");
1353        PMIU_printf(1, "  But the necessary mpiexec is not in your path.\n");
1354        return(-1);
1355    }
1356    else
1357    {
1358        char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE];
1359        char *p;
1360        int connectStdio = 0;
1361
1362        /* Allow one connection back from the created mpiexec program */
1363        PMI_fd =  accept_one_connection(singinit_listen_sock);
1364        if (PMI_fd < 0) {
1365            PMIU_printf( 1, "Failed to establish singleton init connection\n" );
1366            return PMI_FAIL;
1367        }
1368        /* Execute the singleton init protocol */
1369        rc = PMIU_readline( PMI_fd, buf, PMIU_MAXLINE );
1370        PMIU_printf( PMI_debug_init, "Singinit: read %s\n", buf );
1371
1372        PMIU_parse_keyvals( buf );
1373        PMIU_getval( "cmd", cmd, PMIU_MAXLINE );
1374        if (strcmp( cmd, "singinit" ) != 0) {
1375            PMIU_printf( 1, "unexpected command from PM: %s\n", cmd );
1376            return PMI_FAIL;
1377        }
1378        p = PMIU_getval( "authtype", cmd, PMIU_MAXLINE );
1379        if (p && strcmp( cmd, "none" ) != 0) {
1380            PMIU_printf( 1, "unsupported authentication method %s\n", cmd );
1381            return PMI_FAIL;
1382        }
1383        /* p = PMIU_getval( "authstring", cmd, PMIU_MAXLINE ); */
1384       
1385        /* If we're successful, send back our own singinit */
1386        rc = MPIU_Snprintf( buf, PMIU_MAXLINE, 
1387     "cmd=singinit pmi_version=%d pmi_subversion=%d stdio=yes authtype=none\n",
1388                        PMI_VERSION, PMI_SUBVERSION );
1389        if (rc < 0) {
1390            return PMI_FAIL;
1391        }
1392        PMIU_printf( PMI_debug_init, "GetResponse with %s\n", buf );
1393
1394        rc = GetResponse( buf, "singinit_info", 0 );
1395        if (rc != 0) {
1396            PMIU_printf( 1, "GetResponse failed\n" );
1397            return PMI_FAIL;
1398        }
1399        p = PMIU_getval( "versionok", cmd, PMIU_MAXLINE );
1400        if (p && strcmp( cmd, "yes" ) != 0) {
1401            PMIU_printf( 1, "Process manager needs a different PMI version\n" );
1402            return PMI_FAIL;
1403        }
1404        p = PMIU_getval( "stdio", cmd, PMIU_MAXLINE );
1405        if (p && strcmp( cmd, "yes" ) == 0) {
1406            PMIU_printf( PMI_debug_init, "PM agreed to connect stdio\n" );
1407            connectStdio = 1;
1408        }
1409        p = PMIU_getval( "kvsname", singinit_kvsname, sizeof(singinit_kvsname) );
1410        PMIU_printf( PMI_debug_init, "kvsname to use is %s\n", 
1411                     singinit_kvsname );
1412       
1413        if (connectStdio) {
1414            PMIU_printf( PMI_debug_init, 
1415                         "Accepting three connections for stdin, out, err\n" );
1416            stdin_sock  = accept_one_connection(singinit_listen_sock);
1417            dup2(stdin_sock, 0);
1418            stdout_sock = accept_one_connection(singinit_listen_sock);
1419            dup2(stdout_sock,1);
1420            stderr_sock = accept_one_connection(singinit_listen_sock);
1421            dup2(stderr_sock,2);
1422        }
1423        PMIU_printf( PMI_debug_init, "Done with singinit handshake\n" );
1424    }
1425    return 0;
1426}
1427
1428/* Promote PMI to a fully initialized version if it was started as
1429   a singleton init */
1430static int PMIi_InitIfSingleton(void)
1431{
1432    int rc;
1433    static int firstcall = 1;
1434
1435    if (PMI_initialized != SINGLETON_INIT_BUT_NO_PM || !firstcall) return 0;
1436
1437    /* We only try to init as a singleton the first time */
1438    firstcall = 0;
1439
1440    /* First, start (if necessary) an mpiexec, connect to it,
1441       and start the singleton init handshake */
1442    rc = PMII_singinit();
1443
1444    if (rc < 0)
1445        return(-1);
1446    PMI_initialized = SINGLETON_INIT_WITH_PM;    /* do this right away */
1447    PMI_size        = 1;
1448    PMI_rank        = 0;
1449    PMI_debug       = 0;
1450    PMI_spawned     = 0;
1451
1452    PMII_getmaxes( &PMI_kvsname_max, &PMI_keylen_max, &PMI_vallen_max );
1453
1454    /* FIXME: We need to support a distinct kvsname for each
1455       process group */
1456    PMI_KVS_Put( singinit_kvsname, cached_singinit_key, cached_singinit_val );
1457
1458    return 0;
1459}
1460
1461static int accept_one_connection(int list_sock)
1462{
1463    int gotit, new_sock;
1464    struct sockaddr_in from;
1465    socklen_t len;
1466
1467    len = sizeof(from);
1468    gotit = 0;
1469    while ( ! gotit )
1470    {
1471        new_sock = accept(list_sock, (struct sockaddr *)&from, &len);
1472        if (new_sock == -1)
1473        {
1474            if (errno == EINTR)    /* interrupted? If so, try again */
1475                continue;
1476            else
1477            {
1478                PMIU_printf(1, "accept failed in accept_one_connection\n");
1479                exit(-1);
1480            }
1481        }
1482        else
1483            gotit = 1;
1484    }
1485    return(new_sock);
1486}
1487
1488#endif
1489/* end USE_PMI_PORT */
1490
1491/* Get the FD to use for PMI operations.  If a port is used, rather than
1492   a pre-established FD (i.e., via pipe), this routine will handle the
1493   initial handshake. 
1494*/
1495static int getPMIFD( int *notset )
1496{
1497    char *p;
1498
1499    /* Set the default */
1500    PMI_fd = -1;
1501   
1502    p = getenv( "PMI_FD" );
1503
1504    if (p) {
1505        PMI_fd = atoi( p );
1506        return 0;
1507    }
1508
1509#ifdef USE_PMI_PORT
1510    p = getenv( "PMI_PORT" );
1511    if (p) {
1512        int portnum;
1513        char hostname[MAXHOSTNAME+1];
1514        char *pn, *ph;
1515        int id = 0;
1516
1517        /* Connect to the indicated port (in format hostname:portnumber)
1518           and get the fd for the socket */
1519       
1520        /* Split p into host and port */
1521        pn = p;
1522        ph = hostname;
1523        while (*pn && *pn != ':' && (ph - hostname) < MAXHOSTNAME) {
1524            *ph++ = *pn++;
1525        }
1526        *ph = 0;
1527
1528        if (PMI_debug) {
1529            DBG_PRINTF( ("Connecting to %s\n", p) );
1530        }
1531        if (*pn == ':') {
1532            portnum = atoi( pn+1 );
1533            /* FIXME: Check for valid integer after : */
1534            /* This routine only gets the fd to use to talk to
1535               the process manager. The handshake below is used
1536               to setup the initial values */
1537            PMI_fd = PMII_Connect_to_pm( hostname, portnum );
1538            if (PMI_fd < 0) {
1539                PMIU_printf( 1, "Unable to connect to %s on %d\n", 
1540                             hostname, portnum );
1541                return -1;
1542            }
1543        }
1544        else {
1545            PMIU_printf( 1, "unable to decode hostport from %s\n", p );
1546            return PMI_FAIL;
1547        }
1548
1549        /* We should first handshake to get size, rank, debug. */
1550        p = getenv( "PMI_ID" );
1551        if (p) {
1552            id = atoi( p );
1553            /* PMII_Set_from_port sets up the values that are delivered
1554               by enviroment variables when a separate port is not used */
1555            PMII_Set_from_port( PMI_fd, id );
1556            *notset = 0;
1557        }
1558        return 0;
1559    }
1560#endif
1561
1562    /* Singleton init case - its ok to return success with no fd set */
1563    return 0;
1564}
Note: See TracBrowser for help on using the browser.