#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <pmix_tool.h>
#include "examples.h"
static int attach_to_running_job(char *nspace);
static mylock_t waiting_for_debugger;
static pmix_proc_t myproc;
static void querycbfunc(pmix_status_t status, pmix_info_t *info, size_t ninfo, void *cbdata,
pmix_release_cbfunc_t release_fn, void *release_cbdata)
{
EXAMPLES_HIDE_UNUSED_PARAMS(status);
myquery_data_t *mq = (myquery_data_t *) cbdata;
size_t n;
if (0 < ninfo) {
PMIX_INFO_CREATE(mq->info, ninfo);
mq->ninfo = ninfo;
for (n = 0; n < ninfo; n++) {
fprintf(stderr, "Transferring %s\n", info[n].key);
PMIX_INFO_XFER(&mq->info[n], &info[n]);
}
}
if (NULL != release_fn) {
release_fn(release_cbdata);
}
DEBUG_WAKEUP_THREAD(&mq->lock);
}
static void notification_fn(size_t evhdlr_registration_id, pmix_status_t status,
const pmix_proc_t *source, pmix_info_t info[], size_t ninfo,
pmix_info_t results[], size_t nresults,
pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata)
{
EXAMPLES_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source,
info, ninfo, results, nresults);
if (NULL != cbfunc) {
cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata);
}
}
static void release_fn(size_t evhdlr_registration_id, pmix_status_t status,
const pmix_proc_t *source, pmix_info_t info[], size_t ninfo,
pmix_info_t results[], size_t nresults,
pmix_event_notification_cbfunc_fn_t cbfunc, void *cbdata)
{
EXAMPLES_HIDE_UNUSED_PARAMS(evhdlr_registration_id, status, source,
info, ninfo, results, nresults);
if (NULL != cbfunc) {
cbfunc(PMIX_EVENT_ACTION_COMPLETE, NULL, 0, NULL, NULL, cbdata);
}
DEBUG_WAKEUP_THREAD(&waiting_for_debugger);
}
static void evhandler_reg_callbk(pmix_status_t status, size_t evhandler_ref, void *cbdata)
{
mylock_t *lock = (mylock_t *) cbdata;
if (PMIX_SUCCESS != status) {
fprintf(stderr, "Client %s:%d EVENT HANDLER REGISTRATION FAILED WITH STATUS %d, ref=%lu\n",
myproc.nspace, myproc.rank, status, (unsigned long) evhandler_ref);
}
lock->status = status;
DEBUG_WAKEUP_THREAD(lock);
}
static pmix_status_t spawn_debugger(char *appspace)
{
pmix_status_t rc;
pmix_info_t *dinfo;
pmix_app_t *debugger;
size_t dninfo;
char cwd[1024];
char dspace[PMIX_MAX_NSLEN + 1];
PMIX_APP_CREATE(debugger, 1);
debugger[0].cmd = strdup("./debuggerd");
PMIX_ARGV_APPEND(rc, debugger[0].argv, "./debuggerd");
if (NULL == getcwd(cwd, 1024)) { fprintf(stderr, "Debugger: getcwd() failed\n");
PMIX_APP_FREE(debugger, 1);
return PMIX_ERROR;
}
debugger[0].cwd = strdup(cwd);
dninfo = 4;
PMIX_INFO_CREATE(dinfo, dninfo);
PMIX_INFO_LOAD(&dinfo[0], PMIX_MAPBY, "ppr:1:node",
PMIX_STRING); PMIX_INFO_LOAD(&dinfo[1], PMIX_DEBUGGER_DAEMONS, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&dinfo[2], PMIX_DEBUG_JOB, appspace, PMIX_STRING); PMIX_INFO_LOAD(&dinfo[3], PMIX_NOTIFY_COMPLETION, NULL,
PMIX_BOOL);
fprintf(stderr, "Debugger: spawning %s\n", debugger[0].cmd);
if (PMIX_SUCCESS != (rc = PMIx_Spawn(dinfo, dninfo, debugger, 1, dspace))) {
fprintf(stderr, "Debugger daemons failed to launch with error: %s\n",
PMIx_Error_string(rc));
}
fprintf(stderr, "SPAWNED DEBUGGERD\n");
PMIX_INFO_FREE(dinfo, dninfo);
PMIX_APP_FREE(debugger, 1);
return rc;
}
#define DBGR_LOOP_LIMIT 10
int main(int argc, char **argv)
{
pmix_status_t rc;
pmix_info_t *info;
pmix_app_t *app;
size_t ninfo, napps;
char *nspace = NULL;
char appspace[PMIX_MAX_NSLEN + 1];
int i;
pmix_query_t *query;
size_t nq, n;
myquery_data_t myquery_data;
bool cospawn = false, stop_on_exec = false;
char cwd[1024];
pmix_status_t code = PMIX_ERR_JOB_TERMINATED;
mylock_t mylock;
for (i = 1; i < argc; i++) {
if (0 == strcmp(argv[i], "-h") || 0 == strcmp(argv[i], "--help")) {
}
if (0 == strcmp(argv[i], "-a") || 0 == strcmp(argv[i], "--attach")) {
if (NULL != nspace) {
fprintf(stderr, "Cannot attach to more than one nspace\n");
exit(1);
}
++i;
if (argc == i) {
fprintf(stderr, "The %s option requires an <nspace> argument\n", argv[i]);
exit(1);
}
nspace = strdup(argv[i]);
} else {
fprintf(stderr, "Unknown option: %s\n", argv[i]);
exit(1);
}
}
info = NULL;
ninfo = 0;
DEBUG_CONSTRUCT_LOCK(&waiting_for_debugger);
PMIX_INFO_CREATE(info, 1);
PMIX_INFO_LOAD(&info[0], PMIX_CONNECT_SYSTEM_FIRST, NULL, PMIX_BOOL);
if (PMIX_SUCCESS != (rc = PMIx_tool_init(&myproc, info, ninfo))) {
fprintf(stderr, "PMIx_tool_init failed: %d\n", rc);
exit(rc);
}
PMIX_INFO_FREE(info, ninfo);
fprintf(stderr, "Tool ns %s rank %d: Running\n", myproc.nspace, myproc.rank);
DEBUG_CONSTRUCT_LOCK(&mylock);
PMIx_Register_event_handler(NULL, 0, NULL, 0, notification_fn, evhandler_reg_callbk,
(void *) &mylock);
DEBUG_WAIT_THREAD(&mylock);
DEBUG_DESTRUCT_LOCK(&mylock);
DEBUG_CONSTRUCT_LOCK(&mylock);
PMIx_Register_event_handler(&code, 1, NULL, 0, release_fn, evhandler_reg_callbk,
(void *) &mylock);
DEBUG_WAIT_THREAD(&mylock);
DEBUG_DESTRUCT_LOCK(&mylock);
if (NULL != nspace) {
if (PMIX_SUCCESS != (rc = attach_to_running_job(nspace))) {
fprintf(stderr, "Failed to attach to nspace %s: error code %d\n", nspace, rc);
goto done;
}
} else {
nq = 1;
PMIX_QUERY_CREATE(query, nq);
PMIX_ARGV_APPEND(rc, query[0].keys, PMIX_QUERY_SPAWN_SUPPORT);
PMIX_ARGV_APPEND(rc, query[0].keys, PMIX_QUERY_DEBUG_SUPPORT);
DEBUG_CONSTRUCT_LOCK(&myquery_data.lock);
myquery_data.info = NULL;
myquery_data.ninfo = 0;
fprintf(stderr, "Debugger: querying capabilities\n");
if (PMIX_SUCCESS
!= (rc = PMIx_Query_info_nb(query, nq, querycbfunc, (void *) &myquery_data))) {
fprintf(stderr, "PMIx_Query_info failed: %d\n", rc);
goto done;
}
DEBUG_WAIT_THREAD(&myquery_data.lock);
DEBUG_DESTRUCT_LOCK(&myquery_data.lock);
if (2 != myquery_data.ninfo) {
fprintf(stderr, "PMIx Query returned an incorrect number of results: %lu\n",
myquery_data.ninfo);
PMIX_INFO_FREE(myquery_data.info, myquery_data.ninfo);
goto done;
}
for (n = 0; n < myquery_data.ninfo; n++) {
if (0 == strcmp(myquery_data.info[n].key, PMIX_QUERY_SPAWN_SUPPORT)) {
if (NULL != strstr(myquery_data.info[n].value.data.string, PMIX_COSPAWN_APP)) {
cospawn = true;
} else {
cospawn = false;
}
} else if (0 == strcmp(myquery_data.info[n].key, PMIX_QUERY_DEBUG_SUPPORT)) {
if (NULL
!= strstr(myquery_data.info[n].value.data.string, PMIX_DEBUG_STOP_ON_EXEC)) {
stop_on_exec = true;
} else {
stop_on_exec = false;
}
}
}
if (cospawn) {
} else {
napps = 1;
PMIX_APP_CREATE(app, napps);
app[0].cmd = strdup("client");
PMIX_ARGV_APPEND(rc, app[0].argv, "./client");
if (NULL == getcwd(cwd, 1024)) { fprintf(stderr, "Debugger: getcwd failed\n");
rc = PMIX_ERROR;
goto done;
}
app[0].cwd = strdup(cwd);
app[0].maxprocs = 2;
ninfo = 4;
PMIX_INFO_CREATE(info, ninfo);
PMIX_INFO_LOAD(&info[0], PMIX_MAPBY, "slot", PMIX_STRING); if (stop_on_exec) {
PMIX_INFO_LOAD(&info[1], PMIX_DEBUG_STOP_ON_EXEC, NULL,
PMIX_BOOL); } else {
PMIX_INFO_LOAD(&info[1], PMIX_DEBUG_STOP_IN_INIT, NULL,
PMIX_BOOL); }
PMIX_INFO_LOAD(&info[2], PMIX_FWD_STDOUT, NULL, PMIX_BOOL); PMIX_INFO_LOAD(&info[3], PMIX_FWD_STDERR, NULL, PMIX_BOOL);
fprintf(stderr, "Debugger: spawning %s\n", app[0].cmd);
if (PMIX_SUCCESS != (rc = PMIx_Spawn(info, ninfo, app, napps, appspace))) {
fprintf(stderr, "Application failed to launch with error: %s(%d)\n",
PMIx_Error_string(rc), rc);
goto done;
}
PMIX_INFO_FREE(info, ninfo);
PMIX_APP_FREE(app, napps);
if (PMIX_SUCCESS != (rc = spawn_debugger(appspace))) {
goto done;
}
}
DEBUG_WAIT_THREAD(&waiting_for_debugger);
}
done:
DEBUG_DESTRUCT_LOCK(&waiting_for_debugger);
PMIx_tool_finalize();
return (rc);
}
static int attach_to_running_job(char *nspace)
{
pmix_status_t rc;
pmix_query_t *query;
size_t nq;
myquery_data_t *q;
EXAMPLES_HIDE_UNUSED_PARAMS(nspace);
nq = 1;
PMIX_QUERY_CREATE(query, nq);
PMIX_ARGV_APPEND(rc, query[0].keys, PMIX_QUERY_NAMESPACES);
q = (myquery_data_t *) malloc(sizeof(myquery_data_t));
DEBUG_CONSTRUCT_LOCK(&q->lock);
if (PMIX_SUCCESS != (rc = PMIx_Query_info_nb(query, nq, querycbfunc, (void *) q))) {
fprintf(stderr, "Client ns %s rank %d: PMIx_Query_info failed: %d\n", myproc.nspace,
myproc.rank, rc);
PMIX_QUERY_FREE(query, nq);
return -1;
}
DEBUG_WAIT_THREAD(&q->lock);
DEBUG_DESTRUCT_LOCK(&q->lock);
if (NULL == q->info) {
fprintf(stderr, "Query returned no info\n");
PMIX_QUERY_FREE(query, nq);
return -1;
}
if (PMIX_STRING != q->info[0].value.type) {
fprintf(stderr, "Query returned incorrect data type: %d\n", q->info[0].value.type);
PMIX_QUERY_FREE(query, nq);
return -1;
}
if (NULL == q->info[0].value.data.string) {
fprintf(stderr, "Query returned no active nspaces\n");
PMIX_QUERY_FREE(query, nq);
return -1;
}
fprintf(stderr, "Query returned %s\n", q->info[0].value.data.string);
PMIX_QUERY_FREE(query, nq);
return 0;
#if 0#endif
}