-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpid/ch3/src/ch3u_comm_spawn_multiple.c
        -:    0:Graph:ch3u_comm_spawn_multiple.gcno
        -:    0:Data:ch3u_comm_spawn_multiple.gcda
        -:    0:Runs:3459
        -:    0:Programs:899
        -:    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:#include "mpidi_ch3_impl.h"
        -:    8:
        -:    9:/* FIXME:
        -:   10:   Place all of this within the mpid_comm_spawn_multiple file */
        -:   11:
        -:   12:#ifndef MPIDI_CH3_HAS_NO_DYNAMIC_PROCESS
        -:   13:/* 
        -:   14: * We require support for the PMI calls.  If a channel cannot support
        -:   15: * a PMI call, it should provide a stub and return an error code.
        -:   16: */
        -:   17:   
        -:   18:
        -:   19:#ifdef USE_PMI2_API
        -:   20:#include "pmi2.h"
        -:   21:#else
        -:   22:#include "pmi.h"
        -:   23:#endif
        -:   24:
        -:   25:/* Define the name of the kvs key used to provide the port name to the
        -:   26:   children */
        -:   27:#define PARENT_PORT_KVSKEY "PARENT_ROOT_PORT_NAME"
        -:   28:
        -:   29:/* FIXME: We can avoid these two routines if we define PMI as using 
        -:   30:   MPI info values */
        -:   31:/* Turn a SINGLE MPI_Info into an array of PMI_keyvals (return the pointer
        -:   32:   to the array of PMI keyvals) */
        -:   33:#undef FUNCNAME
        -:   34:#define FUNCNAME mpi_to_pmi_keyvals
        -:   35:#undef FCNAME
        -:   36:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:   37:static int  mpi_to_pmi_keyvals( MPID_Info *info_ptr, PMI_keyval_t **kv_ptr, 
        -:   38:				int *nkeys_ptr )
      361:   39:{
        -:   40:    char key[MPI_MAX_INFO_KEY];
      361:   41:    PMI_keyval_t *kv = 0;
      361:   42:    int          i, nkeys = 0, vallen, flag, mpi_errno=MPI_SUCCESS;
        -:   43:
      361:   44:    if (!info_ptr || info_ptr->handle == MPI_INFO_NULL) {
        -:   45:	goto fn_exit;
        -:   46:    }
        -:   47:
        9:   48:    mpi_errno = NMPI_Info_get_nkeys( info_ptr->handle, &nkeys );
        9:   49:    if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
        9:   50:    if (nkeys == 0) {
    #####:   51:	goto fn_exit;
        -:   52:    }
        9:   53:    kv = (PMI_keyval_t *)MPIU_Malloc( nkeys * sizeof(PMI_keyval_t) );
        9:   54:    if (!kv) { MPIU_ERR_POP(mpi_errno); }
        -:   55:
       21:   56:    for (i=0; i<nkeys; i++) {
       12:   57:	mpi_errno = NMPI_Info_get_nthkey( info_ptr->handle, i, key );
       12:   58:	if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
       12:   59:	mpi_errno = NMPI_Info_get_valuelen( info_ptr->handle, key, &vallen, 
        -:   60:					    &flag );
       12:   61:	if (!flag || mpi_errno) { MPIU_ERR_POP(mpi_errno); }
       12:   62:	kv[i].key = MPIU_Strdup(key);
       12:   63:	kv[i].val = MPIU_Malloc( vallen + 1 );
       12:   64:	if (!kv[i].key || !kv[i].val) { 
    #####:   65:	    MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**nomem" );
        -:   66:	}
       12:   67:	mpi_errno = NMPI_Info_get( info_ptr->handle, key, vallen+1,
        -:   68:				   kv[i].val, &flag );
       12:   69:	if (!flag || mpi_errno) { MPIU_ERR_POP(mpi_errno); }
        -:   70:	MPIU_DBG_PRINTF(("key: <%s>, value: <%s>\n", kv[i].key, kv[i].val));
        -:   71:    }
        -:   72:
      361:   73: fn_fail:
      361:   74: fn_exit:
      361:   75:    *kv_ptr    = kv;
      361:   76:    *nkeys_ptr = nkeys;
      361:   77:    return mpi_errno;
        -:   78:}
        -:   79:/* Free the entire array of PMI keyvals */
        -:   80:static void free_pmi_keyvals(PMI_keyval_t **kv, int size, int *counts)
      357:   81:{
        -:   82:    int i,j;
        -:   83:
      718:   84:    for (i=0; i<size; i++)
        -:   85:    {
      373:   86:	for (j=0; j<counts[i]; j++)
        -:   87:	{
       12:   88:	    if (kv[i][j].key != NULL)
       12:   89:		MPIU_Free((char *)kv[i][j].key);
       12:   90:	    if (kv[i][j].val != NULL)
       12:   91:		MPIU_Free(kv[i][j].val);
        -:   92:	}
      361:   93:	if (kv[i] != NULL)
        -:   94:	{
        9:   95:	    MPIU_Free(kv[i]);
        -:   96:	}
        -:   97:    }
      357:   98:}
        -:   99:
        -:  100:/*
        -:  101: * MPIDI_CH3_Comm_spawn_multiple()
        -:  102: */
        -:  103:#undef FUNCNAME
        -:  104:#define FUNCNAME MPIDI_Comm_spawn_multiple
        -:  105:#undef FCNAME
        -:  106:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  107:int MPIDI_Comm_spawn_multiple(int count, char **commands, 
        -:  108:                                  char ***argvs, int *maxprocs, 
        -:  109:                                  MPID_Info **info_ptrs, int root,
        -:  110:                                  MPID_Comm *comm_ptr, MPID_Comm
        -:  111:                                  **intercomm, int *errcodes) 
      375:  112:{
        -:  113:    char port_name[MPI_MAX_PORT_NAME];
      375:  114:    int *info_keyval_sizes=0, i, mpi_errno=MPI_SUCCESS;
      375:  115:    PMI_keyval_t **info_keyval_vectors=0, preput_keyval_vector;
      375:  116:    int *pmi_errcodes = 0, pmi_errno;
      375:  117:    int total_num_processes, should_accept = 1;
      375:  118:    MPIU_THREADPRIV_DECL;
        -:  119:
        -:  120:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_COMM_SPAWN_MULTIPLE);
        -:  121:
        -:  122:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_COMM_SPAWN_MULTIPLE);
        -:  123:
      375:  124:    MPIU_THREADPRIV_GET;
      375:  125:    MPIR_Nest_incr();
        -:  126:
      375:  127:    if (comm_ptr->rank == root) {
        -:  128:	/* FIXME: This is *really* awkward.  We should either
        -:  129:	   Fix on MPI-style info data structures for PMI (avoid unnecessary
        -:  130:	   duplication) or add an MPIU_Info_getall(...) that creates
        -:  131:	   the necessary arrays of key/value pairs */
        -:  132:
        -:  133:	/* convert the infos into PMI keyvals */
      357:  134:        info_keyval_sizes   = (int *) MPIU_Malloc(count * sizeof(int));
      357:  135:	info_keyval_vectors = 
        -:  136:	    (PMI_keyval_t**) MPIU_Malloc(count * sizeof(PMI_keyval_t*));
      357:  137:	if (!info_keyval_sizes || !info_keyval_vectors) { 
    #####:  138:	    MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**nomem");
        -:  139:	}
        -:  140:
      357:  141:	if (!info_ptrs) {
    #####:  142:	    for (i=0; i<count; i++) {
    #####:  143:		info_keyval_vectors[i] = 0;
    #####:  144:		info_keyval_sizes[i]   = 0;
        -:  145:	    }
        -:  146:	}
        -:  147:	else {
      718:  148:	    for (i=0; i<count; i++) {
      361:  149:		mpi_errno = mpi_to_pmi_keyvals( info_ptrs[i], 
        -:  150:						&info_keyval_vectors[i],
        -:  151:						&info_keyval_sizes[i] );
      361:  152:		if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
        -:  153:	    }
        -:  154:	}
        -:  155:
        -:  156:	/* create an array for the pmi error codes */
      357:  157:	total_num_processes = 0;
      718:  158:	for (i=0; i<count; i++) {
      361:  159:	    total_num_processes += maxprocs[i];
        -:  160:	}
      357:  161:	pmi_errcodes = (int*)MPIU_Malloc(sizeof(int) * total_num_processes);
      357:  162:	if (pmi_errcodes == NULL) {
    #####:  163:	    MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**nomem");
        -:  164:	}
        -:  165:
        -:  166:	/* initialize them to 0 */
      763:  167:	for (i=0; i<total_num_processes; i++)
      406:  168:	    pmi_errcodes[i] = 0;
        -:  169:
        -:  170:	/* Open a port for the spawned processes to connect to */
        -:  171:	/* FIXME: info may be needed for port name */
      357:  172:        mpi_errno = MPID_Open_port(NULL, port_name);
        -:  173:	/* --BEGIN ERROR HANDLING-- */
      357:  174:        if (mpi_errno != MPI_SUCCESS) 
        -:  175:	{
    #####:  176:	    MPIU_ERR_POP(mpi_errno);
        -:  177:	}
        -:  178:	/* --END ERROR HANDLING-- */
        -:  179:
      357:  180:        preput_keyval_vector.key = PARENT_PORT_KVSKEY;
      357:  181:        preput_keyval_vector.val = port_name;
        -:  182:
        -:  183:	/* Spawn the processes */
        -:  184:	MPIU_THREAD_CS_ENTER(PMI,);
        -:  185:#ifdef USE_PMI2_API
        -:  186:        MPIU_Assert(0); /* FIX for pmi2 DARIUS */
        -:  187:#else
      357:  188:        pmi_errno = PMI_Spawn_multiple(count, (const char **)
        -:  189:                                       commands, 
        -:  190:                                       (const char ***) argvs,
        -:  191:                                       maxprocs, info_keyval_sizes,
        -:  192:                                       (const PMI_keyval_t **)
        -:  193:                                       info_keyval_vectors, 1, 
        -:  194:                                       &preput_keyval_vector,
        -:  195:                                       pmi_errcodes);
        -:  196:	MPIU_THREAD_CS_EXIT(PMI,);
      357:  197:        if (pmi_errno != PMI_SUCCESS) {
    #####:  198:	    MPIU_ERR_SETANDJUMP1(mpi_errno, MPI_ERR_OTHER,
        -:  199:		 "**pmi_spawn_multiple", "**pmi_spawn_multiple %d", pmi_errno);
        -:  200:        }
        -:  201:#endif
        -:  202:
      357:  203:	if (errcodes != MPI_ERRCODES_IGNORE) {
       83:  204:	    for (i=0; i<total_num_processes; i++) {
        -:  205:		/* FIXME: translate the pmi error codes here */
       58:  206:		errcodes[i] = pmi_errcodes[i];
        -:  207:                /* We want to accept if any of the spawns succeeded.
        -:  208:                   Alternatively, this is the same as we want to NOT accept if
        -:  209:                   all of them failed.  should_accept = NAND(e_0, ..., e_n)
        -:  210:                   Remember, success equals false (0). */
       58:  211:                should_accept = should_accept && errcodes[i];
        -:  212:	    }
       25:  213:            should_accept = !should_accept; /* the `N' in NAND */
        -:  214:	}
        -:  215:    }
        -:  216:
      375:  217:    if (errcodes != MPI_ERRCODES_IGNORE) {
       29:  218:        mpi_errno = NMPI_Bcast(&should_accept, 1, MPI_INT, root, comm_ptr->handle);
       29:  219:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  220:
       29:  221:        mpi_errno = NMPI_Bcast(&total_num_processes, 1, MPI_INT, root, comm_ptr->handle);
       29:  222:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  223:        
       29:  224:        mpi_errno = NMPI_Bcast(errcodes, total_num_processes, MPI_INT, root, comm_ptr->handle);
       29:  225:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  226:    }
        -:  227:
      375:  228:    if (should_accept) {
      375:  229:        mpi_errno = MPID_Comm_accept(port_name, NULL, root, comm_ptr, intercomm); 
      375:  230:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  231:    }
        -:  232:    else {
    #####:  233:        MPIU_ERR_SETANDJUMP(mpi_errno, MPI_ERR_OTHER, "**pmi_spawn_multiple");
        -:  234:    }
        -:  235:
      375:  236:    if (comm_ptr->rank == root) {
        -:  237:	/* Close the port opened for the spawned processes to connect to */
      357:  238:	mpi_errno = MPID_Close_port(port_name);
        -:  239:	/* --BEGIN ERROR HANDLING-- */
      357:  240:	if (mpi_errno != MPI_SUCCESS)
        -:  241:	{
    #####:  242:	    MPIU_ERR_POP(mpi_errno);
        -:  243:	}
        -:  244:	/* --END ERROR HANDLING-- */
        -:  245:    }
        -:  246:
      375:  247: fn_exit:
      375:  248:    if (info_keyval_vectors) {
      357:  249:	free_pmi_keyvals(info_keyval_vectors, count, info_keyval_sizes);
      357:  250:	MPIU_Free(info_keyval_sizes);
      357:  251:	MPIU_Free(info_keyval_vectors);
        -:  252:    }
      375:  253:    if (pmi_errcodes) {
      357:  254:	MPIU_Free(pmi_errcodes);
        -:  255:    }
      375:  256:    MPIR_Nest_decr();
        -:  257:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_COMM_SPAWN_MULTIPLE);
      375:  258:    return mpi_errno;
        -:  259: fn_fail:
        -:  260:    goto fn_exit;
        -:  261:}
        -:  262:
        -:  263:/* FIXME: What does this function do?  Who calls it?  Can we assume that
        -:  264:   it is called only dynamic process operations (specifically spawn) 
        -:  265:   are supported?  Do we need the concept of a port? For example,
        -:  266:   could a channel that supported only shared memory call this (it doesn't
        -:  267:   look like it right now, so this could go into util/sock, perhaps?
        -:  268:   
        -:  269:   It might make more sense to have this function provided as a function 
        -:  270:   pointer as part of the channel init setup, particularly since this
        -:  271:   function appears to access channel-specific storage (MPIDI_CH3_Process) */
        -:  272:
        -:  273:
        -:  274:/* This function is used only with mpid_init to set up the parent communicator
        -:  275:   if there is one.  The routine should be in this file because the parent 
        -:  276:   port name is setup with the "preput" arguments to PMI_Spawn_multiple */
        -:  277:static char *parent_port_name = 0;    /* Name of parent port if this
        -:  278:					 process was spawned (and is root
        -:  279:					 of comm world) or null */
        -:  280:
        -:  281:#undef FUNCNAME
        -:  282:#define FUNCNAME MPIDI_CH3_GetParentPort
        -:  283:#undef FCNAME
        -:  284:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  285:int MPIDI_CH3_GetParentPort(char ** parent_port)
      406:  286:{
      406:  287:    int mpi_errno = MPI_SUCCESS;
        -:  288:    int pmi_errno;
        -:  289:    char val[MPIDI_MAX_KVS_VALUE_LEN];
        -:  290:
      406:  291:    if (parent_port_name == NULL)
        -:  292:    {
      406:  293:	char *kvsname = NULL;
        -:  294:	/* We can always use PMI_KVS_Get on our own process group */
      406:  295:	MPIDI_PG_GetConnKVSname( &kvsname );
        -:  296:#ifdef USE_PMI2_API
        -:  297:        {
        -:  298:            int vallen = 0;
        -:  299:            MPIU_THREAD_CS_ENTER(PMI,);
        -:  300:            mpi_errno = PMI2_KVS_Get(kvsname, PMI2_ID_NULL, PARENT_PORT_KVSKEY, val, sizeof(val), &vallen);
        -:  301:            MPIU_THREAD_CS_EXIT(PMI,);
        -:  302:            if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  303:        }
        -:  304:#else
        -:  305:	MPIU_THREAD_CS_ENTER(PMI,);
      406:  306:	pmi_errno = PMI_KVS_Get( kvsname, PARENT_PORT_KVSKEY, val, sizeof(val));
        -:  307:	MPIU_THREAD_CS_EXIT(PMI,);
      406:  308:	if (pmi_errno) {
    #####:  309:            mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_FATAL, FCNAME, __LINE__, MPI_ERR_OTHER, "**pmi_kvs_get", "**pmi_kvs_get %d", pmi_errno);
    #####:  310:            goto fn_exit;
        -:  311:	}
        -:  312:#endif
      406:  313:	parent_port_name = MPIU_Strdup(val);
      406:  314:	if (parent_port_name == NULL) {
    #####:  315:	    MPIU_ERR_POP(mpi_errno); /* FIXME DARIUS */
        -:  316:	}
        -:  317:    }
        -:  318:
      406:  319:    *parent_port = parent_port_name;
        -:  320:
      406:  321: fn_exit:
      406:  322:    return mpi_errno;
        -:  323: fn_fail:
        -:  324:    goto fn_exit;
        -:  325:}
        -:  326:void MPIDI_CH3_FreeParentPort(void)
     3453:  327:{
     3453:  328:    if (parent_port_name) {
      406:  329:	MPIU_Free( parent_port_name );
      406:  330:	parent_port_name = 0;
        -:  331:    }
     3453:  332:}
        -:  333:#endif