-:    0:Source:/home/MPI/testing/mpich2/mpich2/src/mpid/ch3/src/mpidi_pg.c
        -:    0:Graph:mpidi_pg.gcno
        -:    0:Data:mpidi_pg.gcda
        -:    0:Runs:4382
        -:    0:Programs:1376
        -:    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 "mpidimpl.h"
        -:    8:#ifdef USE_PMI2_API
        -:    9:#include "pmi2.h"
        -:   10:#else
        -:   11:#include "pmi.h"
        -:   12:#endif
        -:   13:
        -:   14:#define MAX_JOBID_LEN 1024
        -:   15:
        -:   16:/* FIXME: These routines need a description.  What is their purpose?  Who
        -:   17:   calls them and why?  What does each one do?
        -:   18:*/
        -:   19:static MPIDI_PG_t * MPIDI_PG_list = NULL;
        -:   20:static MPIDI_PG_t * MPIDI_PG_iterator_next = NULL;
        -:   21:static MPIDI_PG_Compare_ids_fn_t MPIDI_PG_Compare_ids_fn;
        -:   22:static MPIDI_PG_Destroy_fn_t MPIDI_PG_Destroy_fn;
        -:   23:
        -:   24:/* Set verbose to 1 to record changes to the process group structure. */
        -:   25:static int verbose = 0;
        -:   26:
        -:   27:/* Key track of the process group corresponding to the MPI_COMM_WORLD 
        -:   28:   of this process */
        -:   29:static MPIDI_PG_t *pg_world = NULL;
        -:   30:
        -:   31:#define MPIDI_MAX_KVS_KEY_LEN      256
        -:   32:
        -:   33:#undef FUNCNAME
        -:   34:#define FUNCNAME MPIDI_PG_Init
        -:   35:#undef FCNAME
        -:   36:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:   37:int MPIDI_PG_Init(int *argc_p, char ***argv_p, 
        -:   38:		  MPIDI_PG_Compare_ids_fn_t compare_ids_fn, 
        -:   39:		  MPIDI_PG_Destroy_fn_t destroy_fn)
     4382:   40:{
     4382:   41:    int mpi_errno = MPI_SUCCESS;
        -:   42:    char *p;
        -:   43:    
     4382:   44:    MPIDI_PG_Compare_ids_fn = compare_ids_fn;
     4382:   45:    MPIDI_PG_Destroy_fn     = destroy_fn;
        -:   46:
        -:   47:    /* Check for debugging options.  We use MPICHD_DBG and -mpichd-dbg 
        -:   48:       to avoid confusion with the code in src/util/dbg/dbg_printf.c */
     4382:   49:    p = getenv( "MPICHD_DBG_PG" );
     4382:   50:    if (p && ( strcmp( p, "YES" ) == 0 || strcmp( p, "yes" ) == 0) )
    #####:   51:	verbose = 1;
     4382:   52:    if (argc_p && argv_p) {
     3710:   53:	int argc = *argc_p, i;
     3710:   54:	char **argv = *argv_p;
        -:   55:        /* applied patch from Juha Jeronen, req #3920 */
     4984:   56:	for (i=1; i<argc && argv[i]; i++) {
     1274:   57:	    if (strcmp( "-mpichd-dbg-pg", argv[i] ) == 0) {
        -:   58:		int j;
    #####:   59:		verbose = 1;
    #####:   60:		for (j=i; j<argc-1; j++) {
    #####:   61:		    argv[j] = argv[j+1];
        -:   62:		}
    #####:   63:		argv[argc-1] = NULL;
    #####:   64:		*argc_p = argc - 1;
    #####:   65:		break;
        -:   66:	    }
        -:   67:	}
        -:   68:    }
        -:   69:
     4382:   70:    return mpi_errno;
        -:   71:}
        -:   72:
        -:   73:#undef FUNCNAME
        -:   74:#define FUNCNAME MPIDI_PG_Finalize
        -:   75:#undef FCNAME
        -:   76:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:   77:/*@ 
        -:   78:   MPIDI_PG_Finalize - Finalize the process groups, including freeing all
        -:   79:   process group structures
        -:   80:  @*/
        -:   81:int MPIDI_PG_Finalize(void)
     4374:   82:{
     4374:   83:    int mpi_errno = MPI_SUCCESS;
        -:   84:    MPIDI_PG_t *pg, *pgNext;
        -:   85:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_FINALIZE);
        -:   86:
        -:   87:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_FINALIZE);
        -:   88:
        -:   89:    /* Print the state of the process groups */
     4374:   90:    if (verbose) {
    #####:   91:	MPIU_PG_Printall( stdout );
        -:   92:    }
        -:   93:
        -:   94:    /* FIXME - straighten out the use of PMI_Finalize - no use after 
        -:   95:       PG_Finalize */
     4374:   96:    if (pg_world->connData) {
        -:   97:#ifdef USE_PMI2_API
        -:   98:        mpi_errno = PMI2_Finalize();
        -:   99:        if (mpi_errno) MPIU_ERR_SET(mpi_errno, MPI_ERR_OTHER, "**ch3|pmi_finalize");
        -:  100:#else
        -:  101:	int rc;
     4374:  102:	rc = PMI_Finalize();
     4374:  103:	if (rc) {
    #####:  104:	    MPIU_ERR_SET1(mpi_errno,MPI_ERR_OTHER, 
        -:  105:			  "**ch3|pmi_finalize", 
        -:  106:			  "**ch3|pmi_finalize %d", rc);
        -:  107:	}
        -:  108:#endif
        -:  109:    }
        -:  110:
        -:  111:    /* Free the storage associated with the process groups */
     4374:  112:    pg = MPIDI_PG_list;
    13281:  113:    while (pg) {
     4533:  114:	pgNext = pg->next;
        -:  115:	
        -:  116:	/* In finalize, we free all process group information, even if
        -:  117:	   the ref count is not zero.  This can happen if the user
        -:  118:	   fails to use MPI_Comm_disconnect on communicators that
        -:  119:	   were created with the dynamic process routines.*/
        -:  120:        /* XXX DJG FIXME-MT should we be checking this? */
        -:  121:	if (MPIU_Object_get_ref(pg) == 0 || 1) {
     4533:  122:	    if (pg == MPIDI_Process.my_pg)
     4374:  123:		MPIDI_Process.my_pg = NULL;
        -:  124:
     4533:  125:	    MPIU_Object_set_ref(pg, 0); /* satisfy assertions in PG_Destroy */
     4533:  126:	    MPIDI_PG_Destroy( pg );
        -:  127:	}
     4533:  128:	pg     = pgNext;
        -:  129:    }
        -:  130:
        -:  131:    /* If COMM_WORLD is still around (it normally should be), 
        -:  132:       try to free it here.  The reason that we need to free it at this 
        -:  133:       point is that comm_world (and comm_self) still exist, and 
        -:  134:       hence the usual process to free the related VC structures will
        -:  135:       not be invoked. */
     4374:  136:    if (MPIDI_Process.my_pg) {
    #####:  137:	MPIDI_PG_Destroy(MPIDI_Process.my_pg);
        -:  138:    } 
     4374:  139:    MPIDI_Process.my_pg = NULL;
        -:  140:
        -:  141:    /* ifdefing out this check because the list will not be NULL in 
        -:  142:       Ch3_finalize because
        -:  143:       one additional reference is retained in MPIDI_Process.my_pg. 
        -:  144:       That reference is released
        -:  145:       only after ch3_finalize returns. If I release it before ch3_finalize, 
        -:  146:       the ssm channel crashes. */
        -:  147:
        -:  148:#if 0
        -:  149:
        -:  150:    if (MPIDI_PG_list != NULL)
        -:  151:    { 
        -:  152:	
        -:  153:	/* --BEGIN ERROR HANDLING-- */
        -:  154:	mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_FATAL, FCNAME, __LINE__, MPI_ERR_INTERN,
        -:  155:        "**dev|pg_finalize|list_not_empty", NULL); 
        -:  156:	/* --END ERROR HANDLING-- */
        -:  157:    }
        -:  158:#endif
        -:  159:
        -:  160:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_FINALIZE);
     4374:  161:    return mpi_errno;
        -:  162:}
        -:  163:
        -:  164:/* FIXME: This routine needs to make it clear that the pg_id, for example
        -:  165:   is saved; thus, if the pg_id is a string, then that string is not 
        -:  166:   copied and must be freed by a PG_Destroy routine */
        -:  167:
        -:  168:/* This routine creates a new process group description and appends it to 
        -:  169:   the list of the known process groups.  The pg_id is saved, not copied.
        -:  170:   The PG_Destroy routine that was set with MPIDI_PG_Init is responsible for
        -:  171:   freeing any storage associated with the pg_id. 
        -:  172:
        -:  173:   The new process group is returned in pg_ptr 
        -:  174:*/
        -:  175:#undef FUNCNAME
        -:  176:#define FUNCNAME MPIDI_PG_Create
        -:  177:#undef FCNAME
        -:  178:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  179:int MPIDI_PG_Create(int vct_sz, void * pg_id, MPIDI_PG_t ** pg_ptr)
     6368:  180:{
     6368:  181:    MPIDI_PG_t * pg = NULL, *pgnext;
        -:  182:    int p;
     6368:  183:    int mpi_errno = MPI_SUCCESS;
     6368:  184:    MPIU_CHKPMEM_DECL(2);
        -:  185:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_CREATE);
        -:  186:
        -:  187:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_CREATE);
        -:  188:    
     6368:  189:    MPIU_CHKPMEM_MALLOC(pg,MPIDI_PG_t*,sizeof(MPIDI_PG_t),mpi_errno,"pg");
    12736:  190:    MPIU_CHKPMEM_MALLOC(pg->vct,MPIDI_VC_t *,sizeof(MPIDI_VC_t)*vct_sz,
        -:  191:			mpi_errno,"pg->vct");
        -:  192:
     6368:  193:    if (verbose) {
    #####:  194:	fprintf( stdout, "Creating a process group of size %d\n", vct_sz );
    #####:  195:	fflush(stdout);
        -:  196:    }
        -:  197:
     6368:  198:    pg->handle = 0;
        -:  199:    /* The reference count indicates the number of vc's that are or 
        -:  200:       have been in use and not disconnected. It starts at zero,
        -:  201:       except for MPI_COMM_WORLD. */
     6368:  202:    MPIU_Object_set_ref(pg, 0);
     6368:  203:    pg->size = vct_sz;
     6368:  204:    pg->id   = pg_id;
        -:  205:    /* Initialize the connection information to null.  Use
        -:  206:       the appropriate MPIDI_PG_InitConnXXX routine to set up these 
        -:  207:       fields */
     6368:  208:    pg->connData           = 0;
     6368:  209:    pg->getConnInfo        = 0;
     6368:  210:    pg->connInfoToString   = 0;
     6368:  211:    pg->connInfoFromString = 0;
     6368:  212:    pg->freeConnInfo       = 0;
        -:  213:
    30185:  214:    for (p = 0; p < vct_sz; p++)
        -:  215:    {
        -:  216:	/* Initialize device fields in the VC object */
    23817:  217:	MPIDI_VC_Init(&pg->vct[p], pg, p);
        -:  218:    }
        -:  219:
        -:  220:    /* We may first need to initialize the channel before calling the channel 
        -:  221:       VC init functions.  This routine may be a no-op; look in the 
        -:  222:       ch3_init.c file in each channel */
     6368:  223:    MPIU_CALL(MPIDI_CH3,PG_Init( pg ));
        -:  224:
        -:  225:    /* These are now done in MPIDI_VC_Init */
        -:  226:#if 0
        -:  227:    for (p = 0; p < vct_sz; p++)
        -:  228:    {
        -:  229:	/* Initialize the channel fields in the VC object */
        -:  230:	MPIDI_CH3_VC_Init( &pg->vct[p] );
        -:  231:    }
        -:  232:#endif
        -:  233:
        -:  234:    /* The first process group is always the world group */
     6368:  235:    if (!pg_world) { pg_world = pg; }
        -:  236:
        -:  237:    /* Add pg's at the tail so that comm world is always the first pg */
     6368:  238:    pg->next = 0;
     6368:  239:    if (!MPIDI_PG_list)
        -:  240:    {
     4382:  241:	MPIDI_PG_list = pg;
        -:  242:    }
        -:  243:    else
        -:  244:    {
     1986:  245:	pgnext = MPIDI_PG_list; 
     4760:  246:	while (pgnext->next)
        -:  247:	{
      788:  248:	    pgnext = pgnext->next;
        -:  249:	}
     1986:  250:	pgnext->next = pg;
        -:  251:    }
     6368:  252:    *pg_ptr = pg;
        -:  253:    
     6368:  254:  fn_exit:
        -:  255:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_CREATE);
     6368:  256:    return mpi_errno;
        -:  257:    
        -:  258:  fn_fail:
    #####:  259:    MPIU_CHKPMEM_REAP();
        -:  260:    goto fn_exit;
        -:  261:}
        -:  262:
        -:  263:#undef FUNCNAME
        -:  264:#define FUNCNAME MPIDI_PG_Destroy
        -:  265:#undef FCNAME
        -:  266:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  267:int MPIDI_PG_Destroy(MPIDI_PG_t * pg)
     6360:  268:{
        -:  269:    MPIDI_PG_t * pg_prev;
        -:  270:    MPIDI_PG_t * pg_cur;
        -:  271:    int i;
     6360:  272:    int mpi_errno = MPI_SUCCESS;
        -:  273:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_DESTROY);
        -:  274:
        -:  275:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_DESTROY);
        -:  276:
     6360:  277:    MPIU_Assert(MPIU_Object_get_ref(pg) == 0);
        -:  278:
     6360:  279:    pg_prev = NULL;
     6360:  280:    pg_cur = MPIDI_PG_list;
    15215:  281:    while(pg_cur != NULL)
        -:  282:    {
     8855:  283:	if (pg_cur == pg)
        -:  284:	{
     6360:  285:	    if (MPIDI_PG_iterator_next == pg)
        -:  286:	    { 
    #####:  287:		MPIDI_PG_iterator_next = MPIDI_PG_iterator_next->next;
        -:  288:	    }
        -:  289:
     6360:  290:            if (pg_prev == NULL)
     4533:  291:                MPIDI_PG_list = pg->next; 
        -:  292:            else
     1827:  293:                pg_prev->next = pg->next;
        -:  294:
        -:  295:            MPIU_DBG_MSG_FMT(CH3_DISCONNECT, VERBOSE, (MPIU_DBG_FDEST, "destroying pg=%p pg->id=%s", pg, (char *)pg->id));
        -:  296:
    30162:  297:            for (i = 0; i < pg->size; ++i) {
        -:  298:                /* FIXME it would be good if we could make this assertion.
        -:  299:                   Unfortunately, either:
        -:  300:                   1) We're not being disciplined and some caller of this
        -:  301:                      function doesn't bother to manage all the refcounts
        -:  302:                      because he thinks he knows better.  Annoying, but not
        -:  303:                      strictly a bug.
        -:  304:		      (wdg - actually, that is a bug - managing the ref
        -:  305:		      counts IS required and missing one is a bug.)
        -:  306:                   2) There is a real bug lurking out there somewhere and we
        -:  307:                      just haven't hit it in the tests yet.  */
        -:  308:                /*MPIU_Assert(MPIU_Object_get_ref(pg->vct[i]) == 0);*/
        -:  309:
        -:  310:                MPIU_DBG_MSG_FMT(CH3_DISCONNECT, VERBOSE, (MPIU_DBG_FDEST, "about to free pg->vct=%p which contains vc=%p", pg->vct, &pg->vct[i]));
        -:  311:
        -:  312:                /* This used to be handled in MPID_VCRT_Release, but that was
        -:  313:                   not the right place to do this.  The VC should only be freed
        -:  314:                   when the PG that it belongs to is freed, not just when the
        -:  315:                   VC's refcount drops to zero. [goodell@ 2008-06-13] */
        -:  316:		/* In that case, the fact that the VC is in the PG should
        -:  317:		   increment the ref count - reflecting the fact that the
        -:  318:		   use in the PG constitutes a reference-count-incrementing
        -:  319:		   use.  Alternately, if the PG is able to recreate a VC, 
        -:  320:		   and can thus free unused (or idle) VCs, it should be allowed
        -:  321:		   to do so.  [wdg 2008-08-31] */
    23802:  322:                mpi_errno = MPIU_CALL(MPIDI_CH3,VC_Destroy(&(pg->vct[i])));
    23802:  323:                if (mpi_errno) { MPIU_ERR_POP(mpi_errno); }
        -:  324:            }
        -:  325:
     6360:  326:	    MPIDI_PG_Destroy_fn(pg);
     6360:  327:	    MPIU_Free(pg->vct);
     6360:  328:	    if (pg->connData) {
     6360:  329:		if (pg->freeConnInfo) {
     6360:  330:		    (*pg->freeConnInfo)( pg );
        -:  331:		}
        -:  332:		else {
    #####:  333:		    MPIU_Free(pg->connData);
        -:  334:		}
        -:  335:	    }
     6360:  336:	    mpi_errno = MPIU_CALL(MPIDI_CH3,PG_Destroy(pg));
     6360:  337:	    MPIU_Free(pg);
        -:  338:
     6360:  339:	    goto fn_exit;
        -:  340:	}
        -:  341:
     2495:  342:	pg_prev = pg_cur;
     2495:  343:	pg_cur = pg_cur->next;
        -:  344:    }
        -:  345:
        -:  346:    /* PG not found if we got here */
    #####:  347:    MPIU_ERR_SET1(mpi_errno,MPI_ERR_OTHER,
        -:  348:		  "**dev|pg_not_found", "**dev|pg_not_found %p", pg);
        -:  349:
     6360:  350:  fn_exit:
        -:  351:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_DESTROY);
     6360:  352:    return mpi_errno;
        -:  353:  fn_fail:
        -:  354:    goto fn_exit;
        -:  355:}
        -:  356:
        -:  357:#undef FUNCNAME
        -:  358:#define FUNCNAME MPIDI_PG_Find
        -:  359:#undef FCNAME
        -:  360:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  361:int MPIDI_PG_Find(void * id, MPIDI_PG_t ** pg_ptr)
    10776:  362:{
        -:  363:    MPIDI_PG_t * pg;
    10776:  364:    int mpi_errno = MPI_SUCCESS;
        -:  365:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_FIND);
        -:  366:
        -:  367:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_FIND);
        -:  368:    
    10776:  369:    pg = MPIDI_PG_list;
    26193:  370:    while (pg != NULL)
        -:  371:    {
    13431:  372:	if (MPIDI_PG_Compare_ids_fn(id, pg->id) != FALSE)
        -:  373:	{
     8790:  374:	    *pg_ptr = pg;
     8790:  375:	    goto fn_exit;
        -:  376:	}
        -:  377:
     4641:  378:	pg = pg->next;
        -:  379:    }
        -:  380:
     1986:  381:    *pg_ptr = NULL;
        -:  382:
    10776:  383:  fn_exit:
        -:  384:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_FIND);
    10776:  385:    return mpi_errno;
        -:  386:}
        -:  387:
        -:  388:
        -:  389:#undef FUNCNAME
        -:  390:#define FUNCNAME MPIDI_PG_Id_compare
        -:  391:#undef FCNAME
        -:  392:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  393:int MPIDI_PG_Id_compare(void * id1, void *id2)
     1567:  394:{
     1567:  395:    return MPIDI_PG_Compare_ids_fn(id1, id2);
        -:  396:}
        -:  397:
        -:  398:/* iter always points at the next element */
        -:  399:#undef FUNCNAME
        -:  400:#define FUNCNAME MPIDI_PG_Get_next
        -:  401:#undef FCNAME
        -:  402:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  403:int MPIDI_PG_Get_next(MPIDI_PG_iterator *iter, MPIDI_PG_t ** pg_ptr)
     9263:  404:{
     9263:  405:    *pg_ptr = (*iter);
     9263:  406:    if ((*iter) != NULL) {
     9262:  407:        (*iter) = (*iter)->next;
        -:  408:    }
        -:  409:
     9263:  410:    return MPI_SUCCESS;
        -:  411:}
        -:  412:
        -:  413:#undef FUNCNAME
        -:  414:#define FUNCNAME MPIDI_PG_Has_next
        -:  415:#undef FCNAME
        -:  416:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  417:int MPIDI_PG_Has_next(MPIDI_PG_iterator *iter)
    #####:  418:{
    #####:  419:    return (*iter != NULL);
        -:  420:}
        -:  421:
        -:  422:#undef FUNCNAME
        -:  423:#define FUNCNAME MPIDI_PG_Get_iterator
        -:  424:#undef FCNAME
        -:  425:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  426:int MPIDI_PG_Get_iterator(MPIDI_PG_iterator *iter)
     9240:  427:{
     9240:  428:    *iter = MPIDI_PG_list;
     9240:  429:    return MPI_SUCCESS;
        -:  430:}
        -:  431:
        -:  432:/* FIXME: What does DEV_IMPLEMENTS_KVS mean?  Why is it used?  Who uses 
        -:  433:   PG_To_string and why?  */
        -:  434:
        -:  435:#ifdef MPIDI_DEV_IMPLEMENTS_KVS
        -:  436:
        -:  437:/* PG_To_string is used in the implementation of connect/accept (and 
        -:  438:   hence in spawn) in ch3u_port.c */
        -:  439:/* Note: Allocated memory that is returned in str_ptr.  The user of
        -:  440:   this routine must free that data */
        -:  441:#undef FUNCNAME
        -:  442:#define FUNCNAME MPIDI_PG_To_string
        -:  443:#undef FCNAME
        -:  444:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  445:int MPIDI_PG_To_string(MPIDI_PG_t *pg_ptr, char **str_ptr, int *lenStr)
     1537:  446:{
     1537:  447:    int mpi_errno = MPI_SUCCESS;
        -:  448:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_TO_STRING);
        -:  449:
        -:  450:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_TO_STRING);
        -:  451:
        -:  452:    /* Replace this with the new string */
     1537:  453:    if (pg_ptr->connInfoToString) {
     1537:  454:	(*pg_ptr->connInfoToString)( str_ptr, lenStr, pg_ptr );
        -:  455:    }
        -:  456:    else {
    #####:  457:	MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_INTERN,"**noConnInfoToString");
        -:  458:    }
        -:  459:
        -:  460:    /*printf( "PgToString: Pg string is %s\n", *str_ptr ); fflush(stdout);*/
     1537:  461:fn_exit:
        -:  462:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_TO_STRING);
     1537:  463:    return mpi_errno;
        -:  464:fn_fail:
        -:  465:    goto fn_exit;
        -:  466:}
        -:  467:
        -:  468:/* This routine takes a string description of a process group (created with 
        -:  469:   MPIDI_PG_To_string, usually on a different process) and returns a pointer to
        -:  470:   the matching process group.  If the group already exists, flag is set to 
        -:  471:   false.  If the group does not exist, it is created with MPIDI_PG_Create (and
        -:  472:   hence is added to the list of active process groups) and flag is set to 
        -:  473:   true.  In addition, the connection information is set up using the 
        -:  474:   information in the input string.
        -:  475:*/
        -:  476:#undef FUNCNAME
        -:  477:#define FUNCNAME MPIDI_PG_Create_from_string
        -:  478:#undef FCNAME
        -:  479:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  480:int MPIDI_PG_Create_from_string(const char * str, MPIDI_PG_t ** pg_pptr, 
        -:  481:				int *flag)
     3404:  482:{
     3404:  483:    int mpi_errno = MPI_SUCCESS;
        -:  484:    const char *p;
        -:  485:    int vct_sz;
     3404:  486:    MPIDI_PG_t *existing_pg, *pg_ptr=0;
        -:  487:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_CREATE_FROM_STRING);
        -:  488:
        -:  489:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_CREATE_FROM_STRING);
        -:  490:
        -:  491:    /*printf( "PgCreateFromString: Creating pg from %s\n", str ); 
        -:  492:      fflush(stdout); */
        -:  493:    /* The pg_id is at the beginning of the string, so we can just pass
        -:  494:       it to the find routine */
        -:  495:    /* printf( "Looking for pg with id %s\n", str );fflush(stdout); */
     3404:  496:    mpi_errno = MPIDI_PG_Find((void *)str, &existing_pg);
     3404:  497:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  498:
     3404:  499:    if (existing_pg != NULL) {
        -:  500:	/* return the existing PG */
     1418:  501:	*pg_pptr = existing_pg;
     1418:  502:	*flag = 0;
        -:  503:	/* Note that the memory for the pg_id is freed in the exit */
     1418:  504:	goto fn_exit;
        -:  505:    }
     1986:  506:    *flag = 1;
        -:  507:
        -:  508:    /* Get the size from the string */
     1986:  509:    p = str;
     1986:  510:    while (*p) p++; p++;
     1986:  511:    vct_sz = atoi(p);
        -:  512:
     1986:  513:    mpi_errno = MPIDI_PG_Create(vct_sz, (void *)str, pg_pptr);
     1986:  514:    if (mpi_errno != MPI_SUCCESS) {
    #####:  515:	MPIU_ERR_POP(mpi_errno);
        -:  516:    }
        -:  517:    
     1986:  518:    pg_ptr = *pg_pptr;
     1986:  519:    pg_ptr->id = MPIU_Strdup( str );
        -:  520:    
        -:  521:    /* Set up the functions to use strings to manage connection information */
     1986:  522:    MPIDI_PG_InitConnString( pg_ptr );
     1986:  523:    (*pg_ptr->connInfoFromString)( str, pg_ptr );
        -:  524:
     3404:  525:fn_exit:
        -:  526:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_CREATE_FROM_STRING);
     3404:  527:    return mpi_errno;
        -:  528:fn_fail:
        -:  529:    goto fn_exit;
        -:  530:}
        -:  531:
        -:  532:#ifdef HAVE_CTYPE_H
        -:  533:/* Needed for isdigit */
        -:  534:#include <ctype.h>
        -:  535:#endif
        -:  536:
        -:  537:/* Convert a process group id into a number.  This is a hash-based approach,
        -:  538: * which has the potential for some collisions.  This is an alternative to the
        -:  539: * previous approach that caused req#3930, which was to sum up the values of the
        -:  540: * characters.  The summing approach worked OK when the id's were all similar
        -:  541: * but with an incrementing prefix or suffix, but terrible for a 32 hex-character
        -:  542: * UUID type of id.
        -:  543: *
        -:  544: * FIXME It would really be best if the PM could give us this value.
        -:  545: */
        -:  546:void MPIDI_PG_IdToNum( MPIDI_PG_t *pg, int *id )
    12667:  547:{
    12667:  548:    const char *p = (const char *)pg->id;
    12667:  549:    int pgid = 0;
        -:  550:
   464117:  551:    while (*p) {
   438783:  552:        pgid += *p++;
   438783:  553:        pgid += (pgid << 10);
   438783:  554:        pgid ^= (pgid >> 6);
        -:  555:    }
    12667:  556:    pgid += (pgid << 3);
    12667:  557:    pgid ^= (pgid >> 11);
    12667:  558:    pgid += (pgid << 15);
        -:  559:
        -:  560:    /* restrict to 31 bits */
    12667:  561:    *id = (pgid & 0x7fffffff);
    12667:  562:}
        -:  563:#else
        -:  564:/* FIXME: This is a temporary hack for devices that do not define
        -:  565:   MPIDI_DEV_IMPLEMENTS_KVS
        -:  566:   FIXME: MPIDI_DEV_IMPLEMENTS_KVS should be removed
        -:  567: */
        -:  568:void MPIDI_PG_IdToNum( MPIDI_PG_t *pg, int *id )
        -:  569:{
        -:  570:    *id = 0;
        -:  571:}
        -:  572:#endif
        -:  573:
        -:  574:/*
        -:  575: * Managing connection information for process groups
        -:  576: * 
        -:  577: *
        -:  578: */
        -:  579:
        -:  580:/* Setting a process's connection information 
        -:  581:   
        -:  582:   This is a collective call (for scalability) over all of the processes in 
        -:  583:   the same MPI_COMM_WORLD.
        -:  584:*/
        -:  585:#undef FUNCNAME
        -:  586:#define FUNCNAME MPIDI_PG_SetConnInfo
        -:  587:#undef FCNAME
        -:  588:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  589:int MPIDI_PG_SetConnInfo( int rank, const char *connString )
     4382:  590:{
        -:  591:#ifdef USE_PMI2_API
        -:  592:    int mpi_errno = MPI_SUCCESS;
        -:  593:    int len;
        -:  594:    char key[PMI2_MAX_KEYLEN];
        -:  595:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_SetConnInfo);
        -:  596:
        -:  597:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_SetConnInfo);
        -:  598:
        -:  599:    len = MPIU_Snprintf(key, sizeof(key), "P%d-businesscard", rank);
        -:  600:    MPIU_ERR_CHKANDJUMP1(len < 0 || len > sizeof(key), mpi_errno, MPI_ERR_OTHER, "**snprintf", "**snprintf %d", len);
        -:  601:
        -:  602:    mpi_errno = PMI2_KVS_Put(key, connString);
        -:  603:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  604:
        -:  605:    mpi_errno = PMI2_KVS_Fence();
        -:  606:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  607:    
        -:  608: fn_exit:
        -:  609:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_SetConnInfo);
        -:  610:    return mpi_errno;
        -:  611: fn_fail:
        -:  612:    goto fn_exit;
        -:  613:#else
     4382:  614:    int mpi_errno = MPI_SUCCESS;
        -:  615:    int pmi_errno;
        -:  616:    int len;
        -:  617:    char key[128];
        -:  618:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_SetConnInfo);
        -:  619:
        -:  620:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_SetConnInfo);
        -:  621:
     4382:  622:    MPIU_Assert(pg_world->connData);
        -:  623:    
     4382:  624:    len = MPIU_Snprintf(key, sizeof(key), "P%d-businesscard", rank);
     4382:  625:    if (len < 0 || len > sizeof(key)) {
    #####:  626:	MPIU_ERR_SETANDJUMP1(mpi_errno,MPI_ERR_OTHER, "**snprintf",
        -:  627:			     "**snprintf %d", len);
        -:  628:    }
     4382:  629:    pmi_errno = PMI_KVS_Put(pg_world->connData, key, connString );
     4382:  630:    if (pmi_errno != PMI_SUCCESS) {
    #####:  631:	MPIU_ERR_SETANDJUMP1(mpi_errno,MPI_ERR_OTHER, "**pmi_kvs_put",
        -:  632:			     "**pmi_kvs_put %d", pmi_errno);
        -:  633:    }
     4382:  634:    pmi_errno = PMI_KVS_Commit(pg_world->connData);
     4382:  635:    if (pmi_errno != PMI_SUCCESS) {
    #####:  636:	MPIU_ERR_SETANDJUMP1(mpi_errno,MPI_ERR_OTHER, "**pmi_kvs_commit",
        -:  637:			     "**pmi_kvs_commit %d", pmi_errno);
        -:  638:    }
        -:  639:    
     4382:  640:    pmi_errno = PMI_Barrier();
     4382:  641:    if (pmi_errno != PMI_SUCCESS) {
    #####:  642:	MPIU_ERR_SETANDJUMP1(mpi_errno,MPI_ERR_OTHER, "**pmi_barrier",
        -:  643:			     "**pmi_barrier %d", pmi_errno);
        -:  644:    }
     4382:  645: fn_exit:
        -:  646:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_SetConnInfo);
     4382:  647:    return mpi_errno;
        -:  648: fn_fail:
        -:  649:    goto fn_exit;
        -:  650:#endif
        -:  651:}
        -:  652:
        -:  653:/* For all of these routines, the format of the process group description
        -:  654:   that is created and used by the connTo/FromString routines is this:
        -:  655:   (All items are strings, terminated by null)
        -:  656:
        -:  657:   process group id string
        -:  658:   sizeof process group (as string)
        -:  659:   conninfo for rank 0
        -:  660:   conninfo for rank 1
        -:  661:   ...
        -:  662:
        -:  663:   The "conninfo for rank 0" etc. for the original (MPI_COMM_WORLD)
        -:  664:   process group are stored in the PMI_KVS space with the keys 
        -:  665:   p<rank>-businesscard .  
        -:  666:
        -:  667:   Fixme: Add a routine to publish the connection info to this file so that
        -:  668:   the key for the businesscard is defined in just this one file.
        -:  669:*/
        -:  670:
        -:  671:
        -:  672:/* The "KVS" versions are for the process group to which the calling 
        -:  673:   process belongs.  These use the PMI_KVS routines to access the
        -:  674:   process information */
        -:  675:#undef FUNCNAME
        -:  676:#define FUNCNAME getConnInfoKVS
        -:  677:#undef FCNAME
        -:  678:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  679:static int getConnInfoKVS( int rank, char *buf, int bufsize, MPIDI_PG_t *pg )
     9012:  680:{
        -:  681:#ifdef USE_PMI2_API
        -:  682:    char key[MPIDI_MAX_KVS_KEY_LEN];
        -:  683:    int  mpi_errno = MPI_SUCCESS, rc;
        -:  684:    int vallen;
        -:  685:
        -:  686:    rc = MPIU_Snprintf(key, MPIDI_MAX_KVS_KEY_LEN, "P%d-businesscard", rank );
        -:  687:    if (rc < 0 || rc > MPIDI_MAX_KVS_KEY_LEN) {
        -:  688:	MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**nomem");
        -:  689:    }
        -:  690:
        -:  691:    mpi_errno = PMI2_KVS_Get(pg->connData, PMI2_ID_NULL, key, buf, bufsize, &vallen);
        -:  692:    if (mpi_errno) {
        -:  693:	MPIDI_PG_CheckForSingleton();
        -:  694:	mpi_errno = PMI2_KVS_Get(pg->connData, PMI2_ID_NULL, key, buf, bufsize, &vallen);
        -:  695:        if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  696:    }
        -:  697: fn_exit:
        -:  698:    return mpi_errno;
        -:  699: fn_fail:
        -:  700:    goto fn_exit;
        -:  701:#else
        -:  702:    char key[MPIDI_MAX_KVS_KEY_LEN];
     9012:  703:    int  mpi_errno = MPI_SUCCESS, rc, pmi_errno;
        -:  704:
     9012:  705:    rc = MPIU_Snprintf(key, MPIDI_MAX_KVS_KEY_LEN, "P%d-businesscard", rank );
     9012:  706:    if (rc < 0 || rc > MPIDI_MAX_KVS_KEY_LEN) {
    #####:  707:	MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**nomem");
        -:  708:    }
     9012:  709:    pmi_errno = PMI_KVS_Get(pg->connData, key, buf, bufsize );
     9012:  710:    if (pmi_errno) {
    #####:  711:	MPIDI_PG_CheckForSingleton();
    #####:  712:	pmi_errno = PMI_KVS_Get(pg->connData, key, buf, bufsize );
        -:  713:    }
     9012:  714:    if (pmi_errno) {
    #####:  715:	MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**pmi_kvs_get");
        -:  716:    }
        -:  717:
     9012:  718: fn_exit:
     9012:  719:    return mpi_errno;
        -:  720: fn_fail:
        -:  721:    goto fn_exit;
        -:  722:#endif
        -:  723:}
        -:  724:
        -:  725:/* *slen is the length of the string, including the null terminator.  So if the
        -:  726:   resulting string is |foo\0bar\0|, then *slen == 8. */
        -:  727:static int connToStringKVS( char **buf_p, int *slen, MPIDI_PG_t *pg )
     1336:  728:{
     1336:  729:    char *string = 0;
     1336:  730:    char *pg_idStr = (char *)pg->id;      /* In the PMI/KVS space,
        -:  731:					     the pg id is a string */
        -:  732:    char buf[MPIDI_MAX_KVS_VALUE_LEN];
     1336:  733:    int   i, j, vallen, rc, mpi_errno = MPI_SUCCESS, len;
        -:  734:    int   curSlen;
        -:  735:
        -:  736:    /* Make an initial allocation of a string with an estimate of the
        -:  737:       needed space */
     1336:  738:    len = 0;
     1336:  739:    curSlen = 10 + pg->size * 128;
     1336:  740:    string = (char *)MPIU_Malloc( curSlen );
        -:  741:
        -:  742:    /* Start with the id of the pg */
    49432:  743:    while (*pg_idStr && len < curSlen) 
    46760:  744:	string[len++] = *pg_idStr++;
     1336:  745:    string[len++] = 0;
        -:  746:    
        -:  747:    /* Add the size of the pg */
     1336:  748:    MPIU_Snprintf( &string[len], curSlen - len, "%d", pg->size );
     1336:  749:    while (string[len]) len++;
     1336:  750:    len++;
        -:  751:
     3974:  752:    for (i=0; i<pg->size; i++) {
     2638:  753:	rc = getConnInfoKVS( i, buf, MPIDI_MAX_KVS_VALUE_LEN, pg );
     2638:  754:	if (rc) {
    #####:  755:	    MPIU_Internal_error_printf( 
        -:  756:		    "Panic: getConnInfoKVS failed for %s (rc=%d)\n", 
        -:  757:		    (char *)pg->id, rc );
        -:  758:	}
        -:  759:#ifndef USE_PERSISTENT_SHARED_MEMORY
        -:  760:	/* FIXME: This is a hack to avoid including shared-memory 
        -:  761:	   queue names in the business card that may be used
        -:  762:	   by processes that were not part of the same COMM_WORLD. 
        -:  763:	   To fix this, the shared memory channels should look at the
        -:  764:	   returned connection info and decide whether to use 
        -:  765:	   sockets or shared memory by determining whether the
        -:  766:	   process is in the same MPI_COMM_WORLD. */
        -:  767:	/* FIXME: The more general problem is that the connection information
        -:  768:	   needs to include some information on the range of validity (e.g.,
        -:  769:	   all processes, same comm world, particular ranks), and that
        -:  770:	   representation needs to be scalable */
        -:  771:/*	printf( "Adding key %s value %s\n", key, val ); */
        -:  772:	{
     2638:  773:	char *p = strstr( buf, "$shm_host" );
     2638:  774:	if (p) p[1] = 0;
        -:  775:	/*	    printf( "(fixed) Adding key %s value %s\n", key, val ); */
        -:  776:	}
        -:  777:#endif
        -:  778:	/* Add the information to the output buffer */
     2638:  779:	vallen = strlen(buf);
        -:  780:	/* Check that this will fix in the remaining space */
     2638:  781:	if (len + vallen + 1 >= curSlen) {
    #####:  782:	    char *nstring = 0;
    #####:  783:            curSlen += (pg->size - i) * (vallen + 1 );
    #####:  784:	    nstring = MPIU_Realloc( string, curSlen);
    #####:  785:	    if (!nstring) {
    #####:  786:		MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER,"**nomem");
        -:  787:	    }
    #####:  788:	    string = nstring;
        -:  789:	}
        -:  790:	/* Append to string */
   153004:  791:	for (j=0; j<vallen+1; j++) {
   150366:  792:	    string[len++] = buf[j];
        -:  793:	}
        -:  794:    }
        -:  795:
     1336:  796:    MPIU_Assert(len <= curSlen);
        -:  797:
     1336:  798:    *buf_p = string;
     1336:  799:    *slen  = len;
     1336:  800: fn_exit:
     1336:  801:    return mpi_errno;
    #####:  802: fn_fail:
    #####:  803:    if (string) MPIU_Free(string);
        -:  804:    goto fn_exit;
        -:  805:}
        -:  806:static int connFromStringKVS( const char *buf ATTRIBUTE((unused)), 
        -:  807:			      MPIDI_PG_t *pg ATTRIBUTE((unused)) )
    #####:  808:{
        -:  809:    /* Fixme: this should be a failure to call this routine */
    #####:  810:    return MPI_SUCCESS;
        -:  811:}
        -:  812:static int connFreeKVS( MPIDI_PG_t *pg )
     4374:  813:{
     4374:  814:    if (pg->connData) {
     4374:  815:	MPIU_Free( pg->connData );
        -:  816:    }
     4374:  817:    return MPI_SUCCESS;
        -:  818:}
        -:  819:
        -:  820:
        -:  821:#undef FUNCNAME
        -:  822:#define FUNCNAME MPIDI_PG_InitConnKVS
        -:  823:#undef FCNAME
        -:  824:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  825:int MPIDI_PG_InitConnKVS( MPIDI_PG_t *pg )
     4382:  826:{
        -:  827:#ifdef USE_PMI2_API
        -:  828:    int mpi_errno = MPI_SUCCESS;
        -:  829:    
        -:  830:    pg->connData = (char *)MPIU_Malloc(MAX_JOBID_LEN);
        -:  831:    if (pg->connData == NULL) {
        -:  832:	MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER, "**nomem");
        -:  833:    }
        -:  834:    
        -:  835:    mpi_errno = PMI2_Job_GetId(pg->connData, MAX_JOBID_LEN);
        -:  836:    if (mpi_errno) MPIU_ERR_POP(mpi_errno);
        -:  837:#else
        -:  838:    int pmi_errno, kvs_name_sz;
     4382:  839:    int mpi_errno = MPI_SUCCESS;
        -:  840:
     4382:  841:    pmi_errno = PMI_KVS_Get_name_length_max( &kvs_name_sz );
     4382:  842:    if (pmi_errno != PMI_SUCCESS) {
    #####:  843:	MPIU_ERR_SETANDJUMP1(mpi_errno,MPI_ERR_OTHER, 
        -:  844:			     "**pmi_kvs_get_name_length_max", 
        -:  845:			     "**pmi_kvs_get_name_length_max %d", pmi_errno);
        -:  846:    }
        -:  847:    
     4382:  848:    pg->connData = (char *)MPIU_Malloc(kvs_name_sz + 1);
     4382:  849:    if (pg->connData == NULL) {
    #####:  850:	MPIU_ERR_SETANDJUMP(mpi_errno,MPI_ERR_OTHER, "**nomem");
        -:  851:    }
        -:  852:    
     4382:  853:    pmi_errno = PMI_KVS_Get_my_name(pg->connData, kvs_name_sz);
     4382:  854:    if (pmi_errno != PMI_SUCCESS) {
    #####:  855:	MPIU_ERR_SETANDJUMP1(mpi_errno,MPI_ERR_OTHER, 
        -:  856:			     "**pmi_kvs_get_my_name", 
        -:  857:			     "**pmi_kvs_get_my_name %d", pmi_errno);
        -:  858:    }
        -:  859:#endif
     4382:  860:    pg->getConnInfo        = getConnInfoKVS;
     4382:  861:    pg->connInfoToString   = connToStringKVS;
     4382:  862:    pg->connInfoFromString = connFromStringKVS;
     4382:  863:    pg->freeConnInfo       = connFreeKVS;
        -:  864:
     4382:  865: fn_exit:
     4382:  866:    return mpi_errno;
    #####:  867: fn_fail:
    #####:  868:    if (pg->connData) { MPIU_Free(pg->connData); }
        -:  869:    goto fn_exit;
        -:  870:}
        -:  871:
        -:  872:/* Return the kvsname associated with the MPI_COMM_WORLD of this process. */
        -:  873:int MPIDI_PG_GetConnKVSname( char ** kvsname )
     4346:  874:{
     4346:  875:    *kvsname = pg_world->connData;
     4346:  876:    return MPI_SUCCESS;
        -:  877:}
        -:  878:
        -:  879:/* For process groups that are not our MPI_COMM_WORLD, store the connection
        -:  880:   information in an array of strings.  These routines and structure
        -:  881:   implement the access to this information. */
        -:  882:typedef struct {
        -:  883:    int     toStringLen;   /* Length needed to encode this connection info */
        -:  884:    char ** connStrings;   /* pointer to an array, indexed by rank, containing
        -:  885:			      connection information */
        -:  886:} MPIDI_ConnInfo;
        -:  887:
        -:  888:static int getConnInfo( int rank, char *buf, int bufsize, MPIDI_PG_t *pg )
      997:  889:{
      997:  890:    MPIDI_ConnInfo *connInfo = (MPIDI_ConnInfo *)pg->connData;
        -:  891:
        -:  892:    /* printf( "Entering getConnInfo\n" ); fflush(stdout); */
      997:  893:    if (!connInfo || !connInfo->connStrings || !connInfo->connStrings[rank]) {
        -:  894:	/* FIXME: Turn this into a valid error code create/return */
    #####:  895:	printf( "Fatal error in getConnInfo (rank = %d)\n", rank );
    #####:  896:	printf( "connInfo = %p\n", connInfo );fflush(stdout);
    #####:  897:	if (connInfo) {
    #####:  898:	    printf( "connInfo->connStrings = %p\n", connInfo->connStrings );
        -:  899:	}
        -:  900:	/* Fatal error.  Connection information missing */
    #####:  901:	fflush(stdout);   
        -:  902:    }
        -:  903:
        -:  904:    /* printf( "Copying %s to buf\n", connInfo->connStrings[rank] ); fflush(stdout); */
        -:  905:    
      997:  906:    MPIU_Strncpy( buf, connInfo->connStrings[rank], bufsize );
      997:  907:    return MPI_SUCCESS;
        -:  908:}
        -:  909:
        -:  910:#undef FUNCNAME
        -:  911:#define FUNCNAME connToString
        -:  912:#undef FCNAME
        -:  913:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -:  914:static int connToString( char **buf_p, int *slen, MPIDI_PG_t *pg )
      201:  915:{
      201:  916:    int mpi_errno = MPI_SUCCESS;
      201:  917:    char *str = NULL, *pg_id;
      201:  918:    int  i, len=0;
      201:  919:    MPIU_CHKPMEM_DECL(1);
      201:  920:    MPIDI_ConnInfo *connInfo = (MPIDI_ConnInfo *)pg->connData;
        -:  921:
        -:  922:    /* Create this from the string array */
      201:  923:    MPIU_CHKPMEM_MALLOC(str, char *, connInfo->toStringLen, mpi_errno, "str");
        -:  924:
        -:  925:#if defined(MPICH_DEBUG_MEMINIT)
        -:  926:    memset(str, 0, connInfo->toStringLen);
        -:  927:#endif
        -:  928:
      201:  929:    pg_id = pg->id;
        -:  930:    /* FIXME: This is a hack, and it doesn't even work */
        -:  931:    /*    MPIDI_PrintConnStrToFile( stdout, __FILE__, __LINE__, 
        -:  932:	  "connToString: pg id is", (char *)pg_id );*/
        -:  933:    /* This is intended to cause a process to transition from a singleton
        -:  934:       to a non-singleton. */
        -:  935:    /* XXX DJG TODO figure out what this little bit is all about. */
      201:  936:    if (strstr( pg_id, "singinit_kvs" ) == pg_id) {
        -:  937:#ifdef USE_PMI2_API
        -:  938:        MPIU_Assertp(0); /* don't know what to do here for pmi2 yet.  DARIUS */
        -:  939:#else
    #####:  940:	PMI_Get_id( pg->id, 256 );
        -:  941:#endif
        -:  942:    }
        -:  943:    
     7035:  944:    while (*pg_id) str[len++] = *pg_id++;
      201:  945:    str[len++] = 0;
        -:  946:    
      201:  947:    MPIU_Snprintf( &str[len], 20, "%d", pg->size);
        -:  948:    /* Skip over the length */
      402:  949:    while (str[len++]);
        -:  950:
        -:  951:    /* Copy each connection string */
     1003:  952:    for (i=0; i<pg->size; i++) {
      802:  953:	char *p = connInfo->connStrings[i];
      802:  954:	while (*p) { str[len++] = *p++; }
      802:  955:	str[len++] = 0;
        -:  956:    }
        -:  957:
      201:  958:    if (len > connInfo->toStringLen) {
    #####:  959:	*buf_p = 0;
    #####:  960:	*slen  = 0;
    #####:  961:        MPIU_ERR_INTERNALANDJUMP(mpi_errno, "len > connInfo->toStringLen");
        -:  962:    }
        -:  963:
      201:  964:    *buf_p = str;
      201:  965:    *slen = len;
        -:  966:
      201:  967:fn_exit:
      201:  968:    MPIU_CHKPMEM_COMMIT();
      201:  969:    return mpi_errno;
        -:  970:fn_fail:
    #####:  971:    MPIU_CHKPMEM_REAP();
        -:  972:    goto fn_exit;
        -:  973:    
        -:  974:}
        -:  975:static int connFromString( const char *buf, MPIDI_PG_t *pg )
     1986:  976:{
     1986:  977:    MPIDI_ConnInfo *conninfo = 0;
     1986:  978:    int i, mpi_errno = MPI_SUCCESS;
     1986:  979:    const char *buf0 = buf;   /* save the start of buf */
        -:  980:
        -:  981:    /* printf( "Starting with buf = %s\n", buf );fflush(stdout); */
        -:  982:
        -:  983:    /* Skip the pg id */
     1986:  984:    while (*buf) buf++; buf++;
        -:  985:
        -:  986:    /* Determine the size of the pg */
     1986:  987:    pg->size = atoi( buf );
     1986:  988:    while (*buf) buf++; buf++;
        -:  989:
     1986:  990:    conninfo = (MPIDI_ConnInfo *)MPIU_Malloc( sizeof(MPIDI_ConnInfo) );
     1986:  991:    conninfo->connStrings = (char **)MPIU_Malloc( pg->size * sizeof(char *));
        -:  992:
        -:  993:    /* For now, make a copy of each item */
     6510:  994:    for (i=0; i<pg->size; i++) {
        -:  995:	/* printf( "Adding conn[%d] = %s\n", i, buf );fflush(stdout); */
     4524:  996:	conninfo->connStrings[i] = MPIU_Strdup( buf );
     4524:  997:	while (*buf) buf++;
     4524:  998:	buf++;
        -:  999:    }
     1986: 1000:    pg->connData = conninfo;
        -: 1001:	
        -: 1002:    /* Save the length of the string needed to encode the connection
        -: 1003:       information */
     1986: 1004:    conninfo->toStringLen = (int)(buf - buf0) + 1;
        -: 1005:
     1986: 1006:    return mpi_errno;
        -: 1007:}
        -: 1008:static int connFree( MPIDI_PG_t *pg )
     1986: 1009:{
     1986: 1010:    MPIDI_ConnInfo *conninfo = (MPIDI_ConnInfo *)pg->connData;
        -: 1011:    int i;
        -: 1012:
     6510: 1013:    for (i=0; i<pg->size; i++) {
     4524: 1014:	MPIU_Free( conninfo->connStrings[i] );
        -: 1015:    }
     1986: 1016:    MPIU_Free( conninfo->connStrings );
     1986: 1017:    MPIU_Free( conninfo );
        -: 1018:
     1986: 1019:    return MPI_SUCCESS;
        -: 1020:}
        -: 1021:
        -: 1022:#ifdef USE_DBG_LOGGING
        -: 1023:/* This is a temporary routine that is used to print out the pg string.
        -: 1024:   A better approach may be to convert it into a single (long) string
        -: 1025:   with no nulls. */
        -: 1026:int MPIDI_PrintConnStr( const char *file, int line, 
        -: 1027:			const char *label, const char *str )
        -: 1028:{
        -: 1029:    int pg_size, i;
        -: 1030:
        -: 1031:    MPIU_DBG_Outevent( file, line, MPIU_DBG_CH3_CONNECT, 0, "%s", label );
        -: 1032:    MPIU_DBG_Outevent( file, line, MPIU_DBG_CH3_CONNECT, 0, "%s", str );
        -: 1033:    
        -: 1034:    /* Skip the pg id */
        -: 1035:    while (*str) str++; str++;
        -: 1036:
        -: 1037:    /* Determine the size of the pg */
        -: 1038:    pg_size = atoi( str );
        -: 1039:    while (*str) str++; str++;
        -: 1040:
        -: 1041:    for (i=0; i<pg_size; i++) {
        -: 1042:	MPIU_DBG_Outevent( file, line, MPIU_DBG_CH3_CONNECT, 0, "%s", str );
        -: 1043:	while (*str) str++;
        -: 1044:	str++;
        -: 1045:    }
        -: 1046:    return 0;
        -: 1047:}
        -: 1048:int MPIDI_PrintConnStrToFile( FILE *fd, const char *file, int line, 
        -: 1049:			      const char *label, const char *str )
        -: 1050:{
        -: 1051:    int pg_size, i;
        -: 1052:
        -: 1053:    fprintf( fd, "ConnStr from %s(%d); %s\n\t%s\n", file, line, label, str );
        -: 1054:    
        -: 1055:    /* Skip the pg id */
        -: 1056:    while (*str) str++; str++;
        -: 1057:
        -: 1058:    fprintf( fd, "\t%s\n", str );
        -: 1059:    /* Determine the size of the pg */
        -: 1060:    pg_size = atoi( str );
        -: 1061:    while (*str) str++; str++;
        -: 1062:
        -: 1063:    for (i=0; i<pg_size; i++) {
        -: 1064:	fprintf( fd, "\t%s\n", str ); 
        -: 1065:	while (*str) str++;
        -: 1066:	str++;
        -: 1067:    }
        -: 1068:    fflush(stdout);
        -: 1069:    return 0;
        -: 1070:}
        -: 1071:#endif
        -: 1072:
        -: 1073:int MPIDI_PG_InitConnString( MPIDI_PG_t *pg )
     1986: 1074:{
     1986: 1075:    int mpi_errno = MPI_SUCCESS;
        -: 1076:
     1986: 1077:    pg->connData           = 0;
     1986: 1078:    pg->getConnInfo        = getConnInfo;
     1986: 1079:    pg->connInfoToString   = connToString;
     1986: 1080:    pg->connInfoFromString = connFromString;
     1986: 1081:    pg->freeConnInfo       = connFree;
        -: 1082:
     1986: 1083:    return mpi_errno;
        -: 1084:}
        -: 1085:
        -: 1086:/* Temp to get connection value for rank r */
        -: 1087:#undef FUNCNAME
        -: 1088:#define FUNCNAME MPIDI_PG_GetConnString
        -: 1089:#undef FCNAME
        -: 1090:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -: 1091:int MPIDI_PG_GetConnString( MPIDI_PG_t *pg, int rank, char *val, int vallen )
     7371: 1092:{
     7371: 1093:    int mpi_errno = MPI_SUCCESS;
        -: 1094:
     7371: 1095:    if (pg->getConnInfo) {
     7371: 1096:	mpi_errno = (*pg->getConnInfo)( rank, val, vallen, pg );
        -: 1097:    }
        -: 1098:    else {
    #####: 1099:	MPIU_Internal_error_printf( "Panic: no getConnInfo defined!\n" );
        -: 1100:    }
        -: 1101:
     7371: 1102:    return mpi_errno;
        -: 1103:}
        -: 1104:
        -: 1105:
        -: 1106:#undef FUNCNAME
        -: 1107:#define FUNCNAME MPIDI_PG_Dup_vcr
        -: 1108:#undef FCNAME
        -: 1109:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -: 1110:/*@
        -: 1111:  MPIDI_PG_Dup_vcr - Duplicate a virtual connection from a process group
        -: 1112:
        -: 1113:  Notes:
        -: 1114:  This routine provides a dup of a virtual connection given a process group
        -: 1115:  and a rank in that group.  This routine is used only in initializing
        -: 1116:  the MPI-1 communicators 'MPI_COMM_WORLD' and 'MPI_COMM_SELF', and in creating
        -: 1117:  the initial intercommunicator after an 'MPI_Comm_spawn', 
        -: 1118:  'MPI_Comm_spawn_multiple', or 'MPI_Comm_connect/MPI_Comm_accept'.  
        -: 1119:
        -: 1120:  In addition to returning a dup of the virtual connection, it manages the
        -: 1121:  reference count of the process group, which is always the number of inuse
        -: 1122:  virtual connections.
        -: 1123:  @*/
        -: 1124:int MPIDI_PG_Dup_vcr( MPIDI_PG_t *pg, int rank, MPIDI_VC_t **vc_p )
     6938: 1125:{
        -: 1126:    MPIDI_VC_t *vc;
        -: 1127:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_DUP_VCR);
        -: 1128:
        -: 1129:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_DUP_VCR);
        -: 1130:
     6938: 1131:    vc = &pg->vct[rank];
        -: 1132:    /* Increase the reference count of the vc.  If the reference count 
        -: 1133:       increases from 0 to 1, increase the reference count of the 
        -: 1134:       process group *and* the reference count of the vc (this
        -: 1135:       allows us to distinquish between Comm_free and Comm_disconnect) */
        -: 1136:    /* FIXME-MT: This should be a fetch and increment for thread-safety */
     6938: 1137:    if (MPIU_Object_get_ref(vc) == 0) {
     5720: 1138:	MPIDI_PG_add_ref(pg);
     5720: 1139:	MPIDI_VC_add_ref(vc);
        -: 1140:    }
     6938: 1141:    MPIDI_VC_add_ref(vc);
     6938: 1142:    *vc_p = vc;
        -: 1143:
        -: 1144:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_DUP_VCR);
     6938: 1145:    return MPI_SUCCESS;
        -: 1146:}
        -: 1147:
        -: 1148:/* FIXME: This routine should invoke a close method on the connection,
        -: 1149:   rather than have all of the code here */
        -: 1150:#undef FUNCNAME
        -: 1151:#define FUNCNAME MPIDI_PG_Close_VCs
        -: 1152:#undef FCNAME
        -: 1153:#define FCNAME MPIDI_QUOTE(FUNCNAME)
        -: 1154:/*@
        -: 1155:  MPIDI_PG_Close_VCs - Close all virtual connections on all process groups.
        -: 1156:  
        -: 1157:  Note:
        -: 1158:  This routine is used in MPID_Finalize.  It is here to keep the process-group
        -: 1159:  related functions together.
        -: 1160:  @*/
        -: 1161:int MPIDI_PG_Close_VCs( void )
     4374: 1162:{
     4374: 1163:    MPIDI_PG_t * pg = MPIDI_PG_list;
     4374: 1164:    int mpi_errno = MPI_SUCCESS;
        -: 1165:    MPIDI_STATE_DECL(MPID_STATE_MPIDI_PG_CLOSE_VCS);
        -: 1166:
        -: 1167:    MPIDI_FUNC_ENTER(MPID_STATE_MPIDI_PG_CLOSE_VCS);
        -: 1168:
    13281: 1169:    while (pg) {
        -: 1170:	int i, inuse;
        -: 1171:
        -: 1172:	MPIU_DBG_MSG_S(CH3_DISCONNECT,VERBOSE,"Closing vcs for pg %s",
        -: 1173:		       (char *)pg->id );
        -: 1174:
        -: 1175:
    24047: 1176:	for (i = 0; i < pg->size; i++)
        -: 1177:	{
    19514: 1178:	    MPIDI_VC_t * vc = &pg->vct[i];
        -: 1179:	    /* If the VC is myself then skip the close message */
    19514: 1180:	    if (pg == MPIDI_Process.my_pg && i == MPIDI_Process.my_pg_rank) {
        -: 1181:                /* XXX DJG FIXME-MT should we be checking this? */
     4374: 1182:                if (MPIU_Object_get_ref(vc) != 0) {
     4374: 1183:                    MPIDI_PG_release_ref(pg, &inuse);
        -: 1184:                }
        -: 1185:		continue;
        -: 1186:	    }
        -: 1187:
    15140: 1188:	    if (vc->state == MPIDI_VC_STATE_ACTIVE || 
        -: 1189:		vc->state == MPIDI_VC_STATE_REMOTE_CLOSE
        -: 1190:#if defined(MPIDI_CH3_USES_SSHM) && 0
        -: 1191:		/* FIXME: Remove this IFDEF */
        -: 1192:		/* sshm queues are uni-directional.  A VC that is connected 
        -: 1193:		 * in the read direction is marked MPIDI_VC_STATE_INACTIVE
        -: 1194:		 * so that a connection will be formed on the first write.  
        -: 1195:		 * Since the other side is marked MPIDI_VC_STATE_ACTIVE for 
        -: 1196:		 * writing 
        -: 1197:		 * we need to initiate the close protocol on the read side 
        -: 1198:		 * even if the write state is MPIDI_VC_STATE_INACTIVE. */
        -: 1199:		|| ((vc->state == MPIDI_VC_STATE_INACTIVE) && 
        -: 1200:		    ((MPIDI_CH3I_VC *)(vc->channel_private))->shm_read_connected)
        -: 1201:#endif
        -: 1202:		)
        -: 1203:	    {
    11292: 1204:		MPIDI_CH3U_VC_SendClose( vc, i );
        -: 1205:	    }
        -: 1206:	    else
        -: 1207:	    {
        -: 1208:                /* XXX DJG FIXME-MT should we be checking this? */
     3848: 1209:                if (vc->state == MPIDI_VC_STATE_INACTIVE && MPIU_Object_get_ref(vc) != 0) {
        -: 1210:		    /* FIXME: If the reference count for the vc is not 0,
        -: 1211:		       something is wrong */
     3836: 1212:                    MPIDI_PG_release_ref(pg, &inuse);
        -: 1213:                }
        -: 1214:
        -: 1215:		MPIU_DBG_MSG_FMT(CH3_DISCONNECT,VERBOSE,(MPIU_DBG_FDEST,
        -: 1216:		     "vc=%p: not sending a close to %d, vc in state %s", vc,i,
        -: 1217:		     MPIDI_VC_GetStateString(vc->state)));
        -: 1218:	    }
        -: 1219:	}
     4533: 1220:	pg = pg->next;
        -: 1221:    }
        -: 1222:    /* Note that we do not free the process groups within this routine, even
        -: 1223:       if the reference counts have gone to zero. That is done once the 
        -: 1224:       connections are in fact closed (by the final progress loop that
        -: 1225:       handles any close requests that this code generates) */
        -: 1226:
        -: 1227:    MPIDI_FUNC_EXIT(MPID_STATE_MPIDI_PG_CLOSE_VCS);
     4374: 1228:    return mpi_errno;
        -: 1229:}
        -: 1230:
        -: 1231:/*
        -: 1232: * This routine may be called to print the contents (including states and
        -: 1233: * reference counts) for process groups.
        -: 1234: */
        -: 1235:int MPIU_PG_Printall( FILE *fp )
    #####: 1236:{
        -: 1237:    MPIDI_PG_t *pg;
        -: 1238:    int         i;
        -: 1239:		  
    #####: 1240:    pg = MPIDI_PG_list;
        -: 1241:
    #####: 1242:    fprintf( fp, "Process groups:\n" );
    #####: 1243:    while (pg) {
        -: 1244:        /* XXX DJG FIXME-MT should we be checking this? */
    #####: 1245:	fprintf( fp, "size = %d, refcount = %d, id = %s\n", 
        -: 1246:		 pg->size, MPIU_Object_get_ref(pg), (char *)pg->id );
    #####: 1247:	for (i=0; i<pg->size; i++) {
    #####: 1248:	    fprintf( fp, "\tVCT rank = %d, refcount = %d, lpid = %d, state = %d \n", 
        -: 1249:		     pg->vct[i].pg_rank, MPIU_Object_get_ref(&pg->vct[i]),
        -: 1250:		     pg->vct[i].lpid, (int)pg->vct[i].state );
        -: 1251:	}
    #####: 1252:	fflush(fp);
    #####: 1253:	pg = pg->next;
        -: 1254:    }
        -: 1255:
    #####: 1256:    return 0;
        -: 1257:}
        -: 1258:
        -: 1259:int MPIDI_PG_CheckForSingleton( void )
     1337: 1260:{
        -: 1261:
        -: 1262:#ifdef USE_PMI2_API
        -: 1263:    MPIU_Assertp(0); /* figure this out for pmi2 DARIUS */
        -: 1264:#else
     1337: 1265:    if (strstr((char*)pg_world->id,"singinit_kvs") == (char *)pg_world->id) {
        -: 1266:	char buf[256];
        -: 1267:	/* Force an enroll */
    #####: 1268:	PMI_KVS_Get( "foobar", "foobar", buf, sizeof(buf) );
    #####: 1269:	PMI_Get_id( pg_world->id, 256 );
    #####: 1270:	PMI_KVS_Get_my_name( pg_world->connData, 256 );
        -: 1271:    }
        -: 1272:#endif
     1337: 1273:    return MPI_SUCCESS;
        -: 1274:}