-: 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
|