/* Implement the singleton init handshake. See the discussion in simplepmi.c for the protocol */ int PMI_InitSingletonConnection(int fd, PMIProcess * pmiprocess) { char buf[PMIU_MAXLINE], cmd[PMIU_MAXLINE]; int rc; char version[PMIU_MAXLINE], subversion[PMIU_MAXLINE]; /* We start with the singinit command, wait for the singinit from * the client, and then send the singinit_info */ MPL_snprintf(buf, PMIU_MAXLINE, "cmd=singinit pmi_version=%d pmi_subversion=%d stdio=no authtype=none\n", PMI_VERSION, PMI_SUBVERSION); PMIWriteLine(fd, buf); PMIReadLine(fd, buf, PMIU_MAXLINE); PMIU_parse_keyvals(buf); PMIU_getval("cmd", cmd, MAXPMICMD); if (strcmp(cmd, "singinit")) { PMIU_printf(1, "Unexpected cmd %s\n", cmd); return -1; } /* Could look at authtype */ /* check version compatibility with PMI client library */ PMIU_getval("pmi_version", version, PMIU_MAXLINE); PMIU_getval("pmi_subversion", subversion, PMIU_MAXLINE); if (PMI_VERSION == atoi(version) && PMI_SUBVERSION >= atoi(subversion)) rc = 0; else rc = -1; MPL_snprintf(buf, PMIU_MAXLINE, "cmd=singinit_info versionok=%s stdio=no kvsname=%s\n", (rc == 0) ? "yes" : "no", (char *) (pmiprocess->group->kvs->kvsname)); PMIWriteLine(fd, buf); return 0; }
/* * Handle an incoming "put" command */ static int fPMI_Handle_put(PMIProcess * pentry) { int rc = 0; PMIKVSpace *kvs; char kvsname[MAXKVSNAME]; char message[PMIU_MAXLINE], outbuf[PMIU_MAXLINE]; char key[MAXKEYLEN], val[MAXVALLEN]; PMIU_getval("kvsname", kvsname, MAXKVSNAME); DBG_PRINTFCOND(pmidebug, ("Put: Finding kvs %s\n", kvsname)); kvs = fPMIKVSFindSpace(kvsname); if (kvs) { /* should check here for duplicate key and raise error */ PMIU_getval("key", key, MAXKEYLEN); PMIU_getval("value", val, MAXVALLEN); rc = fPMIKVSAddPair(kvs, key, val); if (rc == 1) { rc = -1; /* no duplicate keys allowed */ MPL_snprintf(message, PMIU_MAXLINE, "duplicate_key %s", key); } else if (rc == -1) { rc = -1; MPL_snprintf(message, PMIU_MAXLINE, "no_room_in_kvs_%s", kvsname); } else { rc = 0; MPL_strncpy(message, "success", PMIU_MAXLINE); } } else { rc = -1; MPL_snprintf(message, PMIU_MAXLINE, "kvs_%s_not_found", kvsname); } MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=put_result rc=%d msg=%s\n", rc, message); PMIWriteLine(pentry->fd, outbuf); return 0; }
/* * These routines are called when communication is established through * a port instead of an fd, and no information is communicated * through environment variables. */ static int fPMI_Handle_init_port(PMIProcess * pentry) { char outbuf[PMIU_MAXLINE]; DBG_PRINTFCOND(pmidebug, ("Entering fPMI_Handle_init_port to start connection\n")); /* simple_pmi wants to see cmd=initack after the initack request before * the other data */ PMIWriteLine(pentry->fd, "cmd=initack\n"); MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=set size=%d\n", pentry->group->nProcess); PMIWriteLine(pentry->fd, outbuf); MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=set rank=%d\n", pentry->pState->wRank); PMIWriteLine(pentry->fd, outbuf); MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=set debug=%d\n", pmidebug); PMIWriteLine(pentry->fd, outbuf); return 0; }
/* Handle an incoming get_appnum command */ static int fPMI_Handle_get_appnum(PMIProcess * pentry) { ProcessApp *app = pentry->pState->app; char outbuf[PMIU_MAXLINE]; MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=appnum appnum=%d\n", app->myAppNum); PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("%s", outbuf)); return 0; }
/* Handle an incoming get_universe_size command */ static int fPMI_Handle_get_universe_size(PMIProcess * pentry) { char outbuf[PMIU_MAXLINE]; /* Import the universe size from the process structures */ MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=universe_size size=%d\n", pUniv.size); PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("%s", outbuf)); return 0; }
/* Handle an incoming "get_maxes" command */ static int fPMI_Handle_get_maxes(PMIProcess * pentry) { char outbuf[PMIU_MAXLINE]; MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=maxes kvsname_max=%d keylen_max=%d vallen_max=%d\n", MAXKVSNAME, MAXKEYLEN, MAXVALLEN); PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("%s", outbuf)); return 0; }
/* ------------------------------------------------------------------------- */ static int fPMI_Handle_finalize(PMIProcess * pentry) { char outbuf[PMIU_MAXLINE]; pentry->pState->status = PROCESS_FINALIZED; /* send back an acknowledgement to release the process */ MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=finalize_ack\n"); PMIWriteLine(pentry->fd, outbuf); return 0; }
/* * Handle an incoming "create_kvs" command */ static int fPMI_Handle_create_kvs(PMIProcess * pentry) { char kvsname[MAXKVSNAME], outbuf[PMIU_MAXLINE]; int rc; rc = fPMIKVSGetNewSpace(kvsname, sizeof(kvsname)); if (rc) { /* PANIC - allocation failed */ return 1; } MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=newkvs kvsname=%s\n", kvsname); PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("Handle_create_kvs new name %s\n", kvsname)); return 0; }
/* Handle an incoming get_my_kvsname command */ static int fPMI_Handle_get_my_kvsname(PMIProcess * pentry) { char outbuf[PMIU_MAXLINE]; PMIKVSpace *kvs; kvs = pentry->group->kvs; if (kvs && kvs->kvsname) { MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=my_kvsname kvsname=%s\n", kvs->kvsname); } else { MPL_internal_error_printf("Group has no associated KVS"); return -1; } PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("%s", outbuf)); return 0; }
/* * Handle an incoming "barrier" command * * Need a structure that has the fds for all members of a pmi group */ static int fPMI_Handle_barrier(PMIProcess * pentry) { int i; PMIGroup *group = pentry->group; DBG_PRINTFCOND(pmidebug, ("Entering PMI_Handle_barrier for group %d\n", group->groupID)); group->nInBarrier++; if (group->nInBarrier == group->nProcess) { for (i = 0; i < group->nProcess; i++) { PMIWriteLine(group->pmiProcess[i]->fd, "cmd=barrier_out\n"); } group->nInBarrier = 0; } return 0; }
/* * Handle incoming "getbyidx" command */ static int fPMI_Handle_getbyidx( PMIProcess *pentry ) { int j, jNext, rc=0; PMIKVSpace *kvs; char kvsname[MAXKVSNAME], j_char[8], outbuf[PMIU_MAXLINE]; PMIKVPair *p; PMIU_getval( "kvsname", kvsname, MAXKVSNAME ); kvs = fPMIKVSFindSpace( kvsname ); if (kvs) { PMIU_getval( "idx", j_char, sizeof(j_char) ); j = atoi( j_char ); jNext = j+1; if (kvs->lastIdx >= 0 && j >= kvs->lastIdx) { for (p = kvs->lastByIdx, j-= kvs->lastIdx; j-- > 0 && p; p = p->nextPair ); } else { for (p = kvs->pairs; j-- > 0 && p; p = p->nextPair) ; } if (p) { MPIU_Snprintf( outbuf, PMIU_MAXLINE, "cmd=getbyidx_results " "rc=0 nextidx=%d key=%s val=%s\n", jNext, p->key, p->val ); kvs->lastIdx = jNext-1; kvs->lastByIdx = p; } else { MPIU_Snprintf( outbuf, PMIU_MAXLINE, "cmd=getbyidx_results rc=-1 " "reason=no_more_keyvals\n" ); kvs->lastIdx = -1; kvs->lastByIdx = 0; } } else { rc = -1; MPIU_Snprintf( outbuf, PMIU_MAXLINE, "cmd=getbyidx_results rc=-1 " "reason=kvs_%s_not_found\n", kvsname ); } PMIWriteLine( pentry->fd, outbuf ); DBG_PRINTFCOND(pmidebug,( "%s", outbuf )); return rc; }
/* * Handle an incoming "destroy_kvs" command */ static int fPMI_Handle_destroy_kvs(PMIProcess * pentry) { int rc = 0; PMIKVSpace *kvs; char kvsname[MAXKVSNAME]; char message[PMIU_MAXLINE], outbuf[PMIU_MAXLINE]; PMIU_getval("kvsname", kvsname, MAXKVSNAME); kvs = fPMIKVSFindSpace(kvsname); if (kvs) { PMIKVSFree(kvs); MPL_snprintf(message, PMIU_MAXLINE, "KVS_%s_successfully_destroyed", kvsname); } else { MPL_snprintf(message, PMIU_MAXLINE, "KVS %s not found", kvsname); rc = -1; } MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=kvs_destroyed rc=%d msg=%s\n", rc, message); PMIWriteLine(pentry->fd, outbuf); return 0; }
/* * Handle incoming "get" command */ static int fPMI_Handle_get( PMIProcess *pentry ) { PMIKVSpace *kvs; int rc=0; char kvsname[MAXKVSNAME]; char message[PMIU_MAXLINE], key[PMIU_MAXLINE], value[PMIU_MAXLINE]; char outbuf[PMIU_MAXLINE]; PMIU_getval( "kvsname", kvsname, MAXKVSNAME ); DBG_PRINTFCOND(pmidebug,( "Get: Finding kvs %s\n", kvsname ) ); kvs = fPMIKVSFindSpace( kvsname ); if (kvs) { PMIU_getval( "key", key, PMIU_MAXLINE ); /* Here we could intercept internal keys, e.g., pmiPrivate keys. */ rc = fPMIKVSFindKey( kvs, key, value, sizeof(value) ); if (rc == 0) { rc = 0; MPIU_Strncpy( message, "success", PMIU_MAXLINE ); } else if (rc) { rc = -1; MPIU_Strncpy( value, "unknown", PMIU_MAXLINE ); MPIU_Snprintf( message, PMIU_MAXLINE, "key_%s_not_found", kvsname ); } } else { rc = -1; MPIU_Strncpy( value, "unknown", PMIU_MAXLINE ); MPIU_Snprintf( message, PMIU_MAXLINE, "kvs_%s_not_found", kvsname ); } MPIU_Snprintf( outbuf, PMIU_MAXLINE, "cmd=get_result rc=%d msg=%s value=%s\n", rc, message, value ); PMIWriteLine( pentry->fd, outbuf ); DBG_PRINTFCOND( pmidebug, ("%s", outbuf )); return rc; }
/* Handle an incoming "init" command */ static int fPMI_Handle_init(PMIProcess * pentry) { char version[PMIU_MAXLINE]; char subversion[PMIU_MAXLINE]; char outbuf[PMIU_MAXLINE]; int rc; /* check version compatibility with PMI client library */ PMIU_getval("pmi_version", version, PMIU_MAXLINE); PMIU_getval("pmi_subversion", subversion, PMIU_MAXLINE); if (PMI_VERSION == atoi(version) && PMI_SUBVERSION >= atoi(subversion)) rc = 0; else rc = -1; pentry->pState->status = PROCESS_COMMUNICATING; MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=response_to_init pmi_version=%d pmi_subversion=%d rc=%d\n", PMI_VERSION, PMI_SUBVERSION, rc); PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("%s", outbuf)); return 0; }
static int fPMI_Handle_spawn(PMIProcess * pentry) { char inbuf[PMIU_MAXLINE]; char *(args[PMI_MAX_ARGS]); char key[MAXKEYLEN]; char outbuf[PMIU_MAXLINE]; ProcessWorld *pWorld; ProcessApp *app = 0; int preputNum = 0, rc; int i; int totspawns = 0, spawnnum = 0; PMIKVSpace *kvs = 0; /* Variables for info */ char curInfoKey[PMI_MAX_INFO_KEY], curInfoVal[PMI_MAX_INFO_VAL]; int curInfoIdx = -1; DBG_PRINTFCOND(pmidebug, ("Entering fPMI_Handle_spawn\n")); if (!pentry->spawnWorld) { pWorld = (ProcessWorld *) MPL_malloc(sizeof(ProcessWorld), MPL_MEM_PM); if (!pWorld) return 1; pentry->spawnWorld = pWorld; pWorld->apps = 0; pWorld->nProcess = 0; pWorld->nextWorld = 0; pWorld->nApps = 0; pWorld->worldNum = pUniv.nWorlds++; /* FIXME: What should be the defaults for the spawned env? * Should the default be the env ov the spawner? */ pWorld->genv = 0; pentry->spawnKVS = fPMIKVSAllocate(); } else { pWorld = pentry->spawnWorld; } kvs = pentry->spawnKVS; /* Note that each mcmd=spawn creates an app. When all apps * are present, then then can be linked to a world. A * spawnmultiple command makes use of multiple mcmd=spawn PMI * commands */ /* Create a new app */ app = (ProcessApp *) MPL_malloc(sizeof(ProcessApp), MPL_MEM_PM); if (!app) return 1; app->myAppNum = 0; app->exename = 0; app->arch = 0; app->path = 0; app->wdir = 0; app->hostname = 0; app->args = 0; app->nArgs = 0; app->soft.nelm = 0; app->nProcess = 0; app->pState = 0; app->nextApp = 0; app->env = 0; app->pWorld = pWorld; /* Add to the pentry spawn structure */ if (pentry->spawnAppTail) { pentry->spawnAppTail->nextApp = app; } else { pentry->spawnApp = app; pWorld->apps = app; } pentry->spawnAppTail = app; for (i = 0; i < PMI_MAX_ARGS; i++) args[i] = 0; /* Get lines until we find either cmd or mcmd (an error) or endcmd * (expected end) */ while ((rc = PMIUBufferedReadLine(pentry, inbuf, sizeof(inbuf))) > 0) { char *cmdPtr, *valPtr, *p; /* Find the command = format */ p = inbuf; /* Find first nonblank */ while (*p && isascii(*p) && isspace(*p)) p++; if (!*p) { /* Empty string. Ignore */ continue; } cmdPtr = p++; /* Find '=' */ while (*p && *p != '=') p++; if (!*p) { /* No =. Check for endcmd */ p--; /* Trim spaces */ while (isascii(*p) && isspace(*p)) p--; /* Add null to end */ *++p = 0; if (strcmp("endcmd", cmdPtr) == 0) { break; } /* FIXME: Otherwise, we have a problem */ MPL_error_printf("Malformed PMI command (no endcmd seen\n"); return 1; } else { *p = 0; } /* Found an = . value is the rest of the line */ valPtr = ++p; while (*p && *p != '\n') p++; if (*p) *p = 0; /* Remove the newline */ /* Now, process the cmd and value */ if (strcmp("nprocs", cmdPtr) == 0) { app->nProcess = atoi(valPtr); pWorld->nProcess += app->nProcess; } else if (strcmp("execname", cmdPtr) == 0) { app->exename = MPL_strdup(valPtr); } else if (strcmp("totspawns", cmdPtr) == 0) { /* This tells us how many separate spawn commands * we expect to see (e.g., for spawn multiple). * Each spawn command is a separate "app" */ totspawns = atoi(valPtr); } else if (strcmp("spawnssofar", cmdPtr) == 0) { /* This tells us which app we are (starting from 1) */ spawnnum = atoi(valPtr); app->myAppNum = spawnnum - 1; } else if (strcmp("argcnt", cmdPtr) == 0) { /* argcnt may not be set before the args */ app->nArgs = atoi(valPtr); } else if (strncmp("arg", cmdPtr, 3) == 0) { int argnum; /* argcnt may not be set before the args */ /* Handle arg%d. Values are 1 - origin */ argnum = atoi(cmdPtr + 3) - 1; if (argnum < 0 || argnum >= PMI_MAX_ARGS) { MPL_error_printf ("Malformed PMI Spawn command; the index of an argument in the command is %d but must be between 0 and %d\n", argnum, PMI_MAX_ARGS - 1); return 1; } args[argnum] = MPL_strdup(valPtr); } else if (strcmp("preput_num", cmdPtr) == 0) { preputNum = atoi(valPtr); } else if (strncmp("preput_key_", cmdPtr, 11) == 0) { /* Save the key */ MPL_strncpy(key, valPtr, sizeof(key)); } else if (strncmp("preput_val_", cmdPtr, 11) == 0) { /* Place the key,val into the space associate with the current * PMI group */ fPMIKVSAddPair(kvs, key, valPtr); } /* Info is on a per-app basis (it is an array of info items in * spawn multiple). We can ignore most info values. * The ones that are handled are processed by a * separate routine (not yet implemented). * simple_pmi.c sends (key,value), so we can keep just the * last key and pass the key/value to the registered info * handler, along with tha app structure. Alternately, * we could save all info items and let the user's * spawner handle it */ else if (strcmp("info_num", cmdPtr) == 0) { /* Number of info values */ ; } else if (strncmp("info_key_", cmdPtr, 9) == 0) { /* The actual name has a digit, which indicates *which* info * key this is */ curInfoIdx = atoi(cmdPtr + 9); MPL_strncpy(curInfoKey, valPtr, sizeof(curInfoKey)); } else if (strncmp("info_val_", cmdPtr, 9) == 0) { /* The actual name has a digit, which indicates *which* info * value this is */ int idx = atoi(cmdPtr + 9); if (idx != curInfoIdx) { MPL_error_printf ("Malformed PMI command: info keys and values not ordered as expected (expected value %d but got %d)\n", curInfoIdx, idx); return 1; } else { MPL_strncpy(curInfoVal, valPtr, sizeof(curInfoVal)); /* Apply this info item */ fPMIInfoKey(app, curInfoKey, curInfoVal); /* printf("Got info %s+%s\n", curInfoKey, curInfoVal); */ } } else { MPL_error_printf("Unrecognized PMI subcommand on spawnmult: %s\n", cmdPtr); return 1; } } if (app->nArgs > 0) { app->args = (const char **) MPL_malloc(app->nArgs * sizeof(char *), MPL_MEM_PM); for (i = 0; i < app->nArgs; i++) { app->args[i] = args[i]; args[i] = 0; } } pWorld->nApps++; /* Now that we've read the commands, invoke the user's spawn command */ if (totspawns == spawnnum) { PMISetupNewGroup(pWorld->nProcess, kvs); if (userSpawner) { rc = (*userSpawner) (pWorld, userSpawnerData); } else { MPL_error_printf("Unable to spawn %s\n", app->exename); rc = 1; MPIE_PrintProcessWorld(stdout, pWorld); } MPL_snprintf(outbuf, PMIU_MAXLINE, "cmd=spawn_result rc=%d\n", rc); PMIWriteLine(pentry->fd, outbuf); DBG_PRINTFCOND(pmidebug, ("%s", outbuf)); /* Clear for the next spawn */ pentry->spawnApp = 0; pentry->spawnAppTail = 0; pentry->spawnKVS = 0; pentry->spawnWorld = 0; } /* If totspawnnum != spawnnum, then we are expecting a * spawnmult with additional items */ return 0; }