1
/* -*- Mode: C; c-basic-offset:4 ; -*- */
3
* (C) 2001 by Argonne National Laboratory.
4
* See COPYRIGHT in top-level directory.
14
#ifdef DYNAMIC_TASKING
16
extern mpidi_dynamic_tasking;
18
/* Define the name of the kvs key used to provide the port name to the
20
#define MPIDI_PARENT_PORT_KVSKEY "PARENT_ROOT_PORT_NAME"
22
/* FIXME: We can avoid these two routines if we define PMI as using
24
/* Turn a SINGLE MPI_Info into an array of PMI_keyvals (return the pointer
25
to the array of PMI keyvals) */
26
static int MPIDI_mpi_to_pmi_keyvals( MPID_Info *info_ptr, PMI_keyval_t **kv_ptr, int *nkeys_ptr )
28
char key[MPI_MAX_INFO_KEY];
30
int i, nkeys = 0, vallen, flag, mpi_errno=MPI_SUCCESS;
32
if (!info_ptr || info_ptr->handle == MPI_INFO_NULL) {
36
MPIR_Info_get_nkeys_impl( info_ptr, &nkeys );
40
kv = (PMI_keyval_t *)MPIU_Malloc( nkeys * sizeof(PMI_keyval_t) );
42
for (i=0; i<nkeys; i++) {
43
mpi_errno = MPIR_Info_get_nthkey_impl( info_ptr, i, key );
45
TRACE_ERR("MPIR_Info_get_nthkey_impl returned with mpi_errno=%d\n", mpi_errno);
46
MPIR_Info_get_valuelen_impl( info_ptr, key, &vallen, &flag );
48
kv[i].key = MPIU_Strdup(key);
49
kv[i].val = MPIU_Malloc( vallen + 1 );
50
MPIR_Info_get_impl( info_ptr, key, vallen+1, kv[i].val, &flag );
51
TRACE_OUT("key: <%s>, value: <%s>\n", kv[i].key, kv[i].val);
62
/* Free the entire array of PMI keyvals */
63
static void MPIDI_free_pmi_keyvals(PMI_keyval_t **kv, int size, int *counts)
67
for (i=0; i<size; i++)
69
for (j=0; j<counts[i]; j++)
71
if (kv[i][j].key != NULL)
72
MPIU_Free((char *)kv[i][j].key);
73
if (kv[i][j].val != NULL)
74
MPIU_Free(kv[i][j].val);
84
MPID_Comm_spawn_multiple -
88
. char *array_of_commands[] - commands
89
. char* *array_of_argv[] - arguments
90
. int array_of_maxprocs[] - maxprocs
91
. MPI_Info array_of_info[] - infos
93
- MPI_Comm comm - communicator
96
+ MPI_Comm *intercomm - intercommunicator
97
- int array_of_errcodes[] - error codes
105
#define FUNCNAME MPID_Comm_spawn_multiple
107
#define FCNAME MPIU_QUOTE(FUNCNAME)
108
int MPID_Comm_spawn_multiple(int count, char *array_of_commands[],
109
char ** array_of_argv[], const int array_of_maxprocs[],
110
MPID_Info * array_of_info_ptrs[], int root,
111
MPID_Comm * comm_ptr, MPID_Comm ** intercomm,
112
int array_of_errcodes[])
114
int mpi_errno = MPI_SUCCESS;
116
if(mpidi_dynamic_tasking == 0) {
117
fprintf(stderr, "Received spawn request for non-dynamic jobs\n");
118
MPIU_ERR_SETANDSTMT(mpi_errno, MPI_ERR_SPAWN,
119
return mpi_errno, "**spawn");
122
/* We allow an empty implementation of this function to
123
simplify building MPICH on systems that have difficulty
124
supporing process creation */
125
mpi_errno = MPIDI_Comm_spawn_multiple(count, array_of_commands,
126
array_of_argv, array_of_maxprocs,
128
root, comm_ptr, intercomm,
135
* MPIDI_Comm_spawn_multiple()
137
int MPIDI_Comm_spawn_multiple(int count, char **commands,
138
char ***argvs, int *maxprocs,
139
MPID_Info **info_ptrs, int root,
140
MPID_Comm *comm_ptr, MPID_Comm
141
**intercomm, int *errcodes)
143
char port_name[MPI_MAX_PORT_NAME];
148
int *info_keyval_sizes=0, i, mpi_errno=MPI_SUCCESS;
149
PMI_keyval_t **info_keyval_vectors=0, preput_keyval_vector;
150
int *pmi_errcodes = 0, pmi_errno=0;
151
int total_num_processes, should_accept = 1;
152
MPID_Info tmp_info_ptr;
156
if (comm_ptr->rank == root) {
157
/* create an array for the pmi error codes */
158
total_num_processes = 0;
159
for (i=0; i<count; i++) {
160
total_num_processes += maxprocs[i];
162
pmi_errcodes = (int*)MPIU_Malloc(sizeof(int) * total_num_processes);
164
/* initialize them to 0 */
165
for (i=0; i<total_num_processes; i++)
168
/* Open a port for the spawned processes to connect to */
169
/* FIXME: info may be needed for port name */
170
mpi_errno = MPID_Open_port(NULL, port_name);
171
TRACE_ERR("mpi_errno from MPID_Open_port=%d\n", mpi_errno);
173
/* Spawn the processes */
175
MPIU_Assert(count > 0);
177
int *argcs = MPIU_Malloc(count*sizeof(int));
178
struct MPID_Info preput;
179
struct MPID_Info *preput_p[2] = { &preput, &tmp_info_ptr };
183
info_keyval_sizes = MPIU_Malloc(count * sizeof(int));
185
/* FIXME cheating on constness */
186
preput.key = (char *)MPIDI_PARENT_PORT_KVSKEY;
187
preput.value = port_name;
188
preput.next = &tmp_info_ptr;
190
tmp_info_ptr.key = "COMMCTX";
191
len=sprintf(ctxid_str, "%d", comm_ptr->context_id);
192
TRACE_ERR("COMMCTX=%d\n", comm_ptr->context_id);
194
tmp_info_ptr.value = ctxid_str;
195
tmp_info_ptr.next = NULL;
197
/* compute argcs array */
198
for (i = 0; i < count; ++i) {
200
if (argvs != NULL && argvs[i] != NULL) {
201
while (argvs[i][argcs[i]]) {
207
/*MPIU_THREAD_CS_ENTER(PMI,);*/
208
/* release the global CS for spawn PMI calls */
209
MPIU_THREAD_CS_EXIT(ALLFUNC,);
210
pmi_errno = PMI2_Job_Spawn(count, (const char **)commands,
211
argcs, (const char ***)argvs,
213
info_keyval_sizes, (const MPID_Info **)info_ptrs,
214
2, (const struct MPID_Info **)preput_p,
217
TRACE_ERR("after PMI2_Job_Spawn - pmi_errno=%d jobId=%s\n", pmi_errno, jobId);
218
MPIU_THREAD_CS_ENTER(ALLFUNC,);
220
tmp=MPIU_Strdup(jobId);
221
tmp_ret = atoi(strtok(tmp, ";"));
223
if( (pmi_errno == PMI2_SUCCESS) && (tmp_ret != -1) ) {
224
pami_task_t leader_taskid = atoi(strtok(NULL, ";"));
225
pami_endpoint_t ldest;
227
PAMI_Endpoint_create(MPIDI_Client, leader_taskid, 0, &ldest);
228
TRACE_ERR("PAMI_Resume to taskid=%d\n", leader_taskid);
229
PAMI_Resume(MPIDI_Context[0], &ldest, 1);
235
if (pmi_errno != PMI2_SUCCESS) {
236
TRACE_ERR("PMI2_Job_Spawn returned with pmi_errno=%d\n", pmi_errno);
240
/* FIXME: This is *really* awkward. We should either
241
Fix on MPI-style info data structures for PMI (avoid unnecessary
242
duplication) or add an MPIU_Info_getall(...) that creates
243
the necessary arrays of key/value pairs */
245
/* convert the infos into PMI keyvals */
246
info_keyval_sizes = (int *) MPIU_Malloc(count * sizeof(int));
247
info_keyval_vectors =
248
(PMI_keyval_t**) MPIU_Malloc(count * sizeof(PMI_keyval_t*));
251
for (i=0; i<count; i++) {
252
info_keyval_vectors[i] = 0;
253
info_keyval_sizes[i] = 0;
257
for (i=0; i<count; i++) {
258
mpi_errno = MPIDI_mpi_to_pmi_keyvals( info_ptrs[i],
259
&info_keyval_vectors[i],
260
&info_keyval_sizes[i] );
261
if (mpi_errno) { TRACE_ERR("MPIDI_mpi_to_pmi_keyvals returned with mpi_errno=%d\n", mpi_errno); }
265
preput_keyval_vector.key = MPIDI_PARENT_PORT_KVSKEY;
266
preput_keyval_vector.val = port_name;
268
pmi_errno = PMI_Spawn_multiple(count, (const char **)
270
(const char ***) argvs,
271
maxprocs, info_keyval_sizes,
272
(const PMI_keyval_t **)
273
info_keyval_vectors, 1,
274
&preput_keyval_vector,
276
TRACE_ERR("pmi_errno from PMI_Spawn_multiple=%d\n", pmi_errno);
279
if (errcodes != MPI_ERRCODES_IGNORE) {
280
for (i=0; i<total_num_processes; i++) {
281
/* FIXME: translate the pmi error codes here */
282
errcodes[i] = pmi_errcodes[0];
283
/* We want to accept if any of the spawns succeeded.
284
Alternatively, this is the same as we want to NOT accept if
285
all of them failed. should_accept = NAND(e_0, ..., e_n)
286
Remember, success equals false (0). */
287
should_accept = should_accept && errcodes[i];
289
should_accept = !should_accept; /* the `N' in NAND */
293
if( (pmi_errno == PMI2_SUCCESS) && (tmp_ret == -1) )
295
if( (pmi_errno == PMI_SUCCESS) && (tmp_ret == -1) )
300
if (errcodes != MPI_ERRCODES_IGNORE) {
302
mpi_errno = MPIR_Bcast_impl(&should_accept, 1, MPI_INT, root, comm_ptr, &errflag);
303
if (mpi_errno) TRACE_ERR("MPIR_Bcast_impl returned with mpi_errno=%d\n", mpi_errno);
305
mpi_errno = MPIR_Bcast_impl(&pmi_errno, 1, MPI_INT, root, comm_ptr, &errflag);
306
if (mpi_errno) TRACE_ERR("MPIR_Bcast_impl returned with mpi_errno=%d\n", mpi_errno);
308
mpi_errno = MPIR_Bcast_impl(&total_num_processes, 1, MPI_INT, root, comm_ptr, &errflag);
309
if (mpi_errno) TRACE_ERR("MPIR_Bcast_impl returned with mpi_errno=%d\n", mpi_errno);
311
mpi_errno = MPIR_Bcast_impl(errcodes, total_num_processes, MPI_INT, root, comm_ptr, &errflag);
312
if (mpi_errno) TRACE_ERR("MPIR_Bcast_impl returned with mpi_errno=%d\n", mpi_errno);
316
mpi_errno = MPID_Comm_accept(port_name, NULL, root, comm_ptr, intercomm);
317
TRACE_ERR("mpi_errno from MPID_Comm_accept=%d\n", mpi_errno);
319
if( (pmi_errno == PMI2_SUCCESS) && (errcodes[0] != 0) ) {
320
MPIR_Comm_create(intercomm);
324
if (comm_ptr->rank == root) {
325
/* Close the port opened for the spawned processes to connect to */
326
mpi_errno = MPID_Close_port(port_name);
327
/* --BEGIN ERROR HANDLING-- */
328
if (mpi_errno != MPI_SUCCESS)
329
TRACE_ERR("MPID_Close_port returned with mpi_errno=%d\n", mpi_errno);
330
/* --END ERROR HANDLING-- */
334
mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_FATAL, __FILE__, __LINE__, MPI_ERR_SPAWN,
335
"**mpi_comm_spawn", 0);
339
if (info_keyval_vectors) {
340
MPIDI_free_pmi_keyvals(info_keyval_vectors, count, info_keyval_sizes);
341
MPIU_Free(info_keyval_vectors);
343
if (info_keyval_sizes) {
344
MPIU_Free(info_keyval_sizes);
347
MPIU_Free(pmi_errcodes);
355
/* This function is used only with mpid_init to set up the parent communicator
356
if there is one. The routine should be in this file because the parent
357
port name is setup with the "preput" arguments to PMI_Spawn_multiple */
358
static char *parent_port_name = 0; /* Name of parent port if this
359
process was spawned (and is root
360
of comm world) or null */
362
#define FUNCNAME MPIDI_GetParentPort
364
#define FCNAME MPIU_QUOTE(FUNCNAME)
365
int MPIDI_GetParentPort(char ** parent_port)
367
int mpi_errno = MPI_SUCCESS;
369
char val[MPIDI_MAX_KVS_VALUE_LEN];
371
if (parent_port_name == NULL)
373
char *kvsname = NULL;
374
/* We can always use PMI_KVS_Get on our own process group */
375
MPIDI_PG_GetConnKVSname( &kvsname );
379
pmi_errno = PMI2_KVS_Get(kvsname, PMI2_ID_NULL, MPIDI_PARENT_PORT_KVSKEY, val, sizeof(val), &vallen);
380
TRACE_ERR("PMI2_KVS_Get - val=%s\n", val);
382
TRACE_ERR("PMI2_KVS_Get returned with pmi_errno=%d\n", pmi_errno);
385
/*MPIU_THREAD_CS_ENTER(PMI,);*/
386
pmi_errno = PMI_KVS_Get( kvsname, MPIDI_PARENT_PORT_KVSKEY, val, sizeof(val));
387
/* MPIU_THREAD_CS_EXIT(PMI,);*/
389
mpi_errno = MPIR_Err_create_code(MPI_SUCCESS, MPIR_ERR_FATAL, FCNAME, __LINE__, MPI_ERR_OTHER, "**pmi_kvsget", "**pmi_kvsget %d", pmi_errno);
393
parent_port_name = MPIU_Strdup(val);
396
*parent_port = parent_port_name;
405
void MPIDI_FreeParentPort(void)
407
if (parent_port_name) {
408
MPIU_Free( parent_port_name );
409
parent_port_name = 0;