#include "src/include/pmix_config.h"
#include "include/pmix.h"
#include "src/client/pmix_client_ops.h"
#include "src/hwloc/pmix_hwloc.h"
#include "src/include/pmix_globals.h"
#include "src/util/pmix_error.h"
static void _loadtp(int sd, short args, void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
PMIX_HIDE_UNUSED_PARAMS(sd, args);
cb->pstatus = pmix_hwloc_load_topology(cb->topo);
PMIX_WAKEUP_THREAD(&cb->lock);
}
PMIX_EXPORT pmix_status_t PMIx_Load_topology(pmix_topology_t *topo)
{
pmix_status_t rc;
pmix_cb_t cb;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
PMIX_CONSTRUCT(&cb, pmix_cb_t);
cb.topo = topo;
PMIX_THREADSHIFT(&cb, _loadtp);
PMIX_WAIT_THREAD(&cb.lock);
rc = cb.pstatus;
PMIX_DESTRUCT(&cb);
return rc;
}
PMIX_EXPORT pmix_status_t PMIx_Parse_cpuset_string(const char *cpuset_string, pmix_cpuset_t *cpuset)
{
pmix_status_t rc;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
rc = pmix_hwloc_parse_cpuset_string(cpuset_string, cpuset);
return rc;
}
PMIX_EXPORT pmix_status_t PMIx_Get_cpuset(pmix_cpuset_t *cpuset, pmix_bind_envelope_t ref)
{
pmix_status_t rc;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
rc = pmix_hwloc_get_cpuset(cpuset, ref);
return rc;
}
PMIX_EXPORT pmix_status_t PMIx_Get_relative_locality(const char *locality1, const char *locality2,
pmix_locality_t *locality)
{
pmix_status_t rc;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
rc = pmix_hwloc_get_relative_locality(locality1, locality2, locality);
return rc;
}
static void icbrelfn(void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
PMIX_RELEASE(cb);
}
static void distcb(pmix_status_t status, pmix_device_distance_t *dist, size_t ndist, void *cbdata,
pmix_release_cbfunc_t release_fn, void *release_cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
size_t n;
cb->status = status;
cb->nvals = ndist;
if (PMIX_SUCCESS == status && 0 < ndist) {
PMIX_DEVICE_DIST_CREATE(cb->dist, cb->nvals);
for (n = 0; n < cb->nvals; n++) {
if (NULL != dist[n].uuid) {
cb->dist[n].uuid = strdup(dist[n].uuid);
}
if (NULL != dist[n].osname) {
cb->dist[n].osname = strdup(dist[n].osname);
}
cb->dist[n].type = dist[n].type;
cb->dist[n].mindist = dist[n].mindist;
cb->dist[n].maxdist = dist[n].maxdist;
}
}
if (NULL != release_fn) {
release_fn(release_cbdata);
}
PMIX_WAKEUP_THREAD(&cb->lock);
}
pmix_status_t PMIx_Compute_distances(pmix_topology_t *topo, pmix_cpuset_t *cpuset,
pmix_info_t info[], size_t ninfo,
pmix_device_distance_t *distances[], size_t *ndist)
{
pmix_cb_t cb;
pmix_status_t rc;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
if (pmix_globals.init_cntr <= 0) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
return PMIX_ERR_INIT;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_distances");
*distances = NULL;
*ndist = 0;
PMIX_CONSTRUCT(&cb, pmix_cb_t);
rc = PMIx_Compute_distances_nb(topo, cpuset, info, ninfo, distcb, &cb);
if (PMIX_SUCCESS != rc) {
PMIX_DESTRUCT(&cb);
return rc;
}
PMIX_WAIT_THREAD(&cb.lock);
rc = cb.status;
if (NULL != cb.dist) {
*distances = cb.dist;
*ndist = cb.nvals;
cb.dist = NULL;
cb.nvals = 0;
}
PMIX_DESTRUCT(&cb);
pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_distances completed");
return rc;
}
static void dcbfunc(int sd, short args, void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
PMIX_HIDE_UNUSED_PARAMS(sd, args);
if (NULL != cb->cbfunc.distfn) {
cb->cbfunc.distfn(cb->status, cb->dist, cb->nvals, cb->cbdata, icbrelfn, cb);
return;
}
PMIX_RELEASE(cb);
}
static void direcv(struct pmix_peer_t *peer, pmix_ptl_hdr_t *hdr, pmix_buffer_t *buf, void *cbdata)
{
pmix_cb_t *cb = (pmix_cb_t *) cbdata;
pmix_status_t rc;
int cnt;
PMIX_HIDE_UNUSED_PARAMS(hdr);
pmix_output_verbose(2, pmix_globals.debug_output,
"pmix:compute_dist recv from server with %d bytes", (int) buf->bytes_used);
if (PMIX_BUFFER_IS_EMPTY(buf)) {
rc = PMIX_ERR_UNREACH;
goto complete;
}
cnt = 1;
PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->status, &cnt, PMIX_STATUS);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
if (PMIX_SUCCESS != cb->status) {
rc = cb->status;
goto complete;
}
cnt = 1;
PMIX_BFROPS_UNPACK(rc, peer, buf, &cb->nvals, &cnt, PMIX_SIZE);
if (PMIX_SUCCESS != rc && PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
if (0 < cb->nvals) {
PMIX_DEVICE_DIST_CREATE(cb->dist, cb->nvals);
cnt = cb->nvals;
PMIX_BFROPS_UNPACK(rc, peer, buf, cb->dist, &cnt, PMIX_DEVICE_DIST);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
goto complete;
}
}
complete:
pmix_output_verbose(2, pmix_globals.debug_output, "pmix:compute_dist recv from server releasing");
cb->cbfunc.distfn(rc, cb->dist, cb->nvals, cb->cbdata, icbrelfn, (void *) cb);
}
pmix_status_t PMIx_Compute_distances_nb(pmix_topology_t *tp, pmix_cpuset_t *cp,
pmix_info_t info[], size_t ninfo,
pmix_device_dist_cbfunc_t cbfunc, void *cbdata)
{
pmix_cb_t *cb;
pmix_status_t rc;
pmix_buffer_t *msg;
pmix_cmd_t cmd = PMIX_COMPUTE_DEVICE_DISTANCES_CMD;
pmix_topology_t *topo = NULL;
pmix_cpuset_t *cpuset = NULL;
PMIX_ACQUIRE_THREAD(&pmix_global_lock);
cb = PMIX_NEW(pmix_cb_t);
cb->cbfunc.distfn = cbfunc;
cb->cbdata = cbdata;
if (NULL == tp) {
if (NULL == pmix_globals.topology.topology) {
rc = pmix_hwloc_load_topology(&pmix_globals.topology);
if (PMIX_SUCCESS != rc) {
goto request;
}
}
topo = &pmix_globals.topology;
} else {
topo = tp;
}
if (NULL == cp) {
if (NULL == pmix_globals.cpuset.bitmap) {
rc = pmix_hwloc_get_cpuset(&pmix_globals.cpuset, PMIX_CPUBIND_PROCESS);
if (PMIX_SUCCESS != rc) {
goto request;
}
}
cpuset = &pmix_globals.cpuset;
} else {
cpuset = cp;
}
cb->status = pmix_hwloc_compute_distances(topo, cpuset, info, ninfo, &cb->dist, &cb->nvals);
if (PMIX_SUCCESS == cb->status) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
PMIX_THREADSHIFT(cb, dcbfunc);
return PMIX_SUCCESS;
}
request:
if ((PMIX_PEER_IS_SERVER(pmix_globals.mypeer) &&
!PMIX_PEER_IS_TOOL(pmix_globals.mypeer)) ||
!pmix_globals.connected) {
PMIX_RELEASE_THREAD(&pmix_global_lock);
PMIX_RELEASE(cb);
return PMIX_ERR_UNREACH;
}
PMIX_RELEASE_THREAD(&pmix_global_lock);
if (topo == &pmix_globals.topology) {
topo = NULL;
}
msg = PMIX_NEW(pmix_buffer_t);
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &cmd, 1, PMIX_COMMAND);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
PMIX_RELEASE(cb);
return rc;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, topo, 1, PMIX_TOPO);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
PMIX_RELEASE(cb);
return rc;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, cpuset, 1, PMIX_PROC_CPUSET);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
PMIX_RELEASE(cb);
return rc;
}
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, &ninfo, 1, PMIX_SIZE);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
PMIX_RELEASE(cb);
return rc;
}
if (0 < ninfo) {
PMIX_BFROPS_PACK(rc, pmix_client_globals.myserver, msg, info, ninfo, PMIX_INFO);
if (PMIX_SUCCESS != rc) {
PMIX_ERROR_LOG(rc);
PMIX_RELEASE(msg);
PMIX_RELEASE(cb);
return rc;
}
}
PMIX_PTL_SEND_RECV(rc, pmix_client_globals.myserver, msg, direcv, (void *) cb);
if (PMIX_SUCCESS != rc) {
PMIX_RELEASE(msg);
PMIX_RELEASE(cb);
}
return rc;
}