Merge pull request #1548 from rhc54/topic/pmix114
Roll to PMIx 1.1.4rc1 and remove the PMIx 1.2.0 directory...
Этот коммит содержится в:
Коммит
6b38c0e1ef
9
.gitignore
поставляемый
9
.gitignore
поставляемый
@ -301,12 +301,8 @@ opal/mca/hwloc/hwloc*/hwloc/include/private/autogen/config.h
|
||||
|
||||
opal/mca/installdirs/config/install_dirs.h
|
||||
|
||||
opal/mca/pmix/pmix112/pmix/include/pmix/autogen/config.h
|
||||
opal/mca/pmix/pmix112/pmix/include/private/autogen/config.h
|
||||
opal/mca/pmix/pmix112/pmix/include/private/autogen/config.h.in
|
||||
opal/mca/pmix/pmix120/pmix/include/pmix/autogen/config.h
|
||||
opal/mca/pmix/pmix120/pmix/include/private/autogen/config.h
|
||||
opal/mca/pmix/pmix120/pmix/include/private/autogen/config.h.in
|
||||
opal/mca/pmix/pmix114/pmix/include/pmix/autogen/config.h
|
||||
opal/mca/pmix/pmix114/pmix/src/include/private/autogen/config.h
|
||||
|
||||
|
||||
opal/tools/opal-checkpoint/opal-checkpoint
|
||||
@ -452,6 +448,7 @@ orte/test/system/getenv_pmi
|
||||
orte/test/system/pmi_abort
|
||||
orte/test/system/opal_hwloc
|
||||
orte/test/system/opal_db
|
||||
orte/test/system/ulfm
|
||||
|
||||
orte/tools/orte-checkpoint/orte-checkpoint
|
||||
orte/tools/orte-checkpoint/orte-checkpoint.1
|
||||
|
@ -1,53 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2014-2016 Intel, Inc. All rights reserved.
|
||||
# Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
|
||||
# Copyright (c) 2015 Research Organization for Information Science
|
||||
# and Technology (RIST). All rights reserved.
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
EXTRA_DIST = autogen.subdirs
|
||||
|
||||
SUBDIRS = pmix
|
||||
|
||||
sources = \
|
||||
pmix1.h \
|
||||
pmix_pmix1_component.c \
|
||||
pmix_pmix1.c \
|
||||
pmix1_client.c \
|
||||
pmix1_server_south.c \
|
||||
pmix1_server_north.c
|
||||
|
||||
# Make the output library in this directory, and name it either
|
||||
# mca_<type>_<name>.la (for DSO builds) or libmca_<type>_<name>.la
|
||||
# (for static builds).
|
||||
|
||||
if MCA_BUILD_opal_pmix_pmix112_DSO
|
||||
component_noinst =
|
||||
component_install = mca_pmix_pmix112.la
|
||||
else
|
||||
component_noinst = libmca_pmix_pmix112.la
|
||||
component_install =
|
||||
endif
|
||||
|
||||
mcacomponentdir = $(opallibdir)
|
||||
mcacomponent_LTLIBRARIES = $(component_install)
|
||||
mca_pmix_pmix112_la_SOURCES = $(sources)
|
||||
mca_pmix_pmix112_la_CFLAGS = $(opal_pmix_pmix112_CFLAGS)
|
||||
mca_pmix_pmix112_la_CPPFLAGS = \
|
||||
-I$(srcdir)/pmix/include $(opal_pmix_pmix112_CPPFLAGS)
|
||||
mca_pmix_pmix112_la_LDFLAGS = -module -avoid-version $(opal_pmix_pmix112_LDFLAGS)
|
||||
mca_pmix_pmix112_la_LIBADD = $(opal_pmix_pmix112_LIBS)
|
||||
mca_pmix_pmix112_la_DEPENDENCIES = $(mca_pmix_pmix112_la_LIBADD)
|
||||
|
||||
noinst_LTLIBRARIES = $(component_noinst)
|
||||
libmca_pmix_pmix112_la_SOURCES =$(sources)
|
||||
libmca_pmix_pmix112_la_CFLAGS = $(opal_pmix_pmix112_CFLAGS)
|
||||
libmca_pmix_pmix112_la_CPPFLAGS = -I$(srcdir)/pmix/include $(opal_pmix_pmix112_CPPFLAGS)
|
||||
libmca_pmix_pmix112_la_LDFLAGS = -module -avoid-version $(opal_pmix_pmix112_LDFLAGS)
|
||||
libmca_pmix_pmix112_la_LIBADD = $(opal_pmix_pmix112_LIBS)
|
||||
libmca_pmix_pmix112_la_DEPENDENCIES = $(mca_pmix_pmix112_la_LIBADD)
|
@ -1,75 +0,0 @@
|
||||
# -*- shell-script -*-
|
||||
#
|
||||
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
# University Research and Technology
|
||||
# Corporation. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
# of Tennessee Research Foundation. All rights
|
||||
# reserved.
|
||||
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
# University of Stuttgart. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2011-2013 Los Alamos National Security, LLC.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2010-2016 Cisco Systems, Inc. All rights reserved.
|
||||
# Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
# Copyright (c) 2015 Research Organization for Information Science
|
||||
# and Technology (RIST). All rights reserved.
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
# MCA_pmix_pmix112_CONFIG([action-if-found], [action-if-not-found])
|
||||
# -----------------------------------------------------------
|
||||
AC_DEFUN([MCA_opal_pmix_pmix112_CONFIG],[
|
||||
AC_CONFIG_FILES([opal/mca/pmix/pmix112/Makefile])
|
||||
|
||||
OPAL_VAR_SCOPE_PUSH([PMIX_VERSION opal_pmix_pmix112_save_CPPFLAGS opal_pmix_pmix112_save_LDFLAGS opal_pmix_pmix112_save_LIBS opal_pmix_pmix112_basedir opal_pmix_pmix112_save_cflags])
|
||||
|
||||
AS_IF([test "$opal_external_pmix_happy" = "yes"],
|
||||
[AC_MSG_WARN([using an external pmix; disqualifiying this component])
|
||||
opal_pmix_pmix112_happy=0],
|
||||
[PMIX_VERSION=
|
||||
opal_pmix_pmix112_basedir=opal/mca/pmix/pmix112
|
||||
|
||||
opal_pmix_pmix112_save_CFLAGS=$CFLAGS
|
||||
opal_pmix_pmix112_save_CPPFLAGS=$CPPFLAGS
|
||||
opal_pmix_pmix112_save_LDFLAGS=$LDFLAGS
|
||||
opal_pmix_pmix112_save_LIBS=$LIBS
|
||||
|
||||
opal_pmix_pmix112_args="--enable-embedded-mode --with-pmix-symbol-prefix=opal_pmix_pmix112_ --disable-visibility --with-libevent-header=\\\"opal/mca/event/$opal_event_base_include\\\" --with-hwloc-header=\\\"$opal_hwloc_base_include\\\""
|
||||
AS_IF([test "$enable_debug" = "yes"],
|
||||
[opal_pmix_pmix112_args="--enable-debug $opal_pmix_pmix112_args"
|
||||
CFLAGS="$OPAL_CFLAGS_BEFORE_PICKY $OPAL_VISIBILITY_CFLAGS -g"],
|
||||
[opal_pmix_pmix112_args="--disable-debug $opal_pmix_pmix112_args"
|
||||
CFLAGS="$OPAL_CFLAGS_BEFORE_PICKY $OPAL_VISIBILITY_CFLAGS"])
|
||||
CPPFLAGS="-I$OPAL_TOP_SRCDIR -I$OPAL_TOP_BUILDDIR -I$OPAL_TOP_SRCDIR/opal/include -I$OPAL_TOP_BUILDDIR/opal/include $CPPFLAGS"
|
||||
|
||||
OPAL_CONFIG_SUBDIR([$opal_pmix_pmix112_basedir/pmix],
|
||||
[$opal_pmix_pmix112_args $opal_subdir_args 'CFLAGS=$CFLAGS' 'CPPFLAGS=$CPPFLAGS'],
|
||||
[opal_pmix_pmix112_happy=1], [opal_pmix_pmix112_happy=0])
|
||||
|
||||
AS_IF([test $opal_pmix_pmix112_happy -eq 1],
|
||||
[PMIX_VERSION="internal v`$srcdir/$opal_pmix_pmix112_basedir/pmix/config/pmix_get_version.sh $srcdir/$opal_pmix_pmix112_basedir/pmix/VERSION`"
|
||||
# Build flags for our Makefile.am
|
||||
opal_pmix_pmix112_LIBS='$(OPAL_TOP_BUILDDIR)/'"$opal_pmix_pmix112_basedir"'/pmix/libpmix.la'
|
||||
opal_pmix_pmix112_CPPFLAGS='-I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix112/pmix/include/pmix -I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix112/pmix/include -I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix112/pmix -I$(OPAL_TOP_SRCDIR)/opal/mca/pmix/pmix112/pmix'
|
||||
AC_SUBST([opal_pmix_pmix112_LIBS])
|
||||
AC_SUBST([opal_pmix_pmix112_CPPFLAGS])])
|
||||
|
||||
CFLAGS=$opal_pmix_pmix112_save_CFLAGS
|
||||
CPPFLAGS=$opal_pmix_pmix112_save_CPPFLAGS
|
||||
LDFLAGS=$opal_pmix_pmix112_save_LDFLAGS
|
||||
LIBS=$opal_pmix_pmix112_save_LIBS
|
||||
])
|
||||
|
||||
AS_IF([test $opal_pmix_pmix112_happy -eq 1],
|
||||
[$1],
|
||||
[$2])
|
||||
|
||||
OPAL_VAR_SCOPE_POP
|
||||
])dnl
|
@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
pmix_proc_t myproc;
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
char *tmp;
|
||||
pmix_proc_t proc;
|
||||
uint32_t nprocs, n;
|
||||
pmix_info_t *info;
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Init failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: Running\n", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get universe size failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
fprintf(stderr, "Client %s:%d universe size %d\n", myproc.nspace, myproc.rank, nprocs);
|
||||
|
||||
/* put a few values */
|
||||
(void)asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT32;
|
||||
value.data.uint32 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Store_internal failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT64;
|
||||
value.data.uint64 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Put internal failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_STRING;
|
||||
value.data.string = "1234";
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_REMOTE, tmp, &value))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Put internal failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Commit failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call fence to ensure the data is received */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
PMIX_INFO_CREATE(info, 1);
|
||||
(void)strncpy(info->key, PMIX_COLLECT_DATA, PMIX_MAX_KEYLEN);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, info, 1))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Fence failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
PMIX_INFO_FREE(info, 1);
|
||||
|
||||
/* check the returned data */
|
||||
for (n=0; n < nprocs; n++) {
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, tmp, NULL, 0, &val))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s failed: %d\n", myproc.nspace, myproc.rank, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
if (PMIX_UINT64 != val->type) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s returned wrong type: %d\n", myproc.nspace, myproc.rank, tmp, val->type);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
if (1234 != val->data.uint64) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s returned wrong value: %d\n", myproc.nspace, myproc.rank, tmp, (int)val->data.uint64);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s returned correct\n", myproc.nspace, myproc.rank, tmp);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, tmp, NULL, 0, &val))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s failed: %d\n", myproc.nspace, myproc.rank, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
if (PMIX_STRING != val->type) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s returned wrong type: %d\n", myproc.nspace, myproc.rank, tmp, val->type);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
if (0 != strcmp(val->data.string, "1234")) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s returned wrong value: %s\n", myproc.nspace, myproc.rank, tmp, val->data.string);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s returned correct\n", myproc.nspace, myproc.rank, tmp);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
done:
|
||||
/* finalize us */
|
||||
fprintf(stderr, "Client ns %s rank %d: Finalizing\n", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(0);
|
||||
}
|
@ -1,217 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
static uint32_t nprocs;
|
||||
static pmix_proc_t myproc;
|
||||
static uint32_t getcount = 0;
|
||||
|
||||
#define WAIT_FOR_COMPLETION(a) \
|
||||
do { \
|
||||
while ((a)) { \
|
||||
usleep(10); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
static void opcbfunc(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
bool *active = (bool*)cbdata;
|
||||
|
||||
fprintf(stderr, "%s:%d completed fence_nb\n", myproc.nspace, myproc.rank);
|
||||
*active = false;
|
||||
}
|
||||
|
||||
static void valcbfunc(pmix_status_t status,
|
||||
pmix_value_t *val, void *cbdata)
|
||||
{
|
||||
char *key = (char*)cbdata;
|
||||
|
||||
if (PMIX_SUCCESS == status) {
|
||||
if (NULL != strstr(key, "local")) {
|
||||
if (PMIX_UINT64 != val->type) {
|
||||
fprintf(stderr, "%s:%d: PMIx_Get_nb Key %s returned wrong type: %d\n", myproc.nspace, myproc.rank, key, val->type);
|
||||
goto done;
|
||||
}
|
||||
if (1234 != val->data.uint64) {
|
||||
fprintf(stderr, "%s:%d: PMIx_Get_nb Key %s returned wrong value: %d\n", myproc.nspace, myproc.rank, key, (int)val->data.uint64);
|
||||
goto done;
|
||||
}
|
||||
} else if (NULL != strstr(key, "remote")) {
|
||||
if (PMIX_STRING != val->type) {
|
||||
fprintf(stderr, "%s:%d: PMIx_Get_nb Key %s returned wrong type: %d\n", myproc.nspace, myproc.rank, key, val->type);
|
||||
goto done;
|
||||
}
|
||||
if (0 != strcmp(val->data.string, "1234")) {
|
||||
fprintf(stderr, "%s:%d: PMIx_Get_nb Key %s returned wrong value: %s\n", myproc.nspace, myproc.rank, key, val->data.string);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d PMIx_Get_nb returned wrong key: %s\n", myproc.nspace, myproc.rank, key);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "%s:%d PMIx_Get_nb Key %s returned correctly\n", myproc.nspace, myproc.rank, key);
|
||||
} else {
|
||||
fprintf(stderr, "%s:%d PMIx_Get_nb Key %s failed\n", myproc.nspace, myproc.rank, key);
|
||||
}
|
||||
done:
|
||||
free(key);
|
||||
getcount++;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
char *tmp;
|
||||
pmix_proc_t proc;
|
||||
uint32_t n, num_gets;
|
||||
bool active;
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Init failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: Running\n", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get universe size failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
fprintf(stderr, "Client %s:%d universe size %d\n", myproc.nspace, myproc.rank, nprocs);
|
||||
|
||||
/* put a few values */
|
||||
(void)asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT32;
|
||||
value.data.uint32 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Store_internal failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT64;
|
||||
value.data.uint64 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Put internal failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_STRING;
|
||||
value.data.string = "1234";
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_REMOTE, tmp, &value))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Put internal failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* introduce a delay by one rank so we can check what happens
|
||||
* if a "get" is received prior to data being provided */
|
||||
if (0 == myproc.rank) {
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
/* commit the data to the server */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Commit failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call fence_nb, but don't return any data */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
active = true;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence_nb(&proc, 1, NULL, 0, opcbfunc, &active))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Fence failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* get the committed data - ask for someone who doesn't exist as well */
|
||||
num_gets = 0;
|
||||
for (n=0; n <= nprocs; n++) {
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, n);
|
||||
(void)strncpy(proc.nspace, tmp, PMIX_MAX_NSLEN);
|
||||
proc.rank = n;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&proc, tmp,
|
||||
NULL, 0, valcbfunc, tmp))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s failed: %d\n", myproc.nspace, n, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
++num_gets;
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, n);
|
||||
(void)strncpy(proc.nspace, tmp, PMIX_MAX_NSLEN);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&proc, tmp,
|
||||
NULL, 0, valcbfunc, tmp))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get %s failed: %d\n", myproc.nspace, n, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
++num_gets;
|
||||
}
|
||||
|
||||
/* wait for the first fence to finish */
|
||||
WAIT_FOR_COMPLETION(active);
|
||||
|
||||
/* wait for all my "get" calls to complete */
|
||||
while (getcount < num_gets) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
/* call fence again so everyone waits before leaving */
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Fence failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
/* finalize us */
|
||||
fprintf(stderr, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(0);
|
||||
}
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
|
||||
static pmix_proc_t myproc;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
pmix_proc_t proc;
|
||||
uint32_t nprocs;
|
||||
char nsp2[PMIX_MAX_NSLEN+1];
|
||||
pmix_app_t *app;
|
||||
char hostname[1024];
|
||||
pmix_proc_t *peers;
|
||||
size_t npeers, ntmp=0;
|
||||
char *nodelist;
|
||||
|
||||
gethostname(hostname, 1024);
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Init failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
exit(0);
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: Running\n", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get universe size failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
fprintf(stderr, "Client %s:%d universe size %d\n", myproc.nspace, myproc.rank, nprocs);
|
||||
|
||||
/* call fence to sync */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Fence failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* rank=0 calls spawn */
|
||||
if (0 == myproc.rank) {
|
||||
PMIX_APP_CREATE(app, 1);
|
||||
app->cmd = strdup("gumby");
|
||||
app->maxprocs = 2;
|
||||
app->argc = 3;
|
||||
app->argv = (char**)malloc(4 * sizeof(char*));
|
||||
app->argv[0] = strdup("gumby");
|
||||
app->argv[1] = strdup("-n");
|
||||
app->argv[2] = strdup("2");
|
||||
app->argv[3] = NULL;
|
||||
app->env = (char**)malloc(2 * sizeof(char*));
|
||||
app->env[0] = strdup("PMIX_ENV_VALUE=3");
|
||||
app->env[1] = NULL;
|
||||
PMIX_INFO_CREATE(app->info, 2);
|
||||
(void)strncpy(app->info[0].key, "DARTH", PMIX_MAX_KEYLEN);
|
||||
app->info[0].value.type = PMIX_INT8;
|
||||
app->info[0].value.data.int8 = 12;
|
||||
(void)strncpy(app->info[1].key, "VADER", PMIX_MAX_KEYLEN);
|
||||
app->info[1].value.type = PMIX_DOUBLE;
|
||||
app->info[1].value.data.dval = 12.34;
|
||||
|
||||
fprintf(stderr, "Client ns %s rank %d: calling PMIx_Spawn\n", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Spawn(NULL, 0, app, 1, nsp2))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Spawn failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
PMIX_APP_FREE(app, 1);
|
||||
|
||||
/* check to see if we got the expected info back */
|
||||
if (0 != strncmp(nsp2, "DYNSPACE", PMIX_MAX_NSLEN)) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Spawn returned incorrect nspace: %s\n", myproc.nspace, myproc.rank, nsp2);
|
||||
goto done;
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Spawn succeeded returning nspace: %s\n", myproc.nspace, myproc.rank, nsp2);
|
||||
}
|
||||
/* get their universe size */
|
||||
val = NULL;
|
||||
(void)strncpy(proc.nspace, nsp2, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_UNIV_SIZE, NULL, 0, &val)) ||
|
||||
NULL == val) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Get universe size failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
ntmp = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
fprintf(stderr, "Client %s:%d universe %s size %d\n", myproc.nspace, myproc.rank, nsp2, (int)ntmp);
|
||||
}
|
||||
|
||||
/* just cycle the connect/disconnect functions */
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Connect(&proc, 1, NULL, 0))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Connect failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Connect succeeded\n", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Disconnect(&proc, 1, NULL, 0))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Disonnect failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Disconnect succeeded\n", myproc.nspace, myproc.rank);
|
||||
|
||||
/* finally, test the resolve functions */
|
||||
if (0 == myproc.rank) {
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_peers(hostname, NULL, &peers, &npeers))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_peers failed for nspace %s: %d\n", myproc.nspace, myproc.rank, nsp2, rc);
|
||||
goto done;
|
||||
}
|
||||
if ((nprocs+ntmp) != npeers) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_peers returned incorrect npeers: %d vs %d\n", myproc.nspace, myproc.rank, (int)(nprocs+ntmp), (int)npeers);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_peers returned %d npeers\n", myproc.nspace, myproc.rank, (int)npeers);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_nodes(nsp2, &nodelist))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_nodes failed for nspace %s: %d\n", myproc.nspace, myproc.rank, nsp2, rc);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_nodes %s", myproc.nspace, myproc.rank, nodelist);
|
||||
} else {
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_peers(hostname, myproc.nspace, &peers, &npeers))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_peers failed for nspace %s: %d\n", myproc.nspace, myproc.rank, myproc.nspace, rc);
|
||||
goto done;
|
||||
}
|
||||
if (nprocs != npeers) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_peers returned incorrect npeers: %d vs %d\n", myproc.nspace, myproc.rank, nprocs, (int)npeers);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_peers returned %d npeers\n", myproc.nspace, myproc.rank, (int)npeers);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_nodes(myproc.nspace, &nodelist))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_nodes failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Resolve_nodes %s\n", myproc.nspace, myproc.rank, nodelist);
|
||||
}
|
||||
PMIX_PROC_FREE(peers, npeers);
|
||||
free(nodelist);
|
||||
|
||||
done:
|
||||
/* call fence to sync */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
fprintf(stderr, "Client ns %s rank %d: PMIx_Fence failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* finalize us */
|
||||
fprintf(stderr, "Client ns %s rank %d: Finalizing\n", myproc.nspace, myproc.rank);
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(0);
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
#
|
||||
# Copyright 2015 Intel, Inc. All rights reserved
|
||||
# Copyright 2016 Research Organization for Information Science
|
||||
# and Technology (RIST). All rights reserved.
|
||||
#
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
# Only install the headers if we're in standalone mode
|
||||
|
||||
EXTRA_DIST += include/private/autogen/README.txt
|
||||
|
||||
if ! PMIX_EMBEDDED_MODE
|
||||
include_HEADERS = \
|
||||
include/pmix.h \
|
||||
include/pmix_server.h \
|
||||
include/pmi.h \
|
||||
include/pmi2.h
|
||||
|
||||
headers += \
|
||||
include/private/align.h \
|
||||
include/private/hash_string.h \
|
||||
include/private/pmix_socket_errno.h \
|
||||
include/private/pmix_stdint.h \
|
||||
include/private/prefetch.h \
|
||||
include/private/types.h
|
||||
include_pmixdir = $(includedir)/pmix
|
||||
include_pmix_HEADERS = \
|
||||
include/pmix/rename.h \
|
||||
include/pmix/pmix_common.h
|
||||
|
||||
include_pmix_autogendir = $(includedir)/pmix/autogen
|
||||
include_pmix_autogen_HEADERS = \
|
||||
include/pmix/autogen/pmix_config_top.h \
|
||||
include/pmix/autogen/pmix_config_bottom.h
|
||||
nodist_include_pmix_autogen_HEADERS = \
|
||||
include/pmix/autogen/config.h
|
||||
include_private_autogendir = $(includedir)/private/autogen
|
||||
nodist_include_private_autogen_HEADERS = \
|
||||
include/private/autogen/config.h
|
||||
|
||||
endif ! PMIX_EMBEDDED_MODE
|
@ -1,401 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer listed
|
||||
* in this license in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* The copyright holders provide no reassurances that the source code
|
||||
* provided does not infringe any patent, copyright, or any other
|
||||
* intellectual property rights of third parties. The copyright holders
|
||||
* disclaim any liability to any recipient for claims brought against
|
||||
* recipient by any third party for infringement of that parties
|
||||
* intellectual property rights.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIx_H
|
||||
#define PMIx_H
|
||||
|
||||
#include <pmix/autogen/config.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#endif
|
||||
|
||||
/* Symbol transforms */
|
||||
#include <pmix/rename.h>
|
||||
|
||||
/* Structure and constant definitions */
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**** PMIX API ****/
|
||||
|
||||
/* Initialize the PMIx client, returning the process identifier assigned
|
||||
* to this client's application in the provided pmix_proc_t struct.
|
||||
* Passing a parameter of _NULL_ for this parameter is allowed if the user
|
||||
* wishes solely to initialize the PMIx system and does not require
|
||||
* return of the identifier at that time.
|
||||
*
|
||||
* When called the PMIx client will check for the required connection
|
||||
* information of the local PMIx server and will establish the connection.
|
||||
* If the information is not found, or the server connection fails, then
|
||||
* an appropriate error constant will be returned.
|
||||
*
|
||||
* If successful, the function will return PMIX_SUCCESS and will fill the
|
||||
* provided structure with the server-assigned namespace and rank of the
|
||||
* process within the application.
|
||||
*
|
||||
* Note that the PMIx client library is referenced counted, and so multiple
|
||||
* calls to PMIx_Init are allowed. Thus, one way to obtain the namespace and
|
||||
* rank of the process is to simply call PMIx_Init with a non-NULL parameter. */
|
||||
pmix_status_t PMIx_Init(pmix_proc_t *proc);
|
||||
|
||||
/* Finalize the PMIx client, closing the connection to the local server.
|
||||
* An error code will be returned if, for some reason, the connection
|
||||
* cannot be closed. */
|
||||
pmix_status_t PMIx_Finalize(void);
|
||||
|
||||
/* Returns _true_ if the PMIx client has been successfully initialized,
|
||||
* returns _false_ otherwise. Note that the function only reports the
|
||||
* internal state of the PMIx client - it does not verify an active
|
||||
* connection with the server, nor that the server is functional. */
|
||||
int PMIx_Initialized(void);
|
||||
|
||||
|
||||
/* Request that the provided array of procs be aborted, returning the
|
||||
* provided _status_ and printing the provided message. A _NULL_
|
||||
* for the proc array indicates that all processes in the caller's
|
||||
* nspace are to be aborted.
|
||||
*
|
||||
* The response to this request is somewhat dependent on the specific resource
|
||||
* manager and its configuration (e.g., some resource managers will
|
||||
* not abort the application if the provided _status_ is zero unless
|
||||
* specifically configured to do so), and thus lies outside the control
|
||||
* of PMIx itself. However, the client will inform the RM of
|
||||
* the request that the application be aborted, regardless of the
|
||||
* value of the provided _status_.
|
||||
*
|
||||
* Passing a _NULL_ msg parameter is allowed. Note that race conditions
|
||||
* caused by multiple processes calling PMIx_Abort are left to the
|
||||
* server implementation to resolve with regard to which status is
|
||||
* returned and what messages (if any) are printed. */
|
||||
pmix_status_t PMIx_Abort(int status, const char msg[],
|
||||
pmix_proc_t procs[], size_t nprocs);
|
||||
|
||||
|
||||
/* Push a value into the client's namespace. The client library will cache
|
||||
* the information locally until _PMIx_Commit_ is called. The provided scope
|
||||
* value is passed to the local PMIx server, which will distribute the data
|
||||
* as directed. */
|
||||
pmix_status_t PMIx_Put(pmix_scope_t scope, const char key[], pmix_value_t *val);
|
||||
|
||||
|
||||
/* Push all previously _PMIx_Put_ values to the local PMIx server.
|
||||
* This is an asynchronous operation - the library will immediately
|
||||
* return to the caller while the data is transmitted to the local
|
||||
* server in the background */
|
||||
pmix_status_t PMIx_Commit(void);
|
||||
|
||||
|
||||
/* Execute a blocking barrier across the processes identified in the
|
||||
* specified array. Passing a _NULL_ pointer as the _procs_ parameter
|
||||
* indicates that the barrier is to span all processes in the client's
|
||||
* namespace. Each provided pmix_proc_t struct can pass PMIX_RANK_WILDCARD to
|
||||
* indicate that all processes in the given namespace are
|
||||
* participating.
|
||||
*
|
||||
* The info array is used to pass user requests regarding the fence
|
||||
* operation. This can include:
|
||||
*
|
||||
* (a) PMIX_COLLECT_DATA - a boolean indicating whether or not the barrier
|
||||
* operation is to return the _put_ data from all participating processes.
|
||||
* A value of _false_ indicates that the callback is just used as a release
|
||||
* and no data is to be returned at that time. A value of _true_ indicates
|
||||
* that all _put_ data is to be collected by the barrier. Returned data is
|
||||
* cached at the server to reduce memory footprint, and can be retrieved
|
||||
* as needed by calls to PMIx_Get(nb).
|
||||
*
|
||||
* Note that for scalability reasons, the default behavior for PMIx_Fence
|
||||
* is to _not_ collect the data.
|
||||
*
|
||||
* (b) PMIX_COLLECTIVE_ALGO - a comma-delimited string indicating the algos
|
||||
* to be used for executing the barrier, in priority order.
|
||||
*
|
||||
* (c) PMIX_COLLECTIVE_ALGO_REQD - instructs the host RM that it should return
|
||||
* an error if none of the specified algos are available. Otherwise, the RM
|
||||
* is to use one of the algos if possible, but is otherwise free to use any
|
||||
* of its available methods to execute the operation.
|
||||
*
|
||||
* (d) PMIX_TIMEOUT - maximum time for the fence to execute before declaring
|
||||
* an error. By default, the RM shall terminate the operation and notify participants
|
||||
* if one or more of the indicated procs fails during the fence. However,
|
||||
* the timeout parameter can help avoid "hangs" due to programming errors
|
||||
* that prevent one or more procs from reaching the "fence".
|
||||
*/
|
||||
pmix_status_t PMIx_Fence(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo);
|
||||
|
||||
/* Non-blocking version of PMIx_Fence. Note that the function will return
|
||||
* an error if a _NULL_ callback function is given. */
|
||||
pmix_status_t PMIx_Fence_nb(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
|
||||
/* Retrieve information for the specified _key_ as published by the process
|
||||
* identified in the given pmix_proc_t, returning a pointer to the value in the
|
||||
* given address.
|
||||
*
|
||||
* This is a blocking operation - the caller will block until
|
||||
* the specified data has been _PMIx_Put_ by the specified rank. The caller is
|
||||
* responsible for freeing all memory associated with the returned value when
|
||||
* no longer required.
|
||||
*
|
||||
* The info array is used to pass user requests regarding the get
|
||||
* operation. This can include:
|
||||
*
|
||||
* (a) PMIX_TIMEOUT - maximum time for the get to execute before declaring
|
||||
* an error. The timeout parameter can help avoid "hangs" due to programming
|
||||
* errors that prevent the target proc from ever exposing its data.
|
||||
*/
|
||||
pmix_status_t PMIx_Get(const pmix_proc_t *proc, const char key[],
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_value_t **val);
|
||||
|
||||
/* A non-blocking operation version of PMIx_Get - the callback function will
|
||||
* be executed once the specified data has been _PMIx_Put_
|
||||
* by the identified process and retrieved by the local server. The info
|
||||
* array is used as described above for the blocking form of this call. */
|
||||
pmix_status_t PMIx_Get_nb(const pmix_proc_t *proc, const char key[],
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_value_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
|
||||
/* Publish the data in the info array for lookup. By default,
|
||||
* the data will be published into the PMIX_SESSION range and
|
||||
* with PMIX_PERSIST_APP persistence. Changes to those values,
|
||||
* and any additional directives, can be included in the pmix_info_t
|
||||
* array.
|
||||
*
|
||||
* Note that the keys must be unique within the specified
|
||||
* data range or else an error will be returned (first published
|
||||
* wins). Attempts to access the data by procs outside of
|
||||
* the provided data range will be rejected.
|
||||
*
|
||||
* The persistence parameter instructs the server as to how long
|
||||
* the data is to be retained.
|
||||
*
|
||||
* The blocking form will block until the server confirms that the
|
||||
* data has been posted and is available. The non-blocking form will
|
||||
* return immediately, executing the callback when the server confirms
|
||||
* availability of the data.
|
||||
*/
|
||||
pmix_status_t PMIx_Publish(const pmix_info_t info[], size_t ninfo);
|
||||
pmix_status_t PMIx_Publish_nb(const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
|
||||
/* Lookup information published by this or another process. By default,
|
||||
* the search will be conducted across the PMIX_SESSION range. Changes
|
||||
* to the range, and any additional directives, can be provided
|
||||
* in the pmix_info_t array. Note that the search is also constrained
|
||||
* to only data published by the current user ID - i.e., the search
|
||||
* will not return data published by an application being executed
|
||||
* by another user. There currently is no option to override this
|
||||
* behavior - such an option may become available later via an
|
||||
* appropriate pmix_info_t directive.
|
||||
*
|
||||
* The "data" parameter consists of an array of pmix_pdata_t struct with the
|
||||
* keys specifying the requested information. Data will be returned
|
||||
* for each key in the associated info struct - any key that cannot
|
||||
* be found will return with a data type of "PMIX_UNDEF". The function
|
||||
* will return SUCCESS if _any_ values can be found, so the caller
|
||||
* must check each data element to ensure it was returned.
|
||||
*
|
||||
* The proc field in each pmix_pdata_t struct will contain the
|
||||
* nspace/rank of the process that published the data.
|
||||
*
|
||||
* Note: although this is a blocking function, it will _not_ wait
|
||||
* by default for the requested data to be published. Instead, it
|
||||
* will block for the time required by the server to lookup its current
|
||||
* data and return any found items. Thus, the caller is responsible for
|
||||
* ensuring that data is published prior to executing a lookup, or
|
||||
* for retrying until the requested data is found
|
||||
*
|
||||
* Optionally, the info array can be used to modify this behavior
|
||||
* by including:
|
||||
*
|
||||
* (a) PMIX_WAIT - wait for the requested data to be published. The
|
||||
* server is to wait until all data has become available.
|
||||
*
|
||||
* (b) PMIX_TIMEOUT - max time to wait for data to become available.
|
||||
*
|
||||
*/
|
||||
pmix_status_t PMIx_Lookup(pmix_pdata_t data[], size_t ndata,
|
||||
const pmix_info_t info[], size_t ninfo);
|
||||
|
||||
/* Non-blocking form of the _PMIx_Lookup_ function. Data for
|
||||
* the provided NULL-terminated keys array will be returned
|
||||
* in the provided callback function. As above, the default
|
||||
* behavior is to _not_ wait for data to be published. The
|
||||
* info keys can be used to modify the behavior as previously
|
||||
* described */
|
||||
pmix_status_t PMIx_Lookup_nb(char **keys, const pmix_info_t info[], size_t ninfo,
|
||||
pmix_lookup_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
|
||||
/* Unpublish data posted by this process using the given keys.
|
||||
* The function will block until the data has been removed by
|
||||
* the server. A value of _NULL_ for the keys parameter instructs
|
||||
* the server to remove _all_ data published by this process.
|
||||
*
|
||||
* By default, the range is assumed to be PMIX_SESSION. Changes
|
||||
* to the range, and any additional directives, can be provided
|
||||
* in the pmix_info_t array */
|
||||
pmix_status_t PMIx_Unpublish(char **keys,
|
||||
const pmix_info_t info[], size_t ninfo);
|
||||
|
||||
/* Non-blocking form of the _PMIx_Unpublish_ function. The
|
||||
* callback function will be executed once the server confirms
|
||||
* removal of the specified data. */
|
||||
pmix_status_t PMIx_Unpublish_nb(char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
|
||||
/* Spawn a new job. The assigned namespace of the spawned applications
|
||||
* is returned in the nspace parameter - a _NULL_ value in that
|
||||
* location indicates that the caller doesn't wish to have the
|
||||
* namespace returned. The nspace array must be at least of size
|
||||
* PMIX_MAX_NSLEN+1. Behavior of individual resource managers
|
||||
* may differ, but it is expected that failure of any application
|
||||
* process to start will result in termination/cleanup of _all_
|
||||
* processes in the newly spawned job and return of an error
|
||||
* code to the caller.
|
||||
*
|
||||
* By default, the spawned processes will be PMIx "connected" to
|
||||
* the parent process upon successful launch (see PMIx_Connect
|
||||
* description for details). Note that this only means that the
|
||||
* parent process (a) will be given a copy of the new job's
|
||||
* information so it can query job-level info without
|
||||
* incurring any communication penalties, and (b) will receive
|
||||
* notification of errors from process in the child job.
|
||||
*
|
||||
* Job-level directives can be specified in the job_info array. This
|
||||
* can include:
|
||||
*
|
||||
* (a) PMIX_NON_PMI - processes in the spawned job will
|
||||
* not be calling PMIx_Init
|
||||
*
|
||||
* (b) PMIX_TIMEOUT - declare the spawn as having failed if the launched
|
||||
* procs do not call PMIx_Init within the specified time
|
||||
*
|
||||
* (c) PMIX_NOTIFY_COMPLETION - notify the parent process when the
|
||||
* child job terminates, either normally or with error
|
||||
*/
|
||||
pmix_status_t PMIx_Spawn(const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
char nspace[]);
|
||||
|
||||
|
||||
/* Non-blocking form of the _PMIx_Spawn_ function. The callback
|
||||
* will be executed upon launch of the specified applications,
|
||||
* or upon failure to launch any of them. */
|
||||
pmix_status_t PMIx_Spawn_nb(const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
pmix_spawn_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
/* Record the specified processes as "connected". Both blocking and non-blocking
|
||||
* versions are provided. This means that the resource manager should treat the
|
||||
* failure of any process in the specified group as a reportable event, and take
|
||||
* appropriate action. Note that different resource managers may respond to
|
||||
* failures in different manners.
|
||||
*
|
||||
* The callback function is to be called once all participating processes have
|
||||
* called connect. The server is required to return any job-level info for the
|
||||
* connecting processes that might not already have - i.e., if the connect
|
||||
* request involves procs from different nspaces, then each proc shall receive
|
||||
* the job-level info from those nspaces other than their own.
|
||||
*
|
||||
* Note: a process can only engage in _one_ connect operation involving the identical
|
||||
* set of processes at a time. However, a process _can_ be simultaneously engaged
|
||||
* in multiple connect operations, each involving a different set of processes
|
||||
*
|
||||
* As in the case of the fence operation, the info array can be used to pass
|
||||
* user-level directives regarding the algorithm to be used for the collective
|
||||
* operation involved in the "connect", timeout constraints, and other options
|
||||
* available from the host RM */
|
||||
pmix_status_t PMIx_Connect(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo);
|
||||
|
||||
pmix_status_t PMIx_Connect_nb(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
/* Disconnect a previously connected set of processes. An error will be returned
|
||||
* if the specified set of procs was not previously "connected". As above, a process
|
||||
* may be involved in multiple simultaneous disconnect operations. However, a process
|
||||
* is not allowed to reconnect to a set of procs that has not fully completed
|
||||
* disconnect - i.e., you have to fully disconnect before you can reconnect to the
|
||||
* _same_ group of processes. The info array is used as above. */
|
||||
pmix_status_t PMIx_Disconnect(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo);
|
||||
|
||||
pmix_status_t PMIx_Disconnect_nb(const pmix_proc_t ranges[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
/* Given a node name, return an array of processes within the specified nspace
|
||||
* on that node. If the nspace is NULL, then all processes on the node will
|
||||
* be returned. If the specified node does not currently host any processes,
|
||||
* then the returned array will be NULL, and nprocs=0. The caller is responsible
|
||||
* for releasing the array when done with it - the PMIX_PROC_FREE macro is
|
||||
* provided for this purpose.
|
||||
*/
|
||||
pmix_status_t PMIx_Resolve_peers(const char *nodename, const char *nspace,
|
||||
pmix_proc_t **procs, size_t *nprocs);
|
||||
|
||||
|
||||
/* Given an nspace, return the list of nodes hosting processes within
|
||||
* that nspace. The returned string will contain a comma-delimited list
|
||||
* of nodenames. The caller is responsible for releasing the string
|
||||
* when done with it */
|
||||
pmix_status_t PMIx_Resolve_nodes(const char *nspace, char **nodelist);
|
||||
|
||||
END_C_DECLS
|
||||
#endif
|
@ -1,197 +0,0 @@
|
||||
/* -*- c -*-
|
||||
* Copyright © 2009 CNRS
|
||||
* Copyright © 2009-2014 Inria. All rights reserved.
|
||||
* Copyright © 2009-2012 Université Bordeaux
|
||||
* Copyright © 2009-2011 Cisco Systems, Inc. All rights reserved.
|
||||
* See COPYING in top-level directory.
|
||||
*/
|
||||
|
||||
/* The configuration file */
|
||||
|
||||
#ifndef PMIX_PUBLIC_CONFIG_H
|
||||
#define PMIX_PUBLIC_CONFIG_H
|
||||
|
||||
#if (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
|
||||
# define __pmix_restrict __restrict
|
||||
#else
|
||||
# if __STDC_VERSION__ >= 199901L
|
||||
# define __pmix_restrict restrict
|
||||
# else
|
||||
# define __pmix_restrict
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Note that if we're compiling C++, then just use the "inline"
|
||||
keyword, since it's part of C++ */
|
||||
#if defined(c_plusplus) || defined(__cplusplus)
|
||||
# define __pmix_inline inline
|
||||
#elif defined(_MSC_VER) || defined(__HP_cc)
|
||||
# define __pmix_inline __inline
|
||||
#else
|
||||
# define __pmix_inline __inline__
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Note: this is public. We can not assume anything from the compiler used
|
||||
* by the application and thus the PMIX_HAVE_* macros below are not
|
||||
* fetched from the autoconf result here. We only automatically use a few
|
||||
* well-known easy cases.
|
||||
*/
|
||||
|
||||
/* Some handy constants to make the logic below a little more readable */
|
||||
#if defined(__cplusplus) && \
|
||||
(__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR >= 4))
|
||||
#define GXX_ABOVE_3_4 1
|
||||
#else
|
||||
#define GXX_ABOVE_3_4 0
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus) && \
|
||||
(__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95))
|
||||
#define GCC_ABOVE_2_95 1
|
||||
#else
|
||||
#define GCC_ABOVE_2_95 0
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus) && \
|
||||
(__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96))
|
||||
#define GCC_ABOVE_2_96 1
|
||||
#else
|
||||
#define GCC_ABOVE_2_96 0
|
||||
#endif
|
||||
|
||||
#if !defined(__cplusplus) && \
|
||||
(__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3))
|
||||
#define GCC_ABOVE_3_3 1
|
||||
#else
|
||||
#define GCC_ABOVE_3_3 0
|
||||
#endif
|
||||
|
||||
/* Maybe before gcc 2.95 too */
|
||||
#ifdef PMIX_HAVE_ATTRIBUTE_UNUSED
|
||||
#define __PMIX_HAVE_ATTRIBUTE_UNUSED PMIX_HAVE_ATTRIBUTE_UNUSED
|
||||
#elif defined(__GNUC__)
|
||||
# define __PMIX_HAVE_ATTRIBUTE_UNUSED (GXX_ABOVE_3_4 || GCC_ABOVE_2_95)
|
||||
#else
|
||||
# define __PMIX_HAVE_ATTRIBUTE_UNUSED 0
|
||||
#endif
|
||||
#if __PMIX_HAVE_ATTRIBUTE_UNUSED
|
||||
# define __pmix_attribute_unused __attribute__((__unused__))
|
||||
#else
|
||||
# define __pmix_attribute_unused
|
||||
#endif
|
||||
|
||||
#ifdef PMIX_HAVE_ATTRIBUTE_MALLOC
|
||||
#define __PMIX_HAVE_ATTRIBUTE_MALLOC PMIX_HAVE_ATTRIBUTE_MALLOC
|
||||
#elif defined(__GNUC__)
|
||||
# define __PMIX_HAVE_ATTRIBUTE_MALLOC (GXX_ABOVE_3_4 || GCC_ABOVE_2_96)
|
||||
#else
|
||||
# define __PMIX_HAVE_ATTRIBUTE_MALLOC 0
|
||||
#endif
|
||||
#if __PMIX_HAVE_ATTRIBUTE_MALLOC
|
||||
# define __pmix_attribute_malloc __attribute__((__malloc__))
|
||||
#else
|
||||
# define __pmix_attribute_malloc
|
||||
#endif
|
||||
|
||||
#ifdef PMIX_HAVE_ATTRIBUTE_CONST
|
||||
#define __PMIX_HAVE_ATTRIBUTE_CONST PMIX_HAVE_ATTRIBUTE_CONST
|
||||
#elif defined(__GNUC__)
|
||||
# define __PMIX_HAVE_ATTRIBUTE_CONST (GXX_ABOVE_3_4 || GCC_ABOVE_2_95)
|
||||
#else
|
||||
# define __PMIX_HAVE_ATTRIBUTE_CONST 0
|
||||
#endif
|
||||
#if __PMIX_HAVE_ATTRIBUTE_CONST
|
||||
# define __pmix_attribute_const __attribute__((__const__))
|
||||
#else
|
||||
# define __pmix_attribute_const
|
||||
#endif
|
||||
|
||||
#ifdef PMIX_HAVE_ATTRIBUTE_PURE
|
||||
#define __PMIX_HAVE_ATTRIBUTE_PURE PMIX_HAVE_ATTRIBUTE_PURE
|
||||
#elif defined(__GNUC__)
|
||||
# define __PMIX_HAVE_ATTRIBUTE_PURE (GXX_ABOVE_3_4 || GCC_ABOVE_2_96)
|
||||
#else
|
||||
# define __PMIX_HAVE_ATTRIBUTE_PURE 0
|
||||
#endif
|
||||
#if __PMIX_HAVE_ATTRIBUTE_PURE
|
||||
# define __pmix_attribute_pure __attribute__((__pure__))
|
||||
#else
|
||||
# define __pmix_attribute_pure
|
||||
#endif
|
||||
|
||||
#ifdef PMIX_HAVE_ATTRIBUTE_DEPRECATED
|
||||
#define __PMIX_HAVE_ATTRIBUTE_DEPRECATED PMIX_HAVE_ATTRIBUTE_DEPRECATED
|
||||
#elif defined(__GNUC__)
|
||||
# define __PMIX_HAVE_ATTRIBUTE_DEPRECATED (GXX_ABOVE_3_4 || GCC_ABOVE_3_3)
|
||||
#else
|
||||
# define __PMIX_HAVE_ATTRIBUTE_DEPRECATED 0
|
||||
#endif
|
||||
#if __PMIX_HAVE_ATTRIBUTE_DEPRECATED
|
||||
# define __pmix_attribute_deprecated __attribute__((__deprecated__))
|
||||
#else
|
||||
# define __pmix_attribute_deprecated
|
||||
#endif
|
||||
|
||||
#ifdef PMIX_HAVE_ATTRIBUTE_MAY_ALIAS
|
||||
#define __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS PMIX_HAVE_ATTRIBUTE_MAY_ALIAS
|
||||
#elif defined(__GNUC__)
|
||||
# define __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS (GXX_ABOVE_3_4 || GCC_ABOVE_3_3)
|
||||
#else
|
||||
# define __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS 0
|
||||
#endif
|
||||
#if __PMIX_HAVE_ATTRIBUTE_MAY_ALIAS
|
||||
# define __pmix_attribute_may_alias __attribute__((__may_alias__))
|
||||
#else
|
||||
# define __pmix_attribute_may_alias
|
||||
#endif
|
||||
|
||||
#ifndef PMIX_DECLSPEC
|
||||
#ifdef PMIX_C_HAVE_VISIBILITY
|
||||
# if PMIX_C_HAVE_VISIBILITY
|
||||
# define PMIX_DECLSPEC __attribute__((__visibility__("default")))
|
||||
# else
|
||||
# define PMIX_DECLSPEC
|
||||
# endif
|
||||
#else
|
||||
# define PMIX_DECLSPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Defined to 1 on Linux */
|
||||
#undef PMIX_LINUX_SYS
|
||||
|
||||
/* Defined to 1 if the CPU_SET macro works */
|
||||
#undef PMIX_HAVE_CPU_SET
|
||||
|
||||
/* Defined to 1 if you have the `windows.h' header. */
|
||||
#undef PMIX_HAVE_WINDOWS_H
|
||||
#undef pmix_pid_t
|
||||
#undef pmix_thread_t
|
||||
|
||||
/* Whether we need to re-define all the pmix public symbols or not */
|
||||
#undef PMIX_SYM_TRANSFORM
|
||||
|
||||
/* The pmix symbol prefix */
|
||||
#undef PMIX_SYM_PREFIX
|
||||
|
||||
/* The pmix symbol prefix in all caps */
|
||||
#undef PMIX_SYM_PREFIX_CAPS
|
||||
|
||||
/* ensure we have the version info available for external users */
|
||||
#undef PMIX_MAJOR_VERSION
|
||||
#undef PMIX_MINOR_VERSION
|
||||
#undef PMIX_RELEASE_VERSION
|
||||
|
||||
|
||||
#undef BEGIN_C_DECLS
|
||||
#undef END_C_DECLS
|
||||
#if defined(c_plusplus) || defined(__cplusplus)
|
||||
# define BEGIN_C_DECLS extern "C" {
|
||||
# define END_C_DECLS }
|
||||
#else
|
||||
#define BEGIN_C_DECLS /* empty */
|
||||
#define END_C_DECLS /* empty */
|
||||
#endif
|
||||
|
||||
#endif /* PMIX_CONFIG_H */
|
@ -1,925 +0,0 @@
|
||||
/* include/pmix/pmix_common.h. Generated from pmix_common.h.in by configure. */
|
||||
/*
|
||||
* Copyright (c) 2013-2014 Intel, Inc. All rights reserved
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are
|
||||
* met:
|
||||
*
|
||||
* - Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* - Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer listed
|
||||
* in this license in the documentation and/or other materials
|
||||
* provided with the distribution.
|
||||
*
|
||||
* - Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* The copyright holders provide no reassurances that the source code
|
||||
* provided does not infringe any patent, copyright, or any other
|
||||
* intellectual property rights of third parties. The copyright holders
|
||||
* disclaim any liability to any recipient for claims brought against
|
||||
* recipient by any third party for infringement of that parties
|
||||
* intellectual property rights.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIx_COMMON_H
|
||||
#define PMIx_COMMON_H
|
||||
|
||||
#include <pmix/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h> /* for struct timeval */
|
||||
#endif
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**** PMIX CONSTANTS ****/
|
||||
|
||||
/* define maximum value and key sizes */
|
||||
#define PMIX_MAX_NSLEN 255
|
||||
#define PMIX_MAX_KEYLEN 511
|
||||
|
||||
/* define a *wildcard* value for requests involving rank */
|
||||
#define PMIX_RANK_WILDCARD -1
|
||||
|
||||
/* define a set of "standard" PMIx attributes that can
|
||||
* be queried. Implementations (and users) are free to extend as
|
||||
* desired, so the get functions need to be capable
|
||||
* of handling the "not found" condition. Note that these
|
||||
* are attributes of the system and the job as opposed to
|
||||
* values the application (or underlying MPI library)
|
||||
* might choose to expose - i.e., they are values provided
|
||||
* by the resource manager as opposed to the application. Thus,
|
||||
* these keys are RESERVED */
|
||||
#define PMIX_ATTR_UNDEF NULL
|
||||
|
||||
/* identification attributes */
|
||||
#define PMIX_USERID "pmix.euid" // (uint32_t) effective user id
|
||||
#define PMIX_GRPID "pmix.egid" // (uint32_t) effective group id
|
||||
|
||||
/* general proc-level attributes */
|
||||
#define PMIX_CPUSET "pmix.cpuset" // (char*) hwloc bitmap applied to proc upon launch
|
||||
#define PMIX_CREDENTIAL "pmix.cred" // (char*) security credential assigned to proc
|
||||
#define PMIX_SPAWNED "pmix.spawned" // (bool) true if this proc resulted from a call to PMIx_Spawn
|
||||
#define PMIX_ARCH "pmix.arch" // (uint32_t) datatype architecture flag
|
||||
|
||||
/* scratch directory locations for use by applications */
|
||||
#define PMIX_TMPDIR "pmix.tmpdir" // (char*) top-level tmp dir assigned to session
|
||||
#define PMIX_NSDIR "pmix.nsdir" // (char*) sub-tmpdir assigned to namespace
|
||||
#define PMIX_PROCDIR "pmix.pdir" // (char*) sub-nsdir assigned to proc
|
||||
|
||||
/* information about relative ranks as assigned by the RM */
|
||||
#define PMIX_JOBID "pmix.jobid" // (char*) jobid assigned by scheduler
|
||||
#define PMIX_APPNUM "pmix.appnum" // (uint32_t) app number within the job
|
||||
#define PMIX_RANK "pmix.rank" // (uint32_t) process rank within the job
|
||||
#define PMIX_GLOBAL_RANK "pmix.grank" // (uint32_t) rank spanning across all jobs in this session
|
||||
#define PMIX_APP_RANK "pmix.apprank" // (uint32_t) rank within this app
|
||||
#define PMIX_NPROC_OFFSET "pmix.offset" // (uint32_t) starting global rank of this job
|
||||
#define PMIX_LOCAL_RANK "pmix.lrank" // (uint16_t) rank on this node within this job
|
||||
#define PMIX_NODE_RANK "pmix.nrank" // (uint16_t) rank on this node spanning all jobs
|
||||
#define PMIX_LOCALLDR "pmix.lldr" // (uint64_t) opal_identifier of lowest rank on this node within this job
|
||||
#define PMIX_APPLDR "pmix.aldr" // (uint32_t) lowest rank in this app within this job
|
||||
|
||||
/* proc location-related info */
|
||||
/* For PMIX_HOSTNAME, three use-cases exist for PMIx_Get:
|
||||
*
|
||||
* (a) Specifying a namespace with PMIX_RANK_WILDCARD will return
|
||||
* a comma-delimited list of nodes that host procs in that namespace
|
||||
*
|
||||
* (b) Passing a NULL namespace will return a comma-delimited list of all
|
||||
* nodes known to this session, regardless of whether or not they
|
||||
* currently host procs. The rank argument in PMIx_Get is ignored
|
||||
* for this use-case
|
||||
*
|
||||
* (c) Specifying a namespace and a rank will return the name of the
|
||||
* host this proc is on
|
||||
*/
|
||||
#define PMIX_HOSTNAME "pmix.hname" // (char*) see above comment
|
||||
#define PMIX_NODEID "pmix.nodeid" // (uint32_t) node identifier
|
||||
#define PMIX_LOCAL_PEERS "pmix.lpeers" // (char*) comma-delimited string of ranks on this node within the specified nspace
|
||||
#define PMIX_LOCAL_CPUSETS "pmix.lcpus" // (char*) colon-delimited cpusets of local peers within the specified nspace
|
||||
#define PMIX_PROC_URI "pmix.puri" // (char*) URI containing contact info for proc
|
||||
|
||||
/* size info */
|
||||
#define PMIX_UNIV_SIZE "pmix.univ.size" // (uint32_t) #procs in this nspace
|
||||
#define PMIX_JOB_SIZE "pmix.job.size" // (uint32_t) #procs in this job
|
||||
#define PMIX_LOCAL_SIZE "pmix.local.size" // (uint32_t) #procs in this job on this node
|
||||
#define PMIX_NODE_SIZE "pmix.node.size" // (uint32_t) #procs across all jobs on this node
|
||||
#define PMIX_MAX_PROCS "pmix.max.size" // (uint32_t) max #procs for this job
|
||||
|
||||
/* topology info */
|
||||
#define PMIX_NET_TOPO "pmix.ntopo" // (char*) xml-representation of network topology
|
||||
#define PMIX_LOCAL_TOPO "pmix.ltopo" // (char*) xml-representation of local node topology
|
||||
#define PMIX_NODE_LIST "pmix.nlist" // (char*) comma-delimited list of nodes running procs for this job
|
||||
#define PMIX_TOPOLOGY "pmix.topo" // (hwloc_topology_t) pointer to the PMIx client's internal topology object
|
||||
|
||||
/* request-related info */
|
||||
#define PMIX_COLLECT_DATA "pmix.collect" // (bool) collect data and return it at the end of the operation
|
||||
#define PMIX_TIMEOUT "pmix.timeout" // (int) time in sec before specified operation should time out
|
||||
#define PMIX_WAIT "pmix.wait" // (int) caller requests that the server wait until at least the specified
|
||||
// #values are found (0 => all and is the default)
|
||||
#define PMIX_COLLECTIVE_ALGO "pmix.calgo" // (char*) comma-delimited list of algorithms to use for collective
|
||||
#define PMIX_COLLECTIVE_ALGO_REQD "pmix.calreqd" // (bool) if true, indicates that the requested choice of algo is mandatory
|
||||
#define PMIX_NOTIFY_COMPLETION "pmix.notecomp" // (bool) notify parent process upon termination of child job
|
||||
#define PMIX_RANGE "pmix.range" // (int) pmix_data_range_t value for calls to publish/lookup/unpublish
|
||||
#define PMIX_PERSISTENCE "pmix.persist" // (int) pmix_persistence_t value for calls to publish
|
||||
#define PMIX_OPTIONAL "pmix.optional" // (bool) look only in the immediate data store for the requested value - do
|
||||
// not request data from the server if not found
|
||||
|
||||
/* attributes used by host server to pass data to the server convenience library - the
|
||||
* data will then be parsed and provided to the local clients */
|
||||
#define PMIX_PROC_DATA "pmix.pdata" // (pmix_value_array_t) starts with rank, then contains more data
|
||||
#define PMIX_NODE_MAP "pmix.nmap" // (char*) regex of nodes containing procs for this job
|
||||
#define PMIX_PROC_MAP "pmix.pmap" // (char*) regex describing procs on each node within this job
|
||||
#define PMIX_ANL_MAP "pmix.anlmap" // (char*) process mapping in ANL notation (used in PMI-1/PMI-2)
|
||||
|
||||
/* attributes used internally to communicate data from the server to the client */
|
||||
#define PMIX_PROC_BLOB "pmix.pblob" // (pmix_byte_object_t) packed blob of process data
|
||||
#define PMIX_MAP_BLOB "pmix.mblob" // (pmix_byte_object_t) packed blob of process location
|
||||
|
||||
|
||||
/**** PMIX ERROR CONSTANTS ****/
|
||||
/* PMIx errors are always negative, with 0 reserved for success */
|
||||
#define PMIX_ERROR_MIN -42 // set equal to number of non-zero entries in enum
|
||||
|
||||
typedef enum {
|
||||
PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER = PMIX_ERROR_MIN,
|
||||
PMIX_ERR_COMM_FAILURE,
|
||||
PMIX_ERR_NOT_IMPLEMENTED,
|
||||
PMIX_ERR_NOT_SUPPORTED,
|
||||
PMIX_ERR_NOT_FOUND,
|
||||
PMIX_ERR_SERVER_NOT_AVAIL,
|
||||
PMIX_ERR_INVALID_NAMESPACE,
|
||||
PMIX_ERR_INVALID_SIZE,
|
||||
PMIX_ERR_INVALID_KEYVALP,
|
||||
PMIX_ERR_INVALID_NUM_PARSED,
|
||||
|
||||
PMIX_ERR_INVALID_ARGS,
|
||||
PMIX_ERR_INVALID_NUM_ARGS,
|
||||
PMIX_ERR_INVALID_LENGTH,
|
||||
PMIX_ERR_INVALID_VAL_LENGTH,
|
||||
PMIX_ERR_INVALID_VAL,
|
||||
PMIX_ERR_INVALID_KEY_LENGTH,
|
||||
PMIX_ERR_INVALID_KEY,
|
||||
PMIX_ERR_INVALID_ARG,
|
||||
PMIX_ERR_NOMEM,
|
||||
PMIX_ERR_INIT,
|
||||
|
||||
PMIX_ERR_DATA_VALUE_NOT_FOUND,
|
||||
PMIX_ERR_OUT_OF_RESOURCE,
|
||||
PMIX_ERR_RESOURCE_BUSY,
|
||||
PMIX_ERR_BAD_PARAM,
|
||||
PMIX_ERR_IN_ERRNO,
|
||||
PMIX_ERR_UNREACH,
|
||||
PMIX_ERR_TIMEOUT,
|
||||
PMIX_ERR_NO_PERMISSIONS,
|
||||
PMIX_ERR_PACK_MISMATCH,
|
||||
PMIX_ERR_PACK_FAILURE,
|
||||
|
||||
PMIX_ERR_UNPACK_FAILURE,
|
||||
PMIX_ERR_UNPACK_INADEQUATE_SPACE,
|
||||
PMIX_ERR_TYPE_MISMATCH,
|
||||
PMIX_ERR_PROC_ENTRY_NOT_FOUND,
|
||||
PMIX_ERR_UNKNOWN_DATA_TYPE,
|
||||
PMIX_ERR_WOULD_BLOCK,
|
||||
PMIX_ERR_READY_FOR_HANDSHAKE,
|
||||
PMIX_ERR_HANDSHAKE_FAILED,
|
||||
PMIX_ERR_INVALID_CRED,
|
||||
PMIX_EXISTS,
|
||||
|
||||
PMIX_ERR_SILENT,
|
||||
PMIX_ERROR,
|
||||
PMIX_SUCCESS
|
||||
} pmix_status_t;
|
||||
|
||||
|
||||
/**** PMIX DATA TYPES ****/
|
||||
typedef enum {
|
||||
PMIX_UNDEF = 0,
|
||||
PMIX_BOOL, // converted to/from native true/false to uint8 for pack/unpack
|
||||
PMIX_BYTE, // a byte of data
|
||||
PMIX_STRING, // NULL-terminated string
|
||||
PMIX_SIZE, // size_t
|
||||
PMIX_PID, // OS-pid
|
||||
|
||||
PMIX_INT,
|
||||
PMIX_INT8,
|
||||
PMIX_INT16,
|
||||
PMIX_INT32,
|
||||
PMIX_INT64,
|
||||
|
||||
PMIX_UINT,
|
||||
PMIX_UINT8,
|
||||
PMIX_UINT16,
|
||||
PMIX_UINT32,
|
||||
PMIX_UINT64,
|
||||
|
||||
PMIX_FLOAT,
|
||||
PMIX_DOUBLE,
|
||||
|
||||
PMIX_TIMEVAL,
|
||||
PMIX_TIME,
|
||||
|
||||
PMIX_HWLOC_TOPO,
|
||||
PMIX_VALUE,
|
||||
PMIX_INFO_ARRAY,
|
||||
PMIX_PROC,
|
||||
PMIX_APP,
|
||||
PMIX_INFO,
|
||||
PMIX_PDATA,
|
||||
PMIX_BUFFER,
|
||||
PMIX_BYTE_OBJECT,
|
||||
PMIX_KVAL,
|
||||
PMIX_MODEX,
|
||||
PMIX_PERSIST
|
||||
} pmix_data_type_t;
|
||||
|
||||
/* define a scope for data "put" by PMI per the following:
|
||||
*
|
||||
* PMI_LOCAL - the data is intended only for other application
|
||||
* processes on the same node. Data marked in this way
|
||||
* will not be included in data packages sent to remote requestors
|
||||
* PMI_REMOTE - the data is intended solely for applications processes on
|
||||
* remote nodes. Data marked in this way will not be shared with
|
||||
* other processes on the same node
|
||||
* PMI_GLOBAL - the data is to be shared with all other requesting processes,
|
||||
* regardless of location
|
||||
*/
|
||||
#define PMIX_SCOPE PMIX_UINT
|
||||
typedef enum {
|
||||
PMIX_SCOPE_UNDEF = 0,
|
||||
PMIX_LOCAL, // share to procs also on this node
|
||||
PMIX_REMOTE, // share with procs not on this node
|
||||
PMIX_GLOBAL, // share with all procs (local + remote)
|
||||
} pmix_scope_t;
|
||||
|
||||
/* define a range for data "published" by PMI
|
||||
*/
|
||||
#define PMIX_DATA_RANGE PMIX_UINT
|
||||
typedef enum {
|
||||
PMIX_DATA_RANGE_UNDEF = 0,
|
||||
PMIX_NAMESPACE, // data is available to procs in the same nspace only
|
||||
PMIX_SESSION // data available to all procs in session
|
||||
} pmix_data_range_t;
|
||||
|
||||
/* define a "persistence" policy for data published by clients */
|
||||
typedef enum {
|
||||
PMIX_PERSIST_INDEF = 0, // retain until specifically deleted
|
||||
PMIX_PERSIST_FIRST_READ, // delete upon first access
|
||||
PMIX_PERSIST_PROC, // retain until publishing process terminates
|
||||
PMIX_PERSIST_APP, // retain until application terminates
|
||||
PMIX_PERSIST_SESSION // retain until session/allocation terminates
|
||||
} pmix_persistence_t;
|
||||
|
||||
/**** PMIX BYTE OBJECT ****/
|
||||
typedef struct {
|
||||
char *bytes;
|
||||
size_t size;
|
||||
} pmix_byte_object_t;
|
||||
|
||||
|
||||
/**** PMIX PROC OBJECT ****/
|
||||
typedef struct {
|
||||
char nspace[PMIX_MAX_NSLEN+1];
|
||||
int rank;
|
||||
} pmix_proc_t;
|
||||
#define PMIX_PROC_CREATE(m, n) \
|
||||
do { \
|
||||
(m) = (pmix_proc_t*)malloc((n) * sizeof(pmix_proc_t)); \
|
||||
memset((m), 0, (n) * sizeof(pmix_proc_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PROC_RELEASE(m) \
|
||||
do { \
|
||||
PMIX_PROC_FREE((m)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PROC_CONSTRUCT(m) \
|
||||
do { \
|
||||
memset((m), 0, sizeof(pmix_proc_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PROC_DESTRUCT(m)
|
||||
|
||||
#define PMIX_PROC_FREE(m, n) \
|
||||
do { \
|
||||
if (NULL != (m)) { \
|
||||
free((m)); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
|
||||
|
||||
/**** PMIX VALUE STRUCT ****/
|
||||
struct pmix_info_t;
|
||||
|
||||
typedef struct {
|
||||
size_t size;
|
||||
struct pmix_info_t *array;
|
||||
} pmix_info_array_t;
|
||||
/* NOTE: operations can supply a collection of values under
|
||||
* a single key by passing a pmix_value_t containing an
|
||||
* array of type PMIX_INFO_ARRAY, with each array element
|
||||
* containing its own pmix_info_t object */
|
||||
|
||||
typedef struct {
|
||||
pmix_data_type_t type;
|
||||
union {
|
||||
bool flag;
|
||||
uint8_t byte;
|
||||
char *string;
|
||||
size_t size;
|
||||
pid_t pid;
|
||||
int integer;
|
||||
int8_t int8;
|
||||
int16_t int16;
|
||||
int32_t int32;
|
||||
int64_t int64;
|
||||
unsigned int uint;
|
||||
uint8_t uint8;
|
||||
uint16_t uint16;
|
||||
uint32_t uint32;
|
||||
uint64_t uint64;
|
||||
float fval;
|
||||
double dval;
|
||||
struct timeval tv;
|
||||
pmix_info_array_t array;
|
||||
pmix_byte_object_t bo;
|
||||
} data;
|
||||
} pmix_value_t;
|
||||
/* allocate and initialize a specified number of value structs */
|
||||
#define PMIX_VALUE_CREATE(m, n) \
|
||||
do { \
|
||||
int _ii; \
|
||||
(m) = (pmix_value_t*)malloc((n) * sizeof(pmix_value_t)); \
|
||||
memset((m), 0, (n) * sizeof(pmix_value_t)); \
|
||||
for (_ii=0; _ii < (int)(n); _ii++) { \
|
||||
(m)[_ii].type = PMIX_UNDEF; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
/* release a single pmix_value_t struct, including its data */
|
||||
#define PMIX_VALUE_RELEASE(m) \
|
||||
do { \
|
||||
PMIX_VALUE_DESTRUCT((m)); \
|
||||
free((m)); \
|
||||
} while(0);
|
||||
|
||||
/* initialize a single value struct */
|
||||
#define PMIX_VALUE_CONSTRUCT(m) \
|
||||
do { \
|
||||
memset((m), 0, sizeof(pmix_value_t)); \
|
||||
(m)->type = PMIX_UNDEF; \
|
||||
} while(0);
|
||||
|
||||
/* release the memory in the value struct data field */
|
||||
#define PMIX_VALUE_DESTRUCT(m) \
|
||||
do { \
|
||||
if (PMIX_STRING == (m)->type) { \
|
||||
if (NULL != (m)->data.string) { \
|
||||
free((m)->data.string); \
|
||||
} \
|
||||
} else if (PMIX_BYTE_OBJECT == (m)->type) { \
|
||||
if (NULL != (m)->data.bo.bytes) { \
|
||||
free((m)->data.bo.bytes); \
|
||||
} \
|
||||
} else if (PMIX_INFO_ARRAY == (m)->type) { \
|
||||
size_t _n; \
|
||||
pmix_info_t *_p = (pmix_info_t*)((m)->data.array.array); \
|
||||
for (_n=0; _n < (m)->data.array.size; _n++) { \
|
||||
if (PMIX_STRING == _p[_n].value.type) { \
|
||||
if (NULL != _p[_n].value.data.string) { \
|
||||
free(_p[_n].value.data.string); \
|
||||
} \
|
||||
} else if (PMIX_BYTE_OBJECT == _p[_n].value.type) { \
|
||||
if (NULL != _p[_n].value.data.bo.bytes) { \
|
||||
free(_p[_n].value.data.bo.bytes); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
free(_p); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_VALUE_FREE(m, n) \
|
||||
do { \
|
||||
size_t _s; \
|
||||
if (NULL != (m)) { \
|
||||
for (_s=0; _s < (n); _s++) { \
|
||||
PMIX_VALUE_DESTRUCT(&((m)[_s])); \
|
||||
} \
|
||||
free((m)); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
/* expose a function that is resolved in the
|
||||
* PMIx library, but part of a header that
|
||||
* includes internal functions - so we don't
|
||||
* want to expose the entire header here
|
||||
*/
|
||||
extern void pmix_value_load(pmix_value_t *v, void *data,
|
||||
pmix_data_type_t type);
|
||||
|
||||
|
||||
|
||||
|
||||
/**** PMIX INFO STRUCT ****/
|
||||
typedef struct {
|
||||
char key[PMIX_MAX_KEYLEN+1]; // ensure room for the NULL terminator
|
||||
pmix_value_t value;
|
||||
} pmix_info_t;
|
||||
|
||||
/* utility macros for working with pmix_info_t structs */
|
||||
#define PMIX_INFO_CREATE(m, n) \
|
||||
do { \
|
||||
(m) = (pmix_info_t*)malloc((n) * sizeof(pmix_info_t)); \
|
||||
memset((m), 0, (n) * sizeof(pmix_info_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_INFO_CONSTRUCT(m) \
|
||||
do { \
|
||||
memset((m), 0, sizeof(pmix_info_t)); \
|
||||
(m)->value.type = PMIX_UNDEF; \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_INFO_DESTRUCT(m) \
|
||||
do { \
|
||||
PMIX_VALUE_DESTRUCT(&(m)->value); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_INFO_FREE(m, n) \
|
||||
do { \
|
||||
size_t _s; \
|
||||
if (NULL != (m)) { \
|
||||
for (_s=0; _s < (n); _s++) { \
|
||||
PMIX_INFO_DESTRUCT(&((m)[_s])); \
|
||||
} \
|
||||
free((m)); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_INFO_LOAD(m, k, v, t) \
|
||||
do { \
|
||||
(void)strncpy((m)->key, (k), PMIX_MAX_KEYLEN); \
|
||||
pmix_value_load(&((m)->value), (v), (t)); \
|
||||
} while(0);
|
||||
|
||||
|
||||
/**** PMIX LOOKUP RETURN STRUCT ****/
|
||||
typedef struct {
|
||||
pmix_proc_t proc;
|
||||
char key[PMIX_MAX_KEYLEN+1]; // ensure room for the NULL terminator
|
||||
pmix_value_t value;
|
||||
} pmix_pdata_t;
|
||||
|
||||
/* utility macros for working with pmix_pdata_t structs */
|
||||
#define PMIX_PDATA_CREATE(m, n) \
|
||||
do { \
|
||||
(m) = (pmix_pdata_t*)malloc((n) * sizeof(pmix_pdata_t)); \
|
||||
memset((m), 0, (n) * sizeof(pmix_pdata_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PDATA_RELEASE(m) \
|
||||
do { \
|
||||
PMIX_VALUE_DESTRUCT(&(m)->value); \
|
||||
free((m)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PDATA_CONSTRUCT(m) \
|
||||
do { \
|
||||
memset((m), 0, sizeof(pmix_pdata_t)); \
|
||||
(m)->value.type = PMIX_UNDEF; \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PDATA_DESTRUCT(m) \
|
||||
do { \
|
||||
PMIX_VALUE_DESTRUCT(&(m)->value); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PDATA_FREE(m, n) \
|
||||
do { \
|
||||
size_t _s; \
|
||||
if (NULL != (m)) { \
|
||||
for (_s=0; _s < (n); _s++) { \
|
||||
PMIX_PDATA_DESTRUCT(&((m)[_s])); \
|
||||
} \
|
||||
free((m)); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_PDATA_LOAD(m, p, k, v, t) \
|
||||
do { \
|
||||
if (NULL != (m)) { \
|
||||
(void)strncpy((m)->proc.nspace, (p)->nspace, PMIX_MAX_NSLEN); \
|
||||
(m)->proc.rank = (p)->rank; \
|
||||
(void)strncpy((m)->key, (k), PMIX_MAX_KEYLEN); \
|
||||
pmix_value_load(&((m)->value), (v), (t)); \
|
||||
} while(0);
|
||||
|
||||
|
||||
/**** PMIX APP STRUCT ****/
|
||||
typedef struct {
|
||||
char *cmd;
|
||||
int argc;
|
||||
char **argv;
|
||||
char **env;
|
||||
int maxprocs;
|
||||
pmix_info_t *info;
|
||||
size_t ninfo;
|
||||
} pmix_app_t;
|
||||
/* utility macros for working with pmix_app_t structs */
|
||||
#define PMIX_APP_CREATE(m, n) \
|
||||
do { \
|
||||
(m) = (pmix_app_t*)malloc((n) * sizeof(pmix_app_t)); \
|
||||
memset((m), 0, (n) * sizeof(pmix_app_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_APP_RELEASE(m) \
|
||||
do { \
|
||||
PMIX_APP_DESTRUCT((m)); \
|
||||
free((m)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_APP_CONSTRUCT(m) \
|
||||
do { \
|
||||
memset((m), 0, sizeof(pmix_app_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_APP_DESTRUCT(m) \
|
||||
do { \
|
||||
size_t _ii; \
|
||||
if (NULL != (m)->cmd) { \
|
||||
free((m)->cmd); \
|
||||
} \
|
||||
if (NULL != (m)->argv) { \
|
||||
for (_ii=0; NULL != (m)->argv[_ii]; _ii++) { \
|
||||
free((m)->argv[_ii]); \
|
||||
} \
|
||||
free((m)->argv); \
|
||||
} \
|
||||
if (NULL != (m)->env) { \
|
||||
for (_ii=0; NULL != (m)->env[_ii]; _ii++) { \
|
||||
free((m)->env[_ii]); \
|
||||
} \
|
||||
free((m)->env); \
|
||||
} \
|
||||
if (NULL != (m)->info) { \
|
||||
for (_ii=0; _ii < (m)->ninfo; _ii++) { \
|
||||
PMIX_INFO_DESTRUCT(&(m)->info[_ii]); \
|
||||
} \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_APP_FREE(m, n) \
|
||||
do { \
|
||||
size_t _s; \
|
||||
if (NULL != (m)) { \
|
||||
for (_s=0; _s < (n); _s++) { \
|
||||
PMIX_APP_DESTRUCT(&((m)[_s])); \
|
||||
} \
|
||||
free((m)); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
/**** PMIX MODEX STRUCT ****/
|
||||
typedef struct {
|
||||
char nspace[PMIX_MAX_NSLEN+1];
|
||||
int rank;
|
||||
uint8_t *blob;
|
||||
size_t size;
|
||||
} pmix_modex_data_t;
|
||||
/* utility macros for working with pmix_modex_t structs */
|
||||
#define PMIX_MODEX_CREATE(m, n) \
|
||||
do { \
|
||||
(m) = (pmix_modex_data_t*)malloc((n) * sizeof(pmix_modex_data_t)); \
|
||||
memset((m), 0, (n) * sizeof(pmix_modex_data_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_MODEX_RELEASE(m) \
|
||||
do { \
|
||||
PMIX_MODEX_DESTRUCT((m)); \
|
||||
free((m)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_MODEX_CONSTRUCT(m) \
|
||||
do { \
|
||||
memset((m), 0, sizeof(pmix_modex_data_t)); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_MODEX_DESTRUCT(m) \
|
||||
do { \
|
||||
if (NULL != (m)->blob) { \
|
||||
free((m)->blob); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_MODEX_FREE(m, n) \
|
||||
do { \
|
||||
size_t _s; \
|
||||
if (NULL != (m)) { \
|
||||
for (_s=0; _s < (n); _s++) { \
|
||||
PMIX_MODEX_DESTRUCT(&((m)[_s])); \
|
||||
} \
|
||||
free((m)); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
|
||||
/**** CALLBACK FUNCTIONS FOR NON-BLOCKING OPERATIONS ****/
|
||||
|
||||
typedef void (*pmix_release_cbfunc_t)(void *cbdata);
|
||||
|
||||
/* define a callback function that is solely used by servers, and
|
||||
* not clients, to return modex data in response to "fence" and "get"
|
||||
* operations. The returned blob contains the data collected from each
|
||||
* server participating in the operation.
|
||||
*
|
||||
* As the data is "owned" by the host server, provide a secondary
|
||||
* callback function to notify the host server that we are done
|
||||
* with the data so it can be released */
|
||||
typedef void (*pmix_modex_cbfunc_t)(pmix_status_t status,
|
||||
const char *data, size_t ndata,
|
||||
void *cbdata,
|
||||
pmix_release_cbfunc_t release_fn,
|
||||
void *release_cbdata);
|
||||
|
||||
/* define a callback function for calls to PMIx_Spawn_nb - the function
|
||||
* will be called upon completion of the spawn command. The status
|
||||
* will indicate whether or not the spawn succeeded. The nspace
|
||||
* of the spawned processes will be returned, along with any provided
|
||||
* callback data. Note that the returned nspace value will be
|
||||
* released by the library upon return from the callback function, so
|
||||
* the receiver must copy it if it needs to be retained */
|
||||
typedef void (*pmix_spawn_cbfunc_t)(pmix_status_t status,
|
||||
char nspace[], void *cbdata);
|
||||
|
||||
/* define a callback for common operations that simply return
|
||||
* a status. Examples include the non-blocking versions of
|
||||
* Fence, Connect, and Disconnect */
|
||||
typedef void (*pmix_op_cbfunc_t)(pmix_status_t status, void *cbdata);
|
||||
|
||||
/* define a callback function for calls to PMIx_Lookup_nb - the
|
||||
* function will be called upon completion of the command with the
|
||||
* status indicating the success of failure of the request. Any
|
||||
* retrieved data will be returned in an array of pmix_pdata_t structs.
|
||||
* The nspace/rank of the process that provided each data element is
|
||||
* also returned.
|
||||
*
|
||||
* Note that these structures will be released upon return from
|
||||
* the callback function, so the receiver must copy/protect the
|
||||
* data prior to returning if it needs to be retained */
|
||||
|
||||
typedef void (*pmix_lookup_cbfunc_t)(pmix_status_t status,
|
||||
pmix_pdata_t data[], size_t ndata,
|
||||
void *cbdata);
|
||||
|
||||
/* define a callback function for the errhandler. Upon receipt of an
|
||||
* error notification, PMIx will execute the specified notification
|
||||
* callback function, providing:
|
||||
*
|
||||
* status - the error that occurred
|
||||
* procs - the nspace and ranks of the affected processes. A NULL
|
||||
* value indicates that the error occurred in the PMIx
|
||||
* client library within this process itself
|
||||
* nprocs - the number of procs in the provided array
|
||||
* info - any additional info provided regarding the error.
|
||||
* ninfo - the number of info objects in the provided array
|
||||
*
|
||||
* Note that different resource managers may provide differing levels
|
||||
* of support for error notification to application processes. Thus, the
|
||||
* info array may be NULL or may contain detailed information of the error.
|
||||
* It is the responsibility of the application to parse any provided info array
|
||||
* for defined key-values if it so desires.
|
||||
*
|
||||
* Possible uses of the pmix_info_t object include:
|
||||
*
|
||||
* - for the RM to alert the process as to planned actions, such as
|
||||
* to abort the session, in response to the reported error
|
||||
*
|
||||
* - provide a timeout for alternative action to occur, such as for
|
||||
* the application to request an alternate response to the error
|
||||
*
|
||||
* For example, the RM might alert the application to the failure of
|
||||
* a node that resulted in termination of several processes, and indicate
|
||||
* that the overall session will be aborted unless the application
|
||||
* requests an alternative behavior in the next 5 seconds. The application
|
||||
* then has time to respond with a checkpoint request, or a request to
|
||||
* recover from the failure by obtaining replacement nodes and restarting
|
||||
* from some earlier checkpoint.
|
||||
*
|
||||
* Support for these options is left to the discretion of the host RM. Info
|
||||
* keys are included in the common definions above, but also may be augmented
|
||||
* on a per-RM basis.
|
||||
*
|
||||
* On the server side, the notification function is used to inform the host
|
||||
* server of a detected error in the PMIx subsystem and/or client */
|
||||
typedef void (*pmix_notification_fn_t)(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo);
|
||||
|
||||
/* define a callback function for calls to PMIx_Register_errhandler. The
|
||||
* status indicates if the request was successful or not, errhandler_ref is
|
||||
* an integer reference assigned to the errhandler by PMIX, this reference
|
||||
* must be used to deregister the err handler. A ptr to the original
|
||||
* cbdata is returned. */
|
||||
typedef void (*pmix_errhandler_reg_cbfunc_t) (pmix_status_t status,
|
||||
int errhandler_ref,
|
||||
void *cbdata);
|
||||
|
||||
/* define a callback function for calls to PMIx_Get_nb. The status
|
||||
* indicates if the requested data was found or not - a pointer to the
|
||||
* pmix_value_t structure containing the found data is returned. The
|
||||
* pointer will be NULL if the requested data was not found. */
|
||||
typedef void (*pmix_value_cbfunc_t)(pmix_status_t status,
|
||||
pmix_value_t *kv, void *cbdata);
|
||||
|
||||
/**** COMMON SUPPORT FUNCTIONS ****/
|
||||
/* Register an errhandler to report errors. Three types of errors
|
||||
* can be reported:
|
||||
*
|
||||
* (a) those that occur within the client library, but are not
|
||||
* reportable via the API itself (e.g., loss of connection to
|
||||
* the server). These errors typically occur during behind-the-scenes
|
||||
* non-blocking operations.
|
||||
*
|
||||
* (b) job-related errors such as the failure of another process in
|
||||
* the job or in any connected job, impending failure of hardware
|
||||
* within the job's usage footprint, etc.
|
||||
*
|
||||
* (c) system notifications that are made available by the local
|
||||
* administrators
|
||||
*
|
||||
* By default, only errors that directly affect the process and/or
|
||||
* any process to which it is connected (via the PMIx_Connect call)
|
||||
* will be reported. Options to modify that behavior can be provided
|
||||
* in the info array
|
||||
*
|
||||
* Both the client application and the resource manager can register
|
||||
* err handlers for specific errors. PMIx client/server calls the registered
|
||||
* err handler upon receiving error notify notification (via PMIx_Notify_error)
|
||||
* from the other end (Resource Manager/Client application).
|
||||
*
|
||||
* Multiple err handlers can be registered for different errors. PMIX returns
|
||||
* an integer reference to each register handler in the callback fn. The caller
|
||||
* must retain the reference in order to deregister the errhandler.
|
||||
* Modification of the notification behavior can be accomplished by
|
||||
* deregistering the current errhandler, and then registering it
|
||||
* using a new set of info values.
|
||||
*
|
||||
* See pmix_common.h for a description of the notification function */
|
||||
void PMIx_Register_errhandler(pmix_info_t info[], size_t ninfo,
|
||||
pmix_notification_fn_t errhandler,
|
||||
pmix_errhandler_reg_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
/* deregister the errhandler
|
||||
* errhandler_ref is the reference returned by PMIx for the errhandler
|
||||
* to pmix_errhandler_reg_cbfunc_t */
|
||||
void PMIx_Deregister_errhandler(int errhandler_ref,
|
||||
pmix_op_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
/* Report an error to a process for notification via any
|
||||
* registered errhandler. The errhandler registration can be
|
||||
* called by both the server and the client application. On the
|
||||
* server side, the errhandler is used to report errors detected
|
||||
* by PMIx to the host server for handling. On the client side,
|
||||
* the errhandler is used to notify the process of errors
|
||||
* reported by the server - e.g., the failure of another process.
|
||||
*
|
||||
* This function allows the host server to direct the server
|
||||
* convenience library to notify all indicated local procs of
|
||||
* an error. The error can be local, or anywhere in the cluster.
|
||||
* The status indicates the error being reported.
|
||||
*
|
||||
* The client application can also call this function to notify the
|
||||
* resource manager of an error it encountered. It can request the host
|
||||
* server to notify the indicated processes about the error.
|
||||
*
|
||||
* The first array of procs informs the server library as to which
|
||||
* processes should be alerted - e.g., the processes that are in
|
||||
* a directly-affected job or are connected to one that is affected.
|
||||
* Passing a NULL for this array will indicate that all local procs
|
||||
* are to be notified.
|
||||
*
|
||||
* The second array identifies the processes that will be impacted
|
||||
* by the error. This could consist of a single process, or a number
|
||||
* of processes.
|
||||
*
|
||||
* The info array contains any further info the RM can and/or chooses
|
||||
* to provide.
|
||||
*
|
||||
* The callback function will be called upon completion of the
|
||||
* notify_error function's actions. Note that any messages will
|
||||
* have been queued, but may not have been transmitted by this
|
||||
* time. Note that the caller is required to maintain the input
|
||||
* data until the callback function has been executed!
|
||||
*/
|
||||
pmix_status_t PMIx_Notify_error(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_proc_t error_procs[], size_t error_nprocs,
|
||||
pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
/* Provide a string representation of a pmix_status_t value. Note
|
||||
* that the provided string is statically defined and must NOT be
|
||||
* free'd */
|
||||
const char* PMIx_Error_string(pmix_status_t status);
|
||||
|
||||
/* Get the PMIx version string. Note that the provided string is
|
||||
* statically defined and must NOT be free'd */
|
||||
const char* PMIx_Get_version(void);
|
||||
|
||||
/* Store some data locally for retrieval by other areas of the
|
||||
* proc. This is data that has only internal scope - it will
|
||||
* never be "pushed" externally */
|
||||
pmix_status_t PMIx_Store_internal(const pmix_proc_t *proc,
|
||||
const char *key, pmix_value_t *val);
|
||||
|
||||
|
||||
/* Key-Value pair management macros */
|
||||
// TODO: add all possible types/fields here.
|
||||
|
||||
#define PMIX_VAL_FIELD_int(x) ((x)->data.integer)
|
||||
#define PMIX_VAL_FIELD_uint32_t(x) ((x)->data.uint32)
|
||||
#define PMIX_VAL_FIELD_uint16_t(x) ((x)->data.uint16)
|
||||
#define PMIX_VAL_FIELD_string(x) ((x)->data.string)
|
||||
#define PMIX_VAL_FIELD_float(x) ((x)->data.fval)
|
||||
#define PMIX_VAL_FIELD_byte(x) ((x)->data.byte)
|
||||
#define PMIX_VAL_FIELD_flag(x) ((x)->data.flag)
|
||||
|
||||
#define PMIX_VAL_TYPE_int PMIX_INT
|
||||
#define PMIX_VAL_TYPE_uint32_t PMIX_UINT32
|
||||
#define PMIX_VAL_TYPE_uint16_t PMIX_UINT16
|
||||
#define PMIX_VAL_TYPE_string PMIX_STRING
|
||||
#define PMIX_VAL_TYPE_float PMIX_FLOAT
|
||||
#define PMIX_VAL_TYPE_byte PMIX_BYTE
|
||||
#define PMIX_VAL_TYPE_flag PMIX_BOOL
|
||||
|
||||
#define PMIX_VAL_set_assign(_v, _field, _val ) \
|
||||
do { \
|
||||
(_v)->type = PMIX_VAL_TYPE_ ## _field; \
|
||||
PMIX_VAL_FIELD_ ## _field((_v)) = _val; \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_VAL_set_strdup(_v, _field, _val ) \
|
||||
do { \
|
||||
(_v)->type = PMIX_VAL_TYPE_ ## _field; \
|
||||
PMIX_VAL_FIELD_ ## _field((_v)) = strdup(_val); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_VAL_SET_int PMIX_VAL_set_assign
|
||||
#define PMIX_VAL_SET_uint32_t PMIX_VAL_set_assign
|
||||
#define PMIX_VAL_SET_uint16_t PMIX_VAL_set_assign
|
||||
#define PMIX_VAL_SET_string PMIX_VAL_set_strdup
|
||||
#define PMIX_VAL_SET_float PMIX_VAL_set_assign
|
||||
#define PMIX_VAL_SET_byte PMIX_VAL_set_assign
|
||||
#define PMIX_VAL_SET_flag PMIX_VAL_set_assign
|
||||
|
||||
#define PMIX_VAL_SET(_v, _field, _val ) \
|
||||
PMIX_VAL_SET_ ## _field(_v, _field, _val)
|
||||
|
||||
#define PMIX_VAL_cmp_val(_val1, _val2) ((_val1) != (_val2))
|
||||
#define PMIX_VAL_cmp_float(_val1, _val2) (((_val1)>(_val2))?(((_val1)-(_val2))>0.000001):(((_val2)-(_val1))>0.000001))
|
||||
#define PMIX_VAL_cmp_ptr(_val1, _val2) strncmp(_val1, _val2, strlen(_val1)+1)
|
||||
|
||||
#define PMIX_VAL_CMP_int PMIX_VAL_cmp_val
|
||||
#define PMIX_VAL_CMP_uint32_t PMIX_VAL_cmp_val
|
||||
#define PMIX_VAL_CMP_uint16_t PMIX_VAL_cmp_val
|
||||
#define PMIX_VAL_CMP_float PMIX_VAL_cmp_float
|
||||
#define PMIX_VAL_CMP_string PMIX_VAL_cmp_ptr
|
||||
#define PMIX_VAL_CMP_byte PMIX_VAL_cmp_val
|
||||
#define PMIX_VAL_CMP_flag PMIX_VAL_cmp_val
|
||||
|
||||
#define PMIX_VAL_CMP(_field, _val1, _val2) \
|
||||
PMIX_VAL_CMP_ ## _field(_val1, _val2)
|
||||
|
||||
#define PMIX_VAL_FREE(_v) \
|
||||
PMIx_free_value_data(_v)
|
||||
|
||||
END_C_DECLS
|
||||
#endif
|
@ -1,62 +0,0 @@
|
||||
.TH "pmix_abort" "3" "2015\-10\-25" "PMIx Programmer\[aq]s Manual" "\@VERSION\@"
|
||||
.SH NAME
|
||||
.PP
|
||||
PMIx_Abort \- Abort the specified processes
|
||||
.SH SYNOPSIS
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
#include\ <pmix.h>
|
||||
|
||||
pmix_status_t\ PMIx_Abort(int\ status,\ const\ char\ msg[],
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ pmix_proc_t\ procs[],\ size_t\ nprocs);
|
||||
\f[]
|
||||
.fi
|
||||
.SH ARGUMENTS
|
||||
.PP
|
||||
\f[I]status\f[] : Status value to be returned.
|
||||
A value of zero is permitted by PMIx, but may not be returned by some
|
||||
resource managers.
|
||||
.PP
|
||||
\f[I]msg\f[] : A string message to be displayed
|
||||
.PP
|
||||
\f[I]procs\f[] : An array of pmix_proc_t structures defining the
|
||||
processes to be aborted.
|
||||
A \f[I]NULL\f[] for the proc array indicates that all processes in the
|
||||
caller\[aq]s nspace are to be aborted.
|
||||
A wildcard value for the rank in any structure indicates that all
|
||||
processes in that nspace are to be aborted.
|
||||
.PP
|
||||
\f[I]nprocs\f[] : Number of pmix_proc_t structures in the \f[I]procs\f[]
|
||||
array
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Request that the provided array of procs be aborted, returning the
|
||||
provided \f[I]status\f[] and printing the provided message.
|
||||
A \f[I]NULL\f[] for the proc array indicates that all processes in the
|
||||
caller\[aq]s nspace are to be aborted.
|
||||
.PP
|
||||
The response to this request is somewhat dependent on the specific
|
||||
resource manager and its configuration (e.g., some resource managers
|
||||
will not abort the application if the provided \f[I]status\f[] is zero
|
||||
unless specifically configured to do so), and thus lies outside the
|
||||
control of PMIx itself.
|
||||
However, the client will inform the RM of the request that the
|
||||
application be aborted, regardless of the value of the provided
|
||||
\f[I]status\f[].
|
||||
.PP
|
||||
Passing a \f[I]NULL\f[] msg parameter is allowed.
|
||||
Note that race conditions caused by multiple processes calling
|
||||
PMIx_Abort are left to the server implementation to resolve with regard
|
||||
to which status is returned and what messages (if any) are printed.
|
||||
.SH RETURN VALUE
|
||||
.PP
|
||||
Returns PMIX_SUCCESS on success.
|
||||
On error, a negative value corresponding to a PMIx errno is returned.
|
||||
.SH ERRORS
|
||||
.PP
|
||||
PMIx errno values are defined in \f[C]pmix_common.h\f[].
|
||||
.SH NOTES
|
||||
.SH SEE ALSO
|
||||
.SH AUTHORS
|
||||
PMIx.
|
@ -1,35 +0,0 @@
|
||||
.TH "pmix_commit" "3" "2015\-10\-27" "PMIx Programmer\[aq]s Manual" "\@VERSION\@"
|
||||
.SH NAME
|
||||
.PP
|
||||
PMIx_Commit \- Push all previously \f[I]PMIx\f[]Put_ values to the local
|
||||
PMIx server.
|
||||
.SH SYNOPSIS
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
#include\ <pmix.h>
|
||||
|
||||
pmix_status_t\ PMIx_Commit(void);
|
||||
\f[]
|
||||
.fi
|
||||
.SH ARGUMENTS
|
||||
.PP
|
||||
\f[I]none\f[]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
This is an asynchronous operation \- the library will immediately return
|
||||
to the caller while the data is transmitted to the local server in the
|
||||
background
|
||||
.SH RETURN VALUE
|
||||
.PP
|
||||
Returns PMIX_SUCCESS on success.
|
||||
On error, a negative value corresponding to a PMIx errno is returned.
|
||||
.SH ERRORS
|
||||
.PP
|
||||
PMIx errno values are defined in \f[C]pmix_common.h\f[].
|
||||
.SH NOTES
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
\f[C]PMIx_Put\f[](3)
|
||||
.SH AUTHORS
|
||||
PMIx.
|
@ -1,31 +0,0 @@
|
||||
.TH "pmix_finalize" "3" "2015\-10\-27" "PMIx Programmer\[aq]s Manual" "\@VERSION\@"
|
||||
.SH NAME
|
||||
.PP
|
||||
PMIx_Finalize \- Finalize the PMIx Client
|
||||
.SH SYNOPSIS
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
#include\ <pmix.h>
|
||||
|
||||
pmix_status_t\ PMIx_Finalize(void);
|
||||
\f[]
|
||||
.fi
|
||||
.SH ARGUMENTS
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Finalize the PMIx client, closing the connection with the local PMIx
|
||||
server.
|
||||
.SH RETURN VALUE
|
||||
.PP
|
||||
Returns PMIX_SUCCESS on success.
|
||||
On error, a negative value corresponding to a PMIx errno is returned.
|
||||
.SH ERRORS
|
||||
.PP
|
||||
PMIx errno values are defined in \f[C]pmix_common.h\f[].
|
||||
.SH NOTES
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
\f[C]PMIx_Init\f[](3)
|
||||
.SH AUTHORS
|
||||
PMIx.
|
@ -1,49 +0,0 @@
|
||||
.TH "pmix_init" "3" "2015\-10\-25" "PMIx Programmer\[aq]s Manual" "\@VERSION\@"
|
||||
.SH NAME
|
||||
.PP
|
||||
PMIx_Init \- Initialize the PMIx Client
|
||||
.SH SYNOPSIS
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
#include\ <pmix.h>
|
||||
|
||||
pmix_status_t\ PMIx_Init(pmix_proc_t\ *proc);
|
||||
\f[]
|
||||
.fi
|
||||
.SH ARGUMENTS
|
||||
.PP
|
||||
\f[I]proc\f[] : Pointer to a pmix_proc_t object in which the
|
||||
client\[aq]s namespace and rank are to be returned.
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Initialize the PMIx client, returning the process identifier assigned to
|
||||
this client\[aq]s application in the provided pmix_proc_t struct.
|
||||
Passing a parameter of \f[I]NULL\f[] for this parameter is allowed if
|
||||
the user wishes solely to initialize the PMIx system and does not
|
||||
require return of the identifier at that time.
|
||||
.PP
|
||||
When called, the PMIx client will check for the required connection
|
||||
information of the local PMIx server and will establish the connection.
|
||||
If the information is not found, or the server connection fails, then an
|
||||
appropriate error constant will be returned.
|
||||
.PP
|
||||
If successful, the function will return PMIX_SUCCESS and will fill the
|
||||
provided structure with the server\-assigned namespace and rank of the
|
||||
process within the application.
|
||||
.PP
|
||||
Note that the PMIx client library is referenced counted, and so multiple
|
||||
calls to PMIx_Init are allowed.
|
||||
Thus, one way to obtain the namespace and rank of the process is to
|
||||
simply call PMIx_Init with a non\-NULL parameter.
|
||||
.SH RETURN VALUE
|
||||
.PP
|
||||
Returns PMIX_SUCCESS on success.
|
||||
On error, a negative value corresponding to a PMIx errno is returned.
|
||||
.SH ERRORS
|
||||
.PP
|
||||
PMIx errno values are defined in \f[C]pmix_common.h\f[].
|
||||
.SH NOTES
|
||||
.SH SEE ALSO
|
||||
.SH AUTHORS
|
||||
PMIx.
|
@ -1,60 +0,0 @@
|
||||
.TH "pmix_put" "3" "2015\-10\-25" "PMIx Programmer\[aq]s Manual" "\@VERSION\@"
|
||||
.SH NAME
|
||||
.PP
|
||||
PMIx_Put \- Push a value into the client\[aq]s namespace
|
||||
.SH SYNOPSIS
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
#include\ <pmix.h>
|
||||
|
||||
pmix_status_t\ PMIx_Init(pmix_scope_t\ scope,\ const\ char\ key[],\ pmix_value_t\ *val);
|
||||
\f[]
|
||||
.fi
|
||||
.SH ARGUMENTS
|
||||
.PP
|
||||
\f[I]scope\f[] : Defines a scope for data "put" by PMI per the
|
||||
following:
|
||||
.IP
|
||||
.nf
|
||||
\f[C]
|
||||
*\ PMI_LOCAL\ \-\ the\ data\ is\ intended\ only\ for\ other\ application
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ processes\ on\ the\ same\ node.\ Data\ marked\ in\ this\ way
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ will\ not\ be\ included\ in\ data\ packages\ sent\ to\ remote\ requestors
|
||||
*\ PMI_REMOTE\ \-\ the\ data\ is\ intended\ solely\ for\ applications\ processes\ on
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ remote\ nodes.\ Data\ marked\ in\ this\ way\ will\ not\ be\ shared\ with
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ other\ processes\ on\ the\ same\ node
|
||||
*\ PMI_GLOBAL\ \-\ the\ data\ is\ to\ be\ shared\ with\ all\ other\ requesting\ processes,
|
||||
\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ regardless\ of\ location
|
||||
\f[]
|
||||
.fi
|
||||
.PP
|
||||
\f[I]key\f[] String key identifying the information.
|
||||
This can be either one of the PMIx defined attributes, or a
|
||||
user\-defined value
|
||||
.PP
|
||||
\f[I]val\f[] Pointer to a pmix_value_t structure containing the data to
|
||||
be pushed along with the type of the provided data.
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Push a value into the client\[aq]s namespace.
|
||||
The client library will cache the information locally until
|
||||
\f[I]PMIx\f[]Commit_ is called.
|
||||
The provided scope value is passed to the local PMIx server, which will
|
||||
distribute the data as directed.
|
||||
.SH RETURN VALUE
|
||||
.PP
|
||||
Returns PMIX_SUCCESS on success.
|
||||
On error, a negative value corresponding to a PMIx errno is returned.
|
||||
.SH ERRORS
|
||||
.PP
|
||||
PMIx errno values are defined in \f[C]pmix_common.h\f[].
|
||||
.SH NOTES
|
||||
.PP
|
||||
See \[aq]pmix_common.h\[aq] for definition of the pmix_value_t
|
||||
structure.
|
||||
.SH SEE ALSO
|
||||
.PP
|
||||
\f[C]PMIx_Constants\f[](7), \f[C]PMIx_Structures\f[](7)
|
||||
.SH AUTHORS
|
||||
PMIx.
|
@ -1,322 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Data packing subsystem.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_BFROP_H_
|
||||
#define PMIX_BFROP_H_
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
#include "src/buffer_ops/types.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/* internally used object for transferring data
|
||||
* to/from the server and for storing in the
|
||||
* hash tables */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
char *key;
|
||||
pmix_value_t *value;
|
||||
} pmix_kval_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_kval_t);
|
||||
|
||||
/* A non-API function for something that happens in a number
|
||||
* of places throughout the code base - transferring a value to
|
||||
* another pmix_value_t structure
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_value_xfer(pmix_value_t *kv, pmix_value_t *src);
|
||||
PMIX_DECLSPEC void pmix_value_load(pmix_value_t *v, void *data,
|
||||
pmix_data_type_t type);
|
||||
PMIX_DECLSPEC pmix_status_t pmix_value_unload(pmix_value_t *kv, void **data,
|
||||
size_t *sz, pmix_data_type_t type);
|
||||
|
||||
|
||||
#define PMIX_LOAD_BUFFER(b, d, s) \
|
||||
do { \
|
||||
(b)->base_ptr = (char*)(d); \
|
||||
(b)->bytes_used = (s); \
|
||||
(b)->bytes_allocated = (s); \
|
||||
(b)->pack_ptr = ((char*)(b)->base_ptr) + (s); \
|
||||
(b)->unpack_ptr = (b)->base_ptr; \
|
||||
(d) = NULL; \
|
||||
(s) = 0; \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_UNLOAD_BUFFER(b, d, s) \
|
||||
do { \
|
||||
(d) = (char*)(b)->unpack_ptr; \
|
||||
(s) = (b)->bytes_used; \
|
||||
(b)->base_ptr = NULL; \
|
||||
(b)->bytes_used = 0; \
|
||||
(b)->bytes_allocated = 0; \
|
||||
(b)->pack_ptr = NULL; \
|
||||
(b)->unpack_ptr = NULL; \
|
||||
} while (0);
|
||||
|
||||
|
||||
/**
|
||||
* Top-level interface function to pack one or more values into a
|
||||
* buffer.
|
||||
*
|
||||
* The pack function packs one or more values of a specified type into
|
||||
* the specified buffer. The buffer must have already been
|
||||
* initialized via an PMIX_NEW or PMIX_CONSTRUCT call - otherwise, the
|
||||
* pack_value function will return an error. Providing an unsupported
|
||||
* type flag will likewise be reported as an error.
|
||||
*
|
||||
* Note that any data to be packed that is not hard type cast (i.e.,
|
||||
* not type cast to a specific size) may lose precision when unpacked
|
||||
* by a non-homogeneous recipient. The BFROP will do its best to deal
|
||||
* with heterogeneity issues between the packer and unpacker in such
|
||||
* cases. Sending a number larger than can be handled by the recipient
|
||||
* will return an error code (generated by the BFROP upon unpacking) -
|
||||
* the BFROP cannot detect such errors during packing.
|
||||
*
|
||||
* @param *buffer A pointer to the buffer into which the value is to
|
||||
* be packed.
|
||||
*
|
||||
* @param *src A void* pointer to the data that is to be packed. Note
|
||||
* that strings are to be passed as (char **) - i.e., the caller must
|
||||
* pass the address of the pointer to the string as the void*. This
|
||||
* allows the BFROP to use a single interface function, but still allow
|
||||
* the caller to pass multiple strings in a single call.
|
||||
*
|
||||
* @param num_values An int32_t indicating the number of values that are
|
||||
* to be packed, beginning at the location pointed to by src. A string
|
||||
* value is counted as a single value regardless of length. The values
|
||||
* must be contiguous in memory. Arrays of pointers (e.g., string
|
||||
* arrays) should be contiguous, although (obviously) the data pointed
|
||||
* to need not be contiguous across array entries.
|
||||
*
|
||||
* @param type The type of the data to be packed - must be one of the
|
||||
* PMIX defined data types.
|
||||
*
|
||||
* @retval PMIX_SUCCESS The data was packed as requested.
|
||||
*
|
||||
* @retval PMIX_ERROR(s) An appropriate PMIX error code indicating the
|
||||
* problem encountered. This error code should be handled
|
||||
* appropriately.
|
||||
*
|
||||
* @code
|
||||
* pmix_buffer_t *buffer;
|
||||
* int32_t src;
|
||||
*
|
||||
* status_code = pmix_bfrop.pack(buffer, &src, 1, PMIX_INT32);
|
||||
* @endcode
|
||||
*/
|
||||
typedef pmix_status_t (*pmix_bfrop_pack_fn_t)(pmix_buffer_t *buffer, const void *src,
|
||||
int32_t num_values,
|
||||
pmix_data_type_t type);
|
||||
|
||||
/**
|
||||
* Unpack values from a buffer.
|
||||
*
|
||||
* The unpack function unpacks the next value (or values) of a
|
||||
* specified type from the specified buffer.
|
||||
*
|
||||
* The buffer must have already been initialized via an PMIX_NEW or
|
||||
* PMIX_CONSTRUCT call (and assumedly filled with some data) -
|
||||
* otherwise, the unpack_value function will return an
|
||||
* error. Providing an unsupported type flag will likewise be reported
|
||||
* as an error, as will specifying a data type that DOES NOT match the
|
||||
* type of the next item in the buffer. An attempt to read beyond the
|
||||
* end of the stored data held in the buffer will also return an
|
||||
* error.
|
||||
*
|
||||
* NOTE: it is possible for the buffer to be corrupted and that
|
||||
* the BFROP will *think* there is a proper variable type at the
|
||||
* beginning of an unpack region - but that the value is bogus (e.g., just
|
||||
* a byte field in a string array that so happens to have a value that
|
||||
* matches the specified data type flag). Therefore, the data type error check
|
||||
* is NOT completely safe. This is true for ALL unpack functions.
|
||||
*
|
||||
*
|
||||
* Unpacking values is a "destructive" process - i.e., the values are
|
||||
* removed from the buffer, thus reducing the buffer size. It is
|
||||
* therefore not possible for the caller to re-unpack a value from the
|
||||
* same buffer.
|
||||
*
|
||||
* Warning: The caller is responsible for providing adequate memory
|
||||
* storage for the requested data. As noted below, the user
|
||||
* must provide a parameter indicating the maximum number of values that
|
||||
* can be unpacked into the allocated memory. If more values exist in the
|
||||
* buffer than can fit into the memory storage, then the bfrop will unpack
|
||||
* what it can fit into that location and return an error code indicating
|
||||
* that the buffer was only partially unpacked.
|
||||
*
|
||||
* Note that any data that was not hard type cast (i.e., not type cast
|
||||
* to a specific size) when packed may lose precision when unpacked by
|
||||
* a non-homogeneous recipient. The BFROP will do its best to deal with
|
||||
* heterogeneity issues between the packer and unpacker in such
|
||||
* cases. Sending a number larger than can be handled by the recipient
|
||||
* will return an error code generated by the BFROP upon unpacking - the
|
||||
* BFROP cannot detect such errors during packing.
|
||||
*
|
||||
* @param *buffer A pointer to the buffer from which the value will be
|
||||
* extracted.
|
||||
*
|
||||
* @param *dest A void* pointer to the memory location into which the
|
||||
* data is to be stored. Note that these values will be stored
|
||||
* contiguously in memory. For strings, this pointer must be to (char
|
||||
* **) to provide a means of supporting multiple string
|
||||
* operations. The BFROP unpack function will allocate memory for each
|
||||
* string in the array - the caller must only provide adequate memory
|
||||
* for the array of pointers.
|
||||
*
|
||||
* @param type The type of the data to be unpacked - must be one of
|
||||
* the BFROP defined data types.
|
||||
*
|
||||
* @retval *max_num_values The number of values actually unpacked. In
|
||||
* most cases, this should match the maximum number provided in the
|
||||
* parameters - but in no case will it exceed the value of this
|
||||
* parameter. Note that if you unpack fewer values than are actually
|
||||
* available, the buffer will be in an unpackable state - the bfrop will
|
||||
* return an error code to warn of this condition.
|
||||
*
|
||||
* @note The unpack function will return the actual number of values
|
||||
* unpacked in this location.
|
||||
*
|
||||
* @retval PMIX_SUCCESS The next item in the buffer was successfully
|
||||
* unpacked.
|
||||
*
|
||||
* @retval PMIX_ERROR(s) The unpack function returns an error code
|
||||
* under one of several conditions: (a) the number of values in the
|
||||
* item exceeds the max num provided by the caller; (b) the type of
|
||||
* the next item in the buffer does not match the type specified by
|
||||
* the caller; or (c) the unpack failed due to either an error in the
|
||||
* buffer or an attempt to read past the end of the buffer.
|
||||
*
|
||||
* @code
|
||||
* pmix_buffer_t *buffer;
|
||||
* int32_t dest;
|
||||
* char **string_array;
|
||||
* int32_t num_values;
|
||||
*
|
||||
* num_values = 1;
|
||||
* status_code = pmix_bfrop.unpack(buffer, (void*)&dest, &num_values, PMIX_INT32);
|
||||
*
|
||||
* num_values = 5;
|
||||
* string_array = malloc(num_values*sizeof(char *));
|
||||
* status_code = pmix_bfrop.unpack(buffer, (void*)(string_array), &num_values, PMIX_STRING);
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
typedef pmix_status_t (*pmix_bfrop_unpack_fn_t)(pmix_buffer_t *buffer, void *dest,
|
||||
int32_t *max_num_values,
|
||||
pmix_data_type_t type);
|
||||
/**
|
||||
* Copy a payload from one buffer to another
|
||||
* This function will append a copy of the payload in one buffer into
|
||||
* another buffer. If the destination buffer is NOT empty, then the
|
||||
* type of the two buffers MUST match or else an
|
||||
* error will be returned. If the destination buffer IS empty, then
|
||||
* its type will be set to that of the source buffer.
|
||||
* NOTE: This is NOT a destructive procedure - the
|
||||
* source buffer's payload will remain intact, as will any pre-existing
|
||||
* payload in the destination's buffer.
|
||||
*/
|
||||
typedef pmix_status_t (*pmix_bfrop_copy_payload_fn_t)(pmix_buffer_t *dest,
|
||||
pmix_buffer_t *src);
|
||||
|
||||
/**
|
||||
* BFROP initialization function.
|
||||
*
|
||||
* In dynamic libraries, declared objects and functions don't get
|
||||
* loaded until called. We need to ensure that the pmix_bfrop function
|
||||
* structure gets loaded, so we provide an "open" call that is
|
||||
* executed as part of the program startup.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_bfrop_open(void);
|
||||
|
||||
/**
|
||||
* BFROP finalize function
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_bfrop_close(void);
|
||||
|
||||
|
||||
/**
|
||||
* Copy a data value from one location to another.
|
||||
*
|
||||
* Since registered data types can be complex structures, the system
|
||||
* needs some way to know how to copy the data from one location to
|
||||
* another (e.g., for storage in the registry). This function, which
|
||||
* can call other copy functions to build up complex data types, defines
|
||||
* the method for making a copy of the specified data type.
|
||||
*
|
||||
* @param **dest The address of a pointer into which the
|
||||
* address of the resulting data is to be stored.
|
||||
*
|
||||
* @param *src A pointer to the memory location from which the
|
||||
* data is to be copied.
|
||||
*
|
||||
* @param type The type of the data to be copied - must be one of
|
||||
* the BFROP defined data types.
|
||||
*
|
||||
* @retval PMIX_SUCCESS The value was successfully copied.
|
||||
*
|
||||
* @retval PMIX_ERROR(s) An appropriate error code.
|
||||
*
|
||||
*/
|
||||
typedef pmix_status_t (*pmix_bfrop_copy_fn_t)(void **dest, void *src, pmix_data_type_t type);
|
||||
|
||||
/**
|
||||
* Print a data value.
|
||||
*
|
||||
* Since registered data types can be complex structures, the system
|
||||
* needs some way to know how to print them (i.e., convert them to a string
|
||||
* representation). Provided for debug purposes.
|
||||
*
|
||||
* @retval PMIX_SUCCESS The value was successfully printed.
|
||||
*
|
||||
* @retval PMIX_ERROR(s) An appropriate error code.
|
||||
*/
|
||||
typedef pmix_status_t (*pmix_bfrop_print_fn_t)(char **output, char *prefix, void *src, pmix_data_type_t type);
|
||||
|
||||
/**
|
||||
* Base structure for the BFROP
|
||||
*
|
||||
* Base module structure for the BFROP - presents the required function
|
||||
* pointers to the calling interface.
|
||||
*/
|
||||
struct pmix_bfrop_t {
|
||||
pmix_bfrop_pack_fn_t pack;
|
||||
pmix_bfrop_unpack_fn_t unpack;
|
||||
pmix_bfrop_copy_fn_t copy;
|
||||
pmix_bfrop_print_fn_t print;
|
||||
pmix_bfrop_copy_payload_fn_t copy_payload;
|
||||
};
|
||||
typedef struct pmix_bfrop_t pmix_bfrop_t;
|
||||
|
||||
PMIX_DECLSPEC extern pmix_bfrop_t pmix_bfrop; /* holds bfrop function pointers */
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_BFROP_H */
|
@ -1,434 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/buffer_ops/internal.h"
|
||||
|
||||
int pmix_bfrop_copy(void **dest, void *src, pmix_data_type_t type)
|
||||
{
|
||||
pmix_bfrop_type_info_t *info;
|
||||
|
||||
/* check for error */
|
||||
if (NULL == dest) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
if (NULL == src) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
/* Lookup the copy function for this type and call it */
|
||||
|
||||
if (NULL == (info = (pmix_bfrop_type_info_t*)pmix_pointer_array_get_item(&pmix_bfrop_types, type))) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_UNKNOWN_DATA_TYPE);
|
||||
return PMIX_ERR_UNKNOWN_DATA_TYPE;
|
||||
}
|
||||
|
||||
return info->odti_copy_fn(dest, src, type);
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_payload(pmix_buffer_t *dest, pmix_buffer_t *src)
|
||||
{
|
||||
size_t to_copy = 0;
|
||||
char *ptr;
|
||||
/* deal with buffer type */
|
||||
if( NULL == dest->base_ptr ){
|
||||
/* destination buffer is empty - derive src buffer type */
|
||||
dest->type = src->type;
|
||||
} else if( dest->type != src->type ){
|
||||
/* buffer types mismatch */
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
to_copy = src->pack_ptr - src->unpack_ptr;
|
||||
if( NULL == (ptr = pmix_bfrop_buffer_extend(dest, to_copy)) ){
|
||||
PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE);
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
memcpy(ptr,src->unpack_ptr, to_copy);
|
||||
dest->bytes_used += to_copy;
|
||||
dest->pack_ptr += to_copy;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* STANDARD COPY FUNCTION - WORKS FOR EVERYTHING NON-STRUCTURED
|
||||
*/
|
||||
int pmix_bfrop_std_copy(void **dest, void *src, pmix_data_type_t type)
|
||||
{
|
||||
size_t datasize;
|
||||
uint8_t *val = NULL;
|
||||
|
||||
switch(type) {
|
||||
case PMIX_BOOL:
|
||||
datasize = sizeof(bool);
|
||||
break;
|
||||
|
||||
case PMIX_INT:
|
||||
case PMIX_UINT:
|
||||
datasize = sizeof(int);
|
||||
break;
|
||||
|
||||
case PMIX_SIZE:
|
||||
datasize = sizeof(size_t);
|
||||
break;
|
||||
|
||||
case PMIX_PID:
|
||||
datasize = sizeof(pid_t);
|
||||
break;
|
||||
|
||||
case PMIX_BYTE:
|
||||
case PMIX_INT8:
|
||||
case PMIX_UINT8:
|
||||
datasize = 1;
|
||||
break;
|
||||
|
||||
case PMIX_INT16:
|
||||
case PMIX_UINT16:
|
||||
datasize = 2;
|
||||
break;
|
||||
|
||||
case PMIX_INT32:
|
||||
case PMIX_UINT32:
|
||||
datasize = 4;
|
||||
break;
|
||||
|
||||
case PMIX_INT64:
|
||||
case PMIX_UINT64:
|
||||
datasize = 8;
|
||||
break;
|
||||
|
||||
case PMIX_FLOAT:
|
||||
datasize = sizeof(float);
|
||||
break;
|
||||
|
||||
case PMIX_TIMEVAL:
|
||||
datasize = sizeof(struct timeval);
|
||||
break;
|
||||
|
||||
case PMIX_TIME:
|
||||
datasize = sizeof(time_t);
|
||||
break;
|
||||
|
||||
default:
|
||||
return PMIX_ERR_UNKNOWN_DATA_TYPE;
|
||||
}
|
||||
|
||||
val = (uint8_t*)malloc(datasize);
|
||||
if (NULL == val) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
|
||||
memcpy(val, src, datasize);
|
||||
*dest = val;
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* COPY FUNCTIONS FOR NON-STANDARD SYSTEM TYPES */
|
||||
|
||||
/*
|
||||
* STRING
|
||||
*/
|
||||
int pmix_bfrop_copy_string(char **dest, char *src, pmix_data_type_t type)
|
||||
{
|
||||
if (NULL == src) { /* got zero-length string/NULL pointer - store NULL */
|
||||
*dest = NULL;
|
||||
} else {
|
||||
*dest = strdup(src);
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* COPY FUNCTIONS FOR GENERIC PMIX TYPES */
|
||||
pmix_status_t pmix_value_xfer(pmix_value_t *p, pmix_value_t *src)
|
||||
{
|
||||
pmix_info_t *p1, *s1;
|
||||
|
||||
/* copy the right field */
|
||||
p->type = src->type;
|
||||
switch (src->type) {
|
||||
case PMIX_BOOL:
|
||||
p->data.flag = src->data.flag;
|
||||
break;
|
||||
case PMIX_BYTE:
|
||||
p->data.byte = src->data.byte;
|
||||
break;
|
||||
case PMIX_STRING:
|
||||
if (NULL != src->data.string) {
|
||||
p->data.string = strdup(src->data.string);
|
||||
} else {
|
||||
p->data.string = NULL;
|
||||
}
|
||||
break;
|
||||
case PMIX_SIZE:
|
||||
p->data.size = src->data.size;
|
||||
break;
|
||||
case PMIX_PID:
|
||||
p->data.pid = src->data.pid;
|
||||
break;
|
||||
case PMIX_INT:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.integer, &src->data.integer, sizeof(int));
|
||||
break;
|
||||
case PMIX_INT8:
|
||||
p->data.int8 = src->data.int8;
|
||||
break;
|
||||
case PMIX_INT16:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.int16, &src->data.int16, 2);
|
||||
break;
|
||||
case PMIX_INT32:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.int32, &src->data.int32, 4);
|
||||
break;
|
||||
case PMIX_INT64:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.int64, &src->data.int64, 8);
|
||||
break;
|
||||
case PMIX_UINT:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.uint, &src->data.uint, sizeof(unsigned int));
|
||||
break;
|
||||
case PMIX_UINT8:
|
||||
p->data.uint8 = src->data.uint8;
|
||||
break;
|
||||
case PMIX_UINT16:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.uint16, &src->data.uint16, 2);
|
||||
break;
|
||||
case PMIX_UINT32:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.uint32, &src->data.uint32, 4);
|
||||
break;
|
||||
case PMIX_UINT64:
|
||||
/* to avoid alignment issues */
|
||||
memcpy(&p->data.uint64, &src->data.uint64, 8);
|
||||
break;
|
||||
case PMIX_FLOAT:
|
||||
p->data.fval = src->data.fval;
|
||||
break;
|
||||
case PMIX_DOUBLE:
|
||||
p->data.dval = src->data.dval;
|
||||
break;
|
||||
case PMIX_TIMEVAL:
|
||||
p->data.tv.tv_sec = src->data.tv.tv_sec;
|
||||
p->data.tv.tv_usec = src->data.tv.tv_usec;
|
||||
break;
|
||||
case PMIX_INFO_ARRAY:
|
||||
p->data.array.size = src->data.array.size;
|
||||
if (0 < src->data.array.size) {
|
||||
p->data.array.array = (struct pmix_info_t*)malloc(src->data.array.size * sizeof(pmix_info_t));
|
||||
p1 = (pmix_info_t*)p->data.array.array;
|
||||
s1 = (pmix_info_t*)src->data.array.array;
|
||||
memcpy(p1, s1, src->data.array.size * sizeof(pmix_info_t));
|
||||
}
|
||||
break;
|
||||
case PMIX_BYTE_OBJECT:
|
||||
if (NULL != src->data.bo.bytes && 0 < src->data.bo.size) {
|
||||
p->data.bo.bytes = malloc(src->data.bo.size);
|
||||
memcpy(p->data.bo.bytes, src->data.bo.bytes, src->data.bo.size);
|
||||
p->data.bo.size = src->data.bo.size;
|
||||
} else {
|
||||
p->data.bo.bytes = NULL;
|
||||
p->data.bo.size = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pmix_output(0, "COPY-PMIX-VALUE: UNSUPPORTED TYPE %d", (int)src->type);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* PMIX_VALUE */
|
||||
int pmix_bfrop_copy_value(pmix_value_t **dest, pmix_value_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
pmix_value_t *p;
|
||||
|
||||
/* create the new object */
|
||||
*dest = (pmix_value_t*)malloc(sizeof(pmix_value_t));
|
||||
if (NULL == *dest) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
p = *dest;
|
||||
|
||||
/* copy the type */
|
||||
p->type = src->type;
|
||||
/* copy the data */
|
||||
return pmix_value_xfer(p, src);
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_info(pmix_info_t **dest, pmix_info_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = (pmix_info_t*)malloc(sizeof(pmix_info_t));
|
||||
(void)strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN);
|
||||
return pmix_value_xfer(&(*dest)->value, &src->value);
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_buf(pmix_buffer_t **dest, pmix_buffer_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = PMIX_NEW(pmix_buffer_t);
|
||||
pmix_bfrop.copy_payload(*dest, src);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_app(pmix_app_t **dest, pmix_app_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
size_t j;
|
||||
|
||||
*dest = (pmix_app_t*)malloc(sizeof(pmix_app_t));
|
||||
(*dest)->cmd = strdup(src->cmd);
|
||||
(*dest)->argc = src->argc;
|
||||
(*dest)->argv = pmix_argv_copy(src->argv);
|
||||
(*dest)->env = pmix_argv_copy(src->env);
|
||||
(*dest)->maxprocs = src->maxprocs;
|
||||
(*dest)->ninfo = src->ninfo;
|
||||
(*dest)->info = (pmix_info_t*)malloc(src->ninfo * sizeof(pmix_info_t));
|
||||
for (j=0; j < src->ninfo; j++) {
|
||||
(void)strncpy((*dest)->info[j].key, src->info[j].key, PMIX_MAX_KEYLEN);
|
||||
pmix_value_xfer(&(*dest)->info[j].value, &src->info[j].value);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_kval(pmix_kval_t **dest, pmix_kval_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
pmix_kval_t *p;
|
||||
|
||||
/* create the new object */
|
||||
*dest = PMIX_NEW(pmix_kval_t);
|
||||
if (NULL == *dest) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
p = *dest;
|
||||
|
||||
/* copy the type */
|
||||
p->value->type = src->value->type;
|
||||
/* copy the data */
|
||||
return pmix_value_xfer(p->value, src->value);
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_array(pmix_info_array_t **dest,
|
||||
pmix_info_array_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
pmix_info_t *d1, *s1;
|
||||
|
||||
*dest = (pmix_info_array_t*)malloc(sizeof(pmix_info_array_t));
|
||||
(*dest)->size = src->size;
|
||||
(*dest)->array = (struct pmix_info_t*)malloc(src->size * sizeof(pmix_info_t));
|
||||
d1 = (pmix_info_t*)(*dest)->array;
|
||||
s1 = (pmix_info_t*)src->array;
|
||||
memcpy(d1, s1, src->size * sizeof(pmix_info_t));
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_proc(pmix_proc_t **dest, pmix_proc_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = (pmix_proc_t*)malloc(sizeof(pmix_proc_t));
|
||||
if (NULL == *dest) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
(void)strncpy((*dest)->nspace, src->nspace, PMIX_MAX_NSLEN);
|
||||
(*dest)->rank = src->rank;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
#if PMIX_HAVE_HWLOC
|
||||
int pmix_bfrop_copy_topo(hwloc_topology_t *dest,
|
||||
hwloc_topology_t src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
/* use the hwloc dup function */
|
||||
return hwloc_topology_dup(dest, src);
|
||||
}
|
||||
#endif
|
||||
|
||||
int pmix_bfrop_copy_modex(pmix_modex_data_t **dest, pmix_modex_data_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = (pmix_modex_data_t*)malloc(sizeof(pmix_modex_data_t));
|
||||
if (NULL == *dest) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
(*dest)->blob = NULL;
|
||||
(*dest)->size = 0;
|
||||
if (NULL != src->blob) {
|
||||
(*dest)->blob = (uint8_t*)malloc(src->size * sizeof(uint8_t));
|
||||
if (NULL == (*dest)->blob) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
memcpy((*dest)->blob, src->blob, src->size * sizeof(uint8_t));
|
||||
(*dest)->size = src->size;
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_persist(pmix_persistence_t **dest, pmix_persistence_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = (pmix_persistence_t*)malloc(sizeof(pmix_persistence_t));
|
||||
if (NULL == *dest) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
memcpy(*dest, src, sizeof(pmix_persistence_t));
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_bo(pmix_byte_object_t **dest, pmix_byte_object_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = (pmix_byte_object_t*)malloc(sizeof(pmix_byte_object_t));
|
||||
if (NULL == *dest) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
(*dest)->bytes = (char*)malloc(src->size);
|
||||
memcpy((*dest)->bytes, src->bytes, src->size);
|
||||
(*dest)->size = src->size;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_bfrop_copy_pdata(pmix_pdata_t **dest, pmix_pdata_t *src,
|
||||
pmix_data_type_t type)
|
||||
{
|
||||
*dest = (pmix_pdata_t*)malloc(sizeof(pmix_pdata_t));
|
||||
(void)strncpy((*dest)->proc.nspace, src->proc.nspace, PMIX_MAX_NSLEN);
|
||||
(*dest)->proc.rank = src->proc.rank;
|
||||
(void)strncpy((*dest)->key, src->key, PMIX_MAX_KEYLEN);
|
||||
return pmix_value_xfer(&(*dest)->value, &src->value);
|
||||
}
|
||||
|
@ -1,105 +0,0 @@
|
||||
/* -*- C -*-
|
||||
*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007-2011 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Buffer management types.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_BFROP_TYPES_H_
|
||||
#define PMIX_BFROP_TYPES_H_
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include "src/class/pmix_pointer_array.h"
|
||||
#include "src/class/pmix_list.h"
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/* define the results values for comparisons so we can change them in only one place */
|
||||
#define PMIX_VALUE1_GREATER +1
|
||||
#define PMIX_VALUE2_GREATER -1
|
||||
#define PMIX_EQUAL 0
|
||||
|
||||
/**
|
||||
* buffer type
|
||||
*/
|
||||
enum pmix_bfrop_buffer_type_t {
|
||||
PMIX_BFROP_BUFFER_NON_DESC = 0x00,
|
||||
PMIX_BFROP_BUFFER_FULLY_DESC = 0x01
|
||||
};
|
||||
|
||||
typedef enum pmix_bfrop_buffer_type_t pmix_bfrop_buffer_type_t;
|
||||
|
||||
#define PMIX_BFROP_BUFFER_TYPE_HTON(h);
|
||||
#define PMIX_BFROP_BUFFER_TYPE_NTOH(h);
|
||||
|
||||
/**
|
||||
* Structure for holding a buffer */
|
||||
typedef struct {
|
||||
/** First member must be the object's parent */
|
||||
pmix_object_t parent;
|
||||
/** type of buffer */
|
||||
pmix_bfrop_buffer_type_t type;
|
||||
/** Start of my memory */
|
||||
char *base_ptr;
|
||||
/** Where the next data will be packed to (within the allocated
|
||||
memory starting at base_ptr) */
|
||||
char *pack_ptr;
|
||||
/** Where the next data will be unpacked from (within the
|
||||
allocated memory starting as base_ptr) */
|
||||
char *unpack_ptr;
|
||||
|
||||
/** Number of bytes allocated (starting at base_ptr) */
|
||||
size_t bytes_allocated;
|
||||
/** Number of bytes used by the buffer (i.e., amount of data --
|
||||
including overhead -- packed in the buffer) */
|
||||
size_t bytes_used;
|
||||
} pmix_buffer_t;
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION (pmix_buffer_t);
|
||||
|
||||
/* these classes are required by the regex code shared
|
||||
* between the client and server implementations - it
|
||||
* is put here so that both can access these objects */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
int start;
|
||||
int cnt;
|
||||
} pmix_regex_range_t;
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_regex_range_t);
|
||||
|
||||
typedef struct {
|
||||
/* list object */
|
||||
pmix_list_item_t super;
|
||||
char *prefix;
|
||||
char *suffix;
|
||||
int num_digits;
|
||||
pmix_list_t ranges;
|
||||
} pmix_regex_value_t;
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_regex_value_t);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_BFROP_TYPES_H */
|
@ -1,606 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/crc.h"
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
/*
|
||||
* pmix_hash_table_t
|
||||
*/
|
||||
|
||||
static void pmix_hash_table_construct(pmix_hash_table_t* ht);
|
||||
static void pmix_hash_table_destruct(pmix_hash_table_t* ht);
|
||||
|
||||
|
||||
PMIX_CLASS_INSTANCE(
|
||||
pmix_hash_table_t,
|
||||
pmix_object_t,
|
||||
pmix_hash_table_construct,
|
||||
pmix_hash_table_destruct
|
||||
);
|
||||
|
||||
|
||||
static void pmix_hash_table_construct(pmix_hash_table_t* ht)
|
||||
{
|
||||
PMIX_CONSTRUCT(&ht->ht_nodes, pmix_list_t);
|
||||
ht->ht_table = NULL;
|
||||
ht->ht_table_size = 0;
|
||||
ht->ht_size = 0;
|
||||
}
|
||||
|
||||
|
||||
static void pmix_hash_table_destruct(pmix_hash_table_t* ht)
|
||||
{
|
||||
size_t i;
|
||||
pmix_hash_table_remove_all(ht);
|
||||
for(i=0; i<ht->ht_table_size; i++) {
|
||||
PMIX_DESTRUCT(ht->ht_table+i);
|
||||
}
|
||||
if(NULL != ht->ht_table) {
|
||||
free(ht->ht_table);
|
||||
}
|
||||
PMIX_DESTRUCT(&ht->ht_nodes);
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_hash_table_init(pmix_hash_table_t* ht, size_t table_size)
|
||||
{
|
||||
size_t i;
|
||||
size_t power2 = pmix_next_poweroftwo (table_size);
|
||||
|
||||
ht->ht_mask = power2-1;
|
||||
ht->ht_table = (pmix_list_t *)malloc(power2 * sizeof(pmix_list_t));
|
||||
if(NULL == ht->ht_table) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
for(i=ht->ht_table_size; i<power2; i++) {
|
||||
pmix_list_t* list = ht->ht_table+i;
|
||||
PMIX_CONSTRUCT(list, pmix_list_t);
|
||||
}
|
||||
ht->ht_table_size = power2;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
pmix_status_t pmix_hash_table_remove_all(pmix_hash_table_t* ht)
|
||||
{
|
||||
size_t i;
|
||||
for(i=0; i<ht->ht_table_size; i++) {
|
||||
pmix_list_t* list = ht->ht_table+i;
|
||||
while(pmix_list_get_size(list)) {
|
||||
pmix_list_item_t *item = pmix_list_remove_first(list);
|
||||
PMIX_RELEASE(item);
|
||||
}
|
||||
}
|
||||
|
||||
while(pmix_list_get_size(&ht->ht_nodes)) {
|
||||
pmix_list_item_t* item = pmix_list_remove_first(&ht->ht_nodes);
|
||||
PMIX_RELEASE(item);
|
||||
}
|
||||
ht->ht_size = 0;
|
||||
ht->ht_size -= 1;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* pmix_uint32_hash_node_t
|
||||
*/
|
||||
|
||||
struct pmix_uint32_hash_node_t
|
||||
{
|
||||
pmix_list_item_t super;
|
||||
uint32_t hn_key;
|
||||
void *hn_value;
|
||||
};
|
||||
typedef struct pmix_uint32_hash_node_t pmix_uint32_hash_node_t;
|
||||
|
||||
static PMIX_CLASS_INSTANCE(pmix_uint32_hash_node_t,
|
||||
pmix_list_item_t,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
|
||||
pmix_status_t pmix_hash_table_get_value_uint32(pmix_hash_table_t* ht, uint32_t key,
|
||||
void **ptr)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + (key & ht->ht_mask);
|
||||
pmix_uint32_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_get_value_uint32:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_uint32_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_uint32_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_uint32_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key == key) {
|
||||
*ptr = node->hn_value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_hash_table_set_value_uint32(pmix_hash_table_t* ht,
|
||||
uint32_t key, void* value)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + (key & ht->ht_mask);
|
||||
pmix_uint32_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_set_value_uint32:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_uint32_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_uint32_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_uint32_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key == key) {
|
||||
node->hn_value = value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
node = (pmix_uint32_hash_node_t*)pmix_list_remove_first(&ht->ht_nodes);
|
||||
if(NULL == node) {
|
||||
node = PMIX_NEW(pmix_uint32_hash_node_t);
|
||||
if(NULL == node)
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
node->hn_key = key;
|
||||
node->hn_value = value;
|
||||
pmix_list_append(list, (pmix_list_item_t*)node);
|
||||
ht->ht_size++;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_hash_table_remove_value_uint32(pmix_hash_table_t* ht, uint32_t key)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + (key & ht->ht_mask);
|
||||
pmix_uint32_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_remove_value_uint32:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_uint32_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_uint32_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_uint32_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key == key) {
|
||||
pmix_list_remove_item(list, (pmix_list_item_t*)node);
|
||||
pmix_list_append(&ht->ht_nodes, (pmix_list_item_t*)node);
|
||||
ht->ht_size--;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* pmix_uint64_hash_node_t
|
||||
*/
|
||||
|
||||
struct pmix_uint64_hash_node_t
|
||||
{
|
||||
pmix_list_item_t super;
|
||||
uint64_t hn_key;
|
||||
void* hn_value;
|
||||
};
|
||||
typedef struct pmix_uint64_hash_node_t pmix_uint64_hash_node_t;
|
||||
|
||||
static PMIX_CLASS_INSTANCE(pmix_uint64_hash_node_t,
|
||||
pmix_list_item_t,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
|
||||
pmix_status_t pmix_hash_table_get_value_uint64(pmix_hash_table_t* ht, uint64_t key,
|
||||
void **ptr)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + (key & ht->ht_mask);
|
||||
pmix_uint64_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_get_value_uint64:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_uint64_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_uint64_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_uint64_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key == key) {
|
||||
*ptr = node->hn_value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_hash_table_set_value_uint64(pmix_hash_table_t* ht,
|
||||
uint64_t key, void* value)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + (key & ht->ht_mask);
|
||||
pmix_uint64_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_set_value_uint64:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_uint64_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_uint64_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_uint64_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key == key) {
|
||||
node->hn_value = value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
node = (pmix_uint64_hash_node_t*)pmix_list_remove_first(&ht->ht_nodes);
|
||||
if(NULL == node) {
|
||||
node = PMIX_NEW(pmix_uint64_hash_node_t);
|
||||
if(NULL == node) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
}
|
||||
node->hn_key = key;
|
||||
node->hn_value = value;
|
||||
pmix_list_append(list, (pmix_list_item_t*)node);
|
||||
ht->ht_size++;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int pmix_hash_table_remove_value_uint64(pmix_hash_table_t* ht, uint64_t key)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + (key & ht->ht_mask);
|
||||
pmix_uint64_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_remove_value_uint64:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_uint64_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_uint64_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_uint64_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key == key) {
|
||||
pmix_list_remove_item(list, (pmix_list_item_t*)node);
|
||||
pmix_list_append(&ht->ht_nodes, (pmix_list_item_t*)node);
|
||||
ht->ht_size--;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* pmix_ptr_hash_node_t
|
||||
*/
|
||||
|
||||
struct pmix_ptr_hash_node_t
|
||||
{
|
||||
pmix_list_item_t super;
|
||||
void* hn_key;
|
||||
size_t hn_key_size;
|
||||
void* hn_value;
|
||||
};
|
||||
typedef struct pmix_ptr_hash_node_t pmix_ptr_hash_node_t;
|
||||
|
||||
static void pmix_ptr_hash_node_construct(pmix_ptr_hash_node_t* hn)
|
||||
{
|
||||
hn->hn_key_size = 0;
|
||||
hn->hn_key = NULL;
|
||||
hn->hn_value = NULL;
|
||||
}
|
||||
|
||||
static void pmix_ptr_hash_node_destruct(pmix_ptr_hash_node_t* hn)
|
||||
{
|
||||
if(NULL != hn->hn_key) {
|
||||
free(hn->hn_key);
|
||||
}
|
||||
}
|
||||
|
||||
static PMIX_CLASS_INSTANCE(pmix_ptr_hash_node_t,
|
||||
pmix_list_item_t,
|
||||
pmix_ptr_hash_node_construct,
|
||||
pmix_ptr_hash_node_destruct);
|
||||
|
||||
static inline uint32_t pmix_hash_value(size_t mask, const void *key,
|
||||
size_t keysize)
|
||||
{
|
||||
unsigned int crc = pmix_uicrc_partial (key, keysize, 0);
|
||||
return (uint32_t) (crc & mask);
|
||||
}
|
||||
|
||||
int pmix_hash_table_get_value_ptr(pmix_hash_table_t* ht, const void* key,
|
||||
size_t key_size, void **ptr)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + pmix_hash_value(ht->ht_mask, key,
|
||||
key_size);
|
||||
pmix_ptr_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_get_value_ptr:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_ptr_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_ptr_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_ptr_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key_size == key_size &&
|
||||
memcmp(node->hn_key, key, key_size) == 0) {
|
||||
*ptr = node->hn_value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
int pmix_hash_table_set_value_ptr(pmix_hash_table_t* ht, const void* key,
|
||||
size_t key_size, void* value)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + pmix_hash_value(ht->ht_mask, key,
|
||||
key_size);
|
||||
pmix_ptr_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_set_value_ptr:"
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_ptr_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_ptr_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_ptr_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key_size == key_size &&
|
||||
memcmp(node->hn_key, key, key_size) == 0) {
|
||||
node->hn_value = value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
node = (pmix_ptr_hash_node_t*)pmix_list_remove_first(&ht->ht_nodes);
|
||||
if(NULL == node) {
|
||||
node = PMIX_NEW(pmix_ptr_hash_node_t);
|
||||
if(NULL == node) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
}
|
||||
node->hn_key = malloc(key_size);
|
||||
node->hn_key_size = key_size;
|
||||
node->hn_value = value;
|
||||
memcpy(node->hn_key, key, key_size);
|
||||
pmix_list_append(list, (pmix_list_item_t*)node);
|
||||
ht->ht_size++;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int pmix_hash_table_remove_value_ptr(pmix_hash_table_t* ht,
|
||||
const void* key, size_t key_size)
|
||||
{
|
||||
pmix_list_t* list = ht->ht_table + pmix_hash_value(ht->ht_mask,
|
||||
key, key_size);
|
||||
pmix_ptr_hash_node_t *node;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
if(ht->ht_table_size == 0) {
|
||||
pmix_output(0, "pmix_hash_table_remove_value_ptr: "
|
||||
"pmix_hash_table_init() has not been called");
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
#endif
|
||||
for(node = (pmix_ptr_hash_node_t*)pmix_list_get_first(list);
|
||||
node != (pmix_ptr_hash_node_t*)pmix_list_get_end(list);
|
||||
node = (pmix_ptr_hash_node_t*)pmix_list_get_next(node)) {
|
||||
if (node->hn_key_size == key_size &&
|
||||
memcmp(node->hn_key, key, key_size) == 0) {
|
||||
free(node->hn_key);
|
||||
node->hn_key = NULL;
|
||||
node->hn_key_size = 0;
|
||||
pmix_list_remove_item(list, (pmix_list_item_t*)node);
|
||||
pmix_list_append(&ht->ht_nodes, (pmix_list_item_t*)node);
|
||||
ht->ht_size--;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pmix_hash_table_get_first_key_uint32(pmix_hash_table_t *ht, uint32_t *key,
|
||||
void **value, void **node)
|
||||
{
|
||||
size_t i;
|
||||
pmix_uint32_hash_node_t *list_node;
|
||||
|
||||
/* Go through all the lists and return the first element off the
|
||||
first non-empty list */
|
||||
|
||||
for (i = 0; i < ht->ht_table_size; ++i) {
|
||||
if (pmix_list_get_size(ht->ht_table + i) > 0) {
|
||||
list_node = (pmix_uint32_hash_node_t*)
|
||||
pmix_list_get_first(ht->ht_table + i);
|
||||
*node = list_node;
|
||||
*key = list_node->hn_key;
|
||||
*value = list_node->hn_value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* The hash table is empty */
|
||||
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pmix_hash_table_get_next_key_uint32(pmix_hash_table_t *ht, uint32_t *key,
|
||||
void **value, void *in_node,
|
||||
void **out_node)
|
||||
{
|
||||
size_t i;
|
||||
pmix_list_t *list;
|
||||
pmix_list_item_t *item;
|
||||
pmix_uint32_hash_node_t *next;
|
||||
|
||||
/* Try to simply get the next value in the list. If there isn't
|
||||
one, find the next non-empty list and take the first value */
|
||||
|
||||
next = (pmix_uint32_hash_node_t*) in_node;
|
||||
list = ht->ht_table + (next->hn_key & ht->ht_mask);
|
||||
item = pmix_list_get_next(next);
|
||||
if (pmix_list_get_end(list) == item) {
|
||||
item = NULL;
|
||||
for (i = (list - ht->ht_table) + 1; i < ht->ht_table_size; ++i) {
|
||||
if (pmix_list_get_size(ht->ht_table + i) > 0) {
|
||||
item = pmix_list_get_first(ht->ht_table + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't find another non-empty list after this one,
|
||||
then we're at the end of the hash table */
|
||||
|
||||
if (NULL == item) {
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* We found it. Save the values (use "next" to avoid some
|
||||
typecasting) */
|
||||
|
||||
*out_node = (void *) item;
|
||||
next = (pmix_uint32_hash_node_t *) *out_node;
|
||||
*key = next->hn_key;
|
||||
*value = next->hn_value;
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pmix_hash_table_get_first_key_uint64(pmix_hash_table_t *ht, uint64_t *key,
|
||||
void **value, void **node)
|
||||
{
|
||||
size_t i;
|
||||
pmix_uint64_hash_node_t *list_node;
|
||||
|
||||
/* Go through all the lists and return the first element off the
|
||||
first non-empty list */
|
||||
|
||||
for (i = 0; i < ht->ht_table_size; ++i) {
|
||||
if (pmix_list_get_size(ht->ht_table + i) > 0) {
|
||||
list_node = (pmix_uint64_hash_node_t*)
|
||||
pmix_list_get_first(ht->ht_table + i);
|
||||
*node = list_node;
|
||||
*key = list_node->hn_key;
|
||||
*value = list_node->hn_value;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* The hash table is empty */
|
||||
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pmix_hash_table_get_next_key_uint64(pmix_hash_table_t *ht, uint64_t *key,
|
||||
void **value, void *in_node,
|
||||
void **out_node)
|
||||
{
|
||||
size_t i;
|
||||
pmix_list_t *list;
|
||||
pmix_list_item_t *item;
|
||||
pmix_uint64_hash_node_t *next;
|
||||
|
||||
/* Try to simply get the next value in the list. If there isn't
|
||||
one, find the next non-empty list and take the first value */
|
||||
|
||||
next = (pmix_uint64_hash_node_t*) in_node;
|
||||
list = ht->ht_table + (next->hn_key & ht->ht_mask);
|
||||
item = pmix_list_get_next(next);
|
||||
if (pmix_list_get_end(list) == item) {
|
||||
item = NULL;
|
||||
for (i = (list - ht->ht_table) + 1; i < ht->ht_table_size; ++i) {
|
||||
if (pmix_list_get_size(ht->ht_table + i) > 0) {
|
||||
item = pmix_list_get_first(ht->ht_table + i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't find another non-empty list after this one,
|
||||
then we're at the end of the hash table */
|
||||
|
||||
if (NULL == item) {
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* We found it. Save the values (use "next" to avoid some
|
||||
typecasting) */
|
||||
|
||||
*out_node = (void *) item;
|
||||
next = (pmix_uint64_hash_node_t *) *out_node;
|
||||
*key = next->hn_key;
|
||||
*value = next->hn_value;
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
@ -1,334 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* A hash table that may be indexed with either fixed length
|
||||
* (e.g. uint32_t/uint64_t) or arbitrary size binary key
|
||||
* values. However, only one key type may be used in a given table
|
||||
* concurrently.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_HASH_TABLE_H
|
||||
#define PMIX_HASH_TABLE_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <private/prefetch.h>
|
||||
|
||||
#ifdef HAVE_STDINT_H
|
||||
#include <stdint.h>
|
||||
#endif
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_hash_table_t);
|
||||
|
||||
struct pmix_hash_table_t
|
||||
{
|
||||
pmix_object_t super; /**< subclass of pmix_object_t */
|
||||
pmix_list_t ht_nodes; /**< free list of hash nodes */
|
||||
pmix_list_t *ht_table; /**< each item is an array of pmix_fhnode_t nodes */
|
||||
size_t ht_table_size; /**< size of table */
|
||||
size_t ht_size; /**< number of values on table */
|
||||
size_t ht_mask;
|
||||
};
|
||||
typedef struct pmix_hash_table_t pmix_hash_table_t;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the table size, must be called before using
|
||||
* the table.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param size The size of the table, which will be rounded up
|
||||
* (if required) to the next highest power of two (IN).
|
||||
* @return PMIX error code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC int pmix_hash_table_init(pmix_hash_table_t* ht, size_t table_size);
|
||||
|
||||
/**
|
||||
* Alternative form
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_hash_table_init2(pmix_hash_table_t* ht, size_t estimated_max_size,
|
||||
int density_numer, int density_denom,
|
||||
int growth_numer, int growth_denom);
|
||||
|
||||
/**
|
||||
* Returns the number of elements currently stored in the table.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @return The number of elements in the table.
|
||||
*
|
||||
*/
|
||||
|
||||
static inline size_t pmix_hash_table_get_size(pmix_hash_table_t *ht)
|
||||
{
|
||||
return ht->ht_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all elements from the table.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_remove_all(pmix_hash_table_t *ht);
|
||||
|
||||
/**
|
||||
* Retrieve value via uint32_t key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @param ptr The value associated with the key
|
||||
* @return integer return code:
|
||||
* - PMIX_SUCCESS if key was found
|
||||
* - PMIX_ERR_NOT_FOUND if key was not found
|
||||
* - PMIX_ERROR other error
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_value_uint32(pmix_hash_table_t* table, uint32_t key,
|
||||
void** ptr);
|
||||
|
||||
/**
|
||||
* Set value based on uint32_t key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @param value The value to be associated with the key (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_set_value_uint32(pmix_hash_table_t* table, uint32_t key, void* value);
|
||||
|
||||
/**
|
||||
* Remove value based on uint32_t key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_remove_value_uint32(pmix_hash_table_t* table, uint32_t key);
|
||||
|
||||
/**
|
||||
* Retrieve value via uint64_t key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @param ptr The value associated with the key
|
||||
* @return integer return code:
|
||||
* - PMIX_SUCCESS if key was found
|
||||
* - PMIX_ERR_NOT_FOUND if key was not found
|
||||
* - PMIX_ERROR other error
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_value_uint64(pmix_hash_table_t *table, uint64_t key,
|
||||
void **ptr);
|
||||
|
||||
/**
|
||||
* Set value based on uint64_t key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @param value The value to be associated with the key (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_set_value_uint64(pmix_hash_table_t *table, uint64_t key, void* value);
|
||||
|
||||
/**
|
||||
* Remove value based on uint64_t key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_remove_value_uint64(pmix_hash_table_t *table, uint64_t key);
|
||||
|
||||
/**
|
||||
* Retrieve value via arbitrary length binary key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @param ptr The value associated with the key
|
||||
* @return integer return code:
|
||||
* - PMIX_SUCCESS if key was found
|
||||
* - PMIX_ERR_NOT_FOUND if key was not found
|
||||
* - PMIX_ERROR other error
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_value_ptr(pmix_hash_table_t *table, const void* key,
|
||||
size_t keylen, void **ptr);
|
||||
|
||||
/**
|
||||
* Set value based on arbitrary length binary key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @param value The value to be associated with the key (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_set_value_ptr(pmix_hash_table_t *table, const void* key, size_t keylen, void* value);
|
||||
|
||||
/**
|
||||
* Remove value based on arbitrary length binary key.
|
||||
*
|
||||
* @param table The input hash table (IN).
|
||||
* @param key The input key (IN).
|
||||
* @return PMIX return code.
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_remove_value_ptr(pmix_hash_table_t *table, const void* key, size_t keylen);
|
||||
|
||||
|
||||
/** The following functions are only for allowing iterating through
|
||||
the hash table. The calls return along with a key, a pointer to
|
||||
the hash node with the current key, so that subsequent calls do
|
||||
not have to traverse all over again to the key (although it may
|
||||
just be a simple thing - to go to the array element and then
|
||||
traverse through the individual list). But lets take out this
|
||||
inefficiency too. This is similar to having an STL iterator in
|
||||
functionality */
|
||||
|
||||
/**
|
||||
* Get the first 32 bit key from the hash table, which can be used later to
|
||||
* get the next key
|
||||
* @param table The hash table pointer (IN)
|
||||
* @param key The first key (OUT)
|
||||
* @param value The value corresponding to this key (OUT)
|
||||
* @param node The pointer to the hash table internal node which stores
|
||||
* the key-value pair (this is required for subsequent calls
|
||||
* to get_next_key) (OUT)
|
||||
* @return PMIX error code
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_first_key_uint32(pmix_hash_table_t *table, uint32_t *key,
|
||||
void **value, void **node);
|
||||
|
||||
|
||||
/**
|
||||
* Get the next 32 bit key from the hash table, knowing the current key
|
||||
* @param table The hash table pointer (IN)
|
||||
* @param key The key (OUT)
|
||||
* @param value The value corresponding to this key (OUT)
|
||||
* @param in_node The node pointer from previous call to either get_first
|
||||
or get_next (IN)
|
||||
* @param out_node The pointer to the hash table internal node which stores
|
||||
* the key-value pair (this is required for subsequent calls
|
||||
* to get_next_key) (OUT)
|
||||
* @return PMIX error code
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_next_key_uint32(pmix_hash_table_t *table, uint32_t *key,
|
||||
void **value, void *in_node,
|
||||
void **out_node);
|
||||
|
||||
|
||||
/**
|
||||
* Get the first 64 key from the hash table, which can be used later to
|
||||
* get the next key
|
||||
* @param table The hash table pointer (IN)
|
||||
* @param key The first key (OUT)
|
||||
* @param value The value corresponding to this key (OUT)
|
||||
* @param node The pointer to the hash table internal node which stores
|
||||
* the key-value pair (this is required for subsequent calls
|
||||
* to get_next_key) (OUT)
|
||||
* @return PMIX error code
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_first_key_uint64(pmix_hash_table_t *table, uint64_t *key,
|
||||
void **value, void **node);
|
||||
|
||||
|
||||
/**
|
||||
* Get the next 64 bit key from the hash table, knowing the current key
|
||||
* @param table The hash table pointer (IN)
|
||||
* @param key The key (OUT)
|
||||
* @param value The value corresponding to this key (OUT)
|
||||
* @param in_node The node pointer from previous call to either get_first
|
||||
or get_next (IN)
|
||||
* @param out_node The pointer to the hash table internal node which stores
|
||||
* the key-value pair (this is required for subsequent calls
|
||||
* to get_next_key) (OUT)
|
||||
* @return PMIX error code
|
||||
*
|
||||
*/
|
||||
|
||||
PMIX_DECLSPEC pmix_status_t pmix_hash_table_get_next_key_uint64(pmix_hash_table_t *table, uint64_t *key,
|
||||
void **value, void *in_node,
|
||||
void **out_node);
|
||||
|
||||
/**
|
||||
* @brief Returns next power-of-two of the given value.
|
||||
*
|
||||
* @param value The integer value to return power of 2
|
||||
*
|
||||
* @returns The next power of two
|
||||
*
|
||||
* WARNING: *NO* error checking is performed. This is meant to be a
|
||||
* fast inline function.
|
||||
* Using __builtin_clz (count-leading-zeros) uses 4 cycles instead of 77
|
||||
* compared to the loop-version (on Intel Nehalem -- with icc-12.1.0 -O2).
|
||||
*/
|
||||
static inline int pmix_next_poweroftwo(int value)
|
||||
{
|
||||
int power2;
|
||||
|
||||
#if PMIX_C_HAVE_BUILTIN_CLZ
|
||||
if (PMIX_UNLIKELY (0 == value)) {
|
||||
return 1;
|
||||
}
|
||||
power2 = 1 << (8 * sizeof (int) - __builtin_clz(value));
|
||||
#else
|
||||
for (power2 = 1; value > 0; value >>= 1, power2 <<= 1) /* empty */;
|
||||
#endif
|
||||
|
||||
return power2;
|
||||
}
|
||||
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_HASH_TABLE_H */
|
@ -1,260 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2007 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007 Voltaire All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include <pmix.h>
|
||||
|
||||
/*
|
||||
* List classes
|
||||
*/
|
||||
|
||||
static void pmix_list_item_construct(pmix_list_item_t*);
|
||||
static void pmix_list_item_destruct(pmix_list_item_t*);
|
||||
|
||||
PMIX_CLASS_INSTANCE(
|
||||
pmix_list_item_t,
|
||||
pmix_object_t,
|
||||
pmix_list_item_construct,
|
||||
pmix_list_item_destruct
|
||||
);
|
||||
|
||||
static void pmix_list_construct(pmix_list_t*);
|
||||
static void pmix_list_destruct(pmix_list_t*);
|
||||
|
||||
PMIX_CLASS_INSTANCE(
|
||||
pmix_list_t,
|
||||
pmix_object_t,
|
||||
pmix_list_construct,
|
||||
pmix_list_destruct
|
||||
);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* pmix_list_link_item_t interface
|
||||
*
|
||||
*/
|
||||
|
||||
static void pmix_list_item_construct(pmix_list_item_t *item)
|
||||
{
|
||||
item->pmix_list_next = item->pmix_list_prev = NULL;
|
||||
item->item_free = 1;
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
item->pmix_list_item_refcount = 0;
|
||||
item->pmix_list_item_belong_to = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void pmix_list_item_destruct(pmix_list_item_t *item)
|
||||
{
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
assert( 0 == item->pmix_list_item_refcount );
|
||||
assert( NULL == item->pmix_list_item_belong_to );
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* pmix_list_list_t interface
|
||||
*
|
||||
*/
|
||||
|
||||
static void pmix_list_construct(pmix_list_t *list)
|
||||
{
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* These refcounts should never be used in assertions because they
|
||||
should never be removed from this list, added to another list,
|
||||
etc. So set them to sentinel values. */
|
||||
|
||||
PMIX_CONSTRUCT( &(list->pmix_list_sentinel), pmix_list_item_t );
|
||||
list->pmix_list_sentinel.pmix_list_item_refcount = 1;
|
||||
list->pmix_list_sentinel.pmix_list_item_belong_to = list;
|
||||
#endif
|
||||
|
||||
list->pmix_list_sentinel.pmix_list_next = &list->pmix_list_sentinel;
|
||||
list->pmix_list_sentinel.pmix_list_prev = &list->pmix_list_sentinel;
|
||||
list->pmix_list_length = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reset all the pointers to be NULL -- do not actually destroy
|
||||
* anything.
|
||||
*/
|
||||
static void pmix_list_destruct(pmix_list_t *list)
|
||||
{
|
||||
pmix_list_construct(list);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert an item at a specific place in a list
|
||||
*/
|
||||
bool pmix_list_insert(pmix_list_t *list, pmix_list_item_t *item, long long idx)
|
||||
{
|
||||
/* Adds item to list at index and retains item. */
|
||||
int i;
|
||||
volatile pmix_list_item_t *ptr, *next;
|
||||
|
||||
if ( idx >= (long long)list->pmix_list_length ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( 0 == idx )
|
||||
{
|
||||
pmix_list_prepend(list, item);
|
||||
} else {
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that this item is previously on no
|
||||
lists */
|
||||
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
#endif
|
||||
/* pointer to element 0 */
|
||||
ptr = list->pmix_list_sentinel.pmix_list_next;
|
||||
for ( i = 0; i < idx-1; i++ )
|
||||
ptr = ptr->pmix_list_next;
|
||||
|
||||
next = ptr->pmix_list_next;
|
||||
item->pmix_list_next = next;
|
||||
item->pmix_list_prev = ptr;
|
||||
next->pmix_list_prev = item;
|
||||
ptr->pmix_list_next = item;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure this item is only on the list that we
|
||||
just insertted it into */
|
||||
|
||||
item->pmix_list_item_refcount += 1;
|
||||
assert(1 == item->pmix_list_item_refcount);
|
||||
item->pmix_list_item_belong_to = list;
|
||||
#endif
|
||||
}
|
||||
|
||||
list->pmix_list_length++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void
|
||||
pmix_list_transfer(pmix_list_item_t *pos, pmix_list_item_t *begin,
|
||||
pmix_list_item_t *end)
|
||||
{
|
||||
volatile pmix_list_item_t *tmp;
|
||||
|
||||
if (pos != end) {
|
||||
/* remove [begin, end) */
|
||||
end->pmix_list_prev->pmix_list_next = pos;
|
||||
begin->pmix_list_prev->pmix_list_next = end;
|
||||
pos->pmix_list_prev->pmix_list_next = begin;
|
||||
|
||||
/* splice into new position before pos */
|
||||
tmp = pos->pmix_list_prev;
|
||||
pos->pmix_list_prev = end->pmix_list_prev;
|
||||
end->pmix_list_prev = begin->pmix_list_prev;
|
||||
begin->pmix_list_prev = tmp;
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
{
|
||||
volatile pmix_list_item_t* item = begin;
|
||||
while( pos != item ) {
|
||||
item->pmix_list_item_belong_to = pos->pmix_list_item_belong_to;
|
||||
item = item->pmix_list_next;
|
||||
assert(NULL != item);
|
||||
}
|
||||
}
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pmix_list_join(pmix_list_t *thislist, pmix_list_item_t *pos,
|
||||
pmix_list_t *xlist)
|
||||
{
|
||||
if (0 != pmix_list_get_size(xlist)) {
|
||||
pmix_list_transfer(pos, pmix_list_get_first(xlist),
|
||||
pmix_list_get_end(xlist));
|
||||
|
||||
/* fix the sizes */
|
||||
thislist->pmix_list_length += xlist->pmix_list_length;
|
||||
xlist->pmix_list_length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pmix_list_splice(pmix_list_t *thislist, pmix_list_item_t *pos,
|
||||
pmix_list_t *xlist, pmix_list_item_t *first,
|
||||
pmix_list_item_t *last)
|
||||
{
|
||||
size_t change = 0;
|
||||
pmix_list_item_t *tmp;
|
||||
|
||||
if (first != last) {
|
||||
/* figure out how many things we are going to move (have to do
|
||||
* first, since last might be end and then we wouldn't be able
|
||||
* to run the loop)
|
||||
*/
|
||||
for (tmp = first ; tmp != last ; tmp = pmix_list_get_next(tmp)) {
|
||||
change++;
|
||||
}
|
||||
|
||||
pmix_list_transfer(pos, first, last);
|
||||
|
||||
/* fix the sizes */
|
||||
thislist->pmix_list_length += change;
|
||||
xlist->pmix_list_length -= change;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int pmix_list_sort(pmix_list_t* list, pmix_list_item_compare_fn_t compare)
|
||||
{
|
||||
pmix_list_item_t* item;
|
||||
pmix_list_item_t** items;
|
||||
size_t i, index=0;
|
||||
|
||||
if (0 == list->pmix_list_length) {
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
items = (pmix_list_item_t**)malloc(sizeof(pmix_list_item_t*) *
|
||||
list->pmix_list_length);
|
||||
|
||||
if (NULL == items) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
|
||||
while(NULL != (item = pmix_list_remove_first(list))) {
|
||||
items[index++] = item;
|
||||
}
|
||||
|
||||
qsort(items, index, sizeof(pmix_list_item_t*),
|
||||
(int(*)(const void*,const void*))compare);
|
||||
for (i=0; i<index; i++) {
|
||||
pmix_list_append(list,items[i]);
|
||||
}
|
||||
free(items);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
@ -1,909 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007 Voltaire All rights reserved.
|
||||
* Copyright (c) 2013 Los Alamos National Security, LLC. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* The pmix_list_t interface is used to provide a generic
|
||||
* doubly-linked list container for PMIx. It was inspired by (but
|
||||
* is slightly different than) the Standard Template Library (STL)
|
||||
* std::list class. One notable difference from std::list is that
|
||||
* when an pmix_list_t is destroyed, all of the pmix_list_item_t
|
||||
* objects that it contains are orphaned -- they are \em not
|
||||
* destroyed.
|
||||
*
|
||||
* The general idea is that pmix_list_item_t objects can be put on an
|
||||
* pmix_list_t. Hence, you create a new type that derives from
|
||||
* pmix_list_item_t; this new type can then be used with pmix_list_t
|
||||
* containers.
|
||||
*
|
||||
* NOTE: pmix_list_item_t instances can only be on \em one list at a
|
||||
* time. Specifically, if you add an pmix_list_item_t to one list,
|
||||
* and then add it to another list (without first removing it from the
|
||||
* first list), you will effectively be hosing the first list. You
|
||||
* have been warned.
|
||||
*
|
||||
* If PMIX_ENABLE_DEBUG is true, a bunch of checks occur, including
|
||||
* some spot checks for a debugging reference count in an attempt to
|
||||
* ensure that an pmix_list_item_t is only one *one* list at a time.
|
||||
* Given the highly concurrent nature of this class, these spot checks
|
||||
* cannot guarantee that an item is only one list at a time.
|
||||
* Specifically, since it is a desirable attribute of this class to
|
||||
* not use locks for normal operations, it is possible that two
|
||||
* threads may [erroneously] modify an pmix_list_item_t concurrently.
|
||||
*
|
||||
* The only way to guarantee that a debugging reference count is valid
|
||||
* for the duration of an operation is to lock the item_t during the
|
||||
* operation. But this fundamentally changes the desirable attribute
|
||||
* of this class (i.e., no locks). So all we can do is spot-check the
|
||||
* reference count in a bunch of places and check that it is still the
|
||||
* value that we think it should be. But this doesn't mean that you
|
||||
* can run into "unlucky" cases where two threads are concurrently
|
||||
* modifying an item_t, but all the spot checks still return the
|
||||
* "right" values. All we can do is hope that we have enough spot
|
||||
* checks to statistically drive down the possibility of the unlucky
|
||||
* cases happening.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_LIST_H
|
||||
#define PMIX_LIST_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* The class for the list container.
|
||||
*/
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_list_t);
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Base class for items that are put in list (pmix_list_t) containers.
|
||||
*/
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_list_item_t);
|
||||
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Struct of an pmix_list_item_t
|
||||
*/
|
||||
struct pmix_list_item_t
|
||||
{
|
||||
pmix_object_t super;
|
||||
/**< Generic parent class for all PMIx objects */
|
||||
volatile struct pmix_list_item_t *pmix_list_next;
|
||||
/**< Pointer to next list item */
|
||||
volatile struct pmix_list_item_t *pmix_list_prev;
|
||||
/**< Pointer to previous list item */
|
||||
int32_t item_free;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/** Atomic reference count for debugging */
|
||||
volatile int32_t pmix_list_item_refcount;
|
||||
/** The list this item belong to */
|
||||
volatile struct pmix_list_t* pmix_list_item_belong_to;
|
||||
#endif
|
||||
};
|
||||
/**
|
||||
* Base type for items that are put in a list (pmix_list_t) containers.
|
||||
*/
|
||||
typedef struct pmix_list_item_t pmix_list_item_t;
|
||||
|
||||
|
||||
/**
|
||||
* Get the next item in a list.
|
||||
*
|
||||
* @param item A list item.
|
||||
*
|
||||
* @returns The next item in the list
|
||||
*/
|
||||
#define pmix_list_get_next(item) \
|
||||
((item) ? ((pmix_list_item_t*) ((pmix_list_item_t*)(item))->pmix_list_next) : NULL)
|
||||
|
||||
/**
|
||||
* Get the next item in a list.
|
||||
*
|
||||
* @param item A list item.
|
||||
*
|
||||
* @returns The next item in the list
|
||||
*/
|
||||
#define pmix_list_get_prev(item) \
|
||||
((item) ? ((pmix_list_item_t*) ((pmix_list_item_t*)(item))->pmix_list_prev) : NULL)
|
||||
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Struct of an pmix_list_t
|
||||
*/
|
||||
struct pmix_list_t
|
||||
{
|
||||
pmix_object_t super;
|
||||
/**< Generic parent class for all PMIx objects */
|
||||
pmix_list_item_t pmix_list_sentinel;
|
||||
/**< Head and tail item of the list */
|
||||
volatile size_t pmix_list_length;
|
||||
/**< Quick reference to the number of items in the list */
|
||||
};
|
||||
/**
|
||||
* List container type.
|
||||
*/
|
||||
typedef struct pmix_list_t pmix_list_t;
|
||||
|
||||
/** Cleanly destruct a list
|
||||
*
|
||||
* The pmix_list_t destructor doesn't release the items on the
|
||||
* list - so provide two convenience macros that do so and then
|
||||
* destruct/release the list object itself
|
||||
*
|
||||
* @param[in] list List to destruct or release
|
||||
*/
|
||||
#define PMIX_LIST_DESTRUCT(list) \
|
||||
do { \
|
||||
pmix_list_item_t *it; \
|
||||
while (NULL != (it = pmix_list_remove_first(list))) { \
|
||||
PMIX_RELEASE(it); \
|
||||
} \
|
||||
PMIX_DESTRUCT(list); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_LIST_RELEASE(list) \
|
||||
do { \
|
||||
pmix_list_item_t *it; \
|
||||
while (NULL != (it = pmix_list_remove_first(list))) { \
|
||||
PMIX_RELEASE(it); \
|
||||
} \
|
||||
PMIX_RELEASE(list); \
|
||||
} while(0);
|
||||
|
||||
|
||||
/**
|
||||
* Loop over a list.
|
||||
*
|
||||
* @param[in] item Storage for each item
|
||||
* @param[in] list List to iterate over
|
||||
* @param[in] type Type of each list item
|
||||
*
|
||||
* This macro provides a simple way to loop over the items in an pmix_list_t. It
|
||||
* is not safe to call pmix_list_remove_item from within the loop.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* class_foo_t *foo;
|
||||
* pmix_list_foreach(foo, list, class_foo_t) {
|
||||
* do something;
|
||||
* }
|
||||
*/
|
||||
#define PMIX_LIST_FOREACH(item, list, type) \
|
||||
for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next ; \
|
||||
item != (type *) &(list)->pmix_list_sentinel ; \
|
||||
item = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
|
||||
|
||||
/**
|
||||
* Loop over a list in reverse.
|
||||
*
|
||||
* @param[in] item Storage for each item
|
||||
* @param[in] list List to iterate over
|
||||
* @param[in] type Type of each list item
|
||||
*
|
||||
* This macro provides a simple way to loop over the items in an pmix_list_t. It
|
||||
* is not safe to call pmix_list_remove_item from within the loop.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* class_foo_t *foo;
|
||||
* pmix_list_foreach(foo, list, class_foo_t) {
|
||||
* do something;
|
||||
* }
|
||||
*/
|
||||
#define PMIX_LIST_FOREACH_REV(item, list, type) \
|
||||
for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev ; \
|
||||
item != (type *) &(list)->pmix_list_sentinel ; \
|
||||
item = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev)
|
||||
|
||||
/**
|
||||
* Loop over a list in a *safe* way
|
||||
*
|
||||
* @param[in] item Storage for each item
|
||||
* @param[in] next Storage for next item
|
||||
* @param[in] list List to iterate over
|
||||
* @param[in] type Type of each list item
|
||||
*
|
||||
* This macro provides a simple way to loop over the items in an pmix_list_t. It
|
||||
* is safe to call pmix_list_remove_item(list, item) from within the loop.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* class_foo_t *foo, *next;
|
||||
* pmix_list_foreach_safe(foo, next, list, class_foo_t) {
|
||||
* do something;
|
||||
* pmix_list_remove_item (list, (pmix_list_item_t *) foo);
|
||||
* }
|
||||
*/
|
||||
#define PMIX_LIST_FOREACH_SAFE(item, next, list, type) \
|
||||
for (item = (type *) (list)->pmix_list_sentinel.pmix_list_next, \
|
||||
next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next ;\
|
||||
item != (type *) &(list)->pmix_list_sentinel ; \
|
||||
item = next, next = (type *) ((pmix_list_item_t *) (item))->pmix_list_next)
|
||||
|
||||
/**
|
||||
* Loop over a list in a *safe* way
|
||||
*
|
||||
* @param[in] item Storage for each item
|
||||
* @param[in] next Storage for next item
|
||||
* @param[in] list List to iterate over
|
||||
* @param[in] type Type of each list item
|
||||
*
|
||||
* This macro provides a simple way to loop over the items in an pmix_list_t. If
|
||||
* is safe to call pmix_list_remove_item(list, item) from within the loop.
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* class_foo_t *foo, *next;
|
||||
* pmix_list_foreach_safe(foo, next, list, class_foo_t) {
|
||||
* do something;
|
||||
* pmix_list_remove_item (list, (pmix_list_item_t *) foo);
|
||||
* }
|
||||
*/
|
||||
#define PMIX_LIST_FOREACH_SAFE_REV(item, prev, list, type) \
|
||||
for (item = (type *) (list)->pmix_list_sentinel.pmix_list_prev, \
|
||||
prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev ;\
|
||||
item != (type *) &(list)->pmix_list_sentinel ; \
|
||||
item = prev, prev = (type *) ((pmix_list_item_t *) (item))->pmix_list_prev)
|
||||
|
||||
|
||||
/**
|
||||
* Check for empty list
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns true if list's size is 0, false otherwise
|
||||
*
|
||||
* This is an O(1) operation.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining,
|
||||
* so it's usually a cheap operation.
|
||||
*/
|
||||
static inline bool pmix_list_is_empty(pmix_list_t* list)
|
||||
{
|
||||
return (list->pmix_list_sentinel.pmix_list_next ==
|
||||
&(list->pmix_list_sentinel) ? true : false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the first item on the list (does not remove it).
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns A pointer to the first item on the list
|
||||
*
|
||||
* This is an O(1) operation to return the first item on the list. It
|
||||
* should be compared against the returned value from
|
||||
* pmix_list_get_end() to ensure that the list is not empty.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t* pmix_list_get_first(pmix_list_t* list)
|
||||
{
|
||||
pmix_list_item_t* item = (pmix_list_item_t*)list->pmix_list_sentinel.pmix_list_next;
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that the first item is only on one list */
|
||||
|
||||
assert(1 == item->pmix_list_item_refcount);
|
||||
assert( list == item->pmix_list_item_belong_to );
|
||||
#endif
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last item on the list (does not remove it).
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns A pointer to the last item on the list
|
||||
*
|
||||
* This is an O(1) operation to return the last item on the list. It
|
||||
* should be compared against the returned value from
|
||||
* pmix_list_get_begin() to ensure that the list is not empty.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t* pmix_list_get_last(pmix_list_t* list)
|
||||
{
|
||||
pmix_list_item_t* item = (pmix_list_item_t *)list->pmix_list_sentinel.pmix_list_prev;
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that the last item is only on one list */
|
||||
|
||||
assert( 1 == item->pmix_list_item_refcount );
|
||||
assert( list == item->pmix_list_item_belong_to );
|
||||
#endif
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the beginning of the list; an invalid list entry suitable
|
||||
* for comparison only.
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns A pointer to the beginning of the list.
|
||||
*
|
||||
* This is an O(1) operation to return the beginning of the list.
|
||||
* Similar to the STL, this is a special invalid list item -- it
|
||||
* should \em not be used for storage. It is only suitable for
|
||||
* comparison to other items in the list to see if they are valid or
|
||||
* not; it's ususally used when iterating through the items in a list.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t* pmix_list_get_begin(pmix_list_t* list)
|
||||
{
|
||||
return &(list->pmix_list_sentinel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the end of the list; an invalid list entry suitable for
|
||||
* comparison only.
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns A pointer to the end of the list.
|
||||
*
|
||||
* This is an O(1) operation to return the end of the list.
|
||||
* Similar to the STL, this is a special invalid list item -- it
|
||||
* should \em not be used for storage. It is only suitable for
|
||||
* comparison to other items in the list to see if they are valid or
|
||||
* not; it's ususally used when iterating through the items in a list.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t* pmix_list_get_end(pmix_list_t* list)
|
||||
{
|
||||
return &(list->pmix_list_sentinel);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of items in a list
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns The size of the list (size_t)
|
||||
*
|
||||
* This is an O(1) lookup to return the size of the list.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*
|
||||
* \warning The size of the list is cached as part of the list. In
|
||||
* the future, calling \c pmix_list_splice or \c pmix_list_join may
|
||||
* result in this function recomputing the list size, which would be
|
||||
* an O(N) operation. If \c pmix_list_splice or \c pmix_list_join is
|
||||
* never called on the specified list, this function will always be
|
||||
* O(1).
|
||||
*/
|
||||
static inline size_t pmix_list_get_size(pmix_list_t* list)
|
||||
{
|
||||
#if PMIX_ENABLE_DEBUG && 0
|
||||
/* not sure if we really want this running in devel, as it does
|
||||
* slow things down. Wanted for development of splice / join to
|
||||
* make sure length was reset properly
|
||||
*/
|
||||
size_t check_len = 0;
|
||||
pmix_list_item_t *item;
|
||||
|
||||
for (item = pmix_list_get_first(list) ;
|
||||
item != pmix_list_get_end(list) ;
|
||||
item = pmix_list_get_next(item)) {
|
||||
check_len++;
|
||||
}
|
||||
|
||||
if (check_len != list->pmix_list_length) {
|
||||
fprintf(stderr," Error :: pmix_list_get_size - pmix_list_length does not match actual list length\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
#endif
|
||||
|
||||
return list->pmix_list_length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove an item from a list.
|
||||
*
|
||||
* @param list The list container
|
||||
* @param item The item to remove
|
||||
*
|
||||
* @returns A pointer to the item on the list previous to the one
|
||||
* that was removed.
|
||||
*
|
||||
* This is an O(1) operation to remove an item from the list. The
|
||||
* forward / reverse pointers in the list are updated and the item is
|
||||
* removed. The list item that is returned is now "owned" by the
|
||||
* caller -- they are responsible for PMIX_RELEASE()'ing it.
|
||||
*
|
||||
* If debugging is enabled (specifically, if --enable-debug was used
|
||||
* to configure PMIx), this is an O(N) operation because it checks
|
||||
* to see if the item is actually in the list first.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t *pmix_list_remove_item
|
||||
(pmix_list_t *list, pmix_list_item_t *item)
|
||||
{
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
pmix_list_item_t *item_ptr;
|
||||
bool found = false;
|
||||
|
||||
/* check to see that the item is in the list */
|
||||
for (item_ptr = pmix_list_get_first(list);
|
||||
item_ptr != pmix_list_get_end(list);
|
||||
item_ptr = (pmix_list_item_t *)(item_ptr->pmix_list_next)) {
|
||||
if (item_ptr == (pmix_list_item_t *) item) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
fprintf(stderr," Warning :: pmix_list_remove_item - the item %p is not on the list %p \n",(void*) item, (void*) list);
|
||||
fflush(stderr);
|
||||
return (pmix_list_item_t *)NULL;
|
||||
}
|
||||
|
||||
assert( list == item->pmix_list_item_belong_to );
|
||||
#endif
|
||||
|
||||
/* reset next pointer of previous element */
|
||||
item->pmix_list_prev->pmix_list_next=item->pmix_list_next;
|
||||
|
||||
/* reset previous pointer of next element */
|
||||
item->pmix_list_next->pmix_list_prev=item->pmix_list_prev;
|
||||
|
||||
list->pmix_list_length--;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that this item is still only on one list */
|
||||
|
||||
item->pmix_list_item_refcount -= 1;
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
item->pmix_list_item_belong_to = NULL;
|
||||
#endif
|
||||
|
||||
return (pmix_list_item_t *)item->pmix_list_prev;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append an item to the end of the list.
|
||||
*
|
||||
* @param list The list container
|
||||
* @param item The item to append
|
||||
*
|
||||
* This is an O(1) operation to append an item to the end of a list.
|
||||
* The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed that
|
||||
* "ownership" of the item is passed from the caller to the list.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
#define pmix_list_append(l,i) \
|
||||
_pmix_list_append(l,i,__FILE__,__LINE__)
|
||||
#else
|
||||
#define pmix_list_append(l,i) \
|
||||
_pmix_list_append(l,i)
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
|
||||
static inline void _pmix_list_append(pmix_list_t *list, pmix_list_item_t *item
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
, const char* FILE_NAME, int LINENO
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
)
|
||||
{
|
||||
pmix_list_item_t* sentinel = &(list->pmix_list_sentinel);
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that this item is previously on no lists */
|
||||
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
assert( NULL == item->pmix_list_item_belong_to );
|
||||
item->super.cls_init_file_name = FILE_NAME;
|
||||
item->super.cls_init_lineno = LINENO;
|
||||
#endif
|
||||
|
||||
/* set new element's previous pointer */
|
||||
item->pmix_list_prev = sentinel->pmix_list_prev;
|
||||
|
||||
/* reset previous pointer on current last element */
|
||||
sentinel->pmix_list_prev->pmix_list_next = item;
|
||||
|
||||
/* reset new element's next pointer */
|
||||
item->pmix_list_next = sentinel;
|
||||
|
||||
/* reset the list's tail element previous pointer */
|
||||
sentinel->pmix_list_prev = item;
|
||||
|
||||
/* increment list element counter */
|
||||
list->pmix_list_length++;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure this item is only on the list that we just
|
||||
appended it to */
|
||||
|
||||
item->pmix_list_item_refcount += 1;
|
||||
assert(1 == item->pmix_list_item_refcount);
|
||||
item->pmix_list_item_belong_to = list;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prepend an item to the beginning of the list.
|
||||
*
|
||||
* @param list The list container
|
||||
* @param item The item to prepend
|
||||
*
|
||||
* This is an O(1) operation to prepend an item to the beginning of a
|
||||
* list. The pmix_list_item_t is not PMIX_RETAIN()'ed; it is assumed
|
||||
* that "ownership" of the item is passed from the caller to the list.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline void pmix_list_prepend(pmix_list_t *list,
|
||||
pmix_list_item_t *item)
|
||||
{
|
||||
pmix_list_item_t* sentinel = &(list->pmix_list_sentinel);
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that this item is previously on no lists */
|
||||
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
assert( NULL == item->pmix_list_item_belong_to );
|
||||
#endif
|
||||
|
||||
/* reset item's next pointer */
|
||||
item->pmix_list_next = sentinel->pmix_list_next;
|
||||
|
||||
/* reset item's previous pointer */
|
||||
item->pmix_list_prev = sentinel;
|
||||
|
||||
/* reset previous first element's previous poiner */
|
||||
sentinel->pmix_list_next->pmix_list_prev = item;
|
||||
|
||||
/* reset head's next pointer */
|
||||
sentinel->pmix_list_next = item;
|
||||
|
||||
/* increment list element counter */
|
||||
list->pmix_list_length++;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure this item is only on the list that we just
|
||||
prepended it to */
|
||||
|
||||
item->pmix_list_item_refcount += 1;
|
||||
assert(1 == item->pmix_list_item_refcount);
|
||||
item->pmix_list_item_belong_to = list;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the first item from the list and return it.
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns The first item on the list. If the list is empty,
|
||||
* NULL will be returned
|
||||
*
|
||||
* This is an O(1) operation to return the first item on the list. If
|
||||
* the list is not empty, a pointer to the first item in the list will
|
||||
* be returned. Ownership of the item is transferred from the list to
|
||||
* the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t *pmix_list_remove_first(pmix_list_t *list)
|
||||
{
|
||||
/* Removes and returns first item on list.
|
||||
Caller now owns the item and should release the item
|
||||
when caller is done with it.
|
||||
*/
|
||||
volatile pmix_list_item_t *item;
|
||||
if ( 0 == list->pmix_list_length ) {
|
||||
return (pmix_list_item_t *)NULL;
|
||||
}
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that the first item is only on this list */
|
||||
|
||||
assert(1 == list->pmix_list_sentinel.pmix_list_next->pmix_list_item_refcount);
|
||||
#endif
|
||||
|
||||
/* reset list length counter */
|
||||
list->pmix_list_length--;
|
||||
|
||||
/* get pointer to first element on the list */
|
||||
item = list->pmix_list_sentinel.pmix_list_next;
|
||||
|
||||
/* reset previous pointer of next item on the list */
|
||||
item->pmix_list_next->pmix_list_prev = item->pmix_list_prev;
|
||||
|
||||
/* reset the head next pointer */
|
||||
list->pmix_list_sentinel.pmix_list_next = item->pmix_list_next;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
assert( list == item->pmix_list_item_belong_to );
|
||||
item->pmix_list_item_belong_to = NULL;
|
||||
item->pmix_list_prev=(pmix_list_item_t *)NULL;
|
||||
item->pmix_list_next=(pmix_list_item_t *)NULL;
|
||||
|
||||
/* Spot check: ensure that the item we're returning is now on no
|
||||
lists */
|
||||
|
||||
item->pmix_list_item_refcount -= 1;
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
#endif
|
||||
|
||||
return (pmix_list_item_t *) item;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the last item from the list and return it.
|
||||
*
|
||||
* @param list The list container
|
||||
*
|
||||
* @returns The last item on the list. If the list is empty,
|
||||
* NULL will be returned
|
||||
*
|
||||
* This is an O(1) operation to return the last item on the list. If
|
||||
* the list is not empty, a pointer to the last item in the list will
|
||||
* be returned. Ownership of the item is transferred from the list to
|
||||
* the caller; no calls to PMIX_RETAIN() or PMIX_RELEASE() are invoked.
|
||||
*
|
||||
* This is an inlined function in compilers that support inlining, so
|
||||
* it's usually a cheap operation.
|
||||
*/
|
||||
static inline pmix_list_item_t *pmix_list_remove_last(pmix_list_t *list)
|
||||
{
|
||||
/* Removes, releases and returns last item on list.
|
||||
Caller now owns the item and should release the item
|
||||
when caller is done with it.
|
||||
*/
|
||||
volatile pmix_list_item_t *item;
|
||||
if ( 0 == list->pmix_list_length ) {
|
||||
return (pmix_list_item_t *)NULL;
|
||||
}
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that the first item is only on this list */
|
||||
|
||||
assert(1 == list->pmix_list_sentinel.pmix_list_prev->pmix_list_item_refcount);
|
||||
#endif
|
||||
|
||||
/* reset list length counter */
|
||||
list->pmix_list_length--;
|
||||
|
||||
/* get item */
|
||||
item = list->pmix_list_sentinel.pmix_list_prev;
|
||||
|
||||
/* reset previous pointer on next to last pointer */
|
||||
item->pmix_list_prev->pmix_list_next = item->pmix_list_next;
|
||||
|
||||
/* reset tail's previous pointer */
|
||||
list->pmix_list_sentinel.pmix_list_prev = item->pmix_list_prev;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
assert( list == item->pmix_list_item_belong_to );
|
||||
item->pmix_list_next = item->pmix_list_prev = (pmix_list_item_t *)NULL;
|
||||
|
||||
/* Spot check: ensure that the item we're returning is now on no
|
||||
lists */
|
||||
|
||||
item->pmix_list_item_refcount -= 1;
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
item->pmix_list_item_belong_to = NULL;
|
||||
#endif
|
||||
|
||||
return (pmix_list_item_t *) item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the list before a given element
|
||||
*
|
||||
* @param list The list container
|
||||
* @param pos List element to insert \c item before
|
||||
* @param item The item to insert
|
||||
*
|
||||
* Inserts \c item before \c pos. This is an O(1) operation.
|
||||
*/
|
||||
static inline void pmix_list_insert_pos(pmix_list_t *list, pmix_list_item_t *pos,
|
||||
pmix_list_item_t *item)
|
||||
{
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: ensure that the item we're insertting is currently
|
||||
not on any list */
|
||||
|
||||
assert(0 == item->pmix_list_item_refcount);
|
||||
assert( NULL == item->pmix_list_item_belong_to );
|
||||
#endif
|
||||
|
||||
/* point item at the existing elements */
|
||||
item->pmix_list_next = pos;
|
||||
item->pmix_list_prev = pos->pmix_list_prev;
|
||||
|
||||
/* splice into the list */
|
||||
pos->pmix_list_prev->pmix_list_next = item;
|
||||
pos->pmix_list_prev = item;
|
||||
|
||||
/* reset list length counter */
|
||||
list->pmix_list_length++;
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Spot check: double check that this item is only on the list
|
||||
that we just added it to */
|
||||
|
||||
item->pmix_list_item_refcount += 1;
|
||||
assert(1 == item->pmix_list_item_refcount);
|
||||
item->pmix_list_item_belong_to = list;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the list at a specific index location in the list.
|
||||
*
|
||||
* @param list The list container
|
||||
* @param item The item to insert
|
||||
* @param index Location to add the item
|
||||
*
|
||||
* @returns true if insertion succeeded; otherwise false
|
||||
*
|
||||
* This is potentially an O(N) operation to traverse down to the
|
||||
* correct location in the list and add an item.
|
||||
*
|
||||
* Example: if idx = 2 and list = item1->item2->item3->item4, then
|
||||
* after insert, list = item1->item2->item->item3->item4.
|
||||
*
|
||||
* If index is greater than the length of the list, no action is
|
||||
* performed and false is returned.
|
||||
*/
|
||||
PMIX_DECLSPEC bool pmix_list_insert(pmix_list_t *list, pmix_list_item_t *item,
|
||||
long long idx);
|
||||
|
||||
|
||||
/**
|
||||
* Join a list into another list
|
||||
*
|
||||
* @param thislist List container for list being operated on
|
||||
* @param pos List item in \c thislist marking the position before
|
||||
* which items are inserted
|
||||
* @param xlist List container for list being spliced from
|
||||
*
|
||||
* Join a list into another list. All of the elements of \c xlist
|
||||
* are inserted before \c pos and removed from \c xlist.
|
||||
*
|
||||
* This operation is an O(1) operation. Both \c thislist and \c
|
||||
* xlist must be valid list containsers. \c xlist will be empty
|
||||
* but valid after the call. All pointers to \c pmix_list_item_t
|
||||
* containers remain valid, including those that point to elements
|
||||
* in \c xlist.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_list_join(pmix_list_t *thislist, pmix_list_item_t *pos,
|
||||
pmix_list_t *xlist);
|
||||
|
||||
|
||||
/**
|
||||
* Splice a list into another list
|
||||
*
|
||||
* @param thislist List container for list being operated on
|
||||
* @param pos List item in \c thislist marking the position before
|
||||
* which items are inserted
|
||||
* @param xlist List container for list being spliced from
|
||||
* @param first List item in \c xlist marking the start of elements
|
||||
* to be copied into \c thislist
|
||||
* @param last List item in \c xlist marking the end of elements
|
||||
* to be copied into \c thislist
|
||||
*
|
||||
* Splice a subset of a list into another list. The \c [first,
|
||||
* last) elements of \c xlist are moved into \c thislist,
|
||||
* inserting them before \c pos. \c pos must be a valid iterator
|
||||
* in \c thislist and \c [first, last) must be a valid range in \c
|
||||
* xlist. \c postition must not be in the range \c [first, last).
|
||||
* It is, however, valid for \c xlist and \c thislist to be the
|
||||
* same list.
|
||||
*
|
||||
* This is an O(N) operation because the length of both lists must
|
||||
* be recomputed.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_list_splice(pmix_list_t *thislist, pmix_list_item_t *pos,
|
||||
pmix_list_t *xlist, pmix_list_item_t *first,
|
||||
pmix_list_item_t *last);
|
||||
|
||||
/**
|
||||
* Comparison function for pmix_list_sort(), below.
|
||||
*
|
||||
* @param a Pointer to a pointer to an pmix_list_item_t.
|
||||
* Explanation below.
|
||||
* @param b Pointer to a pointer to an pmix_list_item_t.
|
||||
* Explanation below.
|
||||
* @retval 1 if \em a is greater than \em b
|
||||
* @retval 0 if \em a is equal to \em b
|
||||
* @retval 11 if \em a is less than \em b
|
||||
*
|
||||
* This function is invoked by qsort(3) from within
|
||||
* pmix_list_sort(). It is important to understand what
|
||||
* pmix_list_sort() does before invoking qsort, so go read that
|
||||
* documentation first.
|
||||
*
|
||||
* The important thing to realize here is that a and b will be \em
|
||||
* double pointers to the items that you need to compare. Here's
|
||||
* a sample compare function to illustrate this point:
|
||||
*/
|
||||
typedef int (*pmix_list_item_compare_fn_t)(pmix_list_item_t **a,
|
||||
pmix_list_item_t **b);
|
||||
|
||||
/**
|
||||
* Sort a list with a provided compare function.
|
||||
*
|
||||
* @param list The list to sort
|
||||
* @param compare Compare function
|
||||
*
|
||||
* Put crassly, this function's complexity is O(N) + O(log(N)).
|
||||
* Its algorithm is:
|
||||
*
|
||||
* - remove every item from the list and put the corresponding
|
||||
* (pmix_list_item_t*)'s in an array
|
||||
* - call qsort(3) with that array and your compare function
|
||||
* - re-add every element of the now-sorted array to the list
|
||||
*
|
||||
* The resulting list is now ordered. Note, however, that since
|
||||
* an array of pointers is sorted, the comparison function must do
|
||||
* a double de-reference to get to the actual pmix_list_item_t (or
|
||||
* whatever the underlying type is). See the documentation of
|
||||
* pmix_list_item_compare_fn_t for an example).
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_list_sort(pmix_list_t* list, pmix_list_item_compare_fn_t compare);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_LIST_H */
|
@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2007 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Implementation of pmix_object_t, the base pmix foundation class
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
/* Symbol transforms */
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
|
||||
/*
|
||||
* Instantiation of class descriptor for the base class. This is
|
||||
* special, since be mark it as already initialized, with no parent
|
||||
* and no constructor or destructor.
|
||||
*/
|
||||
pmix_class_t pmix_object_t_class = {
|
||||
"pmix_object_t", /* name */
|
||||
NULL, /* parent class */
|
||||
NULL, /* constructor */
|
||||
NULL, /* destructor */
|
||||
1, /* initialized -- this class is preinitialized */
|
||||
0, /* class hierarchy depth */
|
||||
NULL, /* array of constructors */
|
||||
NULL, /* array of destructors */
|
||||
sizeof(pmix_object_t) /* size of the pmix object */
|
||||
};
|
||||
|
||||
/*
|
||||
* Local variables
|
||||
*/
|
||||
static void** classes = NULL;
|
||||
static int num_classes = 0;
|
||||
static int max_classes = 0;
|
||||
static const int increment = 10;
|
||||
|
||||
|
||||
/*
|
||||
* Local functions
|
||||
*/
|
||||
static void save_class(pmix_class_t *cls);
|
||||
static void expand_array(void);
|
||||
|
||||
|
||||
/*
|
||||
* Lazy initialization of class descriptor.
|
||||
*/
|
||||
void pmix_class_initialize(pmix_class_t *cls)
|
||||
{
|
||||
pmix_class_t *c;
|
||||
pmix_construct_t* cls_construct_array;
|
||||
pmix_destruct_t* cls_destruct_array;
|
||||
int cls_construct_array_count;
|
||||
int cls_destruct_array_count;
|
||||
int i;
|
||||
|
||||
assert(cls);
|
||||
|
||||
/* Check to see if anyone initialized
|
||||
this class before we got a chance to */
|
||||
|
||||
if (1 == cls->cls_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* First calculate depth of class hierarchy
|
||||
* And the number of constructors and destructors
|
||||
*/
|
||||
|
||||
cls->cls_depth = 0;
|
||||
cls_construct_array_count = 0;
|
||||
cls_destruct_array_count = 0;
|
||||
for (c = cls; c; c = c->cls_parent) {
|
||||
if( NULL != c->cls_construct ) {
|
||||
cls_construct_array_count++;
|
||||
}
|
||||
if( NULL != c->cls_destruct ) {
|
||||
cls_destruct_array_count++;
|
||||
}
|
||||
cls->cls_depth++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate arrays for hierarchy of constructors and destructors
|
||||
* plus for each a NULL-sentinel
|
||||
*/
|
||||
|
||||
cls->cls_construct_array =
|
||||
(void (**)(pmix_object_t*))malloc((cls_construct_array_count +
|
||||
cls_destruct_array_count + 2) *
|
||||
sizeof(pmix_construct_t) );
|
||||
if (NULL == cls->cls_construct_array) {
|
||||
perror("Out of memory");
|
||||
exit(-1);
|
||||
}
|
||||
cls->cls_destruct_array =
|
||||
cls->cls_construct_array + cls_construct_array_count + 1;
|
||||
|
||||
/*
|
||||
* The constructor array is reversed, so start at the end
|
||||
*/
|
||||
|
||||
cls_construct_array = cls->cls_construct_array + cls_construct_array_count;
|
||||
cls_destruct_array = cls->cls_destruct_array;
|
||||
|
||||
c = cls;
|
||||
*cls_construct_array = NULL; /* end marker for the constructors */
|
||||
for (i = 0; i < cls->cls_depth; i++) {
|
||||
if( NULL != c->cls_construct ) {
|
||||
--cls_construct_array;
|
||||
*cls_construct_array = c->cls_construct;
|
||||
}
|
||||
if( NULL != c->cls_destruct ) {
|
||||
*cls_destruct_array = c->cls_destruct;
|
||||
cls_destruct_array++;
|
||||
}
|
||||
c = c->cls_parent;
|
||||
}
|
||||
*cls_destruct_array = NULL; /* end marker for the destructors */
|
||||
|
||||
cls->cls_initialized = 1;
|
||||
save_class(cls);
|
||||
|
||||
/* All done */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Note that this is finalize for *all* classes.
|
||||
*/
|
||||
int pmix_class_finalize(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (NULL != classes) {
|
||||
for (i = 0; i < num_classes; ++i) {
|
||||
if (NULL != classes[i]) {
|
||||
free(classes[i]);
|
||||
}
|
||||
}
|
||||
free(classes);
|
||||
classes = NULL;
|
||||
num_classes = 0;
|
||||
max_classes = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void save_class(pmix_class_t *cls)
|
||||
{
|
||||
if (num_classes >= max_classes) {
|
||||
expand_array();
|
||||
}
|
||||
|
||||
classes[num_classes] = cls->cls_construct_array;
|
||||
++num_classes;
|
||||
}
|
||||
|
||||
|
||||
static void expand_array(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
max_classes += increment;
|
||||
classes = (void**)realloc(classes, sizeof(void *) * max_classes);
|
||||
if (NULL == classes) {
|
||||
perror("class malloc failed");
|
||||
exit(-1);
|
||||
}
|
||||
for (i = num_classes; i < max_classes; ++i) {
|
||||
classes[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -1,502 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2007 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file:
|
||||
*
|
||||
* A simple C-language object-oriented system with single inheritance
|
||||
* and ownership-based memory management using a retain/release model.
|
||||
*
|
||||
* A class consists of a struct and singly-instantiated class
|
||||
* descriptor. The first element of the struct must be the parent
|
||||
* class's struct. The class descriptor must be given a well-known
|
||||
* name based upon the class struct name (if the struct is sally_t,
|
||||
* the class descriptor should be sally_t_class) and must be
|
||||
* statically initialized as discussed below.
|
||||
*
|
||||
* (a) To define a class
|
||||
*
|
||||
* In a interface (.h) file, define the class. The first element
|
||||
* should always be the parent class, for example
|
||||
* @code
|
||||
* struct sally_t
|
||||
* {
|
||||
* parent_t parent;
|
||||
* void *first_member;
|
||||
* ...
|
||||
* };
|
||||
* typedef struct sally_t sally_t;
|
||||
*
|
||||
* PMIX_CLASS_DECLARATION(sally_t);
|
||||
* @endcode
|
||||
* All classes must have a parent which is also class.
|
||||
*
|
||||
* In an implementation (.c) file, instantiate a class descriptor for
|
||||
* the class like this:
|
||||
* @code
|
||||
* PMIX_CLASS_INSTANCE(sally_t, parent_t, sally_construct, sally_destruct);
|
||||
* @endcode
|
||||
* This macro actually expands to
|
||||
* @code
|
||||
* pmix_class_t sally_t_class = {
|
||||
* "sally_t",
|
||||
* PMIX_CLASS(parent_t), // pointer to parent_t_class
|
||||
* sally_construct,
|
||||
* sally_destruct,
|
||||
* 0, 0, NULL, NULL,
|
||||
* sizeof ("sally_t")
|
||||
* };
|
||||
* @endcode
|
||||
* This variable should be declared in the interface (.h) file using
|
||||
* the PMIX_CLASS_DECLARATION macro as shown above.
|
||||
*
|
||||
* sally_construct, and sally_destruct are function pointers to the
|
||||
* constructor and destructor for the class and are best defined as
|
||||
* static functions in the implementation file. NULL pointers maybe
|
||||
* supplied instead.
|
||||
*
|
||||
* Other class methods may be added to the struct.
|
||||
*
|
||||
* (b) Class instantiation: dynamic
|
||||
*
|
||||
* To create a instance of a class (an object) use PMIX_NEW:
|
||||
* @code
|
||||
* sally_t *sally = PMIX_NEW(sally_t);
|
||||
* @endcode
|
||||
* which allocates memory of sizeof(sally_t) and runs the class's
|
||||
* constructors.
|
||||
*
|
||||
* Use PMIX_RETAIN, PMIX_RELEASE to do reference-count-based
|
||||
* memory management:
|
||||
* @code
|
||||
* PMIX_RETAIN(sally);
|
||||
* PMIX_RELEASE(sally);
|
||||
* PMIX_RELEASE(sally);
|
||||
* @endcode
|
||||
* When the reference count reaches zero, the class's destructor, and
|
||||
* those of its parents, are run and the memory is freed.
|
||||
*
|
||||
* N.B. There is no explicit free/delete method for dynamic objects in
|
||||
* this model.
|
||||
*
|
||||
* (c) Class instantiation: static
|
||||
*
|
||||
* For an object with static (or stack) allocation, it is only
|
||||
* necessary to initialize the memory, which is done using
|
||||
* PMIX_CONSTRUCT:
|
||||
* @code
|
||||
* sally_t sally;
|
||||
*
|
||||
* PMIX_CONSTRUCT(&sally, sally_t);
|
||||
* @endcode
|
||||
* The retain/release model is not necessary here, but before the
|
||||
* object goes out of scope, PMIX_DESTRUCT should be run to release
|
||||
* initialized resources:
|
||||
* @code
|
||||
* PMIX_DESTRUCT(&sally);
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifndef PMIX_OBJECT_H
|
||||
#define PMIX_OBJECT_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif /* HAVE_STDLIB_H */
|
||||
|
||||
#include "include/pmix/rename.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/* Any kind of unique ID should do the job */
|
||||
#define PMIX_PMIX_MAGIC_ID ((0xdeafbeedULL << 32) + 0xdeafbeedULL)
|
||||
#endif
|
||||
|
||||
/* typedefs ***********************************************************/
|
||||
|
||||
typedef struct pmix_object_t pmix_object_t;
|
||||
typedef struct pmix_class_t pmix_class_t;
|
||||
typedef void (*pmix_construct_t) (pmix_object_t *);
|
||||
typedef void (*pmix_destruct_t) (pmix_object_t *);
|
||||
|
||||
|
||||
/* types **************************************************************/
|
||||
|
||||
/**
|
||||
* Class descriptor.
|
||||
*
|
||||
* There should be a single instance of this descriptor for each class
|
||||
* definition.
|
||||
*/
|
||||
struct pmix_class_t {
|
||||
const char *cls_name; /**< symbolic name for class */
|
||||
pmix_class_t *cls_parent; /**< parent class descriptor */
|
||||
pmix_construct_t cls_construct; /**< class constructor */
|
||||
pmix_destruct_t cls_destruct; /**< class destructor */
|
||||
int cls_initialized; /**< is class initialized */
|
||||
int cls_depth; /**< depth of class hierarchy tree */
|
||||
pmix_construct_t *cls_construct_array;
|
||||
/**< array of parent class constructors */
|
||||
pmix_destruct_t *cls_destruct_array;
|
||||
/**< array of parent class destructors */
|
||||
size_t cls_sizeof; /**< size of an object instance */
|
||||
};
|
||||
|
||||
/**
|
||||
* For static initializations of OBJects.
|
||||
*
|
||||
* @param NAME Name of the class to initialize
|
||||
*/
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
#define PMIX_PMIX_STATIC_INIT(BASE_CLASS) { PMIX_PMIX_MAGIC_ID, PMIX_CLASS(BASE_CLASS), 1, __FILE__, __LINE__ }
|
||||
#else
|
||||
#define PMIX_PMIX_STATIC_INIT(BASE_CLASS) { PMIX_CLASS(BASE_CLASS), 1 }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Base object.
|
||||
*
|
||||
* This is special and does not follow the pattern for other classes.
|
||||
*/
|
||||
struct pmix_object_t {
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/** Magic ID -- want this to be the very first item in the
|
||||
struct's memory */
|
||||
uint64_t obj_magic_id;
|
||||
#endif
|
||||
pmix_class_t *obj_class; /**< class descriptor */
|
||||
volatile int32_t obj_reference_count; /**< reference count */
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
const char* cls_init_file_name; /**< In debug mode store the file where the object get contructed */
|
||||
int cls_init_lineno; /**< In debug mode store the line number where the object get contructed */
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
};
|
||||
|
||||
/* macros ************************************************************/
|
||||
|
||||
/**
|
||||
* Return a pointer to the class descriptor associated with a
|
||||
* class type.
|
||||
*
|
||||
* @param NAME Name of class
|
||||
* @return Pointer to class descriptor
|
||||
*/
|
||||
#define PMIX_CLASS(NAME) (&(NAME ## _class))
|
||||
|
||||
|
||||
/**
|
||||
* Static initializer for a class descriptor
|
||||
*
|
||||
* @param NAME Name of class
|
||||
* @param PARENT Name of parent class
|
||||
* @param CONSTRUCTOR Pointer to constructor
|
||||
* @param DESTRUCTOR Pointer to destructor
|
||||
*
|
||||
* Put this in NAME.c
|
||||
*/
|
||||
#define PMIX_CLASS_INSTANCE(NAME, PARENT, CONSTRUCTOR, DESTRUCTOR) \
|
||||
pmix_class_t NAME ## _class = { \
|
||||
# NAME, \
|
||||
PMIX_CLASS(PARENT), \
|
||||
(pmix_construct_t) CONSTRUCTOR, \
|
||||
(pmix_destruct_t) DESTRUCTOR, \
|
||||
0, 0, NULL, NULL, \
|
||||
sizeof(NAME) \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Declaration for class descriptor
|
||||
*
|
||||
* @param NAME Name of class
|
||||
*
|
||||
* Put this in NAME.h
|
||||
*/
|
||||
#define PMIX_CLASS_DECLARATION(NAME) \
|
||||
extern pmix_class_t NAME ## _class
|
||||
|
||||
|
||||
/**
|
||||
* Create an object: dynamically allocate storage and run the class
|
||||
* constructor.
|
||||
*
|
||||
* @param type Type (class) of the object
|
||||
* @return Pointer to the object
|
||||
*/
|
||||
static inline pmix_object_t *pmix_obj_new(pmix_class_t * cls);
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
static inline pmix_object_t *pmix_obj_new_debug(pmix_class_t* type, const char* file, int line)
|
||||
{
|
||||
pmix_object_t* object = pmix_obj_new(type);
|
||||
object->obj_magic_id = PMIX_PMIX_MAGIC_ID;
|
||||
object->cls_init_file_name = file;
|
||||
object->cls_init_lineno = line;
|
||||
return object;
|
||||
}
|
||||
#define PMIX_NEW(type) \
|
||||
((type *)pmix_obj_new_debug(PMIX_CLASS(type), __FILE__, __LINE__))
|
||||
#else
|
||||
#define PMIX_NEW(type) \
|
||||
((type *) pmix_obj_new(PMIX_CLASS(type)))
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
|
||||
/**
|
||||
* Retain an object (by incrementing its reference count)
|
||||
*
|
||||
* @param object Pointer to the object
|
||||
*/
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
#define PMIX_RETAIN(object) \
|
||||
do { \
|
||||
assert(NULL != ((pmix_object_t *) (object))->obj_class); \
|
||||
assert(PMIX_PMIX_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
|
||||
pmix_obj_update((pmix_object_t *) (object), 1); \
|
||||
assert(((pmix_object_t *) (object))->obj_reference_count >= 0); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PMIX_RETAIN(object) pmix_obj_update((pmix_object_t *) (object), 1);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Helper macro for the debug mode to store the locations where the status of
|
||||
* an object change.
|
||||
*/
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
#define PMIX_REMEMBER_FILE_AND_LINENO( OBJECT, FILE, LINENO ) \
|
||||
do { \
|
||||
((pmix_object_t*)(OBJECT))->cls_init_file_name = FILE; \
|
||||
((pmix_object_t*)(OBJECT))->cls_init_lineno = LINENO; \
|
||||
} while(0)
|
||||
#define PMIX_SET_MAGIC_ID( OBJECT, VALUE ) \
|
||||
do { \
|
||||
((pmix_object_t*)(OBJECT))->obj_magic_id = (VALUE); \
|
||||
} while(0)
|
||||
#else
|
||||
#define PMIX_REMEMBER_FILE_AND_LINENO( OBJECT, FILE, LINENO )
|
||||
#define PMIX_SET_MAGIC_ID( OBJECT, VALUE )
|
||||
#endif /* PMIX_ENABLE_DEBUG */
|
||||
|
||||
/**
|
||||
* Release an object (by decrementing its reference count). If the
|
||||
* reference count reaches zero, destruct (finalize) the object and
|
||||
* free its storage.
|
||||
*
|
||||
* Note: If the object is freed, then the value of the pointer is set
|
||||
* to NULL.
|
||||
*
|
||||
* @param object Pointer to the object
|
||||
*/
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
#define PMIX_RELEASE(object) \
|
||||
do { \
|
||||
assert(NULL != ((pmix_object_t *) (object))->obj_class); \
|
||||
assert(PMIX_PMIX_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
|
||||
if (0 == pmix_obj_update((pmix_object_t *) (object), -1)) { \
|
||||
PMIX_SET_MAGIC_ID((object), 0); \
|
||||
pmix_obj_run_destructors((pmix_object_t *) (object)); \
|
||||
PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
|
||||
free(object); \
|
||||
object = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#else
|
||||
#define PMIX_RELEASE(object) \
|
||||
do { \
|
||||
if (0 == pmix_obj_update((pmix_object_t *) (object), -1)) { \
|
||||
pmix_obj_run_destructors((pmix_object_t *) (object)); \
|
||||
free(object); \
|
||||
object = NULL; \
|
||||
} \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Construct (initialize) objects that are not dynamically allocated.
|
||||
*
|
||||
* @param object Pointer to the object
|
||||
* @param type The object type
|
||||
*/
|
||||
|
||||
#define PMIX_CONSTRUCT(object, type) \
|
||||
do { \
|
||||
PMIX_CONSTRUCT_INTERNAL((object), PMIX_CLASS(type)); \
|
||||
} while (0)
|
||||
|
||||
#define PMIX_CONSTRUCT_INTERNAL(object, type) \
|
||||
do { \
|
||||
PMIX_SET_MAGIC_ID((object), PMIX_PMIX_MAGIC_ID); \
|
||||
if (0 == (type)->cls_initialized) { \
|
||||
pmix_class_initialize((type)); \
|
||||
} \
|
||||
((pmix_object_t *) (object))->obj_class = (type); \
|
||||
((pmix_object_t *) (object))->obj_reference_count = 1; \
|
||||
pmix_obj_run_constructors((pmix_object_t *) (object)); \
|
||||
PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* Destruct (finalize) an object that is not dynamically allocated.
|
||||
*
|
||||
* @param object Pointer to the object
|
||||
*/
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
#define PMIX_DESTRUCT(object) \
|
||||
do { \
|
||||
assert(PMIX_PMIX_MAGIC_ID == ((pmix_object_t *) (object))->obj_magic_id); \
|
||||
PMIX_SET_MAGIC_ID((object), 0); \
|
||||
pmix_obj_run_destructors((pmix_object_t *) (object)); \
|
||||
PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PMIX_DESTRUCT(object) \
|
||||
do { \
|
||||
pmix_obj_run_destructors((pmix_object_t *) (object)); \
|
||||
PMIX_REMEMBER_FILE_AND_LINENO( object, __FILE__, __LINE__ ); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_object_t);
|
||||
|
||||
/* declarations *******************************************************/
|
||||
|
||||
/**
|
||||
* Lazy initialization of class descriptor.
|
||||
*
|
||||
* Specifically cache arrays of function pointers for the constructor
|
||||
* and destructor hierarchies for this class.
|
||||
*
|
||||
* @param class Pointer to class descriptor
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_class_initialize(pmix_class_t *);
|
||||
|
||||
/**
|
||||
* Shut down the class system and release all memory
|
||||
*
|
||||
* This function should be invoked as the ABSOLUTE LAST function to
|
||||
* use the class subsystem. It frees all associated memory with ALL
|
||||
* classes, rendering all of them inoperable. It is here so that
|
||||
* tools like valgrind and purify don't report still-reachable memory
|
||||
* upon process termination.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_class_finalize(void);
|
||||
|
||||
/**
|
||||
* Run the hierarchy of class constructors for this object, in a
|
||||
* parent-first order.
|
||||
*
|
||||
* Do not use this function directly: use PMIX_CONSTRUCT() instead.
|
||||
*
|
||||
* WARNING: This implementation relies on a hardwired maximum depth of
|
||||
* the inheritance tree!!!
|
||||
*
|
||||
* Hardwired for fairly shallow inheritance trees
|
||||
* @param size Pointer to the object.
|
||||
*/
|
||||
static inline void pmix_obj_run_constructors(pmix_object_t * object)
|
||||
{
|
||||
pmix_construct_t* cls_construct;
|
||||
|
||||
assert(NULL != object->obj_class);
|
||||
|
||||
cls_construct = object->obj_class->cls_construct_array;
|
||||
while( NULL != *cls_construct ) {
|
||||
(*cls_construct)(object);
|
||||
cls_construct++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Run the hierarchy of class destructors for this object, in a
|
||||
* parent-last order.
|
||||
*
|
||||
* Do not use this function directly: use PMIX_DESTRUCT() instead.
|
||||
*
|
||||
* @param size Pointer to the object.
|
||||
*/
|
||||
static inline void pmix_obj_run_destructors(pmix_object_t * object)
|
||||
{
|
||||
pmix_destruct_t* cls_destruct;
|
||||
|
||||
assert(NULL != object->obj_class);
|
||||
|
||||
cls_destruct = object->obj_class->cls_destruct_array;
|
||||
while( NULL != *cls_destruct ) {
|
||||
(*cls_destruct)(object);
|
||||
cls_destruct++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create new object: dynamically allocate storage and run the class
|
||||
* constructor.
|
||||
*
|
||||
* Do not use this function directly: use PMIX_NEW() instead.
|
||||
*
|
||||
* @param size Size of the object
|
||||
* @param cls Pointer to the class descriptor of this object
|
||||
* @return Pointer to the object
|
||||
*/
|
||||
static inline pmix_object_t *pmix_obj_new(pmix_class_t * cls)
|
||||
{
|
||||
pmix_object_t *object;
|
||||
assert(cls->cls_sizeof >= sizeof(pmix_object_t));
|
||||
|
||||
object = (pmix_object_t *) malloc(cls->cls_sizeof);
|
||||
if (0 == cls->cls_initialized) {
|
||||
pmix_class_initialize(cls);
|
||||
}
|
||||
if (NULL != object) {
|
||||
object->obj_class = cls;
|
||||
object->obj_reference_count = 1;
|
||||
pmix_obj_run_constructors(object);
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Atomically update the object's reference count by some increment.
|
||||
*
|
||||
* This function should not be used directly: it is called via the
|
||||
* macros PMIX_RETAIN and PMIX_RELEASE
|
||||
*
|
||||
* @param object Pointer to the object
|
||||
* @param inc Increment by which to update reference count
|
||||
* @return New value of the reference count
|
||||
*/
|
||||
static inline int pmix_obj_update(pmix_object_t *object, int inc) __pmix_attribute_always_inline__;
|
||||
static inline int pmix_obj_update(pmix_object_t *object, int inc)
|
||||
{
|
||||
return object->obj_reference_count += inc;
|
||||
}
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -1,331 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2007 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#if HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
#include <limits.h>
|
||||
|
||||
#include "src/class/pmix_pointer_array.h"
|
||||
#include "src/util/output.h"
|
||||
#include <pmix.h>
|
||||
|
||||
enum { TABLE_INIT = 1, TABLE_GROW = 2 };
|
||||
|
||||
static void pmix_pointer_array_construct(pmix_pointer_array_t *);
|
||||
static void pmix_pointer_array_destruct(pmix_pointer_array_t *);
|
||||
static bool grow_table(pmix_pointer_array_t *table, int soft, int hard);
|
||||
|
||||
PMIX_CLASS_INSTANCE(pmix_pointer_array_t, pmix_object_t,
|
||||
pmix_pointer_array_construct,
|
||||
pmix_pointer_array_destruct);
|
||||
|
||||
/*
|
||||
* pmix_pointer_array constructor
|
||||
*/
|
||||
static void pmix_pointer_array_construct(pmix_pointer_array_t *array)
|
||||
{
|
||||
array->lowest_free = 0;
|
||||
array->number_free = 0;
|
||||
array->size = 0;
|
||||
array->max_size = INT_MAX;
|
||||
array->block_size = 0;
|
||||
array->addr = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* pmix_pointer_array destructor
|
||||
*/
|
||||
static void pmix_pointer_array_destruct(pmix_pointer_array_t *array)
|
||||
{
|
||||
/* free table */
|
||||
if( NULL != array->addr) {
|
||||
free(array->addr);
|
||||
array->addr = NULL;
|
||||
}
|
||||
|
||||
array->size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize an array object
|
||||
*/
|
||||
pmix_status_t pmix_pointer_array_init(pmix_pointer_array_t* array,
|
||||
int initial_allocation,
|
||||
int max_size, int block_size)
|
||||
{
|
||||
size_t num_bytes;
|
||||
|
||||
/* check for errors */
|
||||
if (NULL == array || max_size < block_size) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
array->max_size = max_size;
|
||||
array->block_size = block_size;
|
||||
|
||||
num_bytes = (0 < initial_allocation ? initial_allocation : block_size);
|
||||
array->number_free = num_bytes;
|
||||
array->size = num_bytes;
|
||||
num_bytes *= sizeof(void*);
|
||||
|
||||
/* Allocate and set the array to NULL */
|
||||
array->addr = (void **)calloc(num_bytes, 1);
|
||||
if (NULL == array->addr) { /* out of memory */
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* add a pointer to dynamic pointer table
|
||||
*
|
||||
* @param table Pointer to pmix_pointer_array_t object (IN)
|
||||
* @param ptr Pointer to be added to table (IN)
|
||||
*
|
||||
* @return Array index where ptr is inserted or PMIX_ERROR if it fails
|
||||
*/
|
||||
int pmix_pointer_array_add(pmix_pointer_array_t *table, void *ptr)
|
||||
{
|
||||
int i, index;
|
||||
|
||||
if (table->number_free == 0) {
|
||||
/* need to grow table */
|
||||
if (!grow_table(table,
|
||||
(NULL == table->addr ? TABLE_INIT : table->size * TABLE_GROW),
|
||||
INT_MAX)) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
assert( (table->addr != NULL) && (table->size > 0) );
|
||||
assert( (table->lowest_free >= 0) && (table->lowest_free < table->size) );
|
||||
assert( (table->number_free > 0) && (table->number_free <= table->size) );
|
||||
|
||||
/*
|
||||
* add pointer to table, and return the index
|
||||
*/
|
||||
|
||||
index = table->lowest_free;
|
||||
assert(table->addr[index] == NULL);
|
||||
table->addr[index] = ptr;
|
||||
table->number_free--;
|
||||
if (table->number_free > 0) {
|
||||
for (i = table->lowest_free + 1; i < table->size; i++) {
|
||||
if (table->addr[i] == NULL) {
|
||||
table->lowest_free = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
table->lowest_free = table->size;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of the dynamic array at a specified location.
|
||||
*
|
||||
*
|
||||
* @param table Pointer to pmix_pointer_array_t object (IN)
|
||||
* @param ptr Pointer to be added to table (IN)
|
||||
*
|
||||
* @return Error code
|
||||
*
|
||||
* Assumption: NULL element is free element.
|
||||
*/
|
||||
pmix_status_t pmix_pointer_array_set_item(pmix_pointer_array_t *table, int index,
|
||||
void * value)
|
||||
{
|
||||
assert(table != NULL);
|
||||
|
||||
/* expand table if required to set a specific index */
|
||||
|
||||
if (table->size <= index) {
|
||||
if (!grow_table(table, ((index / TABLE_GROW) + 1) * TABLE_GROW,
|
||||
index)) {
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* mark element as free, if NULL element */
|
||||
if( NULL == value ) {
|
||||
if (index < table->lowest_free) {
|
||||
table->lowest_free = index;
|
||||
}
|
||||
if( NULL != table->addr[index] ) {
|
||||
table->number_free++;
|
||||
}
|
||||
} else {
|
||||
if (NULL == table->addr[index]) {
|
||||
table->number_free--;
|
||||
}
|
||||
/* Reset lowest_free if required */
|
||||
if ( index == table->lowest_free ) {
|
||||
int i;
|
||||
|
||||
table->lowest_free = table->size;
|
||||
for ( i=index + 1; i<table->size; i++) {
|
||||
if ( NULL == table->addr[i] ){
|
||||
table->lowest_free = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
table->addr[index] = value;
|
||||
|
||||
#if 0
|
||||
pmix_output(0,"pmix_pointer_array_set_item: OUT: "
|
||||
" table %p (size %ld, lowest free %ld, number free %ld)"
|
||||
" addr[%d] = %p\n",
|
||||
table, table->size, table->lowest_free, table->number_free,
|
||||
index, table->addr[index]);
|
||||
#endif
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether a certain element is already in use. If not yet
|
||||
* in use, reserve it.
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
* @param index Index of element to be tested (IN)
|
||||
* @param value New value to be set at element index (IN)
|
||||
*
|
||||
* @return true/false True if element could be reserved
|
||||
* False if element could not be reserved (e.g.in use).
|
||||
*
|
||||
* In contrary to array_set, this function does not allow to overwrite
|
||||
* a value, unless the previous value is NULL ( equiv. to free ).
|
||||
*/
|
||||
bool pmix_pointer_array_test_and_set_item (pmix_pointer_array_t *table,
|
||||
int index, void *value)
|
||||
{
|
||||
assert(table != NULL);
|
||||
assert(index >= 0);
|
||||
|
||||
#if 0
|
||||
pmix_output(0,"pmix_pointer_array_test_and_set_item: IN: "
|
||||
" table %p (size %ld, lowest free %ld, number free %ld)"
|
||||
" addr[%d] = %p\n",
|
||||
table, table->size, table->lowest_free, table->number_free,
|
||||
index, table->addr[index]);
|
||||
#endif
|
||||
|
||||
/* expand table if required to set a specific index */
|
||||
if ( index < table->size && table->addr[index] != NULL ) {
|
||||
/* This element is already in use */
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Do we need to grow the table? */
|
||||
|
||||
if (table->size <= index) {
|
||||
if (!grow_table(table, (((index / TABLE_GROW) + 1) * TABLE_GROW),
|
||||
index)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* allow a specific index to be changed.
|
||||
*/
|
||||
table->addr[index] = value;
|
||||
table->number_free--;
|
||||
/* Reset lowest_free if required */
|
||||
if ( index == table->lowest_free ) {
|
||||
int i;
|
||||
|
||||
table->lowest_free = table->size;
|
||||
for ( i=index; i<table->size; i++) {
|
||||
if ( NULL == table->addr[i] ){
|
||||
table->lowest_free = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
pmix_output(0,"pmix_pointer_array_test_and_set_item: OUT: "
|
||||
" table %p (size %ld, lowest free %ld, number free %ld)"
|
||||
" addr[%d] = %p\n",
|
||||
table, table->size, table->lowest_free, table->number_free,
|
||||
index, table->addr[index]);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
pmix_status_t pmix_pointer_array_set_size(pmix_pointer_array_t *array, int new_size)
|
||||
{
|
||||
if(new_size > array->size) {
|
||||
if (!grow_table(array, new_size, new_size)) {
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static bool grow_table(pmix_pointer_array_t *table, int soft, int hard)
|
||||
{
|
||||
int new_size;
|
||||
int i, new_size_int;
|
||||
void *p;
|
||||
|
||||
/* new_size = ((table->size + num_needed + table->block_size - 1) /
|
||||
table->block_size) * table->block_size; */
|
||||
new_size = soft;
|
||||
if( soft > table->max_size ) {
|
||||
if( hard > table->max_size ) {
|
||||
return false;
|
||||
}
|
||||
new_size = hard;
|
||||
}
|
||||
if( new_size >= table->max_size ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
p = (void **) realloc(table->addr, new_size * sizeof(void *));
|
||||
if (p == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
new_size_int = (int) new_size;
|
||||
table->number_free += new_size_int - table->size;
|
||||
table->addr = (void**)p;
|
||||
for (i = table->size; i < new_size_int; ++i) {
|
||||
table->addr[i] = NULL;
|
||||
}
|
||||
table->size = new_size_int;
|
||||
|
||||
return true;
|
||||
}
|
@ -1,201 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; -*- */
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2008 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_POINTER_ARRAY_H
|
||||
#define PMIX_POINTER_ARRAY_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
|
||||
#if HAVE_STDBOOL_H
|
||||
#include <stdbool.h>
|
||||
#endif
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**
|
||||
* dynamic pointer array
|
||||
*/
|
||||
struct pmix_pointer_array_t {
|
||||
/** base class */
|
||||
pmix_object_t super;
|
||||
/** Index of lowest free element. NOTE: This is only an
|
||||
optimization to know where to search for the first free slot.
|
||||
It does \em not necessarily imply indices all above this index
|
||||
are not taken! */
|
||||
int lowest_free;
|
||||
/** number of free elements in the list */
|
||||
int number_free;
|
||||
/** size of list, i.e. number of elements in addr */
|
||||
int size;
|
||||
/** maximum size of the array */
|
||||
int max_size;
|
||||
/** block size for each allocation */
|
||||
int block_size;
|
||||
/** pointer to array of pointers */
|
||||
void **addr;
|
||||
};
|
||||
/**
|
||||
* Convenience typedef
|
||||
*/
|
||||
typedef struct pmix_pointer_array_t pmix_pointer_array_t;
|
||||
/**
|
||||
* Class declaration
|
||||
*/
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_pointer_array_t);
|
||||
|
||||
/**
|
||||
* Initialize the pointer array with an initial size of initial_allocation.
|
||||
* Set the maximum size of the array, as well as the size of the allocation
|
||||
* block for all subsequent growing operations. Remarque: The pointer array
|
||||
* has to be created bfore calling this function.
|
||||
*
|
||||
* @param array Pointer to pointer of an array (IN/OUT)
|
||||
* @param initial_allocation The number of elements in the initial array (IN)
|
||||
* @param max_size The maximum size of the array (IN)
|
||||
* @param block_size The size for all subsequent grows of the array (IN).
|
||||
*
|
||||
* @return PMIX_SUCCESS if all initializations were succesfull. Otherwise,
|
||||
* the error indicate what went wrong in the function.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_pointer_array_init(pmix_pointer_array_t* array,
|
||||
int initial_allocation,
|
||||
int max_size, int block_size );
|
||||
|
||||
/**
|
||||
* Add a pointer to the array (Grow the array, if need be)
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
* @param ptr Pointer value (IN)
|
||||
*
|
||||
* @return Index of inserted array element. Return value of
|
||||
* (-1) indicates an error.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_pointer_array_add(pmix_pointer_array_t *array, void *ptr);
|
||||
|
||||
/**
|
||||
* Set the value of an element in array
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
* @param index Index of element to be reset (IN)
|
||||
* @param value New value to be set at element index (IN)
|
||||
*
|
||||
* @return PMIX_SUCCESS if item was inserted. Otherwise,
|
||||
* the error indicate what went wrong in the function.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_pointer_array_set_item(pmix_pointer_array_t *array,
|
||||
int index, void *value);
|
||||
|
||||
/**
|
||||
* Get the value of an element in array
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
* @param element_index Index of element to be returned (IN)
|
||||
*
|
||||
* @return Error code. NULL indicates an error.
|
||||
*/
|
||||
|
||||
static inline void *pmix_pointer_array_get_item(pmix_pointer_array_t *table,
|
||||
int element_index)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if( table->size <= element_index ) {
|
||||
return NULL;
|
||||
}
|
||||
p = table->addr[element_index];
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the size of the pointer array
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
*
|
||||
* @returns size Size of the array
|
||||
*
|
||||
* Simple inline function to return the size of the array in order to
|
||||
* hide the member field from external users.
|
||||
*/
|
||||
static inline int pmix_pointer_array_get_size(pmix_pointer_array_t *array)
|
||||
{
|
||||
return array->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the size of the pointer array
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
*
|
||||
* @param size Desired size of the array
|
||||
*
|
||||
* @return PMIX_SUCCESS new size was set. Otherwise,
|
||||
* the error indicate what went wrong in the function.
|
||||
*
|
||||
* Simple function to set the size of the array in order to
|
||||
* hide the member field from external users.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_pointer_array_set_size(pmix_pointer_array_t *array, int size);
|
||||
|
||||
/**
|
||||
* Test whether a certain element is already in use. If not yet
|
||||
* in use, reserve it.
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
* @param index Index of element to be tested (IN)
|
||||
* @param value New value to be set at element index (IN)
|
||||
*
|
||||
* @return true/false True if element could be reserved
|
||||
* False if element could not be reserved (e.g., in use).
|
||||
*
|
||||
* In contrary to array_set, this function does not allow to overwrite
|
||||
* a value, unless the previous value is NULL ( equiv. to free ).
|
||||
*/
|
||||
PMIX_DECLSPEC bool pmix_pointer_array_test_and_set_item (pmix_pointer_array_t *table,
|
||||
int index,
|
||||
void *value);
|
||||
|
||||
/**
|
||||
* Empty the array.
|
||||
*
|
||||
* @param array Pointer to array (IN)
|
||||
*
|
||||
*/
|
||||
static inline void pmix_pointer_array_remove_all(pmix_pointer_array_t *array)
|
||||
{
|
||||
int i;
|
||||
if( array->number_free == array->size )
|
||||
return; /* nothing to do here this time (the array is already empty) */
|
||||
|
||||
array->lowest_free = 0;
|
||||
array->number_free = array->size;
|
||||
for(i=0; i<array->size; i++) {
|
||||
array->addr[i] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_POINTER_ARRAY_H */
|
@ -1,794 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include <pmix.h>
|
||||
#include <pmi.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#define ANL_MAPPING "PMI_process_mapping"
|
||||
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
|
||||
#define PMI_MAX_ID_LEN PMIX_MAX_NSLEN /* Maximim size of PMI process group ID */
|
||||
#define PMI_MAX_KEY_LEN PMIX_MAX_KEYLEN /* Maximum size of a PMI key */
|
||||
#define PMI_MAX_KVSNAME_LEN PMIX_MAX_NSLEN /* Maximum size of KVS name */
|
||||
#define PMI_MAX_VAL_LEN 4096 /* Maximum size of a PMI value */
|
||||
|
||||
#define PMI_CHECK() \
|
||||
do { \
|
||||
if (!pmi_init) { \
|
||||
return PMI_FAIL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* local functions */
|
||||
static pmix_status_t convert_int(int *value, pmix_value_t *kv);
|
||||
static int convert_err(pmix_status_t rc);
|
||||
static pmix_proc_t myproc;
|
||||
static bool data_commited = false;
|
||||
static int pmi_init = 0;
|
||||
|
||||
int PMI_Init(int *spawned)
|
||||
{
|
||||
pmix_value_t *val;
|
||||
pmix_status_t rc;
|
||||
|
||||
if (PMIX_SUCCESS != PMIx_Init(&myproc)) {
|
||||
return PMI_ERR_INIT;
|
||||
}
|
||||
|
||||
if (NULL != spawned) {
|
||||
/* get the spawned flag */
|
||||
if (PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_SPAWNED, NULL, 0, &val)) {
|
||||
rc = convert_int(spawned, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
return convert_err(rc);
|
||||
}
|
||||
} else {
|
||||
/* if not found, default to not spawned */
|
||||
*spawned = 0;
|
||||
}
|
||||
}
|
||||
pmi_init = 1;
|
||||
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_Initialized(PMI_BOOL *initialized)
|
||||
{
|
||||
if (NULL == initialized) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*initialized = (PMIx_Initialized() ? PMI_TRUE : PMI_FALSE);
|
||||
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_Finalize(void)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
pmi_init = 0;
|
||||
rc = PMIx_Finalize();
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI_Abort(int flag, const char msg[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
rc = PMIx_Abort(flag, msg, NULL, 0);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* KVS_Put - we default to PMIX_GLOBAL scope and ignore the
|
||||
* provided kvsname as we only put into our own nspace */
|
||||
int PMI_KVS_Put(const char kvsname[], const char key[], const char value[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t val;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if ((kvsname == NULL) || (strlen(kvsname) > PMI_MAX_KVSNAME_LEN)) {
|
||||
return PMI_ERR_INVALID_KVS;
|
||||
}
|
||||
if ((key == NULL) || (strlen(key) >PMI_MAX_KEY_LEN)) {
|
||||
return PMI_ERR_INVALID_KEY;
|
||||
}
|
||||
if ((value == NULL) || (strlen(value) > PMI_MAX_VAL_LEN)) {
|
||||
return PMI_ERR_INVALID_VAL;
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"PMI_KVS_Put: KVS=%s, key=%s value=%s", kvsname, key, value);
|
||||
|
||||
val.type = PMIX_STRING;
|
||||
val.data.string = (char*)value;
|
||||
rc = PMIx_Put(PMIX_GLOBAL, key, &val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* KVS_Commit */
|
||||
int PMI_KVS_Commit(const char kvsname[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if ((kvsname == NULL) || (strlen(kvsname) > PMI_MAX_KVSNAME_LEN)) {
|
||||
return PMI_ERR_INVALID_KVS;
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output, "PMI_KVS_Commit: KVS=%s",
|
||||
kvsname);
|
||||
|
||||
rc = PMIx_Commit();
|
||||
/* PMIx permits only one data commit! */
|
||||
data_commited = true;
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI_KVS_Get( const char kvsname[], const char key[], char value[], int length)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
uint32_t i;
|
||||
static pmix_proc_t proc;
|
||||
uint32_t procnum;
|
||||
proc = myproc;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if ((kvsname == NULL) || (strlen(kvsname) > PMI_MAX_KVSNAME_LEN)) {
|
||||
return PMI_ERR_INVALID_KVS;
|
||||
}
|
||||
if ((key == NULL) || (strlen(key) >PMI_MAX_KEY_LEN)) {
|
||||
return PMI_ERR_INVALID_KEY;
|
||||
}
|
||||
if (value == NULL) {
|
||||
return PMI_ERR_INVALID_VAL;
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"PMI_KVS_Get: KVS=%s, key=%s value=%s", kvsname, key, value);
|
||||
|
||||
/* PMI-1 expects resource manager to set
|
||||
* process mapping in ANL notation. */
|
||||
if (!strcmp(key, ANL_MAPPING)) {
|
||||
/* we are looking in the job-data. If there is nothing there
|
||||
* we don't want to look in rank's data, thus set rank to widcard */
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS == PMIx_Get(&proc, PMIX_ANL_MAP, NULL, 0, &val) &&
|
||||
(NULL != val) && (PMIX_STRING == val->type)) {
|
||||
strncpy(value, val->data.string, length);
|
||||
PMIX_VALUE_FREE(val, 1);
|
||||
return PMI_SUCCESS;
|
||||
} else {
|
||||
/* artpol:
|
||||
* Some RM's (i.e. SLURM) already have ANL precomputed. The export it
|
||||
* through PMIX_ANL_MAP variable.
|
||||
* If we haven't found it we want to have our own packing functionality
|
||||
* since it's common.
|
||||
* Somebody else has to write it since I've already done that for
|
||||
* GPL'ed SLURM :) */
|
||||
return PMI_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* We don't know what process keeps this data. So it looks like we need to
|
||||
* check each process.
|
||||
* TODO: Is there any beter way?
|
||||
* WARNING: this may lead to the VERY long HANG's if we ask for the unknown key
|
||||
* before we've done Commit on all nodes. We need a workaround for that.
|
||||
*
|
||||
* SOLUTION: perhaps rovide "OK if nothing" info flag to tell PMIx that
|
||||
* the key supposed to already be there and if nothing there - gave up with
|
||||
* an error and don't try to use direct modex.
|
||||
*/
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_JOB_SIZE, NULL, 0, &val))) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmi1: executing put for KVS %s, key %s value %s", kvsname, key,
|
||||
value);
|
||||
return convert_err(rc);
|
||||
}
|
||||
procnum = val->data.uint32;
|
||||
PMIX_VALUE_FREE(val, 1);
|
||||
|
||||
for (i = 0; i < procnum; i++) {
|
||||
proc.rank = i;
|
||||
if (PMIX_SUCCESS == PMIx_Get(&proc, key, NULL, 0, &val) && (NULL != val)
|
||||
&& (PMIX_STRING == val->type)) {
|
||||
strncpy(value, val->data.string, length);
|
||||
PMIX_VALUE_FREE(val, 1);
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
PMIX_VALUE_FREE(val, 1);
|
||||
}
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* Barrier only applies to our own nspace, and we want all
|
||||
* data to be collected upon completion */
|
||||
int PMI_Barrier(void)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_info_t buf;
|
||||
int ninfo = 0;
|
||||
pmix_info_t *info = NULL;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (data_commited) {
|
||||
bool val = 1;
|
||||
info = &buf;
|
||||
PMIX_INFO_CONSTRUCT(info);
|
||||
PMIX_INFO_LOAD(info, PMIX_COLLECT_DATA, &val, PMIX_BOOL);
|
||||
ninfo = 1;
|
||||
}
|
||||
rc = PMIx_Fence(NULL, 0, info, ninfo);
|
||||
|
||||
if (NULL != info) {
|
||||
PMIX_INFO_DESTRUCT(info);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int PMI_Get_size(int *size)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == size) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_JOB_SIZE, NULL, 0, &val)) {
|
||||
rc = convert_int(size, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
int PMI_Get_rank(int *rk)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == rk) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*rk = myproc.rank;
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_Get_universe_size(int *size)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == size) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val)) {
|
||||
rc = convert_int(size, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
int PMI_Get_appnum(int *appnum)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL != appnum &&
|
||||
PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_APPNUM, NULL, 0, &val)) {
|
||||
rc = convert_int(appnum, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
int PMI_Publish_name(const char service_name[], const char port[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_info_t info;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == service_name || NULL == port) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* pass the service/port */
|
||||
(void) strncpy(info.key, service_name, PMIX_MAX_KEYLEN);
|
||||
info.value.type = PMIX_STRING;
|
||||
info.value.data.string = (char*) port;
|
||||
|
||||
/* publish the info - PMI-1 doesn't support
|
||||
* any scope other than inside our own nspace */
|
||||
rc = PMIx_Publish(&info, 1);
|
||||
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI_Unpublish_name(const char service_name[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
char *keys[2];
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == service_name) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* pass the service */
|
||||
keys[0] = (char*) service_name;
|
||||
keys[1] = NULL;
|
||||
|
||||
rc = PMIx_Unpublish(keys, NULL, 0);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI_Lookup_name(const char service_name[], char port[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_pdata_t pdata;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == service_name || NULL == port) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PMIX_PDATA_CONSTRUCT(&pdata);
|
||||
|
||||
/* pass the service */
|
||||
(void) strncpy(pdata.key, service_name, PMIX_MAX_KEYLEN);
|
||||
|
||||
/* PMI-1 doesn't want the nspace back */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Lookup(&pdata, 1, NULL, 0))) {
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* should have received a string back */
|
||||
if (PMIX_STRING != pdata.value.type || NULL == pdata.value.data.string) {
|
||||
return convert_err(PMIX_ERR_NOT_FOUND);
|
||||
}
|
||||
|
||||
/* return the port - sadly, this API doesn't tell us
|
||||
* the size of the port array, and so there is a
|
||||
* potential we could overrun it. As this feature
|
||||
* isn't widely supported in PMI-1, try being
|
||||
* conservative */
|
||||
(void) strncpy(port, pdata.value.data.string, PMIX_MAX_KEYLEN);
|
||||
PMIX_PDATA_DESTRUCT(&pdata);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_Get_id(char id_str[], int length)
|
||||
{
|
||||
/* we already obtained our nspace during PMI_Init,
|
||||
* so all we have to do here is return it */
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
/* bozo check */
|
||||
if (NULL == id_str) {
|
||||
return PMI_ERR_INVALID_ARGS;
|
||||
}
|
||||
if (length < PMI_MAX_ID_LEN) {
|
||||
return PMI_ERR_INVALID_LENGTH;
|
||||
}
|
||||
|
||||
(void) strncpy(id_str, myproc.nspace, length);
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_Get_kvs_domain_id(char id_str[], int length)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
/* same as PMI_Get_id */
|
||||
return PMI_Get_id(id_str, length);
|
||||
}
|
||||
|
||||
int PMI_Get_id_length_max(int *length)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == length) {
|
||||
return PMI_ERR_INVALID_VAL_LENGTH;
|
||||
}
|
||||
|
||||
*length = PMI_MAX_ID_LEN;
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_Get_clique_size(int *size)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == size) {
|
||||
return PMI_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_LOCAL_SIZE, NULL, 0, &val)) {
|
||||
rc = convert_int(size, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
int PMI_Get_clique_ranks(int ranks[], int length)
|
||||
{
|
||||
pmix_value_t *val;
|
||||
char **rks;
|
||||
int i;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == ranks) {
|
||||
return PMI_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_LOCAL_PEERS, NULL, 0, &val)) {
|
||||
/* kv will contain a string of comma-separated
|
||||
* ranks on my node */
|
||||
rks = pmix_argv_split(val->data.string, ',');
|
||||
for (i = 0; NULL != rks[i] && i < length; i++) {
|
||||
ranks[i] = strtol(rks[i], NULL, 10);
|
||||
}
|
||||
pmix_argv_free(rks);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
int PMI_KVS_Get_my_name(char kvsname[], int length)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
/* same as PMI_Get_id */
|
||||
return PMI_Get_id(kvsname, length);
|
||||
}
|
||||
|
||||
int PMI_KVS_Get_name_length_max(int *length)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == length) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*length = PMI_MAX_KVSNAME_LEN;
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_KVS_Get_key_length_max(int *length)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == length) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*length = PMI_MAX_KEY_LEN;
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI_KVS_Get_value_length_max(int *length)
|
||||
{
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == length) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* don't give them an enormous size of some implementations
|
||||
* immediately malloc a data block for their use */
|
||||
*length = PMI_MAX_VAL_LEN;
|
||||
return PMI_SUCCESS;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_KVS_Create(char kvsname[], int length)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_KVS_Destroy(const char kvsname[])
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_KVS_Iter_first(const char kvsname[], char key[], int key_len, char val[], int val_len)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_KVS_Iter_next(const char kvsname[], char key[], int key_len, char val[], int val_len)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
int PMI_Spawn_multiple(int count,
|
||||
const char * cmds[],
|
||||
const char ** argvs[],
|
||||
const int maxprocs[],
|
||||
const int info_keyval_sizesp[],
|
||||
const PMI_keyval_t * info_keyval_vectors[],
|
||||
int preput_keyval_size,
|
||||
const PMI_keyval_t preput_keyval_vector[],
|
||||
int errors[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_app_t *apps;
|
||||
int i, k;
|
||||
size_t j;
|
||||
char *evar;
|
||||
|
||||
PMI_CHECK();
|
||||
|
||||
if (NULL == cmds) {
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* setup the apps */
|
||||
PMIX_APP_CREATE(apps, count);
|
||||
for (i = 0; i < count; i++) {
|
||||
apps[i].cmd = strdup(cmds[i]);
|
||||
apps[i].maxprocs = maxprocs[i];
|
||||
apps[i].argv = pmix_argv_copy((char**) argvs[i]);
|
||||
apps[i].argc = pmix_argv_count(apps[i].argv);
|
||||
apps[i].ninfo = info_keyval_sizesp[i];
|
||||
if (0 < apps[i].ninfo) {
|
||||
apps[i].info = (pmix_info_t*)malloc(apps[i].ninfo * sizeof(pmix_info_t));
|
||||
/* copy the info objects */
|
||||
for (j = 0; j < apps[i].ninfo; j++) {
|
||||
(void)strncpy(apps[i].info[j].key, info_keyval_vectors[i][j].key, PMIX_MAX_KEYLEN);
|
||||
apps[i].info[j].value.type = PMIX_STRING;
|
||||
apps[i].info[j].value.data.string = strdup(info_keyval_vectors[i][j].val);
|
||||
}
|
||||
}
|
||||
/* push the preput values into the apps environ */
|
||||
for (k = 0; k < preput_keyval_size; k++) {
|
||||
(void)asprintf(&evar, "%s=%s", preput_keyval_vector[k].key, preput_keyval_vector[k].val);
|
||||
pmix_argv_append_nosize(&apps[i].env, evar);
|
||||
free(evar);
|
||||
}
|
||||
}
|
||||
|
||||
rc = PMIx_Spawn(NULL, 0, apps, count, NULL);
|
||||
/* tear down the apps array */
|
||||
for (i = 0; i < count; i++) {
|
||||
PMIX_APP_DESTRUCT(&apps[i]);
|
||||
}
|
||||
free(apps);
|
||||
if (NULL != errors) {
|
||||
for (i = 0; i < count; i++) {
|
||||
errors[i] = convert_err(rc);
|
||||
}
|
||||
}
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_Parse_option(int num_args, char *args[], int *num_parsed, PMI_keyval_t **keyvalp, int *size)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_Args_to_keyval(int *argcp, char *((*argvp)[]), PMI_keyval_t **keyvalp, int *size)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_Free_keyvals(PMI_keyval_t keyvalp[], int size)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/* nobody supports this call, which is why it was
|
||||
* dropped for PMI-2 */
|
||||
int PMI_Get_options(char *str, int *length)
|
||||
{
|
||||
return PMI_FAIL;
|
||||
}
|
||||
|
||||
/*** UTILITY FUNCTIONS ***/
|
||||
/* internal function */
|
||||
static pmix_status_t convert_int(int *value, pmix_value_t *kv)
|
||||
{
|
||||
switch (kv->type) {
|
||||
case PMIX_INT:
|
||||
*value = kv->data.integer;
|
||||
break;
|
||||
case PMIX_INT8:
|
||||
*value = kv->data.int8;
|
||||
break;
|
||||
case PMIX_INT16:
|
||||
*value = kv->data.int16;
|
||||
break;
|
||||
case PMIX_INT32:
|
||||
*value = kv->data.int32;
|
||||
break;
|
||||
case PMIX_INT64:
|
||||
*value = kv->data.int64;
|
||||
break;
|
||||
case PMIX_UINT:
|
||||
*value = kv->data.uint;
|
||||
break;
|
||||
case PMIX_UINT8:
|
||||
*value = kv->data.uint8;
|
||||
break;
|
||||
case PMIX_UINT16:
|
||||
*value = kv->data.uint16;
|
||||
break;
|
||||
case PMIX_UINT32:
|
||||
*value = kv->data.uint32;
|
||||
break;
|
||||
case PMIX_UINT64:
|
||||
*value = kv->data.uint64;
|
||||
break;
|
||||
case PMIX_BYTE:
|
||||
*value = kv->data.byte;
|
||||
break;
|
||||
case PMIX_SIZE:
|
||||
*value = kv->data.size;
|
||||
break;
|
||||
case PMIX_BOOL:
|
||||
*value = kv->data.flag;
|
||||
break;
|
||||
default:
|
||||
/* not an integer type */
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static int convert_err(pmix_status_t rc)
|
||||
{
|
||||
switch (rc) {
|
||||
case PMIX_ERR_INVALID_SIZE:
|
||||
return PMI_ERR_INVALID_SIZE;
|
||||
|
||||
case PMIX_ERR_INVALID_KEYVALP:
|
||||
return PMI_ERR_INVALID_KEYVALP;
|
||||
|
||||
case PMIX_ERR_INVALID_NUM_PARSED:
|
||||
return PMI_ERR_INVALID_NUM_PARSED;
|
||||
|
||||
case PMIX_ERR_INVALID_ARGS:
|
||||
return PMI_ERR_INVALID_ARGS;
|
||||
|
||||
case PMIX_ERR_INVALID_NUM_ARGS:
|
||||
return PMI_ERR_INVALID_NUM_ARGS;
|
||||
|
||||
case PMIX_ERR_INVALID_LENGTH:
|
||||
return PMI_ERR_INVALID_LENGTH;
|
||||
|
||||
case PMIX_ERR_INVALID_VAL_LENGTH:
|
||||
return PMI_ERR_INVALID_VAL_LENGTH;
|
||||
|
||||
case PMIX_ERR_INVALID_VAL:
|
||||
return PMI_ERR_INVALID_VAL;
|
||||
|
||||
case PMIX_ERR_INVALID_KEY_LENGTH:
|
||||
return PMI_ERR_INVALID_KEY_LENGTH;
|
||||
|
||||
case PMIX_ERR_INVALID_KEY:
|
||||
return PMI_ERR_INVALID_KEY;
|
||||
|
||||
case PMIX_ERR_INVALID_ARG:
|
||||
return PMI_ERR_INVALID_ARG;
|
||||
|
||||
case PMIX_ERR_NOMEM:
|
||||
return PMI_ERR_NOMEM;
|
||||
|
||||
case PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER:
|
||||
case PMIX_ERR_COMM_FAILURE:
|
||||
case PMIX_ERR_NOT_IMPLEMENTED:
|
||||
case PMIX_ERR_NOT_SUPPORTED:
|
||||
case PMIX_ERR_NOT_FOUND:
|
||||
case PMIX_ERR_SERVER_NOT_AVAIL:
|
||||
case PMIX_ERR_INVALID_NAMESPACE:
|
||||
case PMIX_ERR_DATA_VALUE_NOT_FOUND:
|
||||
case PMIX_ERR_OUT_OF_RESOURCE:
|
||||
case PMIX_ERR_RESOURCE_BUSY:
|
||||
case PMIX_ERR_BAD_PARAM:
|
||||
case PMIX_ERR_IN_ERRNO:
|
||||
case PMIX_ERR_UNREACH:
|
||||
case PMIX_ERR_TIMEOUT:
|
||||
case PMIX_ERR_NO_PERMISSIONS:
|
||||
case PMIX_ERR_PACK_MISMATCH:
|
||||
case PMIX_ERR_PACK_FAILURE:
|
||||
case PMIX_ERR_UNPACK_FAILURE:
|
||||
case PMIX_ERR_UNPACK_INADEQUATE_SPACE:
|
||||
case PMIX_ERR_TYPE_MISMATCH:
|
||||
case PMIX_ERR_PROC_ENTRY_NOT_FOUND:
|
||||
case PMIX_ERR_UNKNOWN_DATA_TYPE:
|
||||
case PMIX_ERR_WOULD_BLOCK:
|
||||
case PMIX_EXISTS:
|
||||
case PMIX_ERROR:
|
||||
return PMI_FAIL;
|
||||
|
||||
case PMIX_ERR_INIT:
|
||||
return PMI_ERR_INIT;
|
||||
|
||||
case PMIX_SUCCESS:
|
||||
return PMI_SUCCESS;
|
||||
default:
|
||||
return PMI_FAIL;
|
||||
}
|
||||
}
|
@ -1,716 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include <pmix.h>
|
||||
#include <pmi2.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
|
||||
#define PMI2_CHECK() \
|
||||
do { \
|
||||
if (!pmi2_init) { \
|
||||
return PMI2_FAIL; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* local functions */
|
||||
static pmix_status_t convert_int(int *value, pmix_value_t *kv);
|
||||
static int convert_err(pmix_status_t rc);
|
||||
static pmix_proc_t myproc;
|
||||
static int pmi2_init = 0;
|
||||
|
||||
int PMI2_Init(int *spawned, int *size, int *rank, int *appnum)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
pmix_proc_t proc;
|
||||
|
||||
if (PMIX_SUCCESS != PMIx_Init(&myproc)) {
|
||||
return PMI2_ERR_INIT;
|
||||
}
|
||||
|
||||
/* get the rank */
|
||||
*rank = myproc.rank;
|
||||
|
||||
/* getting internal key requires special rank value */
|
||||
memcpy(&proc, &myproc, sizeof(myproc));
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
|
||||
if (NULL != size) {
|
||||
/* get the universe size - this will likely pull
|
||||
* down all attributes assigned to the job, thus
|
||||
* making all subsequent "get" operations purely
|
||||
* local */
|
||||
if (PMIX_SUCCESS == PMIx_Get(&proc, PMIX_UNIV_SIZE, NULL, 0, &val)) {
|
||||
rc = convert_int(size, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* cannot continue without this info */
|
||||
return PMI2_ERR_INIT;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != spawned) {
|
||||
/* get the spawned flag */
|
||||
if (PMIX_SUCCESS == PMIx_Get(&proc, PMIX_SPAWNED, NULL, 0, &val)) {
|
||||
rc = convert_int(spawned, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* if not found, default to not spawned */
|
||||
*spawned = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != appnum) {
|
||||
/* get our appnum */
|
||||
if (PMIX_SUCCESS == PMIx_Get(&proc, PMIX_APPNUM, NULL, 0, &val)) {
|
||||
rc = convert_int(appnum, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
/* if not found, default to 0 */
|
||||
*appnum = 0;
|
||||
}
|
||||
}
|
||||
pmi2_init = 1;
|
||||
|
||||
return PMI2_SUCCESS;
|
||||
|
||||
error:
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Initialized(void)
|
||||
{
|
||||
int initialized;
|
||||
initialized = (int)PMIx_Initialized();
|
||||
return initialized;
|
||||
}
|
||||
|
||||
int PMI2_Finalize(void)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
pmi2_init = 0;
|
||||
rc = PMIx_Finalize();
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Abort(int flag, const char msg[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
rc = PMIx_Abort(flag, msg, NULL, 0);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* KVS_Put - we default to PMIX_GLOBAL scope */
|
||||
int PMI2_KVS_Put(const char key[], const char value[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t val;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if ((NULL == key) || (NULL == value)) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
pmix_output_verbose(3, pmix_globals.debug_output,
|
||||
"PMI2_KVS_Put: key=%s value=%s", key, value);
|
||||
|
||||
val.type = PMIX_STRING;
|
||||
val.data.string = (char*)value;
|
||||
rc = PMIx_Put(PMIX_GLOBAL, key, &val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* KVS_Fence */
|
||||
int PMI2_KVS_Fence(void)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* we want all data to be collected upon completion */
|
||||
{
|
||||
pmix_info_t info;
|
||||
int ninfo = 1;
|
||||
bool val = 1;
|
||||
|
||||
PMIX_INFO_CONSTRUCT(&info);
|
||||
PMIX_INFO_LOAD(&info, PMIX_COLLECT_DATA, &val, PMIX_BOOL);
|
||||
rc = PMIx_Fence(NULL, 0, &info, ninfo);
|
||||
PMIX_INFO_DESTRUCT(&info);
|
||||
}
|
||||
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* the jobid is equated to the nspace in PMIx, and the
|
||||
* src_pmi_id equates to the rank. If jobid=NULL, then PMIx
|
||||
* will use the local nspace, which matches the PMI2 spec.
|
||||
* The only type of value supported by PMI2 is a string, so
|
||||
* the return of anything else is an error */
|
||||
int PMI2_KVS_Get(const char *jobid, int src_pmi_id,
|
||||
const char key[], char value [],
|
||||
int maxvalue, int *vallen)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
pmix_proc_t proc;
|
||||
uint32_t procnum = 0;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if ((NULL == key) || (NULL == value)) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
pmix_output_verbose(3, pmix_globals.debug_output,
|
||||
"PMI2_KVS_Get: key=%s jobid=%s src_pmi_id=%d", key, (jobid ? jobid : "null"), src_pmi_id);
|
||||
|
||||
(void)strncpy(proc.nspace, (jobid ? jobid : myproc.nspace), PMIX_MAX_NSLEN);
|
||||
if (src_pmi_id == PMI2_ID_NULL) {
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_JOB_SIZE, NULL, 0, &val))) {
|
||||
return convert_err(rc);
|
||||
}
|
||||
procnum = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
proc.rank = 0;
|
||||
} else {
|
||||
proc.rank = src_pmi_id;
|
||||
}
|
||||
|
||||
do {
|
||||
rc = PMIx_Get(&proc, key, NULL, 0, &val);
|
||||
if (PMIX_SUCCESS == rc && NULL != val) {
|
||||
if (PMIX_STRING != val->type) {
|
||||
/* this is an error */
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
if (NULL != val->data.string) {
|
||||
(void)strncpy(value, val->data.string, maxvalue);
|
||||
*vallen = strlen(val->data.string);
|
||||
}
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
break;
|
||||
} else if (PMIX_ERR_NOT_FOUND == rc) {
|
||||
proc.rank++;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} while (proc.rank < (int)procnum);
|
||||
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Info_GetNodeAttr(const char name[], char value[], int valuelen, int *found, int waitfor)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if ((NULL == name) || (NULL == value) || (NULL == found)) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
*found = 0;
|
||||
rc = PMIx_Get(&myproc, name, NULL, 0, &val);
|
||||
if (PMIX_SUCCESS == rc && NULL != val) {
|
||||
if (PMIX_STRING != val->type) {
|
||||
/* this is an error */
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
if (NULL != val->data.string) {
|
||||
(void)strncpy(value, val->data.string, valuelen);
|
||||
*found = 1;
|
||||
}
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
} else if (PMIX_ERR_NOT_FOUND == rc) {
|
||||
rc = PMIX_SUCCESS;
|
||||
}
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* push info at the PMIX_LOCAL scope */
|
||||
int PMI2_Info_PutNodeAttr(const char name[], const char value[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t val;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if ((NULL == name) || (NULL == value)) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
val.type = PMIX_STRING;
|
||||
val.data.string = (char*)value;
|
||||
rc = PMIx_Put(PMIX_LOCAL, name, &val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Info_GetJobAttr(const char name[], char value[], int valuelen, int *found)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
pmix_proc_t proc;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if ((NULL == name) || (NULL == value) || (NULL == found)) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* getting internal key requires special rank value */
|
||||
memcpy(&proc, &myproc, sizeof(myproc));
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
|
||||
*found = 0;
|
||||
rc = PMIx_Get(&proc, name, NULL, 0, &val);
|
||||
if (PMIX_SUCCESS == rc && NULL != val) {
|
||||
if (PMIX_STRING != val->type) {
|
||||
/* this is an error */
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
if (NULL != val->data.string) {
|
||||
(void)strncpy(value, val->data.string, valuelen);
|
||||
*found = 1;
|
||||
}
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
} else if (PMIX_ERR_NOT_FOUND == rc) {
|
||||
rc = PMIX_SUCCESS;
|
||||
}
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Info_GetJobAttrIntArray(const char name[], int array[], int arraylen, int *outlen, int *found)
|
||||
{
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
|
||||
int PMI2_Nameserv_publish(const char service_name[], const PMI_keyval_t *info_ptr, const char port[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
int nvals;
|
||||
pmix_info_t info[2];
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == service_name || NULL == port) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* pass the service/port */
|
||||
(void)strncpy(info[0].key, service_name, PMIX_MAX_KEYLEN);
|
||||
info[0].value.type = PMIX_STRING;
|
||||
info[0].value.data.string = (char*)port;
|
||||
nvals = 1;
|
||||
|
||||
/* if provided, add any other value */
|
||||
if (NULL != info_ptr) {
|
||||
(void)strncpy(info[1].key, info_ptr->key, PMIX_MAX_KEYLEN);
|
||||
info[1].value.type = PMIX_STRING;
|
||||
info[1].value.data.string = (char*)info_ptr->val;
|
||||
nvals = 2;
|
||||
}
|
||||
/* publish the info - PMI-2 doesn't support
|
||||
* any scope other than inside our own nspace */
|
||||
rc = PMIx_Publish(info, nvals);
|
||||
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Nameserv_unpublish(const char service_name[],
|
||||
const PMI_keyval_t *info_ptr)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
char *keys[3];
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == service_name || NULL == info_ptr) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* pass the service */
|
||||
keys[0] = (char*)service_name;
|
||||
keys[1] = NULL;
|
||||
keys[2] = NULL;
|
||||
|
||||
/* if provided, add any other value */
|
||||
if (NULL != info_ptr) {
|
||||
keys[1] = info_ptr->key;
|
||||
}
|
||||
|
||||
rc = PMIx_Unpublish(keys, NULL, 0);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Nameserv_lookup(const char service_name[], const PMI_keyval_t *info_ptr,
|
||||
char port[], int portLen)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
int nvals;
|
||||
pmix_pdata_t pdata[2];
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == service_name || NULL == info_ptr || NULL == port) {
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
PMIX_PDATA_CONSTRUCT(&pdata[0]);
|
||||
PMIX_PDATA_CONSTRUCT(&pdata[1]);
|
||||
|
||||
/* pass the service */
|
||||
(void)strncpy(pdata[0].key, service_name, PMIX_MAX_KEYLEN);
|
||||
nvals = 1;
|
||||
|
||||
/* if provided, add any other value */
|
||||
if (NULL != info_ptr) {
|
||||
(void)strncpy(pdata[1].key, info_ptr->key, PMIX_MAX_KEYLEN);
|
||||
pdata[1].value.type = PMIX_STRING;
|
||||
pdata[1].value.data.string = info_ptr->val;
|
||||
nvals = 2;
|
||||
}
|
||||
|
||||
/* lookup the info */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Lookup(pdata, nvals, NULL, 0))) {
|
||||
PMIX_PDATA_DESTRUCT(&pdata[0]);
|
||||
PMIX_PDATA_DESTRUCT(&pdata[1]);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
/* should have received a string back */
|
||||
if (PMIX_STRING != pdata[0].value.type ||
|
||||
NULL == pdata[0].value.data.string) {
|
||||
PMIX_PDATA_DESTRUCT(&pdata[0]);
|
||||
PMIX_PDATA_DESTRUCT(&pdata[1]);
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
|
||||
/* return the port */
|
||||
(void)strncpy(port, pdata[0].value.data.string, portLen);
|
||||
PMIX_PDATA_DESTRUCT(&pdata[0]);
|
||||
|
||||
if (NULL != info_ptr) {
|
||||
}
|
||||
PMIX_PDATA_DESTRUCT(&pdata[1]);
|
||||
|
||||
return PMI2_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI2_Job_GetId(char jobid[], int jobid_size)
|
||||
{
|
||||
/* we already obtained our nspace during pmi2_init,
|
||||
* so all we have to do here is return it */
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
/* bozo check */
|
||||
if (NULL == jobid) {
|
||||
return PMI2_ERR_INVALID_ARGS;
|
||||
}
|
||||
(void)strncpy(jobid, myproc.nspace, jobid_size);
|
||||
return PMI2_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI2_Job_GetRank(int *rank)
|
||||
{
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == rank) {
|
||||
return PMI2_ERR_INVALID_ARGS;
|
||||
}
|
||||
*rank = myproc.rank;
|
||||
return PMI2_SUCCESS;
|
||||
}
|
||||
|
||||
int PMI2_Info_GetSize(int *size)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_value_t *val;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == size) {
|
||||
return PMI2_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS == PMIx_Get(&myproc, PMIX_LOCAL_SIZE, NULL, 0, &val)) {
|
||||
rc = convert_int(size, val);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
|
||||
int PMI2_Job_Connect(const char jobid[], PMI2_Connect_comm_t *conn)
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_proc_t proc;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == conn) {
|
||||
return PMI2_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
(void)strncpy(proc.nspace, (jobid ? jobid : myproc.nspace), sizeof(myproc.nspace));
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
rc = PMIx_Connect(&proc, 1, NULL, 0);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Job_Disconnect(const char jobid[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_proc_t proc;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
(void)strncpy(proc.nspace, (jobid ? jobid : myproc.nspace), sizeof(myproc.nspace));
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
rc = PMIx_Disconnect(&proc, 1, NULL, 0);
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
int PMI2_Job_Spawn(int count, const char * cmds[],
|
||||
int argcs[], const char ** argvs[],
|
||||
const int maxprocs[],
|
||||
const int info_keyval_sizes[],
|
||||
const PMI_keyval_t *info_keyval_vectors[],
|
||||
int preput_keyval_size,
|
||||
const PMI_keyval_t *preput_keyval_vector[],
|
||||
char jobId[], int jobIdSize,
|
||||
int errors[])
|
||||
{
|
||||
pmix_status_t rc = PMIX_SUCCESS;
|
||||
pmix_app_t *apps;
|
||||
int i, k;
|
||||
size_t j;
|
||||
char *evar;
|
||||
|
||||
PMI2_CHECK();
|
||||
|
||||
if (NULL == cmds) {
|
||||
return PMI2_ERR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
/* setup the apps */
|
||||
PMIX_APP_CREATE(apps, count);
|
||||
for (i=0; i < count; i++) {
|
||||
apps[i].cmd = strdup(cmds[i]);
|
||||
apps[i].maxprocs = maxprocs[i];
|
||||
apps[i].argv = pmix_argv_copy((char**)argvs[i]);
|
||||
apps[i].argc = pmix_argv_count(apps[i].argv);
|
||||
apps[i].ninfo = info_keyval_sizes[i];
|
||||
apps[i].info = (pmix_info_t*)malloc(apps[i].ninfo * sizeof(pmix_info_t));
|
||||
/* copy the info objects */
|
||||
for (j=0; j < apps[i].ninfo; j++) {
|
||||
(void)strncpy(apps[i].info[j].key, info_keyval_vectors[i][j].key, PMIX_MAX_KEYLEN);
|
||||
apps[i].info[j].value.type = PMIX_STRING;
|
||||
apps[i].info[j].value.data.string = strdup(info_keyval_vectors[i][j].val);
|
||||
}
|
||||
/* push the preput values into the apps environ */
|
||||
for (k=0; k < preput_keyval_size; k++) {
|
||||
(void)asprintf(&evar, "%s=%s", preput_keyval_vector[j]->key, preput_keyval_vector[j]->val);
|
||||
pmix_argv_append_nosize(&apps[i].env, evar);
|
||||
free(evar);
|
||||
}
|
||||
}
|
||||
|
||||
rc = PMIx_Spawn(NULL, 0, apps, count, NULL);
|
||||
/* tear down the apps array */
|
||||
for (i=0; i < count; i++) {
|
||||
PMIX_APP_DESTRUCT(&apps[i]);
|
||||
}
|
||||
free(apps);
|
||||
if (NULL != errors) {
|
||||
for (i=0; i < count; i++) {
|
||||
errors[i] = convert_err(rc);
|
||||
}
|
||||
}
|
||||
|
||||
return convert_err(rc);
|
||||
}
|
||||
|
||||
static pmix_status_t convert_int(int *value, pmix_value_t *kv)
|
||||
{
|
||||
switch(kv->type) {
|
||||
case PMIX_INT:
|
||||
*value = kv->data.integer;
|
||||
break;
|
||||
case PMIX_INT8:
|
||||
*value = kv->data.int8;
|
||||
break;
|
||||
case PMIX_INT16:
|
||||
*value = kv->data.int16;
|
||||
break;
|
||||
case PMIX_INT32:
|
||||
*value = kv->data.int32;
|
||||
break;
|
||||
case PMIX_INT64:
|
||||
*value = kv->data.int64;
|
||||
break;
|
||||
case PMIX_UINT:
|
||||
*value = kv->data.uint;
|
||||
break;
|
||||
case PMIX_UINT8:
|
||||
*value = kv->data.uint8;
|
||||
break;
|
||||
case PMIX_UINT16:
|
||||
*value = kv->data.uint16;
|
||||
break;
|
||||
case PMIX_UINT32:
|
||||
*value = kv->data.uint32;
|
||||
break;
|
||||
case PMIX_UINT64:
|
||||
*value = kv->data.uint64;
|
||||
break;
|
||||
case PMIX_BYTE:
|
||||
*value = kv->data.byte;
|
||||
break;
|
||||
case PMIX_SIZE:
|
||||
*value = kv->data.size;
|
||||
break;
|
||||
case PMIX_BOOL:
|
||||
*value = kv->data.flag;
|
||||
break;
|
||||
default:
|
||||
/* not an integer type */
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static int convert_err(pmix_status_t rc)
|
||||
{
|
||||
switch(rc) {
|
||||
case PMIX_ERR_INVALID_SIZE:
|
||||
return PMI2_ERR_INVALID_SIZE;
|
||||
|
||||
case PMIX_ERR_INVALID_KEYVALP:
|
||||
return PMI2_ERR_INVALID_KEYVALP;
|
||||
|
||||
case PMIX_ERR_INVALID_NUM_PARSED:
|
||||
return PMI2_ERR_INVALID_NUM_PARSED;
|
||||
|
||||
case PMIX_ERR_INVALID_ARGS:
|
||||
return PMI2_ERR_INVALID_ARGS;
|
||||
|
||||
case PMIX_ERR_INVALID_NUM_ARGS:
|
||||
return PMI2_ERR_INVALID_NUM_ARGS;
|
||||
|
||||
case PMIX_ERR_INVALID_LENGTH:
|
||||
return PMI2_ERR_INVALID_LENGTH;
|
||||
|
||||
case PMIX_ERR_INVALID_VAL_LENGTH:
|
||||
return PMI2_ERR_INVALID_VAL_LENGTH;
|
||||
|
||||
case PMIX_ERR_INVALID_VAL:
|
||||
return PMI2_ERR_INVALID_VAL;
|
||||
|
||||
case PMIX_ERR_INVALID_KEY_LENGTH:
|
||||
return PMI2_ERR_INVALID_KEY_LENGTH;
|
||||
|
||||
case PMIX_ERR_INVALID_KEY:
|
||||
return PMI2_ERR_INVALID_KEY;
|
||||
|
||||
case PMIX_ERR_INVALID_ARG:
|
||||
return PMI2_ERR_INVALID_ARG;
|
||||
|
||||
case PMIX_ERR_NOMEM:
|
||||
return PMI2_ERR_NOMEM;
|
||||
|
||||
case PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER:
|
||||
case PMIX_ERR_COMM_FAILURE:
|
||||
case PMIX_ERR_NOT_IMPLEMENTED:
|
||||
case PMIX_ERR_NOT_SUPPORTED:
|
||||
case PMIX_ERR_NOT_FOUND:
|
||||
case PMIX_ERR_SERVER_NOT_AVAIL:
|
||||
case PMIX_ERR_INVALID_NAMESPACE:
|
||||
case PMIX_ERR_DATA_VALUE_NOT_FOUND:
|
||||
case PMIX_ERR_OUT_OF_RESOURCE:
|
||||
case PMIX_ERR_RESOURCE_BUSY:
|
||||
case PMIX_ERR_BAD_PARAM:
|
||||
case PMIX_ERR_IN_ERRNO:
|
||||
case PMIX_ERR_UNREACH:
|
||||
case PMIX_ERR_TIMEOUT:
|
||||
case PMIX_ERR_NO_PERMISSIONS:
|
||||
case PMIX_ERR_PACK_MISMATCH:
|
||||
case PMIX_ERR_PACK_FAILURE:
|
||||
case PMIX_ERR_UNPACK_FAILURE:
|
||||
case PMIX_ERR_UNPACK_INADEQUATE_SPACE:
|
||||
case PMIX_ERR_TYPE_MISMATCH:
|
||||
case PMIX_ERR_PROC_ENTRY_NOT_FOUND:
|
||||
case PMIX_ERR_UNKNOWN_DATA_TYPE:
|
||||
case PMIX_ERR_WOULD_BLOCK:
|
||||
case PMIX_EXISTS:
|
||||
case PMIX_ERROR:
|
||||
return PMI2_FAIL;
|
||||
|
||||
case PMIX_ERR_INIT:
|
||||
return PMI2_ERR_INIT;
|
||||
|
||||
case PMIX_SUCCESS:
|
||||
return PMI2_SUCCESS;
|
||||
default:
|
||||
return PMI2_FAIL;
|
||||
}
|
||||
}
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@ -1,333 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/progress_threads.h"
|
||||
#include "src/usock/usock.h"
|
||||
#include "src/sec/pmix_sec.h"
|
||||
|
||||
#include "pmix_client_ops.h"
|
||||
|
||||
/* callback for wait completion */
|
||||
static void wait_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata);
|
||||
static void op_cbfunc(int status, void *cbdata);
|
||||
|
||||
int PMIx_Connect(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
int rc;
|
||||
pmix_cb_t *cb;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: connect called");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->active = true;
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Connect_nb(procs, nprocs, info, ninfo, op_cbfunc, cb))) {
|
||||
PMIX_RELEASE(cb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* wait for the connect to complete */
|
||||
PMIX_WAIT_FOR_COMPLETION(cb->active);
|
||||
rc = cb->status;
|
||||
PMIX_RELEASE(cb);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: connect completed");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
pmix_status_t PMIx_Connect_nb(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_buffer_t *msg;
|
||||
pmix_cmd_t cmd = PMIX_CONNECTNB_CMD;
|
||||
pmix_status_t rc;
|
||||
pmix_cb_t *cb;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: connect called");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* check for bozo input */
|
||||
if (NULL == procs || 0 >= nprocs) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
msg = PMIX_NEW(pmix_buffer_t);
|
||||
/* pack the cmd */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &cmd, 1, PMIX_CMD))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pack the number of procs */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &nprocs, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, procs, nprocs, PMIX_PROC))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pack the info structs */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &ninfo, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
if (0 < ninfo) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, info, ninfo, PMIX_INFO))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->op_cbfunc = cbfunc;
|
||||
cb->cbdata = cbdata;
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
PMIX_ACTIVATE_SEND_RECV(&pmix_client_globals.myserver, msg, wait_cbfunc, cb);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int PMIx_Disconnect(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
int rc;
|
||||
pmix_cb_t *cb;
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->active = true;
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Disconnect_nb(procs, nprocs, info, ninfo, op_cbfunc, cb))) {
|
||||
PMIX_RELEASE(cb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* wait for the connect to complete */
|
||||
PMIX_WAIT_FOR_COMPLETION(cb->active);
|
||||
rc = cb->status;
|
||||
PMIX_RELEASE(cb);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: disconnect completed");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
pmix_status_t PMIx_Disconnect_nb(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_buffer_t *msg;
|
||||
pmix_cmd_t cmd = PMIX_DISCONNECTNB_CMD;
|
||||
pmix_status_t rc;
|
||||
pmix_cb_t *cb;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: disconnect called");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* check for bozo input */
|
||||
if (NULL == procs || 0 >= nprocs) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
msg = PMIX_NEW(pmix_buffer_t);
|
||||
/* pack the cmd */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &cmd, 1, PMIX_CMD))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pack the number of procs */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &nprocs, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, procs, nprocs, PMIX_PROC))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pack the info structs */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &ninfo, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
if (0 < ninfo) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, info, ninfo, PMIX_INFO))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->op_cbfunc = cbfunc;
|
||||
cb->cbdata = cbdata;
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
PMIX_ACTIVATE_SEND_RECV(&pmix_client_globals.myserver, msg, wait_cbfunc, cb);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: disconnect completed");
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void wait_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
pmix_status_t rc;
|
||||
pmix_status_t ret;
|
||||
int32_t cnt;
|
||||
char *nspace;
|
||||
pmix_buffer_t *bptr;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix:client recv callback activated with %d bytes",
|
||||
(NULL == buf) ? -1 : (int)buf->bytes_used);
|
||||
|
||||
/* unpack the returned status */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &ret, &cnt, PMIX_INT))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
ret = rc;
|
||||
}
|
||||
/* connect has to also pass back data from all nspace's involved in
|
||||
* the operation, including our own. Each will come as a buffer */
|
||||
cnt = 1;
|
||||
while (PMIX_SUCCESS == (rc = pmix_bfrop.unpack(buf, &bptr, &cnt, PMIX_BUFFER))) {
|
||||
/* unpack the nspace for this blob */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(bptr, &nspace, &cnt, PMIX_STRING))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(bptr);
|
||||
continue;
|
||||
}
|
||||
/* extract and process any proc-related info for this nspace */
|
||||
pmix_client_process_nspace_blob(nspace, bptr);
|
||||
PMIX_RELEASE(bptr);
|
||||
}
|
||||
if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
ret = rc;
|
||||
}
|
||||
|
||||
if (NULL != cb->op_cbfunc) {
|
||||
cb->op_cbfunc(ret, cb->cbdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void op_cbfunc(int status, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
|
||||
cb->status = status;
|
||||
cb->active = false;
|
||||
}
|
@ -1,255 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/hash.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/progress_threads.h"
|
||||
#include "src/usock/usock.h"
|
||||
#include "src/sec/pmix_sec.h"
|
||||
|
||||
#include "pmix_client_ops.h"
|
||||
|
||||
static int unpack_return(pmix_buffer_t *data);
|
||||
static int pack_fence(pmix_buffer_t *msg, pmix_cmd_t cmd,
|
||||
const pmix_proc_t *procs, size_t nprocs,
|
||||
const pmix_info_t *info, size_t ninfo);
|
||||
static void wait_cbfunc(struct pmix_peer_t *pr,
|
||||
pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata);
|
||||
static void op_cbfunc(int status, void *cbdata);
|
||||
|
||||
int PMIx_Fence(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
pmix_cb_t *cb;
|
||||
int rc;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: executing fence");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->active = true;
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence_nb(procs, nprocs, info, ninfo,
|
||||
op_cbfunc, cb))) {
|
||||
PMIX_RELEASE(cb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* wait for the fence to complete */
|
||||
PMIX_WAIT_FOR_COMPLETION(cb->active);
|
||||
rc = cb->status;
|
||||
PMIX_RELEASE(cb);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: fence released");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int PMIx_Fence_nb(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_buffer_t *msg;
|
||||
pmix_cmd_t cmd = PMIX_FENCENB_CMD;
|
||||
int rc;
|
||||
pmix_cb_t *cb;
|
||||
pmix_proc_t rg, *rgs;
|
||||
size_t nrg;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: fence_nb called");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* check for bozo input */
|
||||
if (NULL == procs && 0 != nprocs) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
/* if we are given a NULL proc, then the caller is referencing
|
||||
* all procs within our own nspace */
|
||||
if (NULL == procs) {
|
||||
(void)strncpy(rg.nspace, pmix_globals.myid.nspace, PMIX_MAX_NSLEN);
|
||||
rg.rank = PMIX_RANK_WILDCARD;
|
||||
rgs = &rg;
|
||||
nrg = 1;
|
||||
} else {
|
||||
rgs = (pmix_proc_t*)procs;
|
||||
nrg = nprocs;
|
||||
}
|
||||
|
||||
msg = PMIX_NEW(pmix_buffer_t);
|
||||
if (PMIX_SUCCESS != (rc = pack_fence(msg, cmd, rgs, nrg, info, ninfo))) {
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->op_cbfunc = cbfunc;
|
||||
cb->cbdata = cbdata;
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
PMIX_ACTIVATE_SEND_RECV(&pmix_client_globals.myserver, msg, wait_cbfunc, cb);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static pmix_status_t unpack_return(pmix_buffer_t *data)
|
||||
{
|
||||
pmix_status_t rc;
|
||||
int ret;
|
||||
int32_t cnt;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"client:unpack fence called");
|
||||
|
||||
/* unpack the status code */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(data, &ret, &cnt, PMIX_INT))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"client:unpack fence received status %d", ret);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static pmix_status_t pack_fence(pmix_buffer_t *msg, pmix_cmd_t cmd,
|
||||
const pmix_proc_t *procs, size_t nprocs,
|
||||
const pmix_info_t *info, size_t ninfo)
|
||||
{
|
||||
pmix_status_t rc;
|
||||
|
||||
/* pack the cmd */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &cmd, 1, PMIX_CMD))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pack the number of procs */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &nprocs, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
/* pack any provided procs - must always be at least one (our own) */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, procs, nprocs, PMIX_PROC))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
/* pack the number of info */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &ninfo, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
/* pack any provided info - may be NULL */
|
||||
if (NULL != info && 0 < ninfo) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, info, ninfo, PMIX_INFO))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void wait_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
pmix_status_t rc;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: fence_nb callback recvd");
|
||||
|
||||
if (NULL == cb) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
return;
|
||||
}
|
||||
rc = unpack_return(buf);
|
||||
|
||||
/* if a callback was provided, execute it */
|
||||
if (NULL != cb->op_cbfunc) {
|
||||
cb->op_cbfunc(rc, cb->cbdata);
|
||||
}
|
||||
PMIX_RELEASE(cb);
|
||||
}
|
||||
|
||||
static void op_cbfunc(int status, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
|
||||
cb->status = status;
|
||||
cb->active = false;
|
||||
}
|
||||
|
@ -1,500 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/hash.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/progress_threads.h"
|
||||
#include "src/usock/usock.h"
|
||||
#include "src/sec/pmix_sec.h"
|
||||
|
||||
#include "pmix_client_ops.h"
|
||||
|
||||
static pmix_buffer_t* pack_get(char *nspace, int rank,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_cmd_t cmd);
|
||||
|
||||
static void _getnbfn(int sd, short args, void *cbdata);
|
||||
|
||||
static void getnb_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata);
|
||||
|
||||
static void value_cbfunc(int status, pmix_value_t *kv, void *cbdata);
|
||||
|
||||
int PMIx_Get(const pmix_proc_t *proc, const char key[],
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_value_t **val)
|
||||
{
|
||||
pmix_cb_t *cb;
|
||||
int rc;
|
||||
|
||||
if (NULL == proc) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: %s:%d getting value for proc %s:%d key %s",
|
||||
pmix_globals.myid.nspace, pmix_globals.myid.rank,
|
||||
proc->nspace, proc->rank,
|
||||
(NULL == key) ? "NULL" : key);
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->active = true;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get_nb(proc, key, info, ninfo, value_cbfunc, cb))) {
|
||||
PMIX_RELEASE(cb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* wait for the data to return */
|
||||
PMIX_WAIT_FOR_COMPLETION(cb->active);
|
||||
rc = cb->status;
|
||||
*val = cb->value;
|
||||
PMIX_RELEASE(cb);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix:client get completed");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
pmix_status_t PMIx_Get_nb(const pmix_proc_t *proc, const char *key,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_value_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb;
|
||||
|
||||
if (NULL == proc) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: get_nb value for proc %s:%d key %s",
|
||||
proc->nspace, proc->rank,
|
||||
(NULL == key) ? "NULL" : key);
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* protect against bozo input */
|
||||
if (NULL == key) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
/* thread-shift so we can check global objects */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->active = true;
|
||||
(void)strncpy(cb->nspace, proc->nspace, PMIX_MAX_NSLEN);
|
||||
cb->rank = proc->rank;
|
||||
cb->key = (char*)key;
|
||||
cb->info = (pmix_info_t*)info;
|
||||
cb->ninfo = ninfo;
|
||||
cb->value_cbfunc = cbfunc;
|
||||
cb->cbdata = cbdata;
|
||||
PMIX_THREAD_SHIFT(cb, _getnbfn);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void value_cbfunc(int status, pmix_value_t *kv, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
pmix_status_t rc;
|
||||
|
||||
cb->status = status;
|
||||
if (PMIX_SUCCESS == status) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.copy((void**)&cb->value, kv, PMIX_VALUE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
}
|
||||
}
|
||||
cb->active = false;
|
||||
}
|
||||
|
||||
static pmix_buffer_t* pack_get(char *nspace, int rank,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_cmd_t cmd)
|
||||
{
|
||||
pmix_buffer_t *msg;
|
||||
pmix_status_t rc;
|
||||
|
||||
/* nope - see if we can get it */
|
||||
msg = PMIX_NEW(pmix_buffer_t);
|
||||
/* pack the get cmd */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &cmd, 1, PMIX_CMD))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return NULL;
|
||||
}
|
||||
/* pack the request information - we'll get the entire blob
|
||||
* for this proc, so we don't need to pass the key */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &nspace, 1, PMIX_STRING))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return NULL;
|
||||
}
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &rank, 1, PMIX_INT))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return NULL;
|
||||
}
|
||||
/* pack the number of info structs */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &ninfo, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return NULL;
|
||||
}
|
||||
if (0 < ninfo) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, info, ninfo, PMIX_INFO))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* this callback is coming from the usock recv, and thus
|
||||
* is occurring inside of our progress thread - hence, no
|
||||
* need to thread shift */
|
||||
static void getnb_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
pmix_cb_t *cb2;
|
||||
pmix_status_t rc, ret;
|
||||
pmix_value_t *val = NULL;
|
||||
int32_t cnt;
|
||||
pmix_buffer_t *bptr;
|
||||
pmix_kval_t *kp;
|
||||
pmix_nspace_t *ns, *nptr;
|
||||
int rank;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: get_nb callback recvd");
|
||||
if (NULL == cb) {
|
||||
/* nothing we can do */
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
return;
|
||||
}
|
||||
// cache the rank
|
||||
rank = cb->rank;
|
||||
|
||||
/* unpack the status */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &ret, &cnt, PMIX_INT))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* look up the nspace object for this proc */
|
||||
nptr = NULL;
|
||||
PMIX_LIST_FOREACH(ns, &pmix_globals.nspaces, pmix_nspace_t) {
|
||||
if (0 == strncmp(cb->nspace, ns->nspace, PMIX_MAX_NSLEN)) {
|
||||
nptr = ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL == nptr) {
|
||||
/* new nspace - setup a record for it */
|
||||
nptr = PMIX_NEW(pmix_nspace_t);
|
||||
(void)strncpy(nptr->nspace, cb->nspace, PMIX_MAX_NSLEN);
|
||||
pmix_list_append(&pmix_globals.nspaces, &nptr->super);
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS != ret) {
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* we received the entire blob for this process, so
|
||||
* unpack and store it in the modex - this could consist
|
||||
* of buffers from multiple scopes */
|
||||
cnt = 1;
|
||||
while (PMIX_SUCCESS == (rc = pmix_bfrop.unpack(buf, &bptr, &cnt, PMIX_BUFFER))) {
|
||||
cnt = 1;
|
||||
kp = PMIX_NEW(pmix_kval_t);
|
||||
while (PMIX_SUCCESS == (rc = pmix_bfrop.unpack(bptr, kp, &cnt, PMIX_KVAL))) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: unpacked key %s", kp->key);
|
||||
if (PMIX_SUCCESS != (rc = pmix_hash_store(&nptr->modex, cb->rank, kp))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
}
|
||||
if (NULL != cb->key && 0 == strcmp(cb->key, kp->key)) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: found requested value");
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.copy((void**)&val, kp->value, PMIX_VALUE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(kp);
|
||||
val = NULL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
PMIX_RELEASE(kp); // maintain acctg - hash_store does a retain
|
||||
cnt = 1;
|
||||
kp = PMIX_NEW(pmix_kval_t);
|
||||
}
|
||||
cnt = 1;
|
||||
PMIX_RELEASE(kp);
|
||||
PMIX_RELEASE(bptr); // free's the data region
|
||||
if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
rc = PMIX_ERR_SILENT; // avoid error-logging twice
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER != rc) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
} else {
|
||||
rc = PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
done:
|
||||
/* if a callback was provided, execute it */
|
||||
if (NULL != cb && NULL != cb->value_cbfunc) {
|
||||
if (NULL == val) {
|
||||
rc = PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
cb->value_cbfunc(rc, val, cb->cbdata);
|
||||
}
|
||||
if (NULL != val) {
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
}
|
||||
/* we obviously processed this one, so remove it from the
|
||||
* list of pending requests */
|
||||
pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super);
|
||||
PMIX_RELEASE(cb);
|
||||
|
||||
/* now search any pending requests to see if they can be met */
|
||||
PMIX_LIST_FOREACH_SAFE(cb, cb2, &pmix_client_globals.pending_requests, pmix_cb_t) {
|
||||
if (0 == strncmp(nptr->nspace, cb->nspace, PMIX_MAX_NSLEN) && cb->rank == rank) {
|
||||
/* we have the data - see if we can find the key */
|
||||
val = NULL;
|
||||
rc = pmix_hash_fetch(&nptr->modex, rank, cb->key, &val);
|
||||
cb->value_cbfunc(rc, val, cb->cbdata);
|
||||
if (NULL != val) {
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
}
|
||||
pmix_list_remove_item(&pmix_client_globals.pending_requests, &cb->super);
|
||||
PMIX_RELEASE(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void _getnbfn(int fd, short flags, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
pmix_cb_t *cbret;
|
||||
pmix_buffer_t *msg;
|
||||
pmix_value_t *val;
|
||||
pmix_status_t rc;
|
||||
char *nm;
|
||||
pmix_nspace_t *ns, *nptr;
|
||||
size_t n;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: getnbfn value for proc %s:%d key %s",
|
||||
cb->nspace, cb->rank,
|
||||
(NULL == cb->key) ? "NULL" : cb->key);
|
||||
|
||||
/* if the nspace is empty, then the caller is referencing
|
||||
* our own nspace */
|
||||
if (0 == strlen(cb->nspace)) {
|
||||
nm = pmix_globals.myid.nspace;
|
||||
} else {
|
||||
nm = (char*)cb->nspace;
|
||||
}
|
||||
|
||||
/* find the nspace object */
|
||||
nptr = NULL;
|
||||
PMIX_LIST_FOREACH(ns, &pmix_globals.nspaces, pmix_nspace_t) {
|
||||
if (0 == strcmp(nm, ns->nspace)) {
|
||||
nptr = ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL == nptr) {
|
||||
/* we are asking for info about a new nspace - give us
|
||||
* a chance to learn about it from the server. If the
|
||||
* server has never heard of it, the server will return
|
||||
* an error */
|
||||
nptr = PMIX_NEW(pmix_nspace_t);
|
||||
(void)strncpy(nptr->nspace, nm, PMIX_MAX_NSLEN);
|
||||
pmix_list_append(&pmix_globals.nspaces, &nptr->super);
|
||||
/* there is no point in looking for data in this nspace
|
||||
* object, so let's just go generate the request */
|
||||
goto request;
|
||||
}
|
||||
|
||||
/* the requested data could be in the job-data table, so let's
|
||||
* just check there first. */
|
||||
if (PMIX_SUCCESS == (rc = pmix_hash_fetch(&nptr->internal, PMIX_RANK_WILDCARD, cb->key, &val))) {
|
||||
/* found it - we are in an event, so we can
|
||||
* just execute the callback */
|
||||
cb->value_cbfunc(rc, val, cb->cbdata);
|
||||
/* cleanup */
|
||||
if (NULL != val) {
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
}
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
if (PMIX_RANK_WILDCARD == cb->rank) {
|
||||
/* can't be anywhere else */
|
||||
cb->value_cbfunc(PMIX_ERR_NOT_FOUND, NULL, cb->cbdata);
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* it could still be in the job-data table, only stored under its own
|
||||
* rank and not WILDCARD - e.g., this is true of data returned about
|
||||
* ourselves during startup */
|
||||
if (PMIX_SUCCESS == (rc = pmix_hash_fetch(&nptr->internal, cb->rank, cb->key, &val))) {
|
||||
/* found it - we are in an event, so we can
|
||||
* just execute the callback */
|
||||
cb->value_cbfunc(rc, val, cb->cbdata);
|
||||
/* cleanup */
|
||||
if (NULL != val) {
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
}
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* not finding it is not an error - it could be in the
|
||||
* modex hash table, so check it */
|
||||
if (PMIX_SUCCESS == (rc = pmix_hash_fetch(&nptr->modex, cb->rank, cb->key, &val))) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: value retrieved from dstore");
|
||||
/* found it - we are in an event, so we can
|
||||
* just execute the callback */
|
||||
cb->value_cbfunc(rc, val, cb->cbdata);
|
||||
/* cleanup */
|
||||
if (NULL != val) {
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
}
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
} else if (PMIX_ERR_NOT_FOUND == rc) {
|
||||
/* we have the modex data from this proc, but didn't find the key
|
||||
* the user requested. At this time, there is no way for the
|
||||
* key to eventually be found, so all we can do is return
|
||||
* the error */
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"Error requesting key=%s for rank = %d, namespace = %s",
|
||||
cb->key, cb->rank, nm);
|
||||
cb->value_cbfunc(rc, NULL, cb->cbdata);
|
||||
/* protect the data */
|
||||
cb->procs = NULL;
|
||||
cb->key = NULL;
|
||||
cb->info = NULL;
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
request:
|
||||
/* if we got here, then we don't have the data for this proc. If we
|
||||
* are a server, or we are a client and not connected, then there is
|
||||
* nothing more we can do */
|
||||
if (pmix_globals.server || (!pmix_globals.server && !pmix_globals.connected)) {
|
||||
cb->value_cbfunc(PMIX_ERR_NOT_FOUND, NULL, cb->cbdata);
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we also have to check the user's directives to see if they do not want
|
||||
* us to attempt to retrieve it from the server */
|
||||
for (n=0; n < cb->ninfo; n++) {
|
||||
if (0 == strcmp(cb->info[n].key, PMIX_OPTIONAL) &&
|
||||
cb->info[n].value.data.flag) {
|
||||
/* they don't want us to try and retrieve it */
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"PMIx_Get key=%s for rank = %d, namespace = %s was not found - request was optional",
|
||||
cb->key, cb->rank, nm);
|
||||
cb->value_cbfunc(PMIX_ERR_NOT_FOUND, NULL, cb->cbdata);
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if we already have a request in place with the server for data from
|
||||
* this nspace:rank. If we do, then no need to ask again as the
|
||||
* request will return _all_ data from that proc */
|
||||
PMIX_LIST_FOREACH(cbret, &pmix_client_globals.pending_requests, pmix_cb_t) {
|
||||
if (0 == strncmp(cbret->nspace, nm, PMIX_MAX_NSLEN) &&
|
||||
cbret->rank == cb->rank) {
|
||||
/* we do have a pending request, but we still need to track this
|
||||
* outstanding request so we can satisfy it once the data is returned */
|
||||
pmix_list_append(&pmix_client_globals.pending_requests, &cb->super);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* we don't have a pending request, so let's create one - don't worry
|
||||
* about packing the key as we return everything from that proc */
|
||||
msg = pack_get(nm, cb->rank, cb->info, cb->ninfo, PMIX_GETNB_CMD);
|
||||
if (NULL == msg) {
|
||||
cb->value_cbfunc(PMIX_ERROR, NULL, cb->cbdata);
|
||||
PMIX_RELEASE(cb);
|
||||
return;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
pmix_list_append(&pmix_client_globals.pending_requests, &cb->super);
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
PMIX_ACTIVATE_SEND_RECV(&pmix_client_globals.myserver, msg, getnb_cbfunc, cb);
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_CLIENT_OPS_H
|
||||
#define PMIX_CLIENT_OPS_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
typedef struct {
|
||||
pmix_peer_t myserver; // messaging support to/from my server
|
||||
pmix_list_t pending_requests; // list of pmix_cb_t pending data requests
|
||||
} pmix_client_globals_t;
|
||||
|
||||
extern pmix_client_globals_t pmix_client_globals;
|
||||
|
||||
void pmix_client_process_nspace_blob(const char *nspace, pmix_buffer_t *bptr);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_CLIENT_OPS_H */
|
@ -1,225 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
|
||||
#include <pmix.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/progress_threads.h"
|
||||
#include "src/usock/usock.h"
|
||||
#include "src/sec/pmix_sec.h"
|
||||
|
||||
#include "pmix_client_ops.h"
|
||||
|
||||
static void wait_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata);
|
||||
static void spawn_cbfunc(int status, char nspace[], void *cbdata);
|
||||
|
||||
int PMIx_Spawn(const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
char nspace[])
|
||||
{
|
||||
int rc;
|
||||
pmix_cb_t *cb;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: spawn called");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
/* ensure the nspace (if provided) is initialized */
|
||||
if (NULL != nspace) {
|
||||
memset(nspace, 0, PMIX_MAX_NSLEN+1);
|
||||
}
|
||||
|
||||
/* create a callback object */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->active = true;
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Spawn_nb(job_info, ninfo, apps, napps, spawn_cbfunc, cb))) {
|
||||
PMIX_RELEASE(cb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* wait for the result */
|
||||
PMIX_WAIT_FOR_COMPLETION(cb->active);
|
||||
rc = cb->status;
|
||||
if (NULL != nspace) {
|
||||
(void)strncpy(nspace, cb->nspace, PMIX_MAX_NSLEN);
|
||||
}
|
||||
PMIX_RELEASE(cb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
pmix_status_t PMIx_Spawn_nb(const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
pmix_spawn_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_buffer_t *msg;
|
||||
pmix_cmd_t cmd = PMIX_SPAWNNB_CMD;
|
||||
pmix_status_t rc;
|
||||
pmix_cb_t *cb;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix: spawn called");
|
||||
|
||||
if (pmix_globals.init_cntr <= 0) {
|
||||
return PMIX_ERR_INIT;
|
||||
}
|
||||
|
||||
/* if we aren't connected, don't attempt to send */
|
||||
if (!pmix_globals.connected) {
|
||||
return PMIX_ERR_UNREACH;
|
||||
}
|
||||
|
||||
msg = PMIX_NEW(pmix_buffer_t);
|
||||
/* pack the cmd */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &cmd, 1, PMIX_CMD))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* pack the job-level directives */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &ninfo, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
if (0 < ninfo) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, job_info, ninfo, PMIX_INFO))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* pack the apps */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, &napps, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(msg, apps, napps, PMIX_APP))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_RELEASE(msg);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* create a callback object as we need to pass it to the
|
||||
* recv routine so we know which callback to use when
|
||||
* the return message is recvd */
|
||||
cb = PMIX_NEW(pmix_cb_t);
|
||||
cb->spawn_cbfunc = cbfunc;
|
||||
cb->cbdata = cbdata;
|
||||
|
||||
/* push the message into our event base to send to the server */
|
||||
PMIX_ACTIVATE_SEND_RECV(&pmix_client_globals.myserver, msg, wait_cbfunc, cb);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* callback for wait completion */
|
||||
static void wait_cbfunc(struct pmix_peer_t *pr, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
char nspace[PMIX_MAX_NSLEN+1];
|
||||
char *n2;
|
||||
pmix_status_t rc, ret;
|
||||
int32_t cnt;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"pmix:client recv callback activated with %d bytes",
|
||||
(NULL == buf) ? -1 : (int)buf->bytes_used);
|
||||
|
||||
/* init */
|
||||
memset(nspace, 0, PMIX_MAX_NSLEN+1);
|
||||
|
||||
/* unpack the returned status */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &ret, &cnt, PMIX_INT))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
ret = rc;
|
||||
}
|
||||
if (PMIX_SUCCESS == ret) {
|
||||
/* unpack the namespace */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &n2, &cnt, PMIX_STRING))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
ret = rc;
|
||||
}
|
||||
if (NULL != n2) {
|
||||
(void)strncpy(nspace, n2, PMIX_MAX_NSLEN);
|
||||
/* extract and process any proc-related info for this nspace */
|
||||
pmix_client_process_nspace_blob(nspace, buf);
|
||||
free(n2);
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL != cb->spawn_cbfunc) {
|
||||
cb->spawn_cbfunc(ret, nspace, cb->cbdata);
|
||||
}
|
||||
}
|
||||
|
||||
static void spawn_cbfunc(pmix_status_t status, char nspace[], void *cbdata)
|
||||
{
|
||||
pmix_cb_t *cb = (pmix_cb_t*)cbdata;
|
||||
|
||||
cb->status = status;
|
||||
if (NULL != nspace) {
|
||||
(void)strncpy(cb->nspace, nspace, PMIX_MAX_NSLEN);
|
||||
}
|
||||
cb->active = false;
|
||||
}
|
||||
|
@ -1,44 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
#include <private/pmix_socket_errno.h>
|
||||
|
||||
#include <pmix.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
#include <pmix_server.h>
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
void PMIx_Register_errhandler(pmix_info_t info[], size_t ninfo,
|
||||
pmix_notification_fn_t errhandler,
|
||||
pmix_errhandler_reg_cbfunc_t cbfunc,
|
||||
void *cbdata)
|
||||
{
|
||||
/* common err handler registration to be added */
|
||||
}
|
||||
|
||||
void PMIx_Deregister_errhandler(int errhandler_ref,
|
||||
pmix_op_cbfunc_t cbfunc,
|
||||
void *cbdata)
|
||||
{
|
||||
/* common err handler deregistration goes here */
|
||||
}
|
||||
|
||||
pmix_status_t PMIx_Notify_error(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_proc_t error_procs[], size_t error_nprocs,
|
||||
pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
/* common err notify goes here */
|
||||
return PMIX_SUCCESS;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
# University Research and Technology
|
||||
# Corporation. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
# of Tennessee Research Foundation. All rights
|
||||
# reserved.
|
||||
# Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
# University of Stuttgart. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2007 Cisco Systems, Inc. All rights reserved.
|
||||
# Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
# This makefile.am does not stand on its own - it is included from
|
||||
# src/Makefile.am
|
||||
|
||||
headers += \
|
||||
src/include/pmix_globals.h
|
||||
|
||||
sources += \
|
||||
src/include/pmix_globals.c
|
@ -1,157 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014-2015 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/* THIS FILE IS INCLUDED SOLELY TO INSTANTIATE AND INIT/FINALIZE THE GLOBAL CLASSES */
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
#include <private/pmix_socket_errno.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
#include "src/class/pmix_list.h"
|
||||
|
||||
|
||||
pmix_globals_t pmix_globals = {
|
||||
.init_cntr = 0,
|
||||
.pindex = 0,
|
||||
.evbase = NULL,
|
||||
.debug_output = -1,
|
||||
.errhandler = NULL,
|
||||
.server = false,
|
||||
.connected = false,
|
||||
.cache_local = NULL,
|
||||
.cache_remote = NULL
|
||||
};
|
||||
|
||||
|
||||
void pmix_globals_init(void)
|
||||
{
|
||||
memset(&pmix_globals.myid, 0, sizeof(pmix_proc_t));
|
||||
PMIX_CONSTRUCT(&pmix_globals.nspaces, pmix_list_t);
|
||||
}
|
||||
|
||||
void pmix_globals_finalize(void)
|
||||
{
|
||||
PMIX_LIST_DESTRUCT(&pmix_globals.nspaces);
|
||||
if (NULL != pmix_globals.cache_local) {
|
||||
PMIX_RELEASE(pmix_globals.cache_local);
|
||||
}
|
||||
if (NULL != pmix_globals.cache_remote) {
|
||||
PMIX_RELEASE(pmix_globals.cache_remote);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void nscon(pmix_nspace_t *p)
|
||||
{
|
||||
memset(p->nspace, 0, PMIX_MAX_NSLEN);
|
||||
PMIX_CONSTRUCT(&p->nodes, pmix_list_t);
|
||||
PMIX_CONSTRUCT(&p->internal, pmix_hash_table_t);
|
||||
pmix_hash_table_init(&p->internal, 16);
|
||||
PMIX_CONSTRUCT(&p->modex, pmix_hash_table_t);
|
||||
pmix_hash_table_init(&p->modex, 256);
|
||||
p->server = NULL;
|
||||
}
|
||||
static void nsdes(pmix_nspace_t *p)
|
||||
{
|
||||
PMIX_LIST_DESTRUCT(&p->nodes);
|
||||
PMIX_DESTRUCT(&p->internal);
|
||||
PMIX_DESTRUCT(&p->modex);
|
||||
if (NULL != p->server) {
|
||||
PMIX_RELEASE(p->server);
|
||||
}
|
||||
}
|
||||
PMIX_CLASS_INSTANCE(pmix_nspace_t,
|
||||
pmix_list_item_t,
|
||||
nscon, nsdes);
|
||||
|
||||
static void ncon(pmix_nrec_t *p)
|
||||
{
|
||||
p->name = NULL;
|
||||
p->procs = NULL;
|
||||
}
|
||||
static void ndes(pmix_nrec_t *p)
|
||||
{
|
||||
if (NULL != p->name) {
|
||||
free(p->name);
|
||||
}
|
||||
if (NULL != p->procs) {
|
||||
free(p->procs);
|
||||
}
|
||||
}
|
||||
PMIX_CLASS_INSTANCE(pmix_nrec_t,
|
||||
pmix_list_item_t,
|
||||
ncon, ndes);
|
||||
|
||||
static void sncon(pmix_server_nspace_t *p)
|
||||
{
|
||||
p->nlocalprocs = 0;
|
||||
p->all_registered = false;
|
||||
PMIX_CONSTRUCT(&p->job_info, pmix_buffer_t);
|
||||
PMIX_CONSTRUCT(&p->ranks, pmix_list_t);
|
||||
PMIX_CONSTRUCT(&p->mylocal, pmix_hash_table_t);
|
||||
pmix_hash_table_init(&p->mylocal, 16);
|
||||
PMIX_CONSTRUCT(&p->myremote, pmix_hash_table_t);
|
||||
pmix_hash_table_init(&p->myremote, 16);
|
||||
PMIX_CONSTRUCT(&p->remote, pmix_hash_table_t);
|
||||
pmix_hash_table_init(&p->remote, 256);
|
||||
}
|
||||
static void sndes(pmix_server_nspace_t *p)
|
||||
{
|
||||
PMIX_DESTRUCT(&p->job_info);
|
||||
PMIX_LIST_DESTRUCT(&p->ranks);
|
||||
PMIX_DESTRUCT(&p->mylocal);
|
||||
PMIX_DESTRUCT(&p->myremote);
|
||||
PMIX_DESTRUCT(&p->remote);
|
||||
}
|
||||
PMIX_CLASS_INSTANCE(pmix_server_nspace_t,
|
||||
pmix_object_t,
|
||||
sncon, sndes);
|
||||
|
||||
static void info_con(pmix_rank_info_t *info)
|
||||
{
|
||||
info->gid = info->uid = 0;
|
||||
info->nptr = NULL;
|
||||
info->rank = PMIX_RANK_WILDCARD;
|
||||
info->modex_recvd = false;
|
||||
info->proc_cnt = 0;
|
||||
info->server_object = NULL;
|
||||
}
|
||||
static void info_des(pmix_rank_info_t *info)
|
||||
{
|
||||
if (NULL!= info->nptr) {
|
||||
PMIX_RELEASE(info->nptr);
|
||||
}
|
||||
}
|
||||
PMIX_CLASS_INSTANCE(pmix_rank_info_t,
|
||||
pmix_list_item_t,
|
||||
info_con, info_des);
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_GLOBALS_H
|
||||
#define PMIX_GLOBALS_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
#include "src/class/pmix_list.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
#define PMIX_MAX_CRED_SIZE 131072 // set max at 128kbytes
|
||||
|
||||
/* define a global construct that includes values that must be shared
|
||||
* between various parts of the code library. Both the client
|
||||
* and server libraries must instance this structure */
|
||||
typedef struct {
|
||||
int init_cntr; // #times someone called Init - #times called Finalize
|
||||
pmix_proc_t myid;
|
||||
uid_t uid; // my effective uid
|
||||
gid_t gid; // my effective gid
|
||||
int pindex;
|
||||
pmix_event_base_t *evbase;
|
||||
int debug_output;
|
||||
pmix_notification_fn_t errhandler;
|
||||
bool server;
|
||||
bool connected;
|
||||
pmix_list_t nspaces; // list of pmix_nspace_t for the nspaces we know about
|
||||
pmix_buffer_t *cache_local; // data PUT by me to local scope
|
||||
pmix_buffer_t *cache_remote; // data PUT by me to remote scope
|
||||
} pmix_globals_t;
|
||||
|
||||
/* objects for tracking active nspaces */
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
size_t nlocalprocs;
|
||||
bool all_registered; // all local ranks have been defined
|
||||
pmix_buffer_t job_info; // packed copy of the job-level info to be delivered to each proc
|
||||
pmix_list_t ranks; // list of pmix_rank_info_t for connection support of my clients
|
||||
pmix_hash_table_t mylocal; // hash_table for storing data PUT with local/global scope by my clients
|
||||
pmix_hash_table_t myremote; // hash_table for storing data PUT with remote/global scope by my clients
|
||||
pmix_hash_table_t remote; // hash_table for storing data PUT with remote/global scope recvd from remote clients via modex
|
||||
} pmix_server_nspace_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_server_nspace_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
char nspace[PMIX_MAX_NSLEN+1];
|
||||
pmix_list_t nodes; // list of pmix_nrec_t nodes that house procs in this nspace
|
||||
pmix_hash_table_t internal; // hash_table for storing job-level/internal data related to this nspace
|
||||
pmix_hash_table_t modex; // hash_table of received modex data
|
||||
pmix_server_nspace_t *server; // isolate these so the client doesn't instantiate them
|
||||
} pmix_nspace_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_nspace_t);
|
||||
|
||||
typedef struct pmix_rank_info_t {
|
||||
pmix_list_item_t super;
|
||||
pmix_nspace_t *nptr;
|
||||
int rank;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
bool modex_recvd;
|
||||
int proc_cnt; // #clones of this rank we know about
|
||||
void *server_object; // pointer to rank-specific object provided by server
|
||||
} pmix_rank_info_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_rank_info_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
char *name; // name of the node
|
||||
char *procs; // comma-separated list of proc ranks on that node
|
||||
} pmix_nrec_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_nrec_t);
|
||||
|
||||
/* initialize the pmix_global structure */
|
||||
void pmix_globals_init(void);
|
||||
|
||||
/* finalize the pmix_global structure */
|
||||
void pmix_globals_finalize(void);
|
||||
|
||||
extern pmix_globals_t pmix_globals;
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_GLOBALS_H */
|
@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* NOTE: THE MUNGE CLIENT LIBRARY (libmunge) IS LICENSED AS LGPL
|
||||
*
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <munge.h>
|
||||
|
||||
#include "pmix_sec.h"
|
||||
#include "pmix_munge.h"
|
||||
|
||||
static int munge_init(void);
|
||||
static void munge_finalize(void);
|
||||
static char* create_cred(void);
|
||||
static int validate_cred(pmix_peer_t *peer, char *cred);
|
||||
|
||||
pmix_sec_base_module_t pmix_munge_module = {
|
||||
"munge",
|
||||
munge_init,
|
||||
munge_finalize,
|
||||
create_cred,
|
||||
NULL,
|
||||
validate_cred,
|
||||
NULL
|
||||
};
|
||||
|
||||
static char *mycred = NULL;
|
||||
static bool initialized = false;
|
||||
static bool refresh = false;
|
||||
|
||||
static int munge_init(void)
|
||||
{
|
||||
int rc;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge init");
|
||||
|
||||
/* attempt to get a credential as a way of checking that
|
||||
* the munge server is available - cache the credential
|
||||
* for later use */
|
||||
|
||||
if (EMUNGE_SUCCESS != (rc = munge_encode(&mycred, NULL, NULL, 0))) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge failed to create credential: %s",
|
||||
munge_strerror(rc));
|
||||
return PMIX_ERR_SERVER_NOT_AVAIL;
|
||||
}
|
||||
initialized = true;
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void munge_finalize(void)
|
||||
{
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge finalize");
|
||||
if (initialized) {
|
||||
if (NULL != mycred) {
|
||||
free(mycred);
|
||||
mycred = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static char* create_cred(void)
|
||||
{
|
||||
int rc;
|
||||
char *resp=NULL;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge create_cred");
|
||||
|
||||
if (initialized) {
|
||||
if (!refresh) {
|
||||
refresh = true;
|
||||
resp = strdup(mycred);
|
||||
} else {
|
||||
/* munge does not allow reuse of a credential, so we have to
|
||||
* refresh it for every use */
|
||||
if (NULL != mycred) {
|
||||
free(mycred);
|
||||
}
|
||||
if (EMUNGE_SUCCESS != (rc = munge_encode(&mycred, NULL, NULL, 0))) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge failed to create credential: %s",
|
||||
munge_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
resp = strdup(mycred);
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
static int validate_cred(pmix_peer_t *peer, char *cred)
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
munge_err_t rc;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge validate_cred %s", cred);
|
||||
|
||||
/* parse the inbound string */
|
||||
if (EMUNGE_SUCCESS != (rc = munge_decode(cred, NULL, NULL, NULL, &uid, &gid))) {
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge failed to decode credential: %s",
|
||||
munge_strerror(rc));
|
||||
return PMIX_ERR_INVALID_CRED;
|
||||
}
|
||||
|
||||
/* check uid */
|
||||
if (uid != peer->info->uid) {
|
||||
return PMIX_ERR_INVALID_CRED;
|
||||
}
|
||||
|
||||
/* check guid */
|
||||
if (gid != peer->info->gid) {
|
||||
return PMIX_ERR_INVALID_CRED;
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: munge credential valid");
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_MUNGE_H
|
||||
#define PMIX_MUNGE_H
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
extern pmix_sec_base_module_t pmix_munge_module;
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif
|
@ -1,108 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "pmix_sec.h"
|
||||
#include "pmix_native.h"
|
||||
|
||||
static int native_init(void);
|
||||
static void native_finalize(void);
|
||||
static char* create_cred(void);
|
||||
static int validate_cred(pmix_peer_t *peer, char *cred);
|
||||
|
||||
pmix_sec_base_module_t pmix_native_module = {
|
||||
"native",
|
||||
native_init,
|
||||
native_finalize,
|
||||
create_cred,
|
||||
NULL,
|
||||
validate_cred,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int native_init(void)
|
||||
{
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: native init");
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void native_finalize(void)
|
||||
{
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: native finalize");
|
||||
}
|
||||
|
||||
static char* create_cred(void)
|
||||
{
|
||||
char *cred;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: native create_cred");
|
||||
|
||||
/* print them and return the string */
|
||||
(void)asprintf(&cred, "%lu:%lu", (unsigned long)pmix_globals.uid,
|
||||
(unsigned long)pmix_globals.gid);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: using credential %s", cred);
|
||||
|
||||
return cred;
|
||||
}
|
||||
|
||||
static int validate_cred(pmix_peer_t *peer, char *cred)
|
||||
{
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
char **vals;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: native validate_cred %s", cred);
|
||||
|
||||
/* parse the inbound string */
|
||||
vals = pmix_argv_split(cred, ':');
|
||||
if (2 != pmix_argv_count(vals)) {
|
||||
pmix_argv_free(vals);
|
||||
return PMIX_ERR_INVALID_CRED;
|
||||
}
|
||||
|
||||
/* check uid */
|
||||
uid = strtoul(vals[0], NULL, 10);
|
||||
if (uid != peer->info->uid) {
|
||||
pmix_argv_free(vals);
|
||||
return PMIX_ERR_INVALID_CRED;
|
||||
}
|
||||
|
||||
/* check guid */
|
||||
gid = strtoul(vals[1], NULL, 10);
|
||||
if (gid != peer->info->gid) {
|
||||
pmix_argv_free(vals);
|
||||
return PMIX_ERR_INVALID_CRED;
|
||||
}
|
||||
pmix_argv_free(vals);
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"sec: native credential valid");
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_NATIVE_H
|
||||
#define PMIX_NATIVE_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/sec/pmix_sec.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
extern pmix_sec_base_module_t pmix_native_module;
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif
|
@ -1,143 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* This interface is designed to serve as a low-weight plugin mechansim
|
||||
* for security support. PMIx doesn't need much in this regard, but we do
|
||||
* need a mechanism for authenticating connections. Dlopen and
|
||||
* friends are not used, but all the functionality is accessed through
|
||||
* struct's of function pointers, so you can swap between multiple
|
||||
* different implementations at run time, just like typical plugins.
|
||||
* Hence, these entities are referred to as "Security
|
||||
* Pseudo-Components" (SPCs).
|
||||
*
|
||||
* The SPCs are referenced by their names (e.g., "sasl", "munge").
|
||||
*
|
||||
* Only *one* SPC will be active in a given system. The SPC to be
|
||||
* used, however, may be selected at runtime by setting the "PMIX_SEC_MODE"
|
||||
* environmental parameter. This param can consist of either:
|
||||
*
|
||||
* a single SPC name - if this SPC is not available, an error will
|
||||
* be returned
|
||||
*
|
||||
* a comma-separated list of SPC names - the available SPCs will be
|
||||
* queried in the specified order. The first one to return "success"
|
||||
* will be selected and used. An error will be returned if none of
|
||||
* the available SPCs return success.
|
||||
*
|
||||
* either of the above, with a '^' as the first character - this
|
||||
* indicates that the specified SPC(s) are to be excluded from
|
||||
* consideration. The remaining SPCs will be queried until one returns
|
||||
* "success" - if none return success, then an error will be returned.
|
||||
*
|
||||
* Module interface:
|
||||
*
|
||||
* module_init(): The PMIx client and server init functions
|
||||
* call pmix_sec_init(), which will invoke this init function on
|
||||
* each SPC to see if it wants to run. SPCs can gracefully
|
||||
* remove themselves from consideration in this process by returning
|
||||
* PMIX_ERR_NOT_SUPPORTED.
|
||||
*
|
||||
* initiate_connection(): Executes the client side of the
|
||||
* authentication procedure. Returns 0 if successful, or
|
||||
* a non-zero error.
|
||||
*
|
||||
* accept_connection(): Executes the server side of the
|
||||
* authentication procedure. Returns 0 if successful, or
|
||||
* a non-zero error.
|
||||
*
|
||||
* module_finalize(): The PMIx client and server finalize functions
|
||||
* call pmix_sec_finalize(), which, in turn, calls the
|
||||
* module_finalize() function on all available SPCs.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_SEC_H
|
||||
#define PMIX_SEC_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/****** MODULE DEFINITION ******/
|
||||
|
||||
/**
|
||||
* Initialize the module. Returns an error if the module cannot
|
||||
* run, success if it can and wants to be used.
|
||||
*/
|
||||
typedef int (*pmix_sec_base_module_init_fn_t)(void);
|
||||
|
||||
/**
|
||||
* Finalize the module. Tear down any allocated storage, disconnect
|
||||
* from any system support (e.g., LDAP server)
|
||||
*/
|
||||
typedef void (*pmix_sec_base_module_fini_fn_t)(void);
|
||||
|
||||
/**** CLIENT-SIDE FUNCTIONS ****/
|
||||
/**
|
||||
* Create and return a string representation of a credential for this
|
||||
* client
|
||||
*/
|
||||
typedef char* (*pmix_sec_base_module_create_cred_fn_t)(void);
|
||||
|
||||
/**
|
||||
* Perform the client-side handshake. Note that it is not required
|
||||
* (and indeed, would be rare) for a protocol to use both the
|
||||
* credential and handshake interfaces. It is acceptable, therefore,
|
||||
* for one of them to be NULL */
|
||||
typedef pmix_status_t (*pmix_sec_base_module_client_hndshk_fn_t)(int sd);
|
||||
|
||||
|
||||
/**** SERVER-SIDE FUNCTIONS ****/
|
||||
/**
|
||||
* Validate a client's credential
|
||||
*/
|
||||
typedef pmix_status_t (*pmix_sec_base_module_validate_cred_fn_t)(pmix_peer_t *peer, char *cred);
|
||||
|
||||
/**
|
||||
* Perform the server-side handshake. Note that it is not required
|
||||
* (and indeed, would be rare) for a protocol to use both the
|
||||
* credential and handshake interfaces. It is acceptable, therefore,
|
||||
* for one of them to be NULL */
|
||||
typedef pmix_status_t (*pmix_sec_base_module_server_hndshk_fn_t)(pmix_peer_t *peer);
|
||||
|
||||
/**
|
||||
* Struct for holding CPC module function pointers
|
||||
*/
|
||||
typedef struct {
|
||||
char *name;
|
||||
/* init/finalize */
|
||||
pmix_sec_base_module_init_fn_t init;
|
||||
pmix_sec_base_module_fini_fn_t finalize;
|
||||
/** Client-side */
|
||||
pmix_sec_base_module_create_cred_fn_t create_cred;
|
||||
pmix_sec_base_module_client_hndshk_fn_t client_handshake;
|
||||
/** Server-side */
|
||||
pmix_sec_base_module_validate_cred_fn_t validate_cred;
|
||||
pmix_sec_base_module_server_hndshk_fn_t server_handshake;
|
||||
} pmix_sec_base_module_t;
|
||||
|
||||
PMIX_DECLSPEC extern pmix_sec_base_module_t pmix_sec;
|
||||
|
||||
/* initialize and finalize the security system */
|
||||
PMIX_DECLSPEC int pmix_sec_init(void);
|
||||
PMIX_DECLSPEC void pmix_sec_finalize(void);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@ -1,551 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014-2015 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
#include <private/pmix_socket_errno.h>
|
||||
|
||||
#include <pmix_server.h>
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/pmix_environ.h"
|
||||
#include "src/util/progress_threads.h"
|
||||
#include "src/usock/usock.h"
|
||||
#include "src/sec/pmix_sec.h"
|
||||
|
||||
#include "pmix_server_ops.h"
|
||||
|
||||
extern pmix_server_module_t pmix_host_server;
|
||||
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
pmix_status_t status;
|
||||
const char *data;
|
||||
size_t ndata;
|
||||
pmix_dmdx_local_t *lcd;
|
||||
pmix_release_cbfunc_t relcbfunc;
|
||||
void *cbdata;
|
||||
} pmix_dmdx_reply_caddy_t;
|
||||
static void dcd_con(pmix_dmdx_reply_caddy_t *p)
|
||||
{
|
||||
p->status = PMIX_ERROR;
|
||||
p->ndata = 0;
|
||||
p->lcd = NULL;
|
||||
p->relcbfunc = NULL;
|
||||
p->cbdata = NULL;
|
||||
}
|
||||
PMIX_CLASS_INSTANCE(pmix_dmdx_reply_caddy_t,
|
||||
pmix_object_t, dcd_con, NULL);
|
||||
|
||||
|
||||
static void dmdx_cbfunc(pmix_status_t status, const char *data,
|
||||
size_t ndata, void *cbdata,
|
||||
pmix_release_cbfunc_t relfn, void *relcbdata);
|
||||
static pmix_status_t _satisfy_request(pmix_hash_table_t *ht, int rank,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t create_local_tracker(char nspace[], int rank,
|
||||
pmix_info_t info[], size_t ninfo,
|
||||
pmix_modex_cbfunc_t cbfunc,
|
||||
void *cbdata,
|
||||
pmix_dmdx_local_t **lcd);
|
||||
|
||||
|
||||
/* declare a function whose sole purpose is to
|
||||
* free data that we provided to our host server
|
||||
* when servicing dmodex requests */
|
||||
static void relfn(void *cbdata)
|
||||
{
|
||||
char *data = (char*)cbdata;
|
||||
free(data);
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_server_get(pmix_buffer_t *buf,
|
||||
pmix_modex_cbfunc_t cbfunc,
|
||||
void *cbdata)
|
||||
{
|
||||
int32_t cnt;
|
||||
pmix_status_t rc;
|
||||
int rank;
|
||||
char *cptr;
|
||||
char nspace[PMIX_MAX_NSLEN+1];
|
||||
pmix_nspace_t *ns, *nptr;
|
||||
pmix_info_t *info=NULL;
|
||||
size_t ninfo=0;
|
||||
pmix_dmdx_local_t *lcd;
|
||||
pmix_rank_info_t *iptr;
|
||||
pmix_hash_table_t *ht;
|
||||
bool local;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"recvd GET");
|
||||
|
||||
/* setup */
|
||||
memset(nspace, 0, sizeof(nspace));
|
||||
|
||||
/* retrieve the nspace and rank of the requested proc */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &cptr, &cnt, PMIX_STRING))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
(void)strncpy(nspace, cptr, PMIX_MAX_NSLEN);
|
||||
free(cptr);
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &rank, &cnt, PMIX_INT))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
/* retrieve any provided info structs */
|
||||
cnt = 1;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, &ninfo, &cnt, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
if (0 < ninfo) {
|
||||
PMIX_INFO_CREATE(info, ninfo);
|
||||
cnt = ninfo;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.unpack(buf, info, &cnt, PMIX_INFO))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
PMIX_INFO_FREE(info, ninfo);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
/* find the nspace object for this client */
|
||||
nptr = NULL;
|
||||
PMIX_LIST_FOREACH(ns, &pmix_globals.nspaces, pmix_nspace_t) {
|
||||
if (0 == strcmp(nspace, ns->nspace)) {
|
||||
nptr = ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"%s:%d EXECUTE GET FOR %s:%d",
|
||||
pmix_globals.myid.nspace,
|
||||
pmix_globals.myid.rank, nspace, rank);
|
||||
|
||||
if (NULL == nptr || NULL == nptr->server) {
|
||||
/* this is for an nspace we don't know about yet, so
|
||||
* record the request for data from this process and
|
||||
* give the host server a chance to tell us about it */
|
||||
rc = create_local_tracker(nspace, rank, info, ninfo,
|
||||
cbfunc, cbdata, &lcd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* We have to wait for all local clients to be registered before
|
||||
* we can know whether this request is for data from a local or a
|
||||
* remote client because one client might ask for data about another
|
||||
* client that the host RM hasn't told us about yet. Fortunately,
|
||||
* we do know how many clients to expect, so first check to see if
|
||||
* all clients have been registered with us */
|
||||
if (!nptr->server->all_registered) {
|
||||
/* we cannot do anything further, so just track this request
|
||||
* for now */
|
||||
rc = create_local_tracker(nspace, rank, info, ninfo,
|
||||
cbfunc, cbdata, &lcd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Since we know about all the local clients in this nspace,
|
||||
* let's first try to satisfy the request with any available data.
|
||||
* By default, we assume we are looking for data from a remote
|
||||
* client, and then check to see if this is one of my local
|
||||
* clients - if so, then we look in that hash table */
|
||||
ht = &nptr->server->remote;
|
||||
local = false;
|
||||
PMIX_LIST_FOREACH(iptr, &nptr->server->ranks, pmix_rank_info_t) {
|
||||
if (iptr->rank == rank) {
|
||||
/* it is known local client - check the local table */
|
||||
ht = &nptr->server->mylocal;
|
||||
local = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* see if we already have this data */
|
||||
rc = _satisfy_request(ht, rank, cbfunc, cbdata);
|
||||
if( PMIX_SUCCESS == rc ){
|
||||
/* request was successfully satisfied */
|
||||
PMIX_INFO_FREE(info, ninfo);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* If we get here, then we don't have the data at this time. Check
|
||||
* to see if we already have a pending request for the data - if
|
||||
* we do, then we can just wait for it to arrive */
|
||||
rc = create_local_tracker(nspace, rank, info, ninfo,
|
||||
cbfunc, cbdata, &lcd);
|
||||
if (PMIX_SUCCESS == rc) {
|
||||
/* we are already waiting for the data - nothing more
|
||||
* for us to do as the function added the new request
|
||||
* to the tracker for us */
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
if (PMIX_ERR_NOT_FOUND != rc || NULL == lcd) {
|
||||
/* we have a problem - e.g., out of memory */
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Getting here means that we didn't already have a request for
|
||||
* for data pending, and so we created a new tracker for this
|
||||
* request. We know the identity of all our local clients, so
|
||||
* if this is one, then we have nothing further to do - we will
|
||||
* fulfill the request once the process commits its data */
|
||||
if (local) {
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* this isn't a local client of ours, so we need to ask the host
|
||||
* resource manager server to please get the info for us from
|
||||
* whomever is hosting the target process */
|
||||
if (NULL != pmix_host_server.direct_modex) {
|
||||
rc = pmix_host_server.direct_modex(&lcd->proc, info, ninfo, dmdx_cbfunc, lcd);
|
||||
} else {
|
||||
/* if we don't have direct modex feature, just respond with "not found" */
|
||||
cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, cbdata, NULL, NULL);
|
||||
PMIX_INFO_FREE(info, ninfo);
|
||||
pmix_list_remove_item(&pmix_server_globals.local_reqs, &lcd->super);
|
||||
PMIX_LIST_DESTRUCT(&lcd->loc_reqs);
|
||||
PMIX_RELEASE(lcd);
|
||||
rc = PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static pmix_status_t create_local_tracker(char nspace[], int rank,
|
||||
pmix_info_t info[], size_t ninfo,
|
||||
pmix_modex_cbfunc_t cbfunc,
|
||||
void *cbdata,
|
||||
pmix_dmdx_local_t **ld)
|
||||
{
|
||||
pmix_dmdx_local_t *lcd, *cd;
|
||||
pmix_dmdx_request_t *req;
|
||||
pmix_status_t rc;
|
||||
|
||||
/* define default */
|
||||
*ld = NULL;
|
||||
|
||||
/* see if we already have an existing request for data
|
||||
* from this namespace/rank */
|
||||
lcd = NULL;
|
||||
PMIX_LIST_FOREACH(cd, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) {
|
||||
if (0 != strncmp(nspace, cd->proc.nspace, PMIX_MAX_NSLEN) ||
|
||||
rank != cd->proc.rank ) {
|
||||
continue;
|
||||
}
|
||||
lcd = cd;
|
||||
break;
|
||||
}
|
||||
if (NULL != lcd) {
|
||||
/* we already have a request, so just track that someone
|
||||
* else wants data from the same target */
|
||||
rc = PMIX_SUCCESS; // indicates we found an existing request
|
||||
goto complete;
|
||||
}
|
||||
/* we do not have an existing request, so let's create
|
||||
* one and add it to our list */
|
||||
lcd = PMIX_NEW(pmix_dmdx_local_t);
|
||||
if (NULL == lcd){
|
||||
PMIX_INFO_FREE(info, ninfo);
|
||||
return PMIX_ERR_NOMEM;
|
||||
}
|
||||
strncpy(lcd->proc.nspace, nspace, PMIX_MAX_NSLEN);
|
||||
lcd->proc.rank = rank;
|
||||
lcd->info = info;
|
||||
lcd->ninfo = ninfo;
|
||||
pmix_list_append(&pmix_server_globals.local_reqs, &lcd->super);
|
||||
rc = PMIX_ERR_NOT_FOUND; // indicates that we created a new request tracker
|
||||
|
||||
complete:
|
||||
/* track this specific requestor so we return the
|
||||
* data to them */
|
||||
req = PMIX_NEW(pmix_dmdx_request_t);
|
||||
req->cbfunc = cbfunc;
|
||||
req->cbdata = cbdata;
|
||||
pmix_list_append(&lcd->loc_reqs, &req->super);
|
||||
*ld = lcd;
|
||||
return rc;
|
||||
}
|
||||
|
||||
void pmix_pending_nspace_requests(pmix_nspace_t *nptr)
|
||||
{
|
||||
pmix_dmdx_local_t *cd, *cd_next;
|
||||
|
||||
/* Now that we know all local ranks, go along request list and ask for remote data
|
||||
* for the non-local ranks, and resolve all pending requests for local procs
|
||||
* that were waiting for registration to complete
|
||||
*/
|
||||
PMIX_LIST_FOREACH_SAFE(cd, cd_next, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) {
|
||||
pmix_rank_info_t *info;
|
||||
bool found = false;
|
||||
|
||||
if (0 != strncmp(nptr->nspace, cd->proc.nspace, PMIX_MAX_NSLEN) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PMIX_LIST_FOREACH(info, &nptr->server->ranks, pmix_rank_info_t) {
|
||||
if (info->rank == cd->proc.rank) {
|
||||
found = true; // we will satisy this request upon commit from new proc
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* if not found - this is remote process and we need to send
|
||||
* corresponding direct modex request */
|
||||
if( !found ){
|
||||
if( NULL != pmix_host_server.direct_modex ){
|
||||
pmix_host_server.direct_modex(&cd->proc, cd->info, cd->ninfo, dmdx_cbfunc, cd);
|
||||
} else {
|
||||
pmix_dmdx_request_t *req, *req_next;
|
||||
PMIX_LIST_FOREACH_SAFE(req, req_next, &cd->loc_reqs, pmix_dmdx_request_t) {
|
||||
req->cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, req->cbdata, NULL, NULL);
|
||||
pmix_list_remove_item(&cd->loc_reqs, &req->super);
|
||||
PMIX_RELEASE(req);
|
||||
}
|
||||
pmix_list_remove_item(&pmix_server_globals.local_reqs, &cd->super);
|
||||
PMIX_RELEASE(cd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static pmix_status_t _satisfy_request(pmix_hash_table_t *ht, int rank,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_status_t rc;
|
||||
pmix_value_t *val;
|
||||
char *data;
|
||||
size_t sz;
|
||||
pmix_buffer_t xfer, pbkt, *xptr;
|
||||
|
||||
/* check to see if this data already has been
|
||||
* obtained as a result of a prior direct modex request from
|
||||
* a remote peer, or due to data from a local client
|
||||
* having been committed */
|
||||
rc = pmix_hash_fetch(ht, rank, "modex", &val);
|
||||
if (PMIX_SUCCESS == rc && NULL != val) {
|
||||
/* the client is expecting this to arrive as a byte object
|
||||
* containing a buffer, so package it accordingly */
|
||||
PMIX_CONSTRUCT(&pbkt, pmix_buffer_t);
|
||||
PMIX_CONSTRUCT(&xfer, pmix_buffer_t);
|
||||
xptr = &xfer;
|
||||
PMIX_LOAD_BUFFER(&xfer, val->data.bo.bytes, val->data.bo.size);
|
||||
pmix_bfrop.pack(&pbkt, &xptr, 1, PMIX_BUFFER);
|
||||
xfer.base_ptr = NULL; // protect the passed data
|
||||
xfer.bytes_used = 0;
|
||||
PMIX_DESTRUCT(&xfer);
|
||||
PMIX_UNLOAD_BUFFER(&pbkt, data, sz);
|
||||
PMIX_DESTRUCT(&pbkt);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
/* pass it back */
|
||||
cbfunc(rc, data, sz, cbdata, relfn, data);
|
||||
return rc;
|
||||
}
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Resolve pending requests to this namespace/rank */
|
||||
pmix_status_t pmix_pending_resolve(pmix_nspace_t *nptr, int rank,
|
||||
pmix_status_t status, pmix_dmdx_local_t *lcd)
|
||||
{
|
||||
pmix_dmdx_local_t *cd;
|
||||
|
||||
/* find corresponding request (if exists) */
|
||||
if (NULL == lcd && NULL != nptr) {
|
||||
PMIX_LIST_FOREACH(cd, &pmix_server_globals.local_reqs, pmix_dmdx_local_t) {
|
||||
if (0 != strncmp(nptr->nspace, cd->proc.nspace, PMIX_MAX_NSLEN) ||
|
||||
rank != cd->proc.rank) {
|
||||
continue;
|
||||
}
|
||||
lcd = cd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If somebody was interested in this rank */
|
||||
if (NULL != lcd) {
|
||||
pmix_dmdx_request_t *req;
|
||||
|
||||
if (PMIX_SUCCESS != status){
|
||||
/* if we've got an error for this request - just forward it*/
|
||||
PMIX_LIST_FOREACH(req, &lcd->loc_reqs, pmix_dmdx_request_t) {
|
||||
/* if we can't satisfy this request - respond with error */
|
||||
req->cbfunc(status, NULL, 0, req->cbdata, NULL, NULL);
|
||||
}
|
||||
} else if (NULL != nptr) {
|
||||
/* if we've got the blob - try to satisfy requests */
|
||||
pmix_hash_table_t *ht;
|
||||
pmix_rank_info_t *iptr;
|
||||
|
||||
/* by default we are looking for the remote data */
|
||||
ht = &nptr->server->remote;
|
||||
/* check if this rank is local */
|
||||
PMIX_LIST_FOREACH(iptr, &nptr->server->ranks, pmix_rank_info_t) {
|
||||
if (iptr->rank == rank) {
|
||||
ht = &nptr->server->mylocal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* run through all the requests to this rank */
|
||||
PMIX_LIST_FOREACH(req, &lcd->loc_reqs, pmix_dmdx_request_t) {
|
||||
pmix_status_t rc;
|
||||
rc = _satisfy_request(ht, rank, req->cbfunc, req->cbdata);
|
||||
if( PMIX_SUCCESS != rc ){
|
||||
/* if we can't satisfy this particular request (missing key?) */
|
||||
req->cbfunc(rc, NULL, 0, req->cbdata, NULL, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* remove all requests to this rank and cleanup the corresponding structure */
|
||||
pmix_list_remove_item(&pmix_server_globals.local_reqs, (pmix_list_item_t*)lcd);
|
||||
PMIX_RELEASE(lcd);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* process the returned data from the host RM server */
|
||||
static void _process_dmdx_reply(int fd, short args, void *cbdata)
|
||||
{
|
||||
pmix_dmdx_reply_caddy_t *caddy = (pmix_dmdx_reply_caddy_t *)cbdata;
|
||||
pmix_kval_t *kp;
|
||||
pmix_nspace_t *ns, *nptr;
|
||||
pmix_status_t rc;
|
||||
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"[%s:%d] process dmdx reply from %s:%d",
|
||||
__FILE__, __LINE__,
|
||||
caddy->lcd->proc.nspace, caddy->lcd->proc.rank);
|
||||
|
||||
/* find the nspace object for this client */
|
||||
nptr = NULL;
|
||||
PMIX_LIST_FOREACH(ns, &pmix_globals.nspaces, pmix_nspace_t) {
|
||||
if (0 == strcmp(caddy->lcd->proc.nspace, ns->nspace)) {
|
||||
nptr = ns;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (NULL == nptr) {
|
||||
/* should be impossible */
|
||||
PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND);
|
||||
caddy->status = PMIX_ERR_NOT_FOUND;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* if the request was successfully satisfied, then store the data
|
||||
* in our hash table for remote procs. Although we could immediately
|
||||
* resolve any outstanding requests on our tracking list, we instead
|
||||
* store the data first so we can immediately satisfy any future
|
||||
* requests. Then, rather than duplicate the resolve code here, we
|
||||
* will let the pmix_pending_resolve function go ahead and retrieve
|
||||
* it from the hash table */
|
||||
if (PMIX_SUCCESS == caddy->status) {
|
||||
kp = PMIX_NEW(pmix_kval_t);
|
||||
kp->key = strdup("modex");
|
||||
PMIX_VALUE_CREATE(kp->value, 1);
|
||||
kp->value->type = PMIX_BYTE_OBJECT;
|
||||
/* we don't know if the host is going to save this data
|
||||
* or not, so we have to copy it - the client is expecting
|
||||
* this to arrive as a byte object containing a buffer, so
|
||||
* package it accordingly */
|
||||
kp->value->data.bo.bytes = malloc(caddy->ndata);
|
||||
memcpy(kp->value->data.bo.bytes, caddy->data, caddy->ndata);
|
||||
kp->value->data.bo.size = caddy->ndata;
|
||||
/* store it in the appropriate hash */
|
||||
if (PMIX_SUCCESS != (rc = pmix_hash_store(&nptr->server->remote, caddy->lcd->proc.rank, kp))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
}
|
||||
PMIX_RELEASE(kp); // maintain acctg
|
||||
}
|
||||
|
||||
/* always execute the callback to avoid having the client hang */
|
||||
pmix_pending_resolve(nptr, caddy->lcd->proc.rank, caddy->status, caddy->lcd);
|
||||
|
||||
cleanup:
|
||||
/* now call the release function so the host server
|
||||
* knows it can release the data */
|
||||
if (NULL != caddy->relcbfunc) {
|
||||
caddy->relcbfunc(caddy->cbdata);
|
||||
}
|
||||
PMIX_RELEASE(caddy);
|
||||
}
|
||||
|
||||
/* this is the callback function that the host RM server will call
|
||||
* when it gets requested info back from a remote server */
|
||||
static void dmdx_cbfunc(pmix_status_t status,
|
||||
const char *data, size_t ndata, void *cbdata,
|
||||
pmix_release_cbfunc_t release_fn, void *release_cbdata)
|
||||
{
|
||||
pmix_dmdx_reply_caddy_t *caddy;
|
||||
|
||||
/* because the host RM is calling us from their own thread, we
|
||||
* need to thread-shift into our local progress thread before
|
||||
* accessing any global info */
|
||||
caddy = PMIX_NEW(pmix_dmdx_reply_caddy_t);
|
||||
caddy->status = status;
|
||||
/* point to the callers cbfunc */
|
||||
caddy->relcbfunc = release_fn;
|
||||
caddy->cbdata = release_cbdata;
|
||||
|
||||
/* point to the returned data and our own internal
|
||||
* tracker */
|
||||
caddy->data = data;
|
||||
caddy->ndata = ndata;
|
||||
caddy->lcd = (pmix_dmdx_local_t *)cbdata;
|
||||
pmix_output_verbose(2, pmix_globals.debug_output,
|
||||
"[%s:%d] queue dmdx reply for %s:%d",
|
||||
__FILE__, __LINE__,
|
||||
caddy->lcd->proc.nspace, caddy->lcd->proc.rank);
|
||||
event_assign(&caddy->ev, pmix_globals.evbase, -1, EV_WRITE,
|
||||
_process_dmdx_reply, caddy);
|
||||
event_priority_set(&caddy->ev, 0);
|
||||
event_active(&caddy->ev, EV_WRITE, 1);
|
||||
}
|
||||
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@ -1,253 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved
|
||||
* Copyright (c) 2015 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_SERVER_OPS_H
|
||||
#define PMIX_SERVER_OPS_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
#include <pmix_server.h>
|
||||
#include "src/usock/usock.h"
|
||||
#include "src/util/hash.h"
|
||||
|
||||
/* define an object for moving a send
|
||||
* request into the server's event base */
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
int sd;
|
||||
} pmix_snd_caddy_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_snd_caddy_t);
|
||||
|
||||
|
||||
/* define an object for moving a send
|
||||
* request into the server's event base */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_usock_hdr_t hdr;
|
||||
pmix_peer_t *peer;
|
||||
pmix_snd_caddy_t snd;
|
||||
} pmix_server_caddy_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_server_caddy_t);
|
||||
|
||||
typedef enum {
|
||||
PMIX_COLLECT_INVALID = -1,
|
||||
PMIX_COLLECT_NO,
|
||||
PMIX_COLLECT_YES,
|
||||
PMIX_COLLECT_MAX
|
||||
} pmix_collect_t;
|
||||
|
||||
/* define a tracker for collective operations */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_cmd_t type;
|
||||
pmix_proc_t *pcs; // copy of the original array of participants
|
||||
size_t npcs; // number of procs in the array
|
||||
volatile bool active; // flag for waiting for completion
|
||||
bool def_complete; // all local procs have been registered and the trk definition is complete
|
||||
pmix_list_t ranks; // list of pmix_rank_info_t of the local participants
|
||||
pmix_list_t local_cbs; // list of pmix_server_caddy_t for sending result to the local participants
|
||||
uint32_t nlocal; // number of local participants
|
||||
uint32_t local_cnt; // number of local participants who have contributed
|
||||
pmix_info_t *info; // array of info structs
|
||||
size_t ninfo; // number of info structs in array
|
||||
pmix_collect_t collect_type; // whether or not data is to be returned at completion
|
||||
pmix_modex_cbfunc_t modexcbfunc;
|
||||
pmix_op_cbfunc_t op_cbfunc;
|
||||
} pmix_server_trkr_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_server_trkr_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
pmix_server_trkr_t *trk;
|
||||
} pmix_trkr_caddy_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_trkr_caddy_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
volatile bool active;
|
||||
pmix_proc_t proc;
|
||||
uid_t uid;
|
||||
gid_t gid;
|
||||
void *server_object;
|
||||
int nlocalprocs;
|
||||
pmix_info_t *info;
|
||||
size_t ninfo;
|
||||
pmix_op_cbfunc_t opcbfunc;
|
||||
pmix_dmodex_response_fn_t cbfunc;
|
||||
void *cbdata;
|
||||
} pmix_setup_caddy_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_setup_caddy_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
volatile bool active;
|
||||
pmix_status_t status;
|
||||
pmix_proc_t *procs;
|
||||
size_t nprocs;
|
||||
pmix_proc_t *error_procs;
|
||||
size_t error_nprocs;
|
||||
pmix_info_t *info;
|
||||
size_t ninfo;
|
||||
pmix_buffer_t *buf;
|
||||
pmix_op_cbfunc_t cbfunc;
|
||||
void *cbdata;
|
||||
} pmix_notify_caddy_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_notify_caddy_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_setup_caddy_t *cd;
|
||||
} pmix_dmdx_remote_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_dmdx_remote_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_modex_cbfunc_t cbfunc; // cbfunc to be executed when data is available
|
||||
void *cbdata;
|
||||
} pmix_dmdx_request_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_dmdx_request_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_proc_t proc; // id of proc whose data is being requested
|
||||
pmix_list_t loc_reqs; // list of pmix_dmdx_request_t elem's keeping track of
|
||||
// all local ranks that are interested in this namespace-rank
|
||||
pmix_info_t *info; // array of info structs for this request
|
||||
size_t ninfo; // number of info structs
|
||||
} pmix_dmdx_local_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_dmdx_local_t);
|
||||
|
||||
/* connection support */
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
int sd;
|
||||
struct sockaddr addr;
|
||||
} pmix_pending_connection_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_pending_connection_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_pointer_array_t clients; // array of pmix_peer_t local clients
|
||||
pmix_list_t collectives; // list of active pmix_server_trkr_t
|
||||
pmix_list_t remote_pnd; // list of pmix_dmdx_remote_t awaiting arrival of data fror servicing remote req's
|
||||
pmix_list_t local_reqs; // list of pmix_dmdx_local_t awaiting arrival of data from local neighbours
|
||||
volatile bool listen_thread_active; // listen thread is running
|
||||
int listen_socket; // socket listener is watching
|
||||
int stop_thread[2]; // pipe used to stop listener thread
|
||||
pmix_buffer_t gdata; // cache of data given to me for passing to all clients
|
||||
} pmix_server_globals_t;
|
||||
|
||||
#define PMIX_PEER_CADDY(c, p, t) \
|
||||
do { \
|
||||
(c) = PMIX_NEW(pmix_server_caddy_t); \
|
||||
(c)->hdr.tag = (t); \
|
||||
PMIX_RETAIN((p)); \
|
||||
(c)->peer = (p); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_SND_CADDY(c, h, s) \
|
||||
do { \
|
||||
(c) = PMIX_NEW(pmix_server_caddy_t); \
|
||||
(void)memcpy(&(c)->hdr, &(h), sizeof(pmix_usock_hdr_t)); \
|
||||
PMIX_RETAIN((s)); \
|
||||
(c)->snd = (s); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_SETUP_COLLECTIVE(c, t) \
|
||||
do { \
|
||||
(c) = PMIX_NEW(pmix_trkr_caddy_t); \
|
||||
(c)->trk = (t); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_EXECUTE_COLLECTIVE(c, t, f) \
|
||||
do { \
|
||||
PMIX_SETUP_COLLECTIVE(c, t); \
|
||||
event_assign(&((c)->ev), pmix_globals.evbase, -1, \
|
||||
EV_WRITE, (f), (c)); \
|
||||
event_active(&((c)->ev), EV_WRITE, 1); \
|
||||
} while(0);
|
||||
|
||||
|
||||
int pmix_start_listening(struct sockaddr_un *address);
|
||||
void pmix_stop_listening(void);
|
||||
|
||||
bool pmix_server_trk_update(pmix_server_trkr_t *trk);
|
||||
|
||||
void pmix_pending_nspace_requests(pmix_nspace_t *nptr);
|
||||
pmix_status_t pmix_pending_resolve(pmix_nspace_t *nptr, int rank,
|
||||
pmix_status_t status, pmix_dmdx_local_t *lcd);
|
||||
|
||||
|
||||
pmix_status_t pmix_server_abort(pmix_peer_t *peer, pmix_buffer_t *buf,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_commit(pmix_peer_t *peer, pmix_buffer_t *buf);
|
||||
|
||||
pmix_status_t pmix_server_fence(pmix_server_caddy_t *cd,
|
||||
pmix_buffer_t *buf,
|
||||
pmix_modex_cbfunc_t modexcbfunc,
|
||||
pmix_op_cbfunc_t opcbfunc);
|
||||
|
||||
pmix_status_t pmix_server_get(pmix_buffer_t *buf,
|
||||
pmix_modex_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_publish(pmix_peer_t *peer,
|
||||
pmix_buffer_t *buf,
|
||||
pmix_op_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_lookup(pmix_peer_t *peer,
|
||||
pmix_buffer_t *buf,
|
||||
pmix_lookup_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_unpublish(pmix_peer_t *peer,
|
||||
pmix_buffer_t *buf,
|
||||
pmix_op_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_spawn(pmix_peer_t *peer,
|
||||
pmix_buffer_t *buf,
|
||||
pmix_spawn_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_connect(pmix_server_caddy_t *cd,
|
||||
pmix_buffer_t *buf, bool disconnect,
|
||||
pmix_op_cbfunc_t cbfunc);
|
||||
|
||||
void pmix_pack_proc_map(pmix_buffer_t *buf,
|
||||
char **nodes, char **procs);
|
||||
pmix_status_t pmix_regex_parse_nodes(const char *regexp, char ***names);
|
||||
pmix_status_t pmix_regex_parse_procs(const char *regexp, char ***procs);
|
||||
|
||||
void pmix_server_register_errhandler(pmix_info_t info[], size_t ninfo,
|
||||
pmix_notification_fn_t errhandler,
|
||||
pmix_errhandler_reg_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
void pmix_server_deregister_errhandler(int errhandler_ref,
|
||||
pmix_op_cbfunc_t cbfunc,
|
||||
void *cbdata);
|
||||
|
||||
pmix_status_t pmix_server_notify_error(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_proc_t error_procs[], size_t error_nprocs,
|
||||
pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
extern pmix_server_module_t pmix_host_server;
|
||||
extern pmix_server_globals_t pmix_server_globals;
|
||||
|
||||
#endif // PMIX_SERVER_OPS_H
|
@ -1,546 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
|
||||
#include <pmix.h>
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/server/pmix_server_ops.h"
|
||||
|
||||
static pmix_status_t regex_parse_value_ranges(char *base, char *ranges,
|
||||
int num_digits, char *suffix,
|
||||
char ***names);
|
||||
static pmix_status_t regex_parse_value_range(char *base, char *range,
|
||||
int num_digits, char *suffix,
|
||||
char ***names);
|
||||
static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names);
|
||||
static pmix_status_t pmix_regex_extract_ppn(char *regexp, char ***procs);
|
||||
|
||||
/* we need to pass three things to the client:
|
||||
*
|
||||
* (a) the list of nodes involved in this nspace
|
||||
*
|
||||
* (b) the hostname for each proc in this nspace
|
||||
*
|
||||
* (c) the list of procs on each node for reverse lookup
|
||||
*/
|
||||
void pmix_pack_proc_map(pmix_buffer_t *buf,
|
||||
char **nodes, char **procs)
|
||||
{
|
||||
pmix_kval_t kv;
|
||||
pmix_value_t val;
|
||||
pmix_status_t rc;
|
||||
pmix_buffer_t buf2;
|
||||
size_t i, nnodes;
|
||||
|
||||
/* bozo check - need procs for each node */
|
||||
if (pmix_argv_count(nodes) != pmix_argv_count(procs)) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
return;
|
||||
}
|
||||
|
||||
PMIX_CONSTRUCT(&buf2, pmix_buffer_t);
|
||||
PMIX_CONSTRUCT(&kv, pmix_kval_t);
|
||||
kv.value = &val;
|
||||
val.type = PMIX_STRING;
|
||||
|
||||
/* pass the number of nodes involved in this namespace */
|
||||
nnodes = pmix_argv_count(nodes);
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(&buf2, &nnodes, 1, PMIX_SIZE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (i=0; i < nnodes; i++) {
|
||||
/* pass the complete list of procs on this node */
|
||||
kv.key = nodes[i];
|
||||
val.data.string = procs[i];
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(&buf2, &kv, 1, PMIX_KVAL))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
kv.key = NULL;
|
||||
val.data.string = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
kv.key = NULL;
|
||||
val.data.string = NULL;
|
||||
|
||||
/* pass the completed blob */
|
||||
kv.key = PMIX_MAP_BLOB;
|
||||
val.type = PMIX_BYTE_OBJECT;
|
||||
val.data.bo.bytes = buf2.base_ptr;
|
||||
val.data.bo.size = buf2.bytes_used;
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.pack(buf, &kv, 1, PMIX_KVAL))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
}
|
||||
kv.key = NULL;
|
||||
kv.value = NULL;
|
||||
val.data.bo.bytes = NULL;
|
||||
val.data.bo.size = 0;
|
||||
|
||||
cleanup:
|
||||
PMIX_DESTRUCT(&buf2);
|
||||
PMIX_DESTRUCT(&kv);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_regex_parse_nodes(const char *regexp, char ***names)
|
||||
{
|
||||
char *tmp, *ptr;
|
||||
pmix_status_t rc;
|
||||
|
||||
/* set default */
|
||||
*names = NULL;
|
||||
|
||||
/* protect against bozo */
|
||||
if (NULL == regexp) {
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* protect the input string */
|
||||
tmp = strdup(regexp);
|
||||
/* strip the trailing bracket */
|
||||
tmp[strlen(tmp)-1] = '\0';
|
||||
|
||||
/* the regex generator used to create this regex
|
||||
* is tagged at the beginning of the string */
|
||||
if (NULL == (ptr = strchr(tmp, '['))) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
free(tmp);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
*ptr = '\0';
|
||||
++ptr;
|
||||
|
||||
/* if it was done by PMIx, use that parser */
|
||||
if (0 == strcmp(tmp, "pmix")) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_regex_extract_nodes(ptr, names))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
}
|
||||
} else {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
|
||||
rc = PMIX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
free(tmp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
pmix_status_t pmix_regex_parse_procs(const char *regexp, char ***procs)
|
||||
{
|
||||
char *tmp, *ptr;
|
||||
pmix_status_t rc;
|
||||
|
||||
/* set default */
|
||||
*procs = NULL;
|
||||
|
||||
/* protect against bozo */
|
||||
if (NULL == regexp) {
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* protect the input string */
|
||||
tmp = strdup(regexp);
|
||||
/* strip the trailing bracket */
|
||||
tmp[strlen(tmp)-1] = '\0';
|
||||
|
||||
/* the regex generator used to create this regex
|
||||
* is tagged at the beginning of the string */
|
||||
if (NULL == (ptr = strchr(tmp, '['))) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_BAD_PARAM);
|
||||
free(tmp);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
*ptr = '\0';
|
||||
++ptr;
|
||||
|
||||
/* if it was done by PMIx, use that parser */
|
||||
if (0 == strcmp(tmp, "pmix")) {
|
||||
if (PMIX_SUCCESS != (rc = pmix_regex_extract_ppn(ptr, procs))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
}
|
||||
} else {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_NOT_SUPPORTED);
|
||||
rc = PMIX_ERR_NOT_SUPPORTED;
|
||||
}
|
||||
free(tmp);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
static pmix_status_t pmix_regex_extract_nodes(char *regexp, char ***names)
|
||||
{
|
||||
int i, j, k, len;
|
||||
pmix_status_t ret;
|
||||
char *base;
|
||||
char *orig, *suffix;
|
||||
bool found_range = false;
|
||||
bool more_to_come = false;
|
||||
int num_digits;
|
||||
|
||||
/* set the default */
|
||||
*names = NULL;
|
||||
|
||||
if (NULL == regexp) {
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
orig = base = strdup(regexp);
|
||||
if (NULL == base) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE);
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
|
||||
PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output,
|
||||
"pmix:extract:nodes: checking list: %s", regexp));
|
||||
|
||||
do {
|
||||
/* Find the base */
|
||||
len = strlen(base);
|
||||
for (i = 0; i <= len; ++i) {
|
||||
if (base[i] == '[') {
|
||||
/* we found a range. this gets dealt with below */
|
||||
base[i] = '\0';
|
||||
found_range = true;
|
||||
break;
|
||||
}
|
||||
if (base[i] == ',') {
|
||||
/* we found a singleton value, and there are more to come */
|
||||
base[i] = '\0';
|
||||
found_range = false;
|
||||
more_to_come = true;
|
||||
break;
|
||||
}
|
||||
if (base[i] == '\0') {
|
||||
/* we found a singleton value */
|
||||
found_range = false;
|
||||
more_to_come = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == 0 && !found_range) {
|
||||
/* we found a special character at the beginning of the string */
|
||||
free(orig);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
if (found_range) {
|
||||
/* If we found a range, get the number of digits in the numbers */
|
||||
i++; /* step over the [ */
|
||||
for (j=i; j < len; j++) {
|
||||
if (base[j] == ':') {
|
||||
base[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= len) {
|
||||
/* we didn't find the number of digits */
|
||||
free(orig);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
num_digits = strtol(&base[i], NULL, 10);
|
||||
i = j + 1; /* step over the : */
|
||||
/* now find the end of the range */
|
||||
for (j = i; j < len; ++j) {
|
||||
if (base[j] == ']') {
|
||||
base[j] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j >= len) {
|
||||
/* we didn't find the end of the range */
|
||||
free(orig);
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
/* check for a suffix */
|
||||
if (j+1 < len && base[j+1] != ',') {
|
||||
/* find the next comma, if present */
|
||||
for (k=j+1; k < len && base[k] != ','; k++);
|
||||
if (k < len) {
|
||||
base[k] = '\0';
|
||||
}
|
||||
suffix = strdup(&base[j+1]);
|
||||
if (k < len) {
|
||||
base[k] = ',';
|
||||
}
|
||||
j = k-1;
|
||||
} else {
|
||||
suffix = NULL;
|
||||
}
|
||||
PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output,
|
||||
"regex:extract:nodes: parsing range %s %s %s",
|
||||
base, base + i, suffix));
|
||||
|
||||
ret = regex_parse_value_ranges(base, base + i, num_digits, suffix, names);
|
||||
if (NULL != suffix) {
|
||||
free(suffix);
|
||||
}
|
||||
if (PMIX_SUCCESS != ret) {
|
||||
free(orig);
|
||||
return ret;
|
||||
}
|
||||
if (j+1 < len && base[j + 1] == ',') {
|
||||
more_to_come = true;
|
||||
base = &base[j + 2];
|
||||
} else {
|
||||
more_to_come = false;
|
||||
}
|
||||
} else {
|
||||
/* If we didn't find a range, just add the value */
|
||||
if(PMIX_SUCCESS != (ret = pmix_argv_append_nosize(names, base))) {
|
||||
PMIX_ERROR_LOG(ret);
|
||||
free(orig);
|
||||
return ret;
|
||||
}
|
||||
/* step over the comma */
|
||||
i++;
|
||||
/* set base equal to the (possible) next base to look at */
|
||||
base = &base[i];
|
||||
}
|
||||
} while(more_to_come);
|
||||
|
||||
free(orig);
|
||||
|
||||
/* All done */
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse one or more ranges in a set
|
||||
*
|
||||
* @param base The base text of the value name
|
||||
* @param *ranges A pointer to a range. This can contain multiple ranges
|
||||
* (i.e. "1-3,10" or "5" or "9,0100-0130,250")
|
||||
* @param ***names An argv array to add the newly discovered values to
|
||||
*/
|
||||
static pmix_status_t regex_parse_value_ranges(char *base, char *ranges,
|
||||
int num_digits, char *suffix,
|
||||
char ***names)
|
||||
{
|
||||
int i, len;
|
||||
pmix_status_t ret;
|
||||
char *start, *orig;
|
||||
|
||||
/* Look for commas, the separator between ranges */
|
||||
|
||||
len = strlen(ranges);
|
||||
for (orig = start = ranges, i = 0; i < len; ++i) {
|
||||
if (',' == ranges[i]) {
|
||||
ranges[i] = '\0';
|
||||
ret = regex_parse_value_range(base, start, num_digits, suffix, names);
|
||||
if (PMIX_SUCCESS != ret) {
|
||||
PMIX_ERROR_LOG(ret);
|
||||
return ret;
|
||||
}
|
||||
start = ranges + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pick up the last range, if it exists */
|
||||
|
||||
if (start < orig + len) {
|
||||
|
||||
PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output,
|
||||
"regex:parse:ranges: parse range %s (2)", start));
|
||||
|
||||
ret = regex_parse_value_range(base, start, num_digits, suffix, names);
|
||||
if (PMIX_SUCCESS != ret) {
|
||||
PMIX_ERROR_LOG(ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* All done */
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse a single range in a set and add the full names of the values
|
||||
* found to the names argv
|
||||
*
|
||||
* @param base The base text of the value name
|
||||
* @param *ranges A pointer to a single range. (i.e. "1-3" or "5")
|
||||
* @param ***names An argv array to add the newly discovered values to
|
||||
*/
|
||||
static pmix_status_t regex_parse_value_range(char *base, char *range,
|
||||
int num_digits, char *suffix,
|
||||
char ***names)
|
||||
{
|
||||
char *str, tmp[132];
|
||||
size_t i, k, start, end;
|
||||
size_t base_len, len;
|
||||
bool found;
|
||||
pmix_status_t ret;
|
||||
|
||||
if (NULL == base || NULL == range) {
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
len = strlen(range);
|
||||
base_len = strlen(base);
|
||||
/* Silence compiler warnings; start and end are always assigned
|
||||
properly, below */
|
||||
start = end = 0;
|
||||
|
||||
/* Look for the beginning of the first number */
|
||||
|
||||
for (found = false, i = 0; i < len; ++i) {
|
||||
if (isdigit((int) range[i])) {
|
||||
if (!found) {
|
||||
start = atoi(range + i);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND);
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Look for the end of the first number */
|
||||
|
||||
for (found = false; i < len; ++i) {
|
||||
if (!isdigit(range[i])) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Was there no range, just a single number? */
|
||||
|
||||
if (i >= len) {
|
||||
end = start;
|
||||
found = true;
|
||||
} else {
|
||||
/* Nope, there was a range. Look for the beginning of the second
|
||||
* number
|
||||
*/
|
||||
for (; i < len; ++i) {
|
||||
if (isdigit(range[i])) {
|
||||
end = strtol(range + i, NULL, 10);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_NOT_FOUND);
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Make strings for all values in the range */
|
||||
|
||||
len = base_len + num_digits + 32;
|
||||
if (NULL != suffix) {
|
||||
len += strlen(suffix);
|
||||
}
|
||||
str = (char *) malloc(len);
|
||||
if (NULL == str) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE);
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
for (i = start; i <= end; ++i) {
|
||||
memset(str, 0, len);
|
||||
strcpy(str, base);
|
||||
/* we need to zero-pad the digits */
|
||||
for (k=0; k < (size_t)num_digits; k++) {
|
||||
str[k+base_len] = '0';
|
||||
}
|
||||
memset(tmp, 0, 132);
|
||||
snprintf(tmp, 132, "%lu", (unsigned long)i);
|
||||
for (k=0; k < strlen(tmp); k++) {
|
||||
str[base_len + num_digits - k - 1] = tmp[strlen(tmp)-k-1];
|
||||
}
|
||||
/* if there is a suffix, add it */
|
||||
if (NULL != suffix) {
|
||||
strcat(str, suffix);
|
||||
}
|
||||
ret = pmix_argv_append_nosize(names, str);
|
||||
if(PMIX_SUCCESS != ret) {
|
||||
PMIX_ERROR_LOG(ret);
|
||||
free(str);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
free(str);
|
||||
|
||||
/* All done */
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static pmix_status_t pmix_regex_extract_ppn(char *regexp, char ***procs)
|
||||
{
|
||||
char **rngs, **nds, *t, **ps=NULL;
|
||||
int i, j, k, start, end;
|
||||
|
||||
/* split on semi-colons for nodes */
|
||||
nds = pmix_argv_split(regexp, ';');
|
||||
for (j=0; NULL != nds[j]; j++) {
|
||||
/* for each node, split it by comma */
|
||||
rngs = pmix_argv_split(nds[j], ',');
|
||||
/* parse each element */
|
||||
for (i=0; NULL != rngs[i]; i++) {
|
||||
/* look for a range */
|
||||
if (NULL == (t = strchr(rngs[i], '-'))) {
|
||||
/* just one value */
|
||||
pmix_argv_append_nosize(&ps, rngs[i]);
|
||||
} else {
|
||||
/* handle the range */
|
||||
*t = '\0';
|
||||
start = strtol(rngs[i], NULL, 10);
|
||||
++t;
|
||||
end = strtol(t, NULL, 10);
|
||||
for (k=start; k <= end; k++) {
|
||||
asprintf(&t, "%d", k);
|
||||
pmix_argv_append_nosize(&ps, t);
|
||||
free(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
pmix_argv_free(rngs);
|
||||
/* create the node entry */
|
||||
t = pmix_argv_join(ps, ',');
|
||||
pmix_argv_append_nosize(procs, t);
|
||||
free(t);
|
||||
pmix_argv_free(ps);
|
||||
ps = NULL;
|
||||
}
|
||||
|
||||
pmix_argv_free(nds);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
@ -1,290 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef USOCK_H
|
||||
#define USOCK_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_UIO_H
|
||||
#include <sys/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_NET_UIO_H
|
||||
#include <net/uio.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
#include "src/class/pmix_list.h"
|
||||
|
||||
/* define a command type for communicating to the
|
||||
* pmix server */
|
||||
#define PMIX_CMD PMIX_UINT32
|
||||
|
||||
/* define some commands */
|
||||
typedef enum {
|
||||
PMIX_REQ_CMD,
|
||||
PMIX_ABORT_CMD,
|
||||
PMIX_COMMIT_CMD,
|
||||
PMIX_FENCENB_CMD,
|
||||
PMIX_GETNB_CMD,
|
||||
PMIX_FINALIZE_CMD,
|
||||
PMIX_PUBLISHNB_CMD,
|
||||
PMIX_LOOKUPNB_CMD,
|
||||
PMIX_UNPUBLISHNB_CMD,
|
||||
PMIX_SPAWNNB_CMD,
|
||||
PMIX_CONNECTNB_CMD,
|
||||
PMIX_DISCONNECTNB_CMD,
|
||||
PMIX_NOTIFY_CMD
|
||||
} pmix_cmd_t;
|
||||
|
||||
|
||||
/* header for messages */
|
||||
typedef struct {
|
||||
int pindex;
|
||||
uint32_t tag;
|
||||
size_t nbytes;
|
||||
} pmix_usock_hdr_t;
|
||||
|
||||
// forward declaration
|
||||
struct pmix_peer_t;
|
||||
|
||||
/* internally used cbfunc */
|
||||
typedef void (*pmix_usock_cbfunc_t)(struct pmix_peer_t *peer, pmix_usock_hdr_t *hdr,
|
||||
pmix_buffer_t *buf, void *cbdata);
|
||||
|
||||
/* usock structure for sending a message */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_event_t ev;
|
||||
pmix_usock_hdr_t hdr;
|
||||
pmix_buffer_t *data;
|
||||
bool hdr_sent;
|
||||
char *sdptr;
|
||||
size_t sdbytes;
|
||||
} pmix_usock_send_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_usock_send_t);
|
||||
|
||||
/* usock structure for recving a message */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_event_t ev;
|
||||
struct pmix_peer_t *peer;
|
||||
int sd;
|
||||
pmix_usock_hdr_t hdr;
|
||||
char *data;
|
||||
bool hdr_recvd;
|
||||
char *rdptr;
|
||||
size_t rdbytes;
|
||||
} pmix_usock_recv_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_usock_recv_t);
|
||||
|
||||
/* usock structure for tracking posted recvs */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_event_t ev;
|
||||
uint32_t tag;
|
||||
pmix_usock_cbfunc_t cbfunc;
|
||||
void *cbdata;
|
||||
} pmix_usock_posted_recv_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_usock_posted_recv_t);
|
||||
|
||||
/* object for tracking peers - each peer can have multiple
|
||||
* connections. This can occur if the initial app executes
|
||||
* a fork/exec, and the child initiates its own connection
|
||||
* back to the PMIx server. Thus, the trackers should be "indexed"
|
||||
* by the socket, not the process nspace/rank */
|
||||
typedef struct pmix_peer_t {
|
||||
pmix_object_t super;
|
||||
pmix_rank_info_t *info;
|
||||
int proc_cnt;
|
||||
void *server_object;
|
||||
int index;
|
||||
int sd;
|
||||
pmix_event_t send_event; /**< registration with event thread for send events */
|
||||
bool send_ev_active;
|
||||
pmix_event_t recv_event; /**< registration with event thread for recv events */
|
||||
bool recv_ev_active;
|
||||
pmix_list_t send_queue; /**< list of messages to send */
|
||||
pmix_usock_send_t *send_msg; /**< current send in progress */
|
||||
pmix_usock_recv_t *recv_msg; /**< current recv in progress */
|
||||
} pmix_peer_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_peer_t);
|
||||
|
||||
/* usock struct for posting send/recv request */
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
pmix_peer_t *peer;
|
||||
pmix_buffer_t *bfr;
|
||||
pmix_usock_cbfunc_t cbfunc;
|
||||
void *cbdata;
|
||||
} pmix_usock_sr_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_usock_sr_t);
|
||||
|
||||
/* usock struct for tracking ops */
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_event_t ev;
|
||||
volatile bool active;
|
||||
int status;
|
||||
pmix_status_t pstatus;
|
||||
pmix_scope_t scope;
|
||||
pmix_buffer_t data;
|
||||
pmix_usock_cbfunc_t cbfunc;
|
||||
pmix_op_cbfunc_t op_cbfunc;
|
||||
pmix_value_cbfunc_t value_cbfunc;
|
||||
pmix_lookup_cbfunc_t lookup_cbfunc;
|
||||
pmix_spawn_cbfunc_t spawn_cbfunc;
|
||||
void *cbdata;
|
||||
char nspace[PMIX_MAX_NSLEN+1];
|
||||
int rank;
|
||||
char *key;
|
||||
pmix_value_t *value;
|
||||
pmix_proc_t *procs;
|
||||
pmix_info_t *info;
|
||||
size_t ninfo;
|
||||
size_t nvals;
|
||||
} pmix_cb_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_cb_t);
|
||||
|
||||
/* an internal macro for shifting incoming requests
|
||||
* to the internal event thread */
|
||||
#define PMIX_THREAD_SHIFT(c, f) \
|
||||
do { \
|
||||
event_assign(&((c)->ev), pmix_globals.evbase, -1, \
|
||||
EV_WRITE, (f), (c)); \
|
||||
event_active(&((c)->ev), EV_WRITE, 1); \
|
||||
} while(0);
|
||||
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
pmix_event_t ev;
|
||||
void *cbdata;
|
||||
} pmix_timer_t;
|
||||
PMIX_CLASS_DECLARATION(pmix_timer_t);
|
||||
|
||||
/* internal convenience macros */
|
||||
#define PMIX_ACTIVATE_SEND_RECV(p, b, cb, d) \
|
||||
do { \
|
||||
int rc = -1; \
|
||||
pmix_usock_sr_t *ms; \
|
||||
pmix_output_verbose(5, pmix_globals.debug_output, \
|
||||
"[%s:%d] post send to server", \
|
||||
__FILE__, __LINE__); \
|
||||
ms = PMIX_NEW(pmix_usock_sr_t); \
|
||||
ms->peer = (p); \
|
||||
ms->bfr = (b); \
|
||||
ms->cbfunc = (cb); \
|
||||
ms->cbdata = (d); \
|
||||
rc = event_assign(&((ms)->ev), pmix_globals.evbase, -1, \
|
||||
EV_WRITE, pmix_usock_send_recv, (ms)); \
|
||||
pmix_output_verbose(10, pmix_globals.debug_output, \
|
||||
"event_assign returned %d", rc); \
|
||||
event_active(&((ms)->ev), EV_WRITE, 1); \
|
||||
} while(0);
|
||||
|
||||
#define PMIX_ACTIVATE_POST_MSG(ms) \
|
||||
do { \
|
||||
pmix_output_verbose(5, pmix_globals.debug_output, \
|
||||
"[%s:%d] post msg", \
|
||||
__FILE__, __LINE__); \
|
||||
event_assign(&((ms)->ev), pmix_globals.evbase, -1, \
|
||||
EV_WRITE, pmix_usock_process_msg, (ms)); \
|
||||
event_active(&((ms)->ev), EV_WRITE, 1); \
|
||||
} while(0);
|
||||
|
||||
#define CLOSE_THE_SOCKET(socket) \
|
||||
do { \
|
||||
if (0 <= socket) { \
|
||||
shutdown(socket, 2); \
|
||||
close(socket); \
|
||||
socket = -1; \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
|
||||
#define PMIX_WAIT_FOR_COMPLETION(a) \
|
||||
do { \
|
||||
while ((a)) { \
|
||||
usleep(10); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define PMIX_TIMER_EVENT(s, f, d) \
|
||||
do { \
|
||||
pmix_timer_t *tm; \
|
||||
struct timeval tv; \
|
||||
tm = PMIX_NEW(pmix_timer_t); \
|
||||
tm->cbdata = (d); \
|
||||
event_assign(&tm->ev, pmix_globals.evbase, -1, 0, (f), tm); \
|
||||
tv.tv_sec = (s); \
|
||||
tv.tv_usec = 0; \
|
||||
PMIX_OUTPUT_VERBOSE((1, pmix_globals.debug_output, \
|
||||
"defining timer event: %ld sec %ld usec at %s:%d", \
|
||||
(long)tv.tv_sec, (long)tv.tv_usec, \
|
||||
__FILE__, __LINE__)); \
|
||||
event_add(&tm->ev, &tv); \
|
||||
}while(0); \
|
||||
|
||||
|
||||
/* usock common variables */
|
||||
typedef struct {
|
||||
pmix_list_t posted_recvs; // list of pmix_usock_posted_recv_t
|
||||
} pmix_usock_globals_t;
|
||||
extern pmix_usock_globals_t pmix_usock_globals;
|
||||
|
||||
/* usock common functions */
|
||||
void pmix_usock_init(pmix_usock_cbfunc_t cbfunc);
|
||||
void pmix_usock_finalize(void);
|
||||
int pmix_usock_set_nonblocking(int sd);
|
||||
int pmix_usock_set_blocking(int sd);
|
||||
pmix_status_t pmix_usock_send_blocking(int sd, char *ptr, size_t size);
|
||||
pmix_status_t pmix_usock_recv_blocking(int sd, char *data, size_t size);
|
||||
void pmix_usock_send_recv(int sd, short args, void *cbdata);
|
||||
void pmix_usock_send_handler(int sd, short flags, void *cbdata);
|
||||
void pmix_usock_recv_handler(int sd, short flags, void *cbdata);
|
||||
void pmix_usock_process_msg(int fd, short flags, void *cbdata);
|
||||
|
||||
#endif // USOCK_H
|
@ -1,306 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2008 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007 Voltaire. All rights reserved.
|
||||
* Copyright (c) 2012 Los Alamos National Security, LLC. All rights reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Generic routines for "argv"-like handling. Helpful for creating
|
||||
* arrays of strings, especially when creating command lines.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_ARGV_H
|
||||
#define PMIX_ARGV_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**
|
||||
* Append a string (by value) to an new or existing NULL-terminated
|
||||
* argv array.
|
||||
*
|
||||
* @param argc Pointer to the length of the argv array. Must not be
|
||||
* NULL.
|
||||
* @param argv Pointer to an argv array.
|
||||
* @param str Pointer to the string to append.
|
||||
*
|
||||
* @retval PMIX_SUCCESS On success
|
||||
* @retval PMIX_ERROR On failure
|
||||
*
|
||||
* This function adds a string to an argv array of strings by value;
|
||||
* it is permissable to pass a string on the stack as the str
|
||||
* argument to this function.
|
||||
*
|
||||
* To add the first entry to an argv array, call this function with
|
||||
* (*argv == NULL). This function will allocate an array of length
|
||||
* 2; the first entry will point to a copy of the string passed in
|
||||
* arg, the second entry will be set to NULL.
|
||||
*
|
||||
* If (*argv != NULL), it will be realloc'ed to be 1 (char*) larger,
|
||||
* and the next-to-last entry will point to a copy of the string
|
||||
* passed in arg. The last entry will be set to NULL.
|
||||
*
|
||||
* Just to reinforce what was stated above: the string is copied by
|
||||
* value into the argv array; there is no need to keep the original
|
||||
* string (i.e., the arg parameter) after invoking this function.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_append(int *argc, char ***argv, const char *arg) __pmix_attribute_nonnull__(1) __pmix_attribute_nonnull__(3);
|
||||
|
||||
/**
|
||||
* Append to an argv-style array, but ignore the size of the array.
|
||||
*
|
||||
* @param argv Pointer to an argv array.
|
||||
* @param str Pointer to the string to append.
|
||||
*
|
||||
* @retval PMIX_SUCCESS On success
|
||||
* @retval PMIX_ERROR On failure
|
||||
*
|
||||
* This function is identical to the pmix_argv_append() function
|
||||
* except that it does not take a pointer to an argc (integer
|
||||
* representing the size of the array). This is handy for
|
||||
* argv-style arrays that do not have integers that are actively
|
||||
* maintaing their sizes.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_append_nosize(char ***argv, const char *arg);
|
||||
|
||||
/**
|
||||
* Insert the provided arg at the beginning of the array
|
||||
*
|
||||
* @param argv Pointer to an argv array
|
||||
* @param str Pointer to the string to prepend
|
||||
*
|
||||
* @retval PMIX_SUCCESS On success
|
||||
* @retval PMIX_ERROR On failure
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_prepend_nosize(char ***argv, const char *arg);
|
||||
|
||||
/**
|
||||
* Append to an argv-style array, but only if the provided argument
|
||||
* doesn't already exist somewhere in the array. Ignore the size of the array.
|
||||
*
|
||||
* @param argv Pointer to an argv array.
|
||||
* @param str Pointer to the string to append.
|
||||
* @param bool Whether or not to overwrite a matching value if found
|
||||
*
|
||||
* @retval PMIX_SUCCESS On success
|
||||
* @retval PMIX_ERROR On failure
|
||||
*
|
||||
* This function is identical to the pmix_argv_append_nosize() function
|
||||
* except that it only appends the provided argument if it does not already
|
||||
* exist in the provided array, or overwrites it if it is.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_append_unique_nosize(char ***argv, const char *arg, bool overwrite);
|
||||
|
||||
/**
|
||||
* Free a NULL-terminated argv array.
|
||||
*
|
||||
* @param argv Argv array to free.
|
||||
*
|
||||
* This function frees an argv array and all of the strings that it
|
||||
* contains. Since the argv parameter is passed by value, it is not
|
||||
* set to NULL in the caller's scope upon return.
|
||||
*
|
||||
* It is safe to invoke this function with a NULL pointer. It is
|
||||
* not safe to invoke this function with a non-NULL-terminated argv
|
||||
* array.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_argv_free(char **argv);
|
||||
|
||||
/**
|
||||
* Split a string into a NULL-terminated argv array. Do not include empty
|
||||
* strings in result array.
|
||||
*
|
||||
* @param src_string Input string.
|
||||
* @param delimiter Delimiter character.
|
||||
*
|
||||
* @retval argv pointer to new argv array on success
|
||||
* @retval NULL on error
|
||||
*
|
||||
* All strings are insertted into the argv array by value; the
|
||||
* newly-allocated array makes no references to the src_string
|
||||
* argument (i.e., it can be freed after calling this function
|
||||
* without invalidating the output argv).
|
||||
*/
|
||||
PMIX_DECLSPEC char **pmix_argv_split(const char *src_string, int delimiter) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
/**
|
||||
* Split a string into a NULL-terminated argv array. Include empty
|
||||
* strings in result array.
|
||||
*
|
||||
* @param src_string Input string.
|
||||
* @param delimiter Delimiter character.
|
||||
*
|
||||
* @retval argv pointer to new argv array on success
|
||||
* @retval NULL on error
|
||||
*
|
||||
* All strings are insertted into the argv array by value; the
|
||||
* newly-allocated array makes no references to the src_string
|
||||
* argument (i.e., it can be freed after calling this function
|
||||
* without invalidating the output argv).
|
||||
*/
|
||||
PMIX_DECLSPEC char **pmix_argv_split_with_empty(const char *src_string, int delimiter) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
/**
|
||||
* Return the length of a NULL-terminated argv array.
|
||||
*
|
||||
* @param argv The input argv array.
|
||||
*
|
||||
* @retval 0 If NULL is passed as argv.
|
||||
* @retval count Number of entries in the argv array.
|
||||
*
|
||||
* The argv array must be NULL-terminated.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_argv_count(char **argv);
|
||||
|
||||
/**
|
||||
* Join all the elements of an argv array into a single
|
||||
* newly-allocated string.
|
||||
*
|
||||
* @param argv The input argv array.
|
||||
* @param delimiter Delimiter character placed between each argv string.
|
||||
*
|
||||
* @retval new_string Output string on success.
|
||||
* @retval NULL On failure.
|
||||
*
|
||||
* Similar to the Perl join function, this function takes an input
|
||||
* argv and joins them into into a single string separated by the
|
||||
* delimiter character.
|
||||
*
|
||||
* It is the callers responsibility to free the returned string.
|
||||
*/
|
||||
PMIX_DECLSPEC char *pmix_argv_join(char **argv, int delimiter) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
PMIX_DECLSPEC char *pmix_argv_join_range(char **argv, size_t start, size_t end, int delimiter) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
/**
|
||||
* Return the number of bytes consumed by an argv array.
|
||||
*
|
||||
* @param argv The input argv array.
|
||||
*
|
||||
* Count the number of bytes consumed by a NULL-terminated argv
|
||||
* array. This includes the number of bytes used by each of the
|
||||
* strings as well as the pointers used in the argv array.
|
||||
*/
|
||||
PMIX_DECLSPEC size_t pmix_argv_len(char **argv);
|
||||
|
||||
/**
|
||||
* Copy a NULL-terminated argv array.
|
||||
*
|
||||
* @param argv The input argv array.
|
||||
*
|
||||
* @retval argv Copied argv array on success.
|
||||
* @retval NULL On failure.
|
||||
*
|
||||
* Copy an argv array, including copying all off its strings.
|
||||
* Specifically, the output argv will be an array of the same length
|
||||
* as the input argv, and strcmp(argv_in[i], argv_out[i]) will be 0.
|
||||
*/
|
||||
PMIX_DECLSPEC char **pmix_argv_copy(char **argv) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
/**
|
||||
* Delete one or more tokens from the middle of an argv.
|
||||
*
|
||||
* @param argv The argv to delete from
|
||||
* @param start The index of the first token to delete
|
||||
* @param num_to_delete How many tokens to delete
|
||||
*
|
||||
* @retval PMIX_SUCCESS Always
|
||||
*
|
||||
* Delete some tokens from within an existing argv. The start
|
||||
* parameter specifies the first token to delete, and will delete
|
||||
* (num_to_delete-1) tokens following it. argv will be realloc()ed
|
||||
* to *argc - num_deleted size.
|
||||
*
|
||||
* If start is beyond the end of the argv array, this function is
|
||||
* a no-op.
|
||||
*
|
||||
* If num_to_delete runs beyond the end of the argv array, this
|
||||
* function will delete all tokens starting with start to the end
|
||||
* of the array.
|
||||
*
|
||||
* All deleted items in the argv array will have their contents
|
||||
* free()ed (it is assumed that the argv "owns" the memory that
|
||||
* the pointer points to).
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_delete(int *argc, char ***argv,
|
||||
int start, int num_to_delete);
|
||||
|
||||
/**
|
||||
* Insert one argv array into the middle of another
|
||||
*
|
||||
* @param target The argv to insert tokens into
|
||||
* @param start Index where the first token will be placed in target
|
||||
* @param source The argv to copy tokens from
|
||||
*
|
||||
* @retval PMIX_SUCCESS upon success
|
||||
* @retval PMIX_BAD_PARAM if any parameters are non-sensical
|
||||
*
|
||||
* This function takes one arg and inserts it in the middle of
|
||||
* another. The first token in source will be insertted at index
|
||||
* start in the target argv; all other tokens will follow it.
|
||||
* Similar to pmix_argv_append(), the target may be realloc()'ed
|
||||
* to accomodate the new storage requirements.
|
||||
*
|
||||
* The source array is left unaffected -- its contents are copied
|
||||
* by value over to the target array (i.e., the strings that
|
||||
* source points to are strdup'ed into the new locations in
|
||||
* target).
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_insert(char ***target, int start, char **source);
|
||||
|
||||
/**
|
||||
* Insert one argv element in front of a specific position in an array
|
||||
*
|
||||
* @param target The argv to insert tokens into
|
||||
* @param location Index where the token will be placed in target
|
||||
* @param source The token to be inserted
|
||||
*
|
||||
* @retval PMIX_SUCCESS upon success
|
||||
* @retval PMIX_BAD_PARAM if any parameters are non-sensical
|
||||
*
|
||||
* This function takes one arg and inserts it in the middle of
|
||||
* another. The token will be inserted at the specified index
|
||||
* in the target argv; all other tokens will be shifted down.
|
||||
* Similar to pmix_argv_append(), the target may be realloc()'ed
|
||||
* to accomodate the new storage requirements.
|
||||
*
|
||||
* The source token is left unaffected -- its contents are copied
|
||||
* by value over to the target array (i.e., the string that
|
||||
* source points to is strdup'ed into the new location in
|
||||
* target).
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_argv_insert_element(char ***target, int location, char *source);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_ARGV_H */
|
@ -1,139 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2014 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2014 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif /* HAVE_STRING_H */
|
||||
#ifdef HAVE_LIBGEN_H
|
||||
#include <libgen.h>
|
||||
#endif /* HAVE_LIBGEN_H */
|
||||
|
||||
#include "src/util/basename.h"
|
||||
#include "src/util/os_path.h"
|
||||
|
||||
/**
|
||||
* Return a pointer into the original string where the last PATH delimiter
|
||||
* was found. It does not modify the original string. Moreover, it does not
|
||||
* scan the full string, but only the part allowed by the specified number
|
||||
* of characters.
|
||||
* If the last character on the string is a path separator, it will be skipped.
|
||||
*/
|
||||
static inline char* pmix_find_last_path_separator( const char* filename, size_t n )
|
||||
{
|
||||
char* p = (char*)filename + n;
|
||||
|
||||
/* First skip the latest separators */
|
||||
for ( ; p >= filename; p-- ) {
|
||||
if( *p != PMIX_PATH_SEP[0] )
|
||||
break;
|
||||
}
|
||||
|
||||
for ( ; p >= filename; p-- ) {
|
||||
if( *p == PMIX_PATH_SEP[0] )
|
||||
return p;
|
||||
}
|
||||
|
||||
return NULL; /* nothing found inside the filename */
|
||||
}
|
||||
|
||||
char *pmix_basename(const char *filename)
|
||||
{
|
||||
size_t i;
|
||||
char *tmp, *ret = NULL;
|
||||
const char sep = PMIX_PATH_SEP[0];
|
||||
|
||||
/* Check for the bozo case */
|
||||
if (NULL == filename) {
|
||||
return NULL;
|
||||
}
|
||||
if (0 == strlen(filename)) {
|
||||
return strdup("");
|
||||
}
|
||||
if (sep == filename[0] && '\0' == filename[1]) {
|
||||
return strdup(filename);
|
||||
}
|
||||
|
||||
/* Remove trailing sep's (note that we already know that strlen > 0) */
|
||||
tmp = strdup(filename);
|
||||
for (i = strlen(tmp) - 1; i > 0; --i) {
|
||||
if (sep == tmp[i]) {
|
||||
tmp[i] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (0 == i) {
|
||||
tmp[0] = sep;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/* Look for the final sep */
|
||||
ret = pmix_find_last_path_separator( tmp, strlen(tmp) );
|
||||
if (NULL == ret) {
|
||||
return tmp;
|
||||
}
|
||||
ret = strdup(ret + 1);
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* pmix_dirname(const char* filename)
|
||||
{
|
||||
#if defined(HAVE_DIRNAME) || PMIX_HAVE_DIRNAME
|
||||
char* safe_tmp = strdup(filename), *result;
|
||||
result = strdup(dirname(safe_tmp));
|
||||
free(safe_tmp);
|
||||
return result;
|
||||
#else
|
||||
const char* p = pmix_find_last_path_separator(filename, strlen(filename));
|
||||
/* NOTE: p will be NULL if no path separator was in the filename - i.e.,
|
||||
* if filename is just a local file */
|
||||
|
||||
for( ; NULL != p && p != filename; p-- ) {
|
||||
if( (*p == '\\') || (*p == '/') ) {
|
||||
/* If there are several delimiters remove them all */
|
||||
for( --p; p != filename; p-- ) {
|
||||
if( (*p != '\\') && (*p != '/') ) {
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if( p != filename ) {
|
||||
char* ret = (char*)malloc( p - filename + 1 );
|
||||
#ifdef HAVE_STRNCPY_S
|
||||
strncpy_s( ret, (p - filename + 1), filename, p - filename );
|
||||
#else
|
||||
strncpy(ret, filename, p - filename);
|
||||
#endif
|
||||
ret[p - filename] = '\0';
|
||||
return pmix_make_filename_os_friendly(ret);
|
||||
}
|
||||
break; /* return the duplicate of "." */
|
||||
}
|
||||
}
|
||||
return strdup(".");
|
||||
#endif /* defined(HAVE_DIRNAME) || PMIX_HAVE_DIRNAME */
|
||||
}
|
@ -1,114 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*
|
||||
* Returns an OS-independant basename() of a given filename.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_BASENAME_H
|
||||
#define PMIX_BASENAME_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**
|
||||
* Return the basename of a filename.
|
||||
*
|
||||
* @param filename The filename to examine
|
||||
*
|
||||
* @returns A string containing the basename, or NULL if there is an error
|
||||
*
|
||||
* The contents of the \em filename parameter are unchanged. This
|
||||
* function returns a new string containing the basename of the
|
||||
* filename (which must be eventually freed by the caller), or
|
||||
* NULL if there is an error. Trailing "/" characters in the
|
||||
* filename do not count, unless it is in the only part of the
|
||||
* filename (e.g., "/" or "C:\").
|
||||
*
|
||||
* This function will do the Right Things on POSIX and
|
||||
* Windows-based operating systems. For example:
|
||||
*
|
||||
* foo.txt returns "foo.txt"
|
||||
*
|
||||
* /foo/bar/baz returns "baz"
|
||||
*
|
||||
* /yow.c returns "yow.c"
|
||||
*
|
||||
* / returns "/"
|
||||
*
|
||||
* C:\foo\bar\baz returns "baz"
|
||||
*
|
||||
* D:foo.txt returns "foo.txt"
|
||||
*
|
||||
* E:\yow.c returns "yow.c"
|
||||
*
|
||||
* F: returns "F:"
|
||||
*
|
||||
* G:\ returns "G:"
|
||||
*
|
||||
* The caller is responsible for freeing the returned string.
|
||||
*/
|
||||
PMIX_DECLSPEC char *pmix_basename(const char* filename) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
/**
|
||||
* Return the dirname of a filename.
|
||||
*
|
||||
* @param filename The filename to examine
|
||||
*
|
||||
* @returns A string containing the dirname, or NULL if there is an error
|
||||
*
|
||||
* The contents of the \em filename parameter are unchanged. This
|
||||
* function returns a new string containing the dirname of the
|
||||
* filename (which must be eventually freed by the caller), or
|
||||
* NULL if there is an error. Trailing "/" characters in the
|
||||
* filename do not count, unless it is in the only part of the
|
||||
* filename (e.g., "/" or "C:\").
|
||||
*
|
||||
* This function will do the Right Things on POSIX and
|
||||
* Windows-based operating systems. For example:
|
||||
*
|
||||
* foo.txt returns "foo.txt"
|
||||
*
|
||||
* /foo/bar/baz returns "/foo/bar"
|
||||
*
|
||||
* /yow.c returns "/"
|
||||
*
|
||||
* / returns ""
|
||||
*
|
||||
* C:\foo\bar\baz returns "C:\foo\bar"
|
||||
*
|
||||
* D:foo.txt returns "D:"
|
||||
*
|
||||
* E:\yow.c returns "E:"
|
||||
*
|
||||
* F: returns ""
|
||||
*
|
||||
* G:\ returns ""
|
||||
*
|
||||
* The caller is responsible for freeing the returned string.
|
||||
*/
|
||||
PMIX_DECLSPEC char *pmix_dirname(const char* filename) __pmix_attribute_malloc__ __pmix_attribute_warn_unused_result__;
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_BASENAME_H */
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
@ -1,186 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009 IBM Corporation. All rights reserved.
|
||||
* Copyright (c) 2009 Los Alamos National Security, LLC. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef _PMIX_CRC_H_
|
||||
#define _PMIX_CRC_H_
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
#define CRC_POLYNOMIAL ((unsigned int)0x04c11db7)
|
||||
#define CRC_INITIAL_REGISTER ((unsigned int)0xffffffff)
|
||||
|
||||
|
||||
#define PMIX_CSUM( SRC, LEN ) pmix_uicsum( SRC, LEN )
|
||||
#define PMIX_CSUM_PARTIAL( SRC, LEN, UI1, UI2 ) \
|
||||
pmix_uicsum_partial( SRC, LEN, UI1, UI2 )
|
||||
#define PMIX_CSUM_BCOPY_PARTIAL( SRC, DST, LEN1, LEN2, UI1, UI2 ) \
|
||||
pmix_bcopy_uicsum_partial( SRC, DST, LEN1, LEN2, UI1, UI2 )
|
||||
#define PMIX_CSUM_ZERO 0
|
||||
|
||||
|
||||
PMIX_DECLSPEC unsigned long
|
||||
pmix_bcopy_csum_partial(
|
||||
const void * source,
|
||||
void * destination,
|
||||
size_t copylen,
|
||||
size_t csumlen,
|
||||
unsigned long* lastPartialLong,
|
||||
size_t* lastPartialLength
|
||||
);
|
||||
|
||||
static inline unsigned long
|
||||
pmix_bcopy_csum (
|
||||
const void * source,
|
||||
void * destination,
|
||||
size_t copylen,
|
||||
size_t csumlen
|
||||
)
|
||||
{
|
||||
unsigned long plong = 0;
|
||||
size_t plength = 0;
|
||||
return pmix_bcopy_csum_partial(source, destination, copylen, csumlen, &plong, &plength);
|
||||
}
|
||||
|
||||
PMIX_DECLSPEC unsigned int
|
||||
pmix_bcopy_uicsum_partial (
|
||||
const void * source,
|
||||
void * destination,
|
||||
size_t copylen,
|
||||
size_t csumlen,
|
||||
unsigned int* lastPartialInt,
|
||||
size_t* lastPartialLength
|
||||
);
|
||||
|
||||
static inline unsigned int
|
||||
pmix_bcopy_uicsum (
|
||||
const void * source,
|
||||
void * destination,
|
||||
size_t copylen,
|
||||
size_t csumlen
|
||||
)
|
||||
{
|
||||
unsigned int pint = 0;
|
||||
size_t plength = 0;
|
||||
return pmix_bcopy_uicsum_partial(source, destination, copylen, csumlen, &pint, &plength);
|
||||
}
|
||||
|
||||
PMIX_DECLSPEC unsigned long
|
||||
pmix_csum_partial (
|
||||
const void * source,
|
||||
size_t csumlen,
|
||||
unsigned long* lastPartialLong,
|
||||
size_t* lastPartialLength
|
||||
);
|
||||
|
||||
|
||||
static inline unsigned long
|
||||
pmix_csum(const void * source, size_t csumlen)
|
||||
{
|
||||
unsigned long lastPartialLong = 0;
|
||||
size_t lastPartialLength = 0;
|
||||
return pmix_csum_partial(source, csumlen, &lastPartialLong, &lastPartialLength);
|
||||
}
|
||||
/*
|
||||
* The buffer passed to this function is assumed to be 16-bit aligned
|
||||
*/
|
||||
static inline uint16_t
|
||||
pmix_csum16 (const void * source, size_t csumlen)
|
||||
{
|
||||
uint16_t *src = (uint16_t *) source;
|
||||
register uint32_t csum = 0;
|
||||
|
||||
while (csumlen > 1) {
|
||||
csum += *src++;
|
||||
csumlen -= 2;
|
||||
}
|
||||
/* Add leftover byte, if any */
|
||||
if(csumlen > 0)
|
||||
csum += *((unsigned char*)src);
|
||||
/* Fold 32-bit checksum to 16 bits */
|
||||
while(csum >> 16) {
|
||||
csum = (csum & 0xFFFF) + (csum >> 16);
|
||||
}
|
||||
return csum;
|
||||
}
|
||||
|
||||
PMIX_DECLSPEC unsigned int
|
||||
pmix_uicsum_partial (
|
||||
const void * source,
|
||||
size_t csumlen,
|
||||
unsigned int * lastPartialInt,
|
||||
size_t* lastPartialLength
|
||||
);
|
||||
|
||||
static inline unsigned int
|
||||
pmix_uicsum(const void * source, size_t csumlen)
|
||||
{
|
||||
unsigned int lastPartialInt = 0;
|
||||
size_t lastPartialLength = 0;
|
||||
return pmix_uicsum_partial(source, csumlen, &lastPartialInt, &lastPartialLength);
|
||||
}
|
||||
|
||||
/*
|
||||
* CRC Support
|
||||
*/
|
||||
|
||||
void pmix_initialize_crc_table(void);
|
||||
|
||||
PMIX_DECLSPEC unsigned int
|
||||
pmix_bcopy_uicrc_partial(
|
||||
const void * source,
|
||||
void * destination,
|
||||
size_t copylen,
|
||||
size_t crclen,
|
||||
unsigned int partial_crc);
|
||||
|
||||
static inline unsigned int
|
||||
pmix_bcopy_uicrc(
|
||||
const void * source,
|
||||
void * destination,
|
||||
size_t copylen,
|
||||
size_t crclen)
|
||||
{
|
||||
return pmix_bcopy_uicrc_partial(source, destination, copylen, crclen, CRC_INITIAL_REGISTER);
|
||||
}
|
||||
|
||||
PMIX_DECLSPEC unsigned int
|
||||
pmix_uicrc_partial(
|
||||
const void * source,
|
||||
size_t crclen,
|
||||
unsigned int partial_crc);
|
||||
|
||||
|
||||
static inline unsigned int
|
||||
pmix_uicrc(const void * source, size_t crclen)
|
||||
{
|
||||
return pmix_uicrc_partial(source, crclen, CRC_INITIAL_REGISTER);
|
||||
}
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif
|
||||
|
@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007-2012 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include "src/util/error.h"
|
||||
#include "src/include/pmix_globals.h"
|
||||
|
||||
const char* PMIx_Error_string(pmix_status_t errnum)
|
||||
{
|
||||
switch(errnum) {
|
||||
case PMIX_ERR_UNPACK_READ_PAST_END_OF_BUFFER:
|
||||
return "UNPACK-PAST-END";
|
||||
case PMIX_ERR_COMM_FAILURE:
|
||||
return "COMM-FAILURE";
|
||||
case PMIX_ERR_NOT_IMPLEMENTED:
|
||||
return "NOT-IMPLEMENTED";
|
||||
case PMIX_ERR_NOT_SUPPORTED:
|
||||
return "NOT-SUPPORTED";
|
||||
case PMIX_ERR_NOT_FOUND:
|
||||
return "NOT-FOUND";
|
||||
case PMIX_ERR_SERVER_NOT_AVAIL:
|
||||
return "SERVER-NOT-AVAIL";
|
||||
case PMIX_ERR_INVALID_NAMESPACE:
|
||||
return "INVALID-NAMESPACE";
|
||||
case PMIX_ERR_INVALID_SIZE:
|
||||
return "INVALID-SIZE";
|
||||
case PMIX_ERR_INVALID_KEYVALP:
|
||||
return "INVALID-KEYVAL";
|
||||
case PMIX_ERR_INVALID_NUM_PARSED:
|
||||
return "INVALID-NUM-PARSED";
|
||||
|
||||
case PMIX_ERR_INVALID_ARGS:
|
||||
return "INVALID-ARGS";
|
||||
case PMIX_ERR_INVALID_NUM_ARGS:
|
||||
return "INVALID-NUM-ARGS";
|
||||
case PMIX_ERR_INVALID_LENGTH:
|
||||
return "INVALID-LENGTH";
|
||||
case PMIX_ERR_INVALID_VAL_LENGTH:
|
||||
return "INVALID-VAL-LENGTH";
|
||||
case PMIX_ERR_INVALID_VAL:
|
||||
return "INVALID-VAL";
|
||||
case PMIX_ERR_INVALID_KEY_LENGTH:
|
||||
return "INVALID-KEY-LENGTH";
|
||||
case PMIX_ERR_INVALID_KEY:
|
||||
return "INVALID-KEY";
|
||||
case PMIX_ERR_INVALID_ARG:
|
||||
return "INVALID-ARG";
|
||||
case PMIX_ERR_NOMEM:
|
||||
return "NO-MEM";
|
||||
case PMIX_ERR_INIT:
|
||||
return "INIT";
|
||||
|
||||
case PMIX_ERR_DATA_VALUE_NOT_FOUND:
|
||||
return "DATA-VALUE-NOT-FOUND";
|
||||
case PMIX_ERR_OUT_OF_RESOURCE:
|
||||
return "OUT-OF-RESOURCE";
|
||||
case PMIX_ERR_RESOURCE_BUSY:
|
||||
return "RESOURCE-BUSY";
|
||||
case PMIX_ERR_BAD_PARAM:
|
||||
return "BAD-PARAM";
|
||||
case PMIX_ERR_IN_ERRNO:
|
||||
return "ERR-IN-ERRNO";
|
||||
case PMIX_ERR_UNREACH:
|
||||
return "UNREACHABLE";
|
||||
case PMIX_ERR_TIMEOUT:
|
||||
return "TIMEOUT";
|
||||
case PMIX_ERR_NO_PERMISSIONS:
|
||||
return "NO-PERMISSIONS";
|
||||
case PMIX_ERR_PACK_MISMATCH:
|
||||
return "PACK-MISMATCH";
|
||||
case PMIX_ERR_PACK_FAILURE:
|
||||
return "PACK-FAILURE";
|
||||
|
||||
case PMIX_ERR_UNPACK_FAILURE:
|
||||
return "UNPACK-FAILURE";
|
||||
case PMIX_ERR_UNPACK_INADEQUATE_SPACE:
|
||||
return "UNPACK-INADEQUATE-SPACE";
|
||||
case PMIX_ERR_TYPE_MISMATCH:
|
||||
return "TYPE-MISMATCH";
|
||||
case PMIX_ERR_PROC_ENTRY_NOT_FOUND:
|
||||
return "PROC-ENTRY-NOT-FOUND";
|
||||
case PMIX_ERR_UNKNOWN_DATA_TYPE:
|
||||
return "UNKNOWN-DATA-TYPE";
|
||||
case PMIX_ERR_WOULD_BLOCK:
|
||||
return "WOULD-BLOCK";
|
||||
case PMIX_ERR_READY_FOR_HANDSHAKE:
|
||||
return "READY-FOR-HANDSHAKE";
|
||||
case PMIX_ERR_HANDSHAKE_FAILED:
|
||||
return "HANDSHAKE-FAILED";
|
||||
case PMIX_ERR_INVALID_CRED:
|
||||
return "INVALID-CREDENTIAL";
|
||||
case PMIX_EXISTS:
|
||||
return "EXISTS";
|
||||
|
||||
case PMIX_ERR_SILENT:
|
||||
return "SILENT";
|
||||
case PMIX_ERROR:
|
||||
return "ERROR";
|
||||
case PMIX_SUCCESS:
|
||||
return "SUCCESS";
|
||||
}
|
||||
return "ERROR STRING NOT FOUND";
|
||||
}
|
||||
|
||||
void pmix_errhandler_invoke(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
if (NULL != pmix_globals.errhandler) {
|
||||
pmix_globals.errhandler(status, procs, nprocs, info, ninfo);
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015-2016 Intel, Inc. All rights reserved
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_UTIL_ERROR_H
|
||||
#define PMIX_UTIL_ERROR_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include <pmix/pmix_common.h>
|
||||
#include "src/util/output.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
#define PMIX_ERROR_LOG(r) \
|
||||
do { \
|
||||
if (PMIX_ERR_SILENT != (r)) { \
|
||||
pmix_output(0, "PMIX ERROR: %s in file %s at line %d", \
|
||||
PMIx_Error_string((r)), __FILE__, __LINE__); \
|
||||
} \
|
||||
}while(0);
|
||||
|
||||
#define PMIX_REPORT_ERROR(e) \
|
||||
pmix_errhandler_invoke(e, NULL, 0, NULL, 0)
|
||||
|
||||
PMIX_DECLSPEC void pmix_errhandler_invoke(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_UTIL_ERROR_H */
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2014 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2009 Sandia National Laboratories. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
*
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/* @file */
|
||||
|
||||
#ifndef PMIX_UTIL_FD_H_
|
||||
#define PMIX_UTIL_FD_H_
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**
|
||||
* Read a complete buffer from a file descriptor.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
* @param len Number of bytes to read
|
||||
* @param buffer Pre-allocated buffer (large enough to hold len bytes)
|
||||
*
|
||||
* @returns PMIX_SUCCESS upon success.
|
||||
* @returns PMIX_ERR_TIMEOUT if the fd closes before reading the full amount.
|
||||
* @returns PMIX_ERR_IN_ERRNO otherwise.
|
||||
*
|
||||
* Loop over reading from the fd until len bytes are read or an error
|
||||
* occurs. EAGAIN and EINTR are transparently handled.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_fd_read(int fd, int len, void *buffer);
|
||||
|
||||
/**
|
||||
* Write a complete buffer to a file descriptor.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
* @param len Number of bytes to write
|
||||
* @param buffer Buffer to write from
|
||||
*
|
||||
* @returns PMIX_SUCCESS upon success.
|
||||
* @returns PMIX_ERR_IN_ERRNO otherwise.
|
||||
*
|
||||
* Loop over writing to the fd until len bytes are written or an error
|
||||
* occurs. EAGAIN and EINTR are transparently handled.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_fd_write(int fd, int len, const void *buffer);
|
||||
|
||||
/**
|
||||
* Convenience function to set a file descriptor to be close-on-exec.
|
||||
*
|
||||
* @param fd File descriptor
|
||||
*
|
||||
* @returns PMIX_SUCCESS upon success (or if the system does not
|
||||
* support close-on-exec behavior).
|
||||
* @returns PMIX_ERR_IN_ERRNO otherwise.
|
||||
*
|
||||
* This is simply a convenience function because there's a few steps
|
||||
* to setting a file descriptor to be close-on-exec.
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_status_t pmix_fd_set_cloexec(int fd);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif
|
@ -1,267 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2011-2014 Los Alamos National Security, LLC. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/pmix_stdint.h>
|
||||
#include <private/hash_string.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "src/include/pmix_globals.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
#include "src/class/pmix_pointer_array.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/output.h"
|
||||
|
||||
#include "src/util/hash.h"
|
||||
|
||||
/**
|
||||
* Data for a particular pmix process
|
||||
* The name association is maintained in the
|
||||
* proc_data hash table.
|
||||
*/
|
||||
typedef struct {
|
||||
/** Structure can be put on lists (including in hash tables) */
|
||||
pmix_list_item_t super;
|
||||
/* List of pmix_kval_t structures containing all data
|
||||
received from this process */
|
||||
pmix_list_t data;
|
||||
} pmix_proc_data_t;
|
||||
static void pdcon(pmix_proc_data_t *p)
|
||||
{
|
||||
PMIX_CONSTRUCT(&p->data, pmix_list_t);
|
||||
}
|
||||
static void pddes(pmix_proc_data_t *p)
|
||||
{
|
||||
PMIX_LIST_DESTRUCT(&p->data);
|
||||
}
|
||||
static PMIX_CLASS_INSTANCE(pmix_proc_data_t,
|
||||
pmix_list_item_t,
|
||||
pdcon, pddes);
|
||||
|
||||
static pmix_kval_t* lookup_keyval(pmix_list_t *data,
|
||||
const char *key);
|
||||
static pmix_proc_data_t* lookup_proc(pmix_hash_table_t *jtable,
|
||||
uint64_t id, bool create);
|
||||
|
||||
int pmix_hash_store(pmix_hash_table_t *table,
|
||||
int rank, pmix_kval_t *kin)
|
||||
{
|
||||
pmix_proc_data_t *proc_data;
|
||||
uint64_t id;
|
||||
pmix_kval_t *kv;
|
||||
|
||||
pmix_output_verbose(10, pmix_globals.debug_output,
|
||||
"HASH:STORE rank %d key %s",
|
||||
rank, kin->key);
|
||||
|
||||
if (PMIX_RANK_WILDCARD == rank) {
|
||||
id = UINT64_MAX;
|
||||
} else {
|
||||
id = (uint64_t)rank;
|
||||
}
|
||||
|
||||
/* lookup the proc data object for this proc - create
|
||||
* it if we don't */
|
||||
if (NULL == (proc_data = lookup_proc(table, id, true))) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
|
||||
/* see if we already have this key in the data - means we are updating
|
||||
* a pre-existing value
|
||||
*/
|
||||
kv = lookup_keyval(&proc_data->data, kin->key);
|
||||
if (NULL != kv) {
|
||||
pmix_list_remove_item(&proc_data->data, &kv->super);
|
||||
PMIX_RELEASE(kv);
|
||||
}
|
||||
/* store the new value */
|
||||
PMIX_RETAIN(kin);
|
||||
pmix_list_append(&proc_data->data, &kin->super);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
pmix_status_t pmix_hash_fetch(pmix_hash_table_t *table, int rank,
|
||||
const char *key, pmix_value_t **kvs)
|
||||
{
|
||||
pmix_proc_data_t *proc_data;
|
||||
pmix_kval_t *hv;
|
||||
uint64_t id;
|
||||
pmix_status_t rc;
|
||||
|
||||
pmix_output_verbose(10, pmix_globals.debug_output,
|
||||
"HASH:FETCH rank %d key %s",
|
||||
rank, (NULL == key) ? "NULL" : key);
|
||||
|
||||
/* NULL keys are not supported */
|
||||
if (NULL == key) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
}
|
||||
|
||||
if (PMIX_RANK_WILDCARD == rank) {
|
||||
id = UINT64_MAX;
|
||||
} else {
|
||||
id = (uint64_t)rank;
|
||||
}
|
||||
|
||||
/* lookup the proc data object for this proc */
|
||||
if (NULL == (proc_data = lookup_proc(table, id, false))) {
|
||||
pmix_output_verbose(10, pmix_globals.debug_output,
|
||||
"HASH:FETCH proc data for rank %d not found",
|
||||
rank);
|
||||
return PMIX_ERR_PROC_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* find the value from within this proc_data object */
|
||||
if (NULL == (hv = lookup_keyval(&proc_data->data, key))) {
|
||||
pmix_output_verbose(10, pmix_globals.debug_output,
|
||||
"HASH:FETCH data for key %s not found", key);
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* create the copy */
|
||||
if (PMIX_SUCCESS != (rc = pmix_bfrop.copy((void**)kvs, hv->value, PMIX_VALUE))) {
|
||||
PMIX_ERROR_LOG(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int pmix_hash_remove_data(pmix_hash_table_t *table,
|
||||
int rank, const char *key)
|
||||
{
|
||||
pmix_proc_data_t *proc_data;
|
||||
pmix_kval_t *kv;
|
||||
uint64_t id;
|
||||
char *node;
|
||||
|
||||
/* if the rank is wildcard, we want to apply this to
|
||||
* all rank entries */
|
||||
if (PMIX_RANK_WILDCARD == rank) {
|
||||
id = UINT64_MAX;
|
||||
if (PMIX_SUCCESS == pmix_hash_table_get_first_key_uint64(table, &id,
|
||||
(void**)&proc_data,
|
||||
(void**)&node)) {
|
||||
if (NULL != proc_data) {
|
||||
if (NULL == key) {
|
||||
PMIX_RELEASE(proc_data);
|
||||
} else {
|
||||
PMIX_LIST_FOREACH(kv, &proc_data->data, pmix_kval_t) {
|
||||
if (0 == strcmp(key, kv->key)) {
|
||||
pmix_list_remove_item(&proc_data->data, &kv->super);
|
||||
PMIX_RELEASE(kv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (PMIX_SUCCESS == pmix_hash_table_get_next_key_uint64(table, &id,
|
||||
(void**)&proc_data,
|
||||
node, (void**)&node)) {
|
||||
if (NULL != proc_data) {
|
||||
if (NULL == key) {
|
||||
PMIX_RELEASE(proc_data);
|
||||
} else {
|
||||
PMIX_LIST_FOREACH(kv, &proc_data->data, pmix_kval_t) {
|
||||
if (0 == strcmp(key, kv->key)) {
|
||||
pmix_list_remove_item(&proc_data->data, &kv->super);
|
||||
PMIX_RELEASE(kv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* lookup the specified proc */
|
||||
id = (uint64_t)rank;
|
||||
if (NULL == (proc_data = lookup_proc(table, id, false))) {
|
||||
/* no data for this proc */
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* if key is NULL, remove all data for this proc */
|
||||
if (NULL == key) {
|
||||
while (NULL != (kv = (pmix_kval_t*)pmix_list_remove_first(&proc_data->data))) {
|
||||
PMIX_RELEASE(kv);
|
||||
}
|
||||
/* remove the proc_data object itself from the jtable */
|
||||
pmix_hash_table_remove_value_uint64(table, id);
|
||||
/* cleanup */
|
||||
PMIX_RELEASE(proc_data);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* remove this item */
|
||||
PMIX_LIST_FOREACH(kv, &proc_data->data, pmix_kval_t) {
|
||||
if (0 == strcmp(key, kv->key)) {
|
||||
pmix_list_remove_item(&proc_data->data, &kv->super);
|
||||
PMIX_RELEASE(kv);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find data for a given key in a given pmix_list_t.
|
||||
*/
|
||||
static pmix_kval_t* lookup_keyval(pmix_list_t *data,
|
||||
const char *key)
|
||||
{
|
||||
pmix_kval_t *kv;
|
||||
|
||||
PMIX_LIST_FOREACH(kv, data, pmix_kval_t) {
|
||||
if (0 == strcmp(key, kv->key)) {
|
||||
return kv;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find proc_data_t container associated with given
|
||||
* pmix_identifier_t.
|
||||
*/
|
||||
static pmix_proc_data_t* lookup_proc(pmix_hash_table_t *jtable,
|
||||
uint64_t id, bool create)
|
||||
{
|
||||
pmix_proc_data_t *proc_data = NULL;
|
||||
|
||||
pmix_hash_table_get_value_uint64(jtable, id, (void**)&proc_data);
|
||||
if (NULL == proc_data && create) {
|
||||
/* The proc clearly exists, so create a data structure for it */
|
||||
proc_data = PMIX_NEW(pmix_proc_data_t);
|
||||
if (NULL == proc_data) {
|
||||
pmix_output(0, "pmix:client:hash:lookup_pmix_proc: unable to allocate proc_data_t\n");
|
||||
return NULL;
|
||||
}
|
||||
pmix_hash_table_set_value_uint64(jtable, id, proc_data);
|
||||
}
|
||||
|
||||
return proc_data;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2010 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2012 Los Alamos National Security, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_HASH_H
|
||||
#define PMIX_HASH_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/class/pmix_hash_table.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/* store a value in the given hash table for the specified
|
||||
* rank index.*/
|
||||
pmix_status_t pmix_hash_store(pmix_hash_table_t *table,
|
||||
int rank, pmix_kval_t *kv);
|
||||
|
||||
/* Fetch the value for a specified key from within
|
||||
* the given hash_table */
|
||||
pmix_status_t pmix_hash_fetch(pmix_hash_table_t *table, int rank,
|
||||
const char *key, pmix_value_t **kvs);
|
||||
|
||||
/* remove the specified key-value from the given hash_table.
|
||||
* A NULL key will result in removal of all data for the
|
||||
* given rank. A rank of PMIX_RANK_WILDCARD indicates that
|
||||
* the specified key is to be removed from the data for all
|
||||
* ranks in the table. Combining key=NULL with rank=PMIX_RANK_WILDCARD
|
||||
* will therefore result in removal of all data from the
|
||||
* table */
|
||||
pmix_status_t pmix_hash_remove_data(pmix_hash_table_t *table,
|
||||
int rank, const char *key);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_HASH_H */
|
@ -1,966 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2008 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2006 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007-2008 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef HAVE_SYSLOG_H
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include "src/util/pmix_environ.h"
|
||||
#include "src/util/output.h"
|
||||
|
||||
/*
|
||||
* Private data
|
||||
*/
|
||||
static int verbose_stream = -1;
|
||||
static pmix_output_stream_t verbose;
|
||||
static char *output_dir = NULL;
|
||||
static char *output_prefix = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Internal data structures and helpers for the generalized output
|
||||
* stream mechanism.
|
||||
*/
|
||||
typedef struct {
|
||||
bool ldi_used;
|
||||
bool ldi_enabled;
|
||||
int ldi_verbose_level;
|
||||
|
||||
bool ldi_syslog;
|
||||
int ldi_syslog_priority;
|
||||
|
||||
char *ldi_syslog_ident;
|
||||
char *ldi_prefix;
|
||||
int ldi_prefix_len;
|
||||
|
||||
char *ldi_suffix;
|
||||
int ldi_suffix_len;
|
||||
|
||||
bool ldi_stdout;
|
||||
bool ldi_stderr;
|
||||
|
||||
bool ldi_file;
|
||||
bool ldi_file_want_append;
|
||||
char *ldi_file_suffix;
|
||||
int ldi_fd;
|
||||
int ldi_file_num_lines_lost;
|
||||
} output_desc_t;
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static void construct(pmix_object_t *stream);
|
||||
static int do_open(int output_id, pmix_output_stream_t * lds);
|
||||
static int open_file(int i);
|
||||
static void free_descriptor(int output_id);
|
||||
static int make_string(char **no_newline_string, output_desc_t *ldi,
|
||||
const char *format, va_list arglist);
|
||||
static int output(int output_id, const char *format, va_list arglist);
|
||||
|
||||
|
||||
#define PMIX_OUTPUT_MAX_STREAMS 64
|
||||
#if defined(HAVE_SYSLOG)
|
||||
#define USE_SYSLOG 1
|
||||
#else
|
||||
#define USE_SYSLOG 0
|
||||
#endif
|
||||
|
||||
/* global state */
|
||||
bool pmix_output_redirected_to_syslog = false;
|
||||
int pmix_output_redirected_syslog_pri = 0;
|
||||
|
||||
/*
|
||||
* Local state
|
||||
*/
|
||||
static bool initialized = false;
|
||||
static int default_stderr_fd = -1;
|
||||
static output_desc_t info[PMIX_OUTPUT_MAX_STREAMS];
|
||||
static char *temp_str = 0;
|
||||
static size_t temp_str_len = 0;
|
||||
#if defined(HAVE_SYSLOG)
|
||||
static bool syslog_opened = false;
|
||||
#endif
|
||||
static char *redirect_syslog_ident = NULL;
|
||||
|
||||
PMIX_CLASS_INSTANCE(pmix_output_stream_t, pmix_object_t, construct, NULL);
|
||||
|
||||
/*
|
||||
* Setup the output stream infrastructure
|
||||
*/
|
||||
bool pmix_output_init(void)
|
||||
{
|
||||
int i;
|
||||
char hostname[32];
|
||||
char *str;
|
||||
|
||||
if (initialized) {
|
||||
return true;
|
||||
}
|
||||
|
||||
str = getenv("PMIX_OUTPUT_STDERR_FD");
|
||||
if (NULL != str) {
|
||||
default_stderr_fd = atoi(str);
|
||||
}
|
||||
str = getenv("PMIX_OUTPUT_REDIRECT");
|
||||
if (NULL != str) {
|
||||
if (0 == strcasecmp(str, "syslog")) {
|
||||
pmix_output_redirected_to_syslog = true;
|
||||
}
|
||||
}
|
||||
str = getenv("PMIX_OUTPUT_SYSLOG_PRI");
|
||||
if (NULL != str) {
|
||||
if (0 == strcasecmp(str, "info")) {
|
||||
pmix_output_redirected_syslog_pri = LOG_INFO;
|
||||
} else if (0 == strcasecmp(str, "error")) {
|
||||
pmix_output_redirected_syslog_pri = LOG_ERR;
|
||||
} else if (0 == strcasecmp(str, "warn")) {
|
||||
pmix_output_redirected_syslog_pri = LOG_WARNING;
|
||||
} else {
|
||||
pmix_output_redirected_syslog_pri = LOG_ERR;
|
||||
}
|
||||
} else {
|
||||
pmix_output_redirected_syslog_pri = LOG_ERR;
|
||||
}
|
||||
|
||||
str = getenv("PMIX_OUTPUT_SYSLOG_IDENT");
|
||||
if (NULL != str) {
|
||||
redirect_syslog_ident = strdup(str);
|
||||
}
|
||||
|
||||
PMIX_CONSTRUCT(&verbose, pmix_output_stream_t);
|
||||
if (pmix_output_redirected_to_syslog) {
|
||||
verbose.lds_want_syslog = true;
|
||||
verbose.lds_syslog_priority = pmix_output_redirected_syslog_pri;
|
||||
if (NULL != str) {
|
||||
verbose.lds_syslog_ident = strdup(redirect_syslog_ident);
|
||||
}
|
||||
verbose.lds_want_stderr = false;
|
||||
verbose.lds_want_stdout = false;
|
||||
} else {
|
||||
verbose.lds_want_stderr = true;
|
||||
}
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
hostname[sizeof(hostname)-1] = '\0';
|
||||
asprintf(&verbose.lds_prefix, "[%s:%05d] ", hostname, getpid());
|
||||
|
||||
for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) {
|
||||
info[i].ldi_used = false;
|
||||
info[i].ldi_enabled = false;
|
||||
|
||||
info[i].ldi_syslog = pmix_output_redirected_to_syslog;
|
||||
info[i].ldi_file = false;
|
||||
info[i].ldi_file_suffix = NULL;
|
||||
info[i].ldi_file_want_append = false;
|
||||
info[i].ldi_fd = -1;
|
||||
info[i].ldi_file_num_lines_lost = 0;
|
||||
}
|
||||
|
||||
|
||||
initialized = true;
|
||||
|
||||
/* Set some defaults */
|
||||
|
||||
asprintf(&output_prefix, "output-pid%d-", getpid());
|
||||
output_dir = strdup(pmix_tmp_directory());
|
||||
|
||||
/* Open the default verbose stream */
|
||||
verbose_stream = pmix_output_open(&verbose);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Open a stream
|
||||
*/
|
||||
int pmix_output_open(pmix_output_stream_t * lds)
|
||||
{
|
||||
return do_open(-1, lds);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reset the parameters on a stream
|
||||
*/
|
||||
int pmix_output_reopen(int output_id, pmix_output_stream_t * lds)
|
||||
{
|
||||
return do_open(output_id, lds);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Enable and disable output streams
|
||||
*/
|
||||
bool pmix_output_switch(int output_id, bool enable)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
/* Setup */
|
||||
|
||||
if (!initialized) {
|
||||
pmix_output_init();
|
||||
}
|
||||
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS) {
|
||||
ret = info[output_id].ldi_enabled;
|
||||
info[output_id].ldi_enabled = enable;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Reopen all the streams; used during checkpoint/restart.
|
||||
*/
|
||||
void pmix_output_reopen_all(void)
|
||||
{
|
||||
char *str;
|
||||
char hostname[32];
|
||||
|
||||
str = getenv("PMIX_OUTPUT_STDERR_FD");
|
||||
if (NULL != str) {
|
||||
default_stderr_fd = atoi(str);
|
||||
} else {
|
||||
default_stderr_fd = -1;
|
||||
}
|
||||
|
||||
gethostname(hostname, sizeof(hostname));
|
||||
if( NULL != verbose.lds_prefix ) {
|
||||
free(verbose.lds_prefix);
|
||||
verbose.lds_prefix = NULL;
|
||||
}
|
||||
asprintf(&verbose.lds_prefix, "[%s:%05d] ", hostname, getpid());
|
||||
#if 0
|
||||
int i;
|
||||
pmix_output_stream_t lds;
|
||||
|
||||
for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) {
|
||||
|
||||
/* scan till we find ldi_used == 0, which is the end-marker */
|
||||
|
||||
if (!info[i].ldi_used) {
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* set this to zero to ensure that pmix_output_open will
|
||||
* return this same index as the output stream id
|
||||
*/
|
||||
info[i].ldi_used = false;
|
||||
|
||||
#if USE_SYSLOG
|
||||
lds.lds_want_syslog = info[i].ldi_syslog;
|
||||
lds.lds_syslog_priority = info[i].ldi_syslog_priority;
|
||||
lds.lds_syslog_ident = info[i].ldi_syslog_ident;
|
||||
#else
|
||||
lds.lds_want_syslog = false;
|
||||
#endif
|
||||
lds.lds_prefix = info[i].ldi_prefix;
|
||||
lds.lds_suffix = info[i].ldi_suffix;
|
||||
lds.lds_want_stdout = info[i].ldi_stdout;
|
||||
lds.lds_want_stderr = info[i].ldi_stderr;
|
||||
lds.lds_want_file = (-1 == info[i].ldi_fd) ? false : true;
|
||||
/* open all streams in append mode */
|
||||
lds.lds_want_file_append = true;
|
||||
lds.lds_file_suffix = info[i].ldi_file_suffix;
|
||||
|
||||
/*
|
||||
* call pmix_output_open to open the stream. The return value
|
||||
* is guaranteed to be i. So we can ignore it.
|
||||
*/
|
||||
pmix_output_open(&lds);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Close a stream
|
||||
*/
|
||||
void pmix_output_close(int output_id)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Setup */
|
||||
|
||||
if (!initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it's valid, used, enabled, and has an open file descriptor,
|
||||
* free the resources associated with the descriptor */
|
||||
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_used && info[output_id].ldi_enabled) {
|
||||
free_descriptor(output_id);
|
||||
|
||||
/* If no one has the syslog open, we should close it */
|
||||
|
||||
for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) {
|
||||
if (info[i].ldi_used && info[i].ldi_syslog) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_SYSLOG)
|
||||
if (i >= PMIX_OUTPUT_MAX_STREAMS && syslog_opened) {
|
||||
closelog();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Main function to send output to a stream
|
||||
*/
|
||||
void pmix_output(int output_id, const char *format, ...)
|
||||
{
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS) {
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
output(output_id, format, arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send a message to a stream if the verbose level is high enough
|
||||
*/
|
||||
void pmix_output_verbose(int level, int output_id, const char *format, ...)
|
||||
{
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_verbose_level >= level) {
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
output(output_id, format, arglist);
|
||||
va_end(arglist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send a message to a stream if the verbose level is high enough
|
||||
*/
|
||||
void pmix_output_vverbose(int level, int output_id, const char *format,
|
||||
va_list arglist)
|
||||
{
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_verbose_level >= level) {
|
||||
output(output_id, format, arglist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send a message to a string if the verbose level is high enough
|
||||
*/
|
||||
char *pmix_output_string(int level, int output_id, const char *format, ...)
|
||||
{
|
||||
int rc;
|
||||
char *ret = NULL;
|
||||
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_verbose_level >= level) {
|
||||
va_list arglist;
|
||||
va_start(arglist, format);
|
||||
rc = make_string(&ret, &info[output_id], format, arglist);
|
||||
va_end(arglist);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
ret = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Send a message to a string if the verbose level is high enough
|
||||
*/
|
||||
char *pmix_output_vstring(int level, int output_id, const char *format,
|
||||
va_list arglist)
|
||||
{
|
||||
int rc;
|
||||
char *ret = NULL;
|
||||
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_verbose_level >= level) {
|
||||
rc = make_string(&ret, &info[output_id], format, arglist);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
ret = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set the verbosity level of a stream
|
||||
*/
|
||||
void pmix_output_set_verbosity(int output_id, int level)
|
||||
{
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS) {
|
||||
info[output_id].ldi_verbose_level = level;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Control where output flies will go
|
||||
*/
|
||||
void pmix_output_set_output_file_info(const char *dir,
|
||||
const char *prefix,
|
||||
char **olddir,
|
||||
char **oldprefix)
|
||||
{
|
||||
if (NULL != olddir) {
|
||||
*olddir = strdup(output_dir);
|
||||
}
|
||||
if (NULL != oldprefix) {
|
||||
*oldprefix = strdup(output_prefix);
|
||||
}
|
||||
|
||||
if (NULL != dir) {
|
||||
free(output_dir);
|
||||
output_dir = strdup(dir);
|
||||
}
|
||||
if (NULL != prefix) {
|
||||
free(output_prefix);
|
||||
output_prefix = strdup(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Shut down the output stream system
|
||||
*/
|
||||
void pmix_output_finalize(void)
|
||||
{
|
||||
if (initialized) {
|
||||
if (verbose_stream != -1) {
|
||||
pmix_output_close(verbose_stream);
|
||||
}
|
||||
free(verbose.lds_prefix);
|
||||
verbose_stream = -1;
|
||||
|
||||
free (output_prefix);
|
||||
free (output_dir);
|
||||
if(NULL != temp_str) {
|
||||
free(temp_str);
|
||||
temp_str = NULL;
|
||||
temp_str_len = 0;
|
||||
}
|
||||
PMIX_DESTRUCT(&verbose);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
static void construct(pmix_object_t *obj)
|
||||
{
|
||||
pmix_output_stream_t *stream = (pmix_output_stream_t*) obj;
|
||||
|
||||
stream->lds_verbose_level = 0;
|
||||
stream->lds_syslog_priority = 0;
|
||||
stream->lds_syslog_ident = NULL;
|
||||
stream->lds_prefix = NULL;
|
||||
stream->lds_suffix = NULL;
|
||||
stream->lds_is_debugging = false;
|
||||
stream->lds_want_syslog = false;
|
||||
stream->lds_want_stdout = false;
|
||||
stream->lds_want_stderr = false;
|
||||
stream->lds_want_file = false;
|
||||
stream->lds_want_file_append = false;
|
||||
stream->lds_file_suffix = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Back-end of open() and reopen().
|
||||
*/
|
||||
static int do_open(int output_id, pmix_output_stream_t * lds)
|
||||
{
|
||||
int i;
|
||||
bool redirect_to_file = false;
|
||||
char *str, *sfx;
|
||||
|
||||
/* Setup */
|
||||
|
||||
if (!initialized) {
|
||||
pmix_output_init();
|
||||
}
|
||||
|
||||
str = getenv("PMIX_OUTPUT_REDIRECT");
|
||||
if (NULL != str && 0 == strcasecmp(str, "file")) {
|
||||
redirect_to_file = true;
|
||||
}
|
||||
sfx = getenv("PMIX_OUTPUT_SUFFIX");
|
||||
|
||||
/* If output_id == -1, find an available stream, or return
|
||||
* PMIX_ERROR */
|
||||
|
||||
if (-1 == output_id) {
|
||||
for (i = 0; i < PMIX_OUTPUT_MAX_STREAMS; ++i) {
|
||||
if (!info[i].ldi_used) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= PMIX_OUTPUT_MAX_STREAMS) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Otherwise, we're reopening, so we need to free all previous
|
||||
* resources, close files, etc. */
|
||||
|
||||
else {
|
||||
free_descriptor(output_id);
|
||||
i = output_id;
|
||||
}
|
||||
|
||||
/* Special case: if we got NULL for lds, then just use the default
|
||||
* verbose */
|
||||
|
||||
if (NULL == lds) {
|
||||
lds = &verbose;
|
||||
}
|
||||
|
||||
/* Got a stream -- now initialize it and open relevant outputs */
|
||||
|
||||
info[i].ldi_used = true;
|
||||
info[i].ldi_enabled = lds->lds_is_debugging ?
|
||||
(bool) PMIX_ENABLE_DEBUG : true;
|
||||
info[i].ldi_verbose_level = lds->lds_verbose_level;
|
||||
|
||||
#if USE_SYSLOG
|
||||
#if defined(HAVE_SYSLOG)
|
||||
if (pmix_output_redirected_to_syslog) {
|
||||
info[i].ldi_syslog = true;
|
||||
info[i].ldi_syslog_priority = pmix_output_redirected_syslog_pri;
|
||||
if (NULL != redirect_syslog_ident) {
|
||||
info[i].ldi_syslog_ident = strdup(redirect_syslog_ident);
|
||||
openlog(redirect_syslog_ident, LOG_PID, LOG_USER);
|
||||
} else {
|
||||
info[i].ldi_syslog_ident = NULL;
|
||||
openlog("pmix", LOG_PID, LOG_USER);
|
||||
}
|
||||
syslog_opened = true;
|
||||
} else {
|
||||
#endif
|
||||
info[i].ldi_syslog = lds->lds_want_syslog;
|
||||
if (lds->lds_want_syslog) {
|
||||
|
||||
#if defined(HAVE_SYSLOG)
|
||||
if (NULL != lds->lds_syslog_ident) {
|
||||
info[i].ldi_syslog_ident = strdup(lds->lds_syslog_ident);
|
||||
openlog(lds->lds_syslog_ident, LOG_PID, LOG_USER);
|
||||
} else {
|
||||
info[i].ldi_syslog_ident = NULL;
|
||||
openlog("pmix", LOG_PID, LOG_USER);
|
||||
}
|
||||
#endif
|
||||
syslog_opened = true;
|
||||
info[i].ldi_syslog_priority = lds->lds_syslog_priority;
|
||||
}
|
||||
|
||||
#if defined(HAVE_SYSLOG)
|
||||
}
|
||||
#endif
|
||||
|
||||
#else
|
||||
info[i].ldi_syslog = false;
|
||||
#endif
|
||||
|
||||
if (NULL != lds->lds_prefix) {
|
||||
info[i].ldi_prefix = strdup(lds->lds_prefix);
|
||||
info[i].ldi_prefix_len = (int)strlen(lds->lds_prefix);
|
||||
} else {
|
||||
info[i].ldi_prefix = NULL;
|
||||
info[i].ldi_prefix_len = 0;
|
||||
}
|
||||
|
||||
if (NULL != lds->lds_suffix) {
|
||||
info[i].ldi_suffix = strdup(lds->lds_suffix);
|
||||
info[i].ldi_suffix_len = (int)strlen(lds->lds_suffix);
|
||||
} else {
|
||||
info[i].ldi_suffix = NULL;
|
||||
info[i].ldi_suffix_len = 0;
|
||||
}
|
||||
|
||||
if (pmix_output_redirected_to_syslog) {
|
||||
/* since all is redirected to syslog, ensure
|
||||
* we don't duplicate the output to the std places
|
||||
*/
|
||||
info[i].ldi_stdout = false;
|
||||
info[i].ldi_stderr = false;
|
||||
info[i].ldi_file = false;
|
||||
info[i].ldi_fd = -1;
|
||||
} else {
|
||||
/* since we aren't redirecting to syslog, use what was
|
||||
* given to us
|
||||
*/
|
||||
if (NULL != str && redirect_to_file) {
|
||||
info[i].ldi_stdout = false;
|
||||
info[i].ldi_stderr = false;
|
||||
info[i].ldi_file = true;
|
||||
} else {
|
||||
info[i].ldi_stdout = lds->lds_want_stdout;
|
||||
info[i].ldi_stderr = lds->lds_want_stderr;
|
||||
|
||||
info[i].ldi_fd = -1;
|
||||
info[i].ldi_file = lds->lds_want_file;
|
||||
}
|
||||
if (NULL != sfx) {
|
||||
info[i].ldi_file_suffix = strdup(sfx);
|
||||
} else {
|
||||
info[i].ldi_file_suffix = (NULL == lds->lds_file_suffix) ? NULL :
|
||||
strdup(lds->lds_file_suffix);
|
||||
}
|
||||
info[i].ldi_file_want_append = lds->lds_want_file_append;
|
||||
info[i].ldi_file_num_lines_lost = 0;
|
||||
}
|
||||
|
||||
/* Don't open a file in the session directory now -- do that lazily
|
||||
* so that if there's no output, we don't have an empty file */
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
static int open_file(int i)
|
||||
{
|
||||
int flags;
|
||||
char *filename;
|
||||
int n;
|
||||
|
||||
/* first check to see if this file is already open
|
||||
* on someone else's stream - if so, we don't want
|
||||
* to open it twice
|
||||
*/
|
||||
for (n=0; n < PMIX_OUTPUT_MAX_STREAMS; n++) {
|
||||
if (i == n) {
|
||||
continue;
|
||||
}
|
||||
if (!info[n].ldi_used) {
|
||||
continue;
|
||||
}
|
||||
if (!info[n].ldi_file) {
|
||||
continue;
|
||||
}
|
||||
if (NULL != info[i].ldi_file_suffix &&
|
||||
NULL != info[n].ldi_file_suffix) {
|
||||
if (0 != strcmp(info[i].ldi_file_suffix, info[n].ldi_file_suffix)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (NULL == info[i].ldi_file_suffix &&
|
||||
NULL != info[n].ldi_file_suffix) {
|
||||
break;
|
||||
}
|
||||
if (NULL != info[i].ldi_file_suffix &&
|
||||
NULL == info[n].ldi_file_suffix) {
|
||||
break;
|
||||
}
|
||||
if (info[n].ldi_fd < 0) {
|
||||
break;
|
||||
}
|
||||
info[i].ldi_fd = info[n].ldi_fd;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Setup the filename and open flags */
|
||||
|
||||
if (NULL != output_dir) {
|
||||
filename = (char *) malloc(PMIX_PATH_MAX);
|
||||
if (NULL == filename) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
strncpy(filename, output_dir, PMIX_PATH_MAX);
|
||||
strcat(filename, "/");
|
||||
if (NULL != output_prefix) {
|
||||
strcat(filename, output_prefix);
|
||||
}
|
||||
if (info[i].ldi_file_suffix != NULL) {
|
||||
strcat(filename, info[i].ldi_file_suffix);
|
||||
} else {
|
||||
info[i].ldi_file_suffix = NULL;
|
||||
strcat(filename, "output.txt");
|
||||
}
|
||||
flags = O_CREAT | O_RDWR;
|
||||
if (!info[i].ldi_file_want_append) {
|
||||
flags |= O_TRUNC;
|
||||
}
|
||||
|
||||
/* Actually open the file */
|
||||
info[i].ldi_fd = open(filename, flags, 0644);
|
||||
free(filename); /* release the filename in all cases */
|
||||
if (-1 == info[i].ldi_fd) {
|
||||
info[i].ldi_used = false;
|
||||
return PMIX_ERR_IN_ERRNO;
|
||||
}
|
||||
|
||||
/* Make the file be close-on-exec to prevent child inheritance
|
||||
* problems */
|
||||
if (-1 == fcntl(info[i].ldi_fd, F_SETFD, 1)) {
|
||||
return PMIX_ERR_IN_ERRNO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Return successfully even if the session dir did not exist yet;
|
||||
* we'll try opening it later */
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free all the resources associated with a descriptor.
|
||||
*/
|
||||
static void free_descriptor(int output_id)
|
||||
{
|
||||
output_desc_t *ldi;
|
||||
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_used && info[output_id].ldi_enabled) {
|
||||
ldi = &info[output_id];
|
||||
|
||||
if (-1 != ldi->ldi_fd) {
|
||||
close(ldi->ldi_fd);
|
||||
}
|
||||
ldi->ldi_used = false;
|
||||
|
||||
/* If we strduped a prefix, suffix, or syslog ident, free it */
|
||||
|
||||
if (NULL != ldi->ldi_prefix) {
|
||||
free(ldi->ldi_prefix);
|
||||
}
|
||||
ldi->ldi_prefix = NULL;
|
||||
|
||||
if (NULL != ldi->ldi_suffix) {
|
||||
free(ldi->ldi_suffix);
|
||||
}
|
||||
ldi->ldi_suffix = NULL;
|
||||
|
||||
if (NULL != ldi->ldi_file_suffix) {
|
||||
free(ldi->ldi_file_suffix);
|
||||
}
|
||||
ldi->ldi_file_suffix = NULL;
|
||||
|
||||
if (NULL != ldi->ldi_syslog_ident) {
|
||||
free(ldi->ldi_syslog_ident);
|
||||
}
|
||||
ldi->ldi_syslog_ident = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int make_string(char **no_newline_string, output_desc_t *ldi,
|
||||
const char *format, va_list arglist)
|
||||
{
|
||||
size_t len, total_len;
|
||||
bool want_newline = false;
|
||||
|
||||
/* Make the formatted string */
|
||||
|
||||
vasprintf(no_newline_string, format, arglist);
|
||||
total_len = len = strlen(*no_newline_string);
|
||||
if ('\n' != (*no_newline_string)[len - 1]) {
|
||||
want_newline = true;
|
||||
++total_len;
|
||||
} else if (NULL != ldi->ldi_suffix) {
|
||||
/* if we have a suffix, then we don't want a
|
||||
* newline to appear before it
|
||||
*/
|
||||
(*no_newline_string)[len - 1] = '\0';
|
||||
want_newline = true; /* add newline to end after suffix */
|
||||
/* total_len won't change since we just moved the newline
|
||||
* to appear after the suffix
|
||||
*/
|
||||
}
|
||||
if (NULL != ldi->ldi_prefix) {
|
||||
total_len += strlen(ldi->ldi_prefix);
|
||||
}
|
||||
if (NULL != ldi->ldi_suffix) {
|
||||
total_len += strlen(ldi->ldi_suffix);
|
||||
}
|
||||
if (temp_str_len < total_len + want_newline) {
|
||||
if (NULL != temp_str) {
|
||||
free(temp_str);
|
||||
}
|
||||
temp_str = (char *) malloc(total_len * 2);
|
||||
if (NULL == temp_str) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
temp_str_len = total_len * 2;
|
||||
}
|
||||
if (NULL != ldi->ldi_prefix && NULL != ldi->ldi_suffix) {
|
||||
if (want_newline) {
|
||||
snprintf(temp_str, temp_str_len, "%s%s%s\n",
|
||||
ldi->ldi_prefix, *no_newline_string, ldi->ldi_suffix);
|
||||
} else {
|
||||
snprintf(temp_str, temp_str_len, "%s%s%s", ldi->ldi_prefix,
|
||||
*no_newline_string, ldi->ldi_suffix);
|
||||
}
|
||||
} else if (NULL != ldi->ldi_prefix) {
|
||||
if (want_newline) {
|
||||
snprintf(temp_str, temp_str_len, "%s%s\n",
|
||||
ldi->ldi_prefix, *no_newline_string);
|
||||
} else {
|
||||
snprintf(temp_str, temp_str_len, "%s%s", ldi->ldi_prefix,
|
||||
*no_newline_string);
|
||||
}
|
||||
} else if (NULL != ldi->ldi_suffix) {
|
||||
if (want_newline) {
|
||||
snprintf(temp_str, temp_str_len, "%s%s\n",
|
||||
*no_newline_string, ldi->ldi_suffix);
|
||||
} else {
|
||||
snprintf(temp_str, temp_str_len, "%s%s",
|
||||
*no_newline_string, ldi->ldi_suffix);
|
||||
}
|
||||
} else {
|
||||
if (want_newline) {
|
||||
snprintf(temp_str, temp_str_len, "%s\n", *no_newline_string);
|
||||
} else {
|
||||
snprintf(temp_str, temp_str_len, "%s", *no_newline_string);
|
||||
}
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the actual output. Take a va_list so that we can be called from
|
||||
* multiple different places, even functions that took "..." as input
|
||||
* arguments.
|
||||
*/
|
||||
static int output(int output_id, const char *format, va_list arglist)
|
||||
{
|
||||
int rc = PMIX_SUCCESS;
|
||||
char *str, *out = NULL;
|
||||
output_desc_t *ldi;
|
||||
|
||||
/* Setup */
|
||||
|
||||
if (!initialized) {
|
||||
pmix_output_init();
|
||||
}
|
||||
|
||||
/* If it's valid, used, and enabled, output */
|
||||
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS &&
|
||||
info[output_id].ldi_used && info[output_id].ldi_enabled) {
|
||||
ldi = &info[output_id];
|
||||
|
||||
/* Make the strings */
|
||||
if (PMIX_SUCCESS != (rc = make_string(&str, ldi, format, arglist))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Syslog output -- does not use the newline-appended string */
|
||||
#if defined(HAVE_SYSLOG)
|
||||
if (ldi->ldi_syslog) {
|
||||
syslog(ldi->ldi_syslog_priority, "%s", str);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* All others (stdout, stderr, file) use temp_str, potentially
|
||||
with a newline appended */
|
||||
|
||||
out = temp_str;
|
||||
|
||||
/* stdout output */
|
||||
if (ldi->ldi_stdout) {
|
||||
write(fileno(stdout), out, (int)strlen(out));
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
/* stderr output */
|
||||
if (ldi->ldi_stderr) {
|
||||
write((-1 == default_stderr_fd) ?
|
||||
fileno(stderr) : default_stderr_fd,
|
||||
out, (int)strlen(out));
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
/* File output -- first check to see if the file opening was
|
||||
* delayed. If so, try to open it. If we failed to open it,
|
||||
* then just discard (there are big warnings in the
|
||||
* pmix_output.h docs about this!). */
|
||||
|
||||
if (ldi->ldi_file) {
|
||||
if (ldi->ldi_fd == -1) {
|
||||
if (PMIX_SUCCESS != open_file(output_id)) {
|
||||
++ldi->ldi_file_num_lines_lost;
|
||||
} else if (ldi->ldi_file_num_lines_lost > 0 && 0 <= ldi->ldi_fd) {
|
||||
char buffer[BUFSIZ];
|
||||
char *out = buffer;
|
||||
memset(buffer, 0, BUFSIZ);
|
||||
snprintf(buffer, BUFSIZ - 1,
|
||||
"[WARNING: %d lines lost because the PMIx process session directory did\n not exist when pmix_output() was invoked]\n",
|
||||
ldi->ldi_file_num_lines_lost);
|
||||
write(ldi->ldi_fd, buffer, (int)strlen(buffer));
|
||||
ldi->ldi_file_num_lines_lost = 0;
|
||||
if (out != buffer) {
|
||||
free(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ldi->ldi_fd != -1) {
|
||||
write(ldi->ldi_fd, out, (int)strlen(out));
|
||||
}
|
||||
}
|
||||
free(str);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int pmix_output_get_verbosity(int output_id)
|
||||
{
|
||||
if (output_id >= 0 && output_id < PMIX_OUTPUT_MAX_STREAMS && info[output_id].ldi_used) {
|
||||
return info[output_id].ldi_verbose_level;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
@ -1,561 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2006 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2007-2011 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/** @file
|
||||
* PMIX output stream facility.
|
||||
*
|
||||
* The PMIX output stream facility is used to send output from the PMIX
|
||||
* libraries to output devices. It is meant to fully replace all
|
||||
* forms of printf() (and friends). Output streams are opened via the
|
||||
* pmix_output_open() function call, and then sent output via
|
||||
* pmix_output_verbose(), PMIX_OUTPUT(), and pmix_output(). Streams are
|
||||
* closed with pmix_output_close().
|
||||
*
|
||||
* Streams can multiplex output to several kinds of outputs (one of
|
||||
* each):
|
||||
*
|
||||
* - the syslog (if available)
|
||||
* - standard output
|
||||
* - standard error
|
||||
* - file
|
||||
*
|
||||
* Which outputs to use are specified during pmix_output_open().
|
||||
*
|
||||
* WARNING: When using "file" as an output destination, be aware that
|
||||
* the file may not exist until the session directory for the process
|
||||
* exists. This is at least part of the way through MPI_INIT (for
|
||||
* example). Most MCA components and internals of PMIx won't be
|
||||
* affected by this, but some RTE / startup aspects of PMIx will
|
||||
* not be able to write to a file for output. See pmix_output() for
|
||||
* details on what happens in these cases.
|
||||
*
|
||||
* pmix_output_open() returns an integer handle that is used in
|
||||
* successive calls to PMIX_OUTPUT() and pmix_output() to send output to
|
||||
* the stream.
|
||||
*
|
||||
* The default "verbose" stream is opened after invoking
|
||||
* pmix_output_init() (and closed after invoking
|
||||
* pmix_output_finalize()). This stream outputs to stderr only, and
|
||||
* has a stream handle ID of 0.
|
||||
*
|
||||
* It is erroneous to have one thread close a stream and have another
|
||||
* try to write to it. Multiple threads writing to a single stream
|
||||
* will be serialized in an unspecified order.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_OUTPUT_H_
|
||||
#define PMIX_OUTPUT_H_
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#ifdef HAVE_STDARG_H
|
||||
#include <stdarg.h>
|
||||
#endif
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/* There are systems where all output needs to be redirected to syslog
|
||||
* and away from stdout/stderr or files - e.g., embedded systems whose
|
||||
* sole file system is in flash. To support such systems, we provide
|
||||
* the following environmental variables that support redirecting -all-
|
||||
* output (both from pmix_output and stdout/stderr of processes) to
|
||||
* syslog:
|
||||
*
|
||||
* PMIX_OUTPUT_REDIRECT - set to "syslog" to redirect to syslog. Other
|
||||
* options may someday be supported
|
||||
* PMIX_OUTPUT_SYSLOG_PRI - set to "info", "error", or "warn" to have
|
||||
* output sent to syslog at that priority
|
||||
* PMIX_OUTPUT_SYSLOG_IDENT - a string identifier for the log
|
||||
*
|
||||
* We also define two global variables that notify all other
|
||||
* layers that output is being redirected to syslog at the given
|
||||
* priority. These are used, for example, by the IO forwarding
|
||||
* subsystem to tell it to dump any collected output directly to
|
||||
* syslog instead of forwarding it to another location.
|
||||
*/
|
||||
PMIX_DECLSPEC extern bool pmix_output_redirected_to_syslog;
|
||||
PMIX_DECLSPEC extern int pmix_output_redirected_syslog_pri;
|
||||
|
||||
/**
|
||||
* \class pmix_output_stream_t
|
||||
*
|
||||
* Structure used to request the opening of a PMIX output stream. A
|
||||
* pointer to this structure is passed to pmix_output_open() to tell
|
||||
* the pmix_output subsystem where to send output for a given stream.
|
||||
* It is valid to specify multiple destinations of output for a stream
|
||||
* -- output streams can be multiplexed to multiple different
|
||||
* destinations through the pmix_output facility.
|
||||
*
|
||||
* Note that all strings in this struct are cached on the stream by
|
||||
* value; there is no need to keep them allocated after the return
|
||||
* from pmix_output_open().
|
||||
*/
|
||||
struct pmix_output_stream_t {
|
||||
/** Class parent */
|
||||
pmix_object_t super;
|
||||
|
||||
/**
|
||||
* Indicate the starting verbosity level of the stream.
|
||||
*
|
||||
* Verbose levels are a convenience mechanisms, and are only
|
||||
* consulted when output is sent to a stream through the
|
||||
* pmix_output_verbose() function. Verbose levels are ignored in
|
||||
* PMIX_OUTPUT() and pmix_output().
|
||||
*
|
||||
* Valid verbose levels typically start at 0 (meaning "minimal
|
||||
* information"). Higher verbosity levels generally indicate that
|
||||
* more output and diagnostics should be displayed.
|
||||
*/
|
||||
int lds_verbose_level;
|
||||
|
||||
/**
|
||||
* When pmix_output_stream_t::lds_want_syslog is true, this field is
|
||||
* examined to see what priority output from the stream should be
|
||||
* sent to the syslog.
|
||||
*
|
||||
* This value should be set as per the syslog(3) man page. It is
|
||||
* typically the OR value of "facilty" and "level" values described
|
||||
* in the man page.
|
||||
*/
|
||||
int lds_syslog_priority;
|
||||
/**
|
||||
* When pmix_output_stream_t::lds_want_syslog is true, this field is
|
||||
* examined to see what ident value should be passed to openlog(3).
|
||||
*
|
||||
* If a NULL value is given, the string "pmix" is used.
|
||||
*/
|
||||
#if !defined(__WINDOWS__)
|
||||
char *lds_syslog_ident;
|
||||
#elif !defined(_MSC_VER)
|
||||
char *lds_syslog_ident;
|
||||
#else
|
||||
HANDLE lds_syslog_ident;
|
||||
#endif /* !defined(__WINDOWS__) */
|
||||
|
||||
/**
|
||||
* String prefix added to all output on the stream.
|
||||
*
|
||||
* When this field is non-NULL, it is prefixed to all lines of
|
||||
* output on the stream. When this field is NULL, no prefix is
|
||||
* added to each line of output in the stream. The prefix is copied
|
||||
* to an internal structure in the call to pmix_output_open()!
|
||||
*/
|
||||
char *lds_prefix;
|
||||
|
||||
/**
|
||||
* String suffix added to all output on the stream.
|
||||
*
|
||||
* When this field is non-NULL, it is appended to all lines of
|
||||
* output on the stream. When this field is NULL, no suffix is
|
||||
* added to each line of output in the stream. The suffix is copied
|
||||
* to an internal structure in the call to pmix_output_open()!
|
||||
*/
|
||||
char *lds_suffix;
|
||||
|
||||
/**
|
||||
* Indicates whether the output of the stream is
|
||||
* debugging/developer-only output or not.
|
||||
*
|
||||
* This field should be "true" if the output is for debugging
|
||||
* purposes only. In that case, the output will never be sent to
|
||||
* the stream unless PMIX was configured with --enable-debug.
|
||||
*/
|
||||
bool lds_is_debugging;
|
||||
|
||||
/**
|
||||
* Indicates whether output of the stream should be sent to the
|
||||
* syslog or not.
|
||||
*
|
||||
* If this field is true, output from this stream is sent to the
|
||||
* syslog, and the following fields are also examined:
|
||||
*
|
||||
* - lds_syslog_priority
|
||||
* - lds_syslog_ident
|
||||
* - lds_prefix
|
||||
*
|
||||
* If this field is false, the above three fields are ignored.
|
||||
*/
|
||||
bool lds_want_syslog;
|
||||
|
||||
/**
|
||||
* Whether to send stream output to stdout or not.
|
||||
*
|
||||
* If this field is true, stream output is sent to stdout.
|
||||
*/
|
||||
bool lds_want_stdout;
|
||||
/**
|
||||
* Whether to send stream output to stderr or not.
|
||||
*
|
||||
* If this field is true, stream output is sent to stderr.
|
||||
*/
|
||||
bool lds_want_stderr;
|
||||
|
||||
/**
|
||||
* Whether to send stream output to a file or not.
|
||||
*
|
||||
* When this field is true, stream output is sent to a file, and the
|
||||
* following fields are also examined:
|
||||
*
|
||||
* - lds_want_file_append
|
||||
* - lda_file_suffix
|
||||
*/
|
||||
bool lds_want_file;
|
||||
/**
|
||||
* When pmix_output_stream_t::lds_want_file is true, this field
|
||||
* indicates whether to append the file (if it exists) or overwrite
|
||||
* it.
|
||||
*
|
||||
* If false, the file is opened with the O_TRUNC flag.
|
||||
*/
|
||||
bool lds_want_file_append;
|
||||
/**
|
||||
* When pmix_output_stream_t::lds_want_file is true, this field
|
||||
* indicates the string suffix to add to the filename.
|
||||
*
|
||||
* The output file will be in the directory and begin with the
|
||||
* prefix set by pmix_output_set_output_file_info() (e.g.,
|
||||
* "$dir/$prefix$suffix"). If this field is NULL and
|
||||
* lds_want_file is true, then the suffix "output.txt" is used.
|
||||
*
|
||||
* Note that it is possible that the output directory may not
|
||||
* exist when pmix_output_open() is invoked. See pmix_output()
|
||||
* for details on what happens in this situation.
|
||||
*/
|
||||
char *lds_file_suffix;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience typedef
|
||||
*/
|
||||
typedef struct pmix_output_stream_t pmix_output_stream_t;
|
||||
|
||||
/**
|
||||
* Initializes the output stream system and opens a default
|
||||
* "verbose" stream.
|
||||
*
|
||||
* @retval true Upon success.
|
||||
* @retval false Upon failure.
|
||||
*
|
||||
* This should be the first function invoked in the output
|
||||
* subsystem. After this call, the default "verbose" stream is open
|
||||
* and can be written to via calls to pmix_output_verbose() and
|
||||
* pmix_output_error().
|
||||
*
|
||||
* By definition, the default verbose stream has a handle ID of 0,
|
||||
* and has a verbose level of 0.
|
||||
*/
|
||||
PMIX_DECLSPEC bool pmix_output_init(void);
|
||||
|
||||
/**
|
||||
* Shut down the output stream system.
|
||||
*
|
||||
* Shut down the output stream system, including the default verbose
|
||||
* stream.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_finalize(void);
|
||||
|
||||
/**
|
||||
* Opens an output stream.
|
||||
*
|
||||
* @param lds A pointer to pmix_output_stream_t describing what the
|
||||
* characteristics of the output stream should be.
|
||||
*
|
||||
* This function opens an output stream and returns an integer
|
||||
* handle. The caller is responsible for maintaining the handle and
|
||||
* using it in successive calls to PMIX_OUTPUT(), pmix_output(),
|
||||
* pmix_output_switch(), and pmix_output_close().
|
||||
*
|
||||
* If lds is NULL, the default descriptions will be used, meaning
|
||||
* that output will only be sent to stderr.
|
||||
*
|
||||
* It is safe to have multiple threads invoke this function
|
||||
* simultaneously; their execution will be serialized in an
|
||||
* unspecified manner.
|
||||
*
|
||||
* Be sure to see pmix_output() for a description of what happens
|
||||
* when open_open() / pmix_output() is directed to send output to a
|
||||
* file but the process session directory does not yet exist.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_output_open(pmix_output_stream_t *lds);
|
||||
|
||||
/**
|
||||
* Re-opens / redirects an output stream.
|
||||
*
|
||||
* @param output_id Stream handle to reopen
|
||||
* @param lds A pointer to pmix_output_stream_t describing what the
|
||||
* characteristics of the reopened output stream should be.
|
||||
*
|
||||
* This function redirects an existing stream into a new [set of]
|
||||
* location[s], as specified by the lds parameter. If the output_id
|
||||
* passed is invalid, this call is effectively the same as opening a
|
||||
* new stream with a specific stream handle.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_output_reopen(int output_id, pmix_output_stream_t *lds);
|
||||
|
||||
/**
|
||||
* Enables and disables output streams.
|
||||
*
|
||||
* @param output_id Stream handle to switch
|
||||
* @param enable Boolean indicating whether to enable the stream
|
||||
* output or not.
|
||||
*
|
||||
* @returns The previous enable state of the stream (true == enabled,
|
||||
* false == disabled).
|
||||
*
|
||||
* The output of a stream can be temporarily disabled by passing an
|
||||
* enable value to false, and later resumed by passing an enable
|
||||
* value of true. This does not close the stream -- it simply tells
|
||||
* the pmix_output subsystem to intercept and discard any output sent
|
||||
* to the stream via PMIX_OUTPUT() or pmix_output() until the output
|
||||
* is re-enabled.
|
||||
*/
|
||||
PMIX_DECLSPEC bool pmix_output_switch(int output_id, bool enable);
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
* Reopens all existing output streams.
|
||||
*
|
||||
* This function should never be called by user applications; it is
|
||||
* typically only invoked after a restart (i.e., in a new process)
|
||||
* where output streams need to be re-initialized.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_reopen_all(void);
|
||||
|
||||
/**
|
||||
* Close an output stream.
|
||||
*
|
||||
* @param output_id Handle of the stream to close.
|
||||
*
|
||||
* Close an output stream. No output will be sent to the stream
|
||||
* after it is closed. Be aware that output handles tend to be
|
||||
* re-used; it is possible that after a stream is closed, if another
|
||||
* stream is opened, it will get the same handle value.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_close(int output_id);
|
||||
|
||||
/**
|
||||
* Main function to send output to a stream.
|
||||
*
|
||||
* @param output_id Stream id returned from pmix_output_open().
|
||||
* @param format printf-style format string.
|
||||
* @param varargs printf-style varargs list to fill the string
|
||||
* specified by the format parameter.
|
||||
*
|
||||
* This is the main function to send output to custom streams (note
|
||||
* that output to the default "verbose" stream is handled through
|
||||
* pmix_output_verbose() and pmix_output_error()).
|
||||
*
|
||||
* It is never necessary to send a trailing "\n" in the strings to
|
||||
* this function; some streams requires newlines, others do not --
|
||||
* this function will append newlines as necessary.
|
||||
*
|
||||
* Verbosity levels are ignored in this function.
|
||||
*
|
||||
* Note that for output streams that are directed to files, the
|
||||
* files are stored under the process' session directory. If the
|
||||
* session directory does not exist when pmix_output() is invoked,
|
||||
* the output will be discarded! Once the session directory is
|
||||
* created, pmix_output() will automatically create the file and
|
||||
* writing to it.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output(int output_id, const char *format, ...) __pmix_attribute_format__(__printf__, 2, 3);
|
||||
|
||||
/**
|
||||
* Send output to a stream only if the passed verbosity level is
|
||||
* high enough.
|
||||
*
|
||||
* @param output_id Stream id returned from pmix_output_open().
|
||||
* @param level Target verbosity level.
|
||||
* @param format printf-style format string.
|
||||
* @param varargs printf-style varargs list to fill the string
|
||||
* specified by the format parameter.
|
||||
*
|
||||
* Output is only sent to the stream if the current verbosity level
|
||||
* is greater than or equal to the level parameter. This mechanism
|
||||
* can be used to send "information" kinds of output to user
|
||||
* applications, but only when the user has asked for a high enough
|
||||
* verbosity level.
|
||||
*
|
||||
* It is never necessary to send a trailing "\n" in the strings to
|
||||
* this function; some streams requires newlines, others do not --
|
||||
* this function will append newlines as necessary.
|
||||
*
|
||||
* This function is really a convenience wrapper around checking the
|
||||
* current verbosity level set on the stream, and if the passed
|
||||
* level is less than or equal to the stream's verbosity level, this
|
||||
* function will effectively invoke pmix_output to send the output to
|
||||
* the stream.
|
||||
*
|
||||
* @see pmix_output_set_verbosity()
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_verbose(int verbose_level, int output_id,
|
||||
const char *format, ...) __pmix_attribute_format__(__printf__, 3, 4);
|
||||
|
||||
/**
|
||||
* Same as pmix_output_verbose(), but takes a va_list form of varargs.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_vverbose(int verbose_level, int output_id,
|
||||
const char *format, va_list ap) __pmix_attribute_format__(__printf__, 3, 0);
|
||||
|
||||
/**
|
||||
* Send output to a string if the verbosity level is high enough.
|
||||
*
|
||||
* @param output_id Stream id returned from pmix_output_open().
|
||||
* @param level Target verbosity level.
|
||||
* @param format printf-style format string.
|
||||
* @param varargs printf-style varargs list to fill the string
|
||||
* specified by the format parameter.
|
||||
*
|
||||
* Exactly the same as pmix_output_verbose(), except the output it
|
||||
* sent to a string instead of to the stream. If the verbose
|
||||
* level is not high enough, NULL is returned. The caller is
|
||||
* responsible for free()'ing the returned string.
|
||||
*/
|
||||
PMIX_DECLSPEC char *pmix_output_string(int verbose_level, int output_id,
|
||||
const char *format, ...) __pmix_attribute_format__(__printf__, 3, 4);
|
||||
|
||||
/**
|
||||
* Same as pmix_output_string, but accepts a va_list form of varargs.
|
||||
*/
|
||||
PMIX_DECLSPEC char *pmix_output_vstring(int verbose_level, int output_id,
|
||||
const char *format, va_list ap) __pmix_attribute_format__(__printf__, 3, 0);
|
||||
|
||||
/**
|
||||
* Set the verbosity level for a stream.
|
||||
*
|
||||
* @param output_id Stream id returned from pmix_output_open().
|
||||
* @param level New verbosity level
|
||||
*
|
||||
* This function sets the verbosity level on a given stream. It
|
||||
* will be used for all future invocations of pmix_output_verbose().
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_set_verbosity(int output_id, int level);
|
||||
|
||||
/**
|
||||
* Get the verbosity level for a stream
|
||||
*
|
||||
* @param output_id Stream id returned from pmix_output_open()
|
||||
* @returns Verbosity of stream
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_output_get_verbosity(int output_id);
|
||||
|
||||
/**
|
||||
* Set characteristics for output files.
|
||||
*
|
||||
* @param dir Directory where output files will go
|
||||
* @param olddir If non-NULL, the directory where output files
|
||||
* were previously opened
|
||||
* @param prefix Prefix of files in the output directory
|
||||
* @param oldprefix If non-NULL, the old prefix
|
||||
*
|
||||
* This function controls the final filename used for all new
|
||||
* output streams that request output files. Specifically, when
|
||||
* pmix_output_stream_t::lds_want_file is true, the output
|
||||
* filename will be of the form $dir/$prefix$suffix.
|
||||
*
|
||||
* The default value for the output directory is whatever is
|
||||
* specified in the TMPDIR environment variable if it exists, or
|
||||
* $HOME if it does not. The default value for the prefix is
|
||||
* "output-pid<pid>-" (where "<pid>" is replaced by the PID of the
|
||||
* current process).
|
||||
*
|
||||
* If dir or prefix are NULL, new values are not set. The strings
|
||||
* represented by dir and prefix are copied into internal storage;
|
||||
* it is safe to pass string constants or free() these values
|
||||
* after pmix_output_set_output_file_info() returns.
|
||||
*
|
||||
* If olddir or oldprefix are not NULL, copies of the old
|
||||
* directory and prefix (respectively) are returned in these
|
||||
* parameters. The caller is responsible for calling (free) on
|
||||
* these values. This allows one to get the old values, output an
|
||||
* output file in a specific directory and/or with a specific
|
||||
* prefix, and then restore the old values.
|
||||
*
|
||||
* Note that this function only affects the creation of \em new
|
||||
* streams -- streams that have already started writing to output
|
||||
* files are not affected (i.e., their output files are not moved
|
||||
* to the new directory). More specifically, the pmix_output
|
||||
* system only opens/creates output files lazily -- so calling
|
||||
* this function affects both new streams \em and any stream that
|
||||
* was previously opened but had not yet output anything.
|
||||
*/
|
||||
PMIX_DECLSPEC void pmix_output_set_output_file_info(const char *dir,
|
||||
const char *prefix,
|
||||
char **olddir,
|
||||
char **oldprefix);
|
||||
|
||||
#if PMIX_ENABLE_DEBUG
|
||||
/**
|
||||
* Main macro for use in sending debugging output to output streams;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-debug.
|
||||
*
|
||||
* @see pmix_output()
|
||||
*/
|
||||
#define PMIX_OUTPUT(a) pmix_output a
|
||||
|
||||
/**
|
||||
* Macro for use in sending debugging output to the output
|
||||
* streams. Will be "compiled out" when PMIX is configured
|
||||
* without --enable-debug.
|
||||
*
|
||||
* @see pmix_output_verbose()
|
||||
*/
|
||||
#define PMIX_OUTPUT_VERBOSE(a) pmix_output_verbose a
|
||||
#else
|
||||
/**
|
||||
* Main macro for use in sending debugging output to output streams;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-debug.
|
||||
*
|
||||
* @see pmix_output()
|
||||
*/
|
||||
#define PMIX_OUTPUT(a)
|
||||
|
||||
/**
|
||||
* Macro for use in sending debugging output to the output
|
||||
* streams. Will be "compiled out" when PMIX is configured
|
||||
* without --enable-debug.
|
||||
*
|
||||
* @see pmix_output_verbose()
|
||||
*/
|
||||
#define PMIX_OUTPUT_VERBOSE(a)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Declare the class of this type. Note that the constructor for
|
||||
* this class is for convenience only -- it is \em not necessary
|
||||
* to be invoked. If the constructor it used, it sets all values
|
||||
* in the struct to be false / 0 (i.e., turning off all output).
|
||||
* The intended usage is to invoke the constructor and then enable
|
||||
* the output fields that you want.
|
||||
*/
|
||||
PMIX_DECLSPEC PMIX_CLASS_DECLARATION(pmix_output_stream_t);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_OUTPUT_H_ */
|
||||
|
@ -1,239 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2007 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2007-2013 Los Alamos National Security, LLC. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "src/util/printf.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/pmix_environ.h"
|
||||
|
||||
#define PMIX_DEFAULT_TMPDIR "/tmp"
|
||||
|
||||
/*
|
||||
* Merge two environ-like char arrays, ensuring that there are no
|
||||
* duplicate entires
|
||||
*/
|
||||
char **pmix_environ_merge(char **minor, char **major)
|
||||
{
|
||||
int i;
|
||||
char **ret = NULL;
|
||||
char *name, *value;
|
||||
|
||||
/* Check for bozo cases */
|
||||
|
||||
if (NULL == major) {
|
||||
if (NULL == minor) {
|
||||
return NULL;
|
||||
} else {
|
||||
return pmix_argv_copy(minor);
|
||||
}
|
||||
}
|
||||
|
||||
/* First, copy major */
|
||||
|
||||
ret = pmix_argv_copy(major);
|
||||
|
||||
/* Do we have something in minor? */
|
||||
|
||||
if (NULL == minor) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Now go through minor and call pmix_setenv(), but with overwrite
|
||||
as false */
|
||||
|
||||
for (i = 0; NULL != minor[i]; ++i) {
|
||||
value = strchr(minor[i], '=');
|
||||
if (NULL == value) {
|
||||
pmix_setenv(minor[i], NULL, false, &ret);
|
||||
} else {
|
||||
|
||||
/* strdup minor[i] in case it's a constat string */
|
||||
|
||||
name = strdup(minor[i]);
|
||||
value = name + (value - minor[i]);
|
||||
*value = '\0';
|
||||
pmix_setenv(name, value + 1, false, &ret);
|
||||
free(name);
|
||||
}
|
||||
}
|
||||
|
||||
/* All done */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Portable version of setenv(), allowing editing of any environ-like
|
||||
* array
|
||||
*/
|
||||
int pmix_setenv(const char *name, const char *value, bool overwrite,
|
||||
char ***env)
|
||||
{
|
||||
int i;
|
||||
char *newvalue, *compare;
|
||||
size_t len;
|
||||
|
||||
/* Make the new value */
|
||||
|
||||
if (NULL == value) {
|
||||
asprintf(&newvalue, "%s=", name);
|
||||
} else {
|
||||
asprintf(&newvalue, "%s=%s", name, value);
|
||||
}
|
||||
if (NULL == newvalue) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
|
||||
/* Check the bozo case */
|
||||
|
||||
if( NULL == env ) {
|
||||
return PMIX_ERR_BAD_PARAM;
|
||||
} else if (NULL == *env) {
|
||||
i = 0;
|
||||
pmix_argv_append(&i, env, newvalue);
|
||||
free(newvalue);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* If this is the "environ" array, use putenv */
|
||||
if( *env == environ ) {
|
||||
/* THIS IS POTENTIALLY A MEMORY LEAK! But I am doing it
|
||||
because so that we don't violate the law of least
|
||||
astonishmet for PMIX developers (i.e., those that don't
|
||||
check the return code of pmix_setenv() and notice that we
|
||||
returned an error if you passed in the real environ) */
|
||||
putenv(newvalue);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make something easy to compare to */
|
||||
|
||||
asprintf(&compare, "%s=", name);
|
||||
if (NULL == compare) {
|
||||
free(newvalue);
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
len = strlen(compare);
|
||||
|
||||
/* Look for a duplicate that's already set in the env */
|
||||
|
||||
for (i = 0; (*env)[i] != NULL; ++i) {
|
||||
if (0 == strncmp((*env)[i], compare, len)) {
|
||||
if (overwrite) {
|
||||
free((*env)[i]);
|
||||
(*env)[i] = newvalue;
|
||||
free(compare);
|
||||
return PMIX_SUCCESS;
|
||||
} else {
|
||||
free(compare);
|
||||
free(newvalue);
|
||||
return PMIX_EXISTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we found no match, append this value */
|
||||
|
||||
i = pmix_argv_count(*env);
|
||||
pmix_argv_append(&i, env, newvalue);
|
||||
|
||||
/* All done */
|
||||
|
||||
free(compare);
|
||||
free(newvalue);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Portable version of unsetenv(), allowing editing of any
|
||||
* environ-like array
|
||||
*/
|
||||
int pmix_unsetenv(const char *name, char ***env)
|
||||
{
|
||||
int i;
|
||||
char *compare;
|
||||
size_t len;
|
||||
bool found;
|
||||
|
||||
/* Check for bozo case */
|
||||
|
||||
if (NULL == *env) {
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Make something easy to compare to */
|
||||
|
||||
asprintf(&compare, "%s=", name);
|
||||
if (NULL == compare) {
|
||||
return PMIX_ERR_OUT_OF_RESOURCE;
|
||||
}
|
||||
len = strlen(compare);
|
||||
|
||||
/* Look for a duplicate that's already set in the env. If we find
|
||||
it, free it, and then start shifting all elements down one in
|
||||
the array. */
|
||||
|
||||
found = false;
|
||||
for (i = 0; (*env)[i] != NULL; ++i) {
|
||||
if (0 != strncmp((*env)[i], compare, len))
|
||||
continue;
|
||||
if (environ != *env) {
|
||||
free((*env)[i]);
|
||||
}
|
||||
for (; (*env)[i] != NULL; ++i)
|
||||
(*env)[i] = (*env)[i + 1];
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
free(compare);
|
||||
|
||||
/* All done */
|
||||
|
||||
return (found) ? PMIX_SUCCESS : PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
const char* pmix_tmp_directory( void )
|
||||
{
|
||||
const char* str;
|
||||
|
||||
if( NULL == (str = getenv("TMPDIR")) )
|
||||
if( NULL == (str = getenv("TEMP")) )
|
||||
if( NULL == (str = getenv("TMP")) )
|
||||
str = PMIX_DEFAULT_TMPDIR;
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* pmix_home_directory( void )
|
||||
{
|
||||
char* home = getenv("HOME");
|
||||
|
||||
return home;
|
||||
}
|
||||
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2007 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/** @file
|
||||
*
|
||||
* Buffer safe printf functions for portability to archaic platforms.
|
||||
*/
|
||||
|
||||
#ifndef PMIX_PRINTF_H
|
||||
#define PMIX_PRINTF_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
BEGIN_C_DECLS
|
||||
|
||||
/**
|
||||
* Writes to a string under the control of a format string
|
||||
* that specifies how subsequent arguments are converted for output.
|
||||
*
|
||||
* @param str Output string buffer
|
||||
* @param size Size of string buffer
|
||||
* @param fmt Output format
|
||||
* @return Length of output string
|
||||
*
|
||||
* At most size-1 characters are printed into the output string (the
|
||||
* size'th character then gets the terminating `\0'); if the return
|
||||
* value is greater than or equal to the size argument, the string was
|
||||
* too short and some of the printed characters were discarded. The
|
||||
* output is always null-terminated.
|
||||
*
|
||||
* Returns the number of characters that would have been printed if
|
||||
* the size were unlimited (again, not including the final `\0').
|
||||
*
|
||||
* THIS IS A PORTABILITY FEATURE: USE snprintf() in CODE.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_snprintf(char *str, size_t size, const char *fmt, ...) __pmix_attribute_format__(__printf__, 3, 4);
|
||||
|
||||
|
||||
/**
|
||||
* Writes to a string under the control of a format string that
|
||||
* specifies how arguments accessed via the variable-length argument
|
||||
* facilities of stdarg(3) are converted for output.
|
||||
*
|
||||
* @param str Output string buffer
|
||||
* @param size Size of string buffer
|
||||
* @param fmt Output format
|
||||
* @param ap Variable argument list pointer
|
||||
* @return Length of output string
|
||||
*
|
||||
* At most size-1 characters are printed into the output string (the
|
||||
* size'th character then gets the terminating `\0'); if the return
|
||||
* value is greater than or equal to the size argument, the string was
|
||||
* too short and some of the printed characters were discarded. The
|
||||
* output is always null-terminated.
|
||||
*
|
||||
* Returns the number of characters that would have been printed if
|
||||
* the size were unlimited (again, not including the final `\0').
|
||||
*
|
||||
* THIS IS A PORTABILITY FEATURE: USE vsnprintf() in CODE.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_vsnprintf(char *str, size_t size, const char *fmt, va_list ap) __pmix_attribute_format__(__printf__, 3, 0);
|
||||
|
||||
/**
|
||||
* Allocates and writes to a string under the control of a format
|
||||
* string that specifies how subsequent arguments are converted for
|
||||
* output.
|
||||
*
|
||||
* @param *ptr Pointer to output string buffer
|
||||
* @param fmt Output format
|
||||
* @return Length of output string
|
||||
*
|
||||
* Sets *ptr to be a pointer to a buffer sufficiently large to hold
|
||||
* the formatted string. This pointer should be passed to free(3) to
|
||||
* release the allocated storage when it is no longer needed. If
|
||||
* sufficient space cannot be allocated, asprintf() and vasprintf()
|
||||
* will return -1 and set ret to be a NULL pointer.
|
||||
*
|
||||
* Returns the number of characters printed.
|
||||
*
|
||||
* THIS IS A PORTABILITY FEATURE: USE asprintf() in CODE.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_asprintf(char **ptr, const char *fmt, ...) __pmix_attribute_format__(__printf__, 2, 3);
|
||||
|
||||
|
||||
/**
|
||||
* Allocates and writes to a string under the control of a format
|
||||
* string that specifies how arguments accessed via the
|
||||
* variable-length argument facilities of stdarg(3) are converted for
|
||||
* output.
|
||||
*
|
||||
* @param *ptr Pointer to output string buffer
|
||||
* @param fmt Output format
|
||||
* @param ap Variable argument list pointer
|
||||
* @return Length of output string
|
||||
*
|
||||
* Sets *ptr to be a pointer to a buffer sufficiently large to hold
|
||||
* the formatted string. This pointer should be passed to free(3) to
|
||||
* release the allocated storage when it is no longer needed. If
|
||||
* sufficient space cannot be allocated, asprintf() and vasprintf()
|
||||
* will return -1 and set ret to be a NULL pointer.
|
||||
*
|
||||
* Returns the number of characters printed.
|
||||
*
|
||||
* THIS IS A PORTABILITY FEATURE: USE vasprintf() in CODE.
|
||||
*/
|
||||
PMIX_DECLSPEC int pmix_vasprintf(char **ptr, const char *fmt, va_list ap) __pmix_attribute_format__(__printf__, 2, 0);
|
||||
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
#endif /* PMIX_PRINTF_H */
|
||||
|
@ -1,129 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include PMIX_EVENT_HEADER
|
||||
#include PMIX_EVENT2_THREAD_HEADER
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/util/error.h"
|
||||
#include "src/util/fd.h"
|
||||
|
||||
#include <pmix/pmix_common.h>
|
||||
#include "src/util/progress_threads.h"
|
||||
|
||||
static volatile bool evlib_active;
|
||||
static int block_pipe[2];
|
||||
static pmix_event_t block_ev;
|
||||
static pthread_t engine;
|
||||
static bool block_active = false;
|
||||
static bool thread_initalized = false;
|
||||
|
||||
static void wakeup(int fd, short args, void *cbdata)
|
||||
{
|
||||
/* if this event fired, then the blocker event will
|
||||
* be deleted from the event base by libevent, so flag
|
||||
* it so we don't try to delete it again */
|
||||
block_active = false;
|
||||
}
|
||||
static void* progress_engine(void *obj)
|
||||
{
|
||||
pmix_event_base_t *ev_base = (pmix_event_base_t *)obj;
|
||||
while (evlib_active) {
|
||||
event_base_loop(ev_base, EVLOOP_ONCE);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pmix_event_base_t* pmix_start_progress_thread()
|
||||
{
|
||||
pmix_event_base_t *ev_base;
|
||||
/* Setup threading */
|
||||
evthread_use_pthreads();
|
||||
/* Create base for events */
|
||||
if (NULL == (ev_base = (pmix_event_base_t*)event_base_new())) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_OUT_OF_RESOURCE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* add an event it can block on */
|
||||
if (0 > pipe(block_pipe)) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_IN_ERRNO);
|
||||
return NULL;
|
||||
}
|
||||
/* Make sure the pipe FDs are set to close-on-exec so that
|
||||
they don't leak into children */
|
||||
if (pmix_fd_set_cloexec(block_pipe[0]) != PMIX_SUCCESS ||
|
||||
pmix_fd_set_cloexec(block_pipe[1]) != PMIX_SUCCESS) {
|
||||
PMIX_ERROR_LOG(PMIX_ERR_IN_ERRNO);
|
||||
close(block_pipe[0]);
|
||||
close(block_pipe[1]);
|
||||
event_base_free(ev_base);
|
||||
return NULL;
|
||||
}
|
||||
event_assign(&block_ev, ev_base, block_pipe[0],
|
||||
EV_READ, wakeup, NULL);
|
||||
event_add(&block_ev, 0);
|
||||
evlib_active = true;
|
||||
block_active = true;
|
||||
|
||||
/* fork off a thread to progress it */
|
||||
if (0 > pthread_create(&engine, NULL, progress_engine, (void*)ev_base)) {
|
||||
PMIX_ERROR_LOG(PMIX_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
if (!thread_initalized) {
|
||||
thread_initalized = true;
|
||||
}
|
||||
return ev_base;
|
||||
}
|
||||
|
||||
void pmix_stop_progress_thread(pmix_event_base_t *ev_base)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!thread_initalized) {
|
||||
/* nothing we can do */
|
||||
return;
|
||||
}
|
||||
|
||||
/* mark it as inactive */
|
||||
evlib_active = false;
|
||||
/* if present, use the block to break it loose just in
|
||||
* case the thread is blocked in a call to select for
|
||||
* a long time */
|
||||
if (block_active) {
|
||||
i=1;
|
||||
write(block_pipe[1], &i, sizeof(int));
|
||||
}
|
||||
/* break the event loop - this will cause the loop to exit
|
||||
* upon completion of any current event */
|
||||
event_base_loopbreak(ev_base);
|
||||
/* wait for thread to exit */
|
||||
pthread_join(engine, NULL);
|
||||
if (block_active) {
|
||||
/* delete the blocking event */
|
||||
event_del(&block_ev);
|
||||
block_active = false;
|
||||
}
|
||||
/* close the pipes */
|
||||
close(block_pipe[0]);
|
||||
close(block_pipe[1]);
|
||||
return;
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PROGRESS_THREADS_H
|
||||
#define PROGRESS_THREADS_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
/* start a progress thread, assigning it the provided name for
|
||||
* tracking purposes. If create_block is true, then this function
|
||||
* will also create a pipe so that libevent has something to block
|
||||
* against, thus keeping the thread from free-running
|
||||
*/
|
||||
PMIX_DECLSPEC pmix_event_base_t* pmix_start_progress_thread(void);
|
||||
|
||||
/* stop the progress thread of the provided name. This function will
|
||||
* also cleanup the blocking pipes and release the event base if
|
||||
* the cleanup param is true */
|
||||
PMIX_DECLSPEC void pmix_stop_progress_thread(pmix_event_base_t *ev_base);
|
||||
|
||||
#endif
|
@ -1,421 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2014 Artem Polyakov <artpol84@gmail.com>
|
||||
* Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef PMIX_UTIL_TIMING_H
|
||||
#define PMIX_UTIL_TIMING_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/rename.h>
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
|
||||
#if PMIX_ENABLE_TIMING
|
||||
|
||||
#define PMIX_TIMING_DESCR_MAX 1024
|
||||
#define PMIX_TIMING_BUFSIZE 32
|
||||
#define PMIX_TIMING_OUTBUF_SIZE (10*1024)
|
||||
|
||||
typedef enum {
|
||||
PMIX_TIMING_TRACE,
|
||||
PMIX_TIMING_INTDESCR,
|
||||
PMIX_TIMING_INTBEGIN,
|
||||
PMIX_TIMING_INTEND
|
||||
} pmix_event_type_t;
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
int fib;
|
||||
pmix_event_type_t type;
|
||||
const char *func;
|
||||
const char *file;
|
||||
int line;
|
||||
double ts, ts_ovh;
|
||||
char descr[PMIX_TIMING_DESCR_MAX];
|
||||
int id;
|
||||
} pmix_timing_event_t;
|
||||
|
||||
typedef double (*get_ts_t)(void);
|
||||
|
||||
typedef struct pmix_timing_t
|
||||
{
|
||||
int next_id_cntr;
|
||||
// not thread safe!
|
||||
// The whole implementation is not thread safe now
|
||||
// since it is supposed to be used in service
|
||||
// thread only. Fix in the future or now?
|
||||
int current_id;
|
||||
pmix_list_t *events;
|
||||
pmix_timing_event_t *buffer;
|
||||
size_t buffer_offset, buffer_size;
|
||||
get_ts_t get_ts;
|
||||
} pmix_timing_t;
|
||||
|
||||
typedef struct {
|
||||
pmix_timing_t *t;
|
||||
pmix_timing_event_t *ev;
|
||||
int errcode;
|
||||
} pmix_timing_prep_t;
|
||||
|
||||
/* Pass down our namespace and rank for pretty-print purposes */
|
||||
void pmix_init_id(char* nspace, int rank);
|
||||
|
||||
/**
|
||||
* Initialize timing structure.
|
||||
*
|
||||
* @param t pointer to the timing handler structure
|
||||
*/
|
||||
void pmix_timing_init(pmix_timing_t *t);
|
||||
|
||||
/**
|
||||
* Prepare timing event, do all printf-like processing.
|
||||
* Should not be directly used - for service purposes only.
|
||||
*
|
||||
* @param t pointer to the timing handler structure
|
||||
* @param fmt printf-like format
|
||||
* @param ... other parameters that should be converted to string representation
|
||||
*
|
||||
* @retval partly filled pmix_timing_prep_t structure
|
||||
*/
|
||||
pmix_timing_prep_t pmix_timing_prep_ev(pmix_timing_t *t, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* Prepare timing event, ignore printf-like processing.
|
||||
* Should not be directly used - for service purposes only.
|
||||
*
|
||||
* @param t pointer to the timing handler structure
|
||||
* @param fmt printf-like format
|
||||
* @param ... other parameters that should be converted to string representation
|
||||
*
|
||||
* @retval partly filled pmix_timing_prep_t structure
|
||||
*/
|
||||
pmix_timing_prep_t pmix_timing_prep_ev_end(pmix_timing_t *t, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* Enqueue timing event into the list of events in handler 't'.
|
||||
*
|
||||
* @param p result of pmix_timing_prep_ev
|
||||
* @param func function name where event occurs
|
||||
* @param file file name where event occurs
|
||||
* @param line line number in the file
|
||||
*
|
||||
* @retval
|
||||
*/
|
||||
void pmix_timing_add_step(pmix_timing_prep_t p, const char *func,
|
||||
const char *file, int line);
|
||||
|
||||
/**
|
||||
* Enqueue the description of the interval into a list of events
|
||||
* in handler 't'.
|
||||
*
|
||||
* @param p result of pmix_timing_prep_ev
|
||||
* @param func function name where event occurs
|
||||
* @param file file name where event occurs
|
||||
* @param line line number in the file
|
||||
*
|
||||
* @retval id of event interval
|
||||
*/
|
||||
int pmix_timing_descr(pmix_timing_prep_t p, const char *func,
|
||||
const char *file, int line);
|
||||
|
||||
/**
|
||||
* Enqueue the beginning of timing interval that already has the
|
||||
* description and assigned id into the list of events
|
||||
* in handler 't'.
|
||||
*
|
||||
* @param p result of pmix_timing_prep_ev
|
||||
* @param func function name where event occurs
|
||||
* @param file file name where event occurs
|
||||
* @param line line number in the file
|
||||
*
|
||||
* @retval
|
||||
*/
|
||||
void pmix_timing_start_id(pmix_timing_t *t, int id, const char *func,
|
||||
const char *file, int line);
|
||||
|
||||
/**
|
||||
* Enqueue the end of timing interval that already has
|
||||
* description and assigned id into the list of events
|
||||
* in handler 't'.
|
||||
*
|
||||
* @param p result of pmix_timing_prep_ev
|
||||
* @param func function name where event occurs
|
||||
* @param file file name where event occurs
|
||||
* @param line line number in the file
|
||||
*
|
||||
* @retval
|
||||
*/
|
||||
void pmix_timing_end(pmix_timing_t *t, int id, const char *func,
|
||||
const char *file, int line );
|
||||
|
||||
/**
|
||||
* Enqueue both description and start of timing interval
|
||||
* into the list of events and assign its id.
|
||||
*
|
||||
* @param p result of pmix_timing_prep_ev
|
||||
* @param func function name where event occurs
|
||||
* @param file file name where event occurs
|
||||
* @param line line number in the file
|
||||
*
|
||||
* @retval interval id
|
||||
*/
|
||||
static inline int pmix_timing_start_init(pmix_timing_prep_t p,
|
||||
const char *func,
|
||||
const char *file, int line)
|
||||
{
|
||||
int id = pmix_timing_descr(p, func, file, line);
|
||||
if( id < 0 )
|
||||
return id;
|
||||
pmix_timing_start_id(p.t, id, func, file, line);
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* The wrapper that is used to stop last measurement in PMIX_TIMING_MNEXT.
|
||||
*
|
||||
* @param p result of pmix_timing_prep_ev
|
||||
* @param func function name where event occurs
|
||||
* @param file file name where event occurs
|
||||
* @param line line number in the file
|
||||
*
|
||||
* @retval interval id
|
||||
*/
|
||||
void pmix_timing_end_prep(pmix_timing_prep_t p,
|
||||
const char *func, const char *file, int line);
|
||||
|
||||
/**
|
||||
* Report all events that were enqueued in the timing handler 't'.
|
||||
* - if fname == NULL the output will be done using pmix_output and
|
||||
* each line will be prefixed with "prefix" to ease grep'ing.
|
||||
* - otherwise the corresponding file will be used for output in "append" mode
|
||||
* WARRNING: not all filesystems provide enough support for that feature, some records may
|
||||
* disappear.
|
||||
*
|
||||
* @param t timing handler
|
||||
* @param account_overhead consider malloc overhead introduced by timing code
|
||||
* @param prefix prefix to use when no fname was specifyed to ease grep'ing
|
||||
* @param fname name of the output file (may be NULL)
|
||||
*
|
||||
* @retval PMIX_SUCCESS On success
|
||||
* @retval PMIX_ERROR or PMIX_ERR_OUT_OF_RESOURCE On failure
|
||||
*/
|
||||
pmix_status_t pmix_timing_report(pmix_timing_t *t, char *fname);
|
||||
|
||||
/**
|
||||
* Report all intervals that were enqueued in the timing handler 't'.
|
||||
* - if fname == NULL the output will be done using pmix_output and
|
||||
* each line will be prefixed with "prefix" to ease grep'ing.
|
||||
* - otherwise the corresponding file will be used for output in "append" mode
|
||||
* WARRNING: not all filesystems provide enough support for that feature, some records may
|
||||
* disappear.
|
||||
*
|
||||
* @param t timing handler
|
||||
* @param account_overhead consider malloc overhead introduced by timing code
|
||||
* @param fname name of the output file (may be NULL)
|
||||
*
|
||||
* @retval PMIX_SUCCESS On success
|
||||
* @retval PMIX_ERROR or PMIX_ERR_OUT_OF_RESOURCE On failure
|
||||
*/
|
||||
pmix_status_t pmix_timing_deltas(pmix_timing_t *t, char *fname);
|
||||
|
||||
/**
|
||||
* Release all memory allocated for the timing handler 't'.
|
||||
*
|
||||
* @param t timing handler
|
||||
*
|
||||
* @retval
|
||||
*/
|
||||
void pmix_timing_release(pmix_timing_t *t);
|
||||
|
||||
/**
|
||||
* Macro for passing down process id - compiled out
|
||||
* when configured without --enable-timing
|
||||
*/
|
||||
#define PMIX_TIMING_ID(n, r) pmix_timing_id((n), (r));
|
||||
|
||||
/**
|
||||
* Main macro for use in declaring pmix timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
*/
|
||||
#define PMIX_TIMING_DECLARE(t) pmix_timing_t t; /* need semicolon here to avoid warnings when not enabled */
|
||||
|
||||
/**
|
||||
* Main macro for use in declaring external pmix timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
*/
|
||||
#define PMIX_TIMING_DECLARE_EXT(x, t) x extern pmix_timing_t t; /* need semicolon here to avoid warnings when not enabled */
|
||||
|
||||
/**
|
||||
* Main macro for use in initializing pmix timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_init()
|
||||
*/
|
||||
#define PMIX_TIMING_INIT(t) pmix_timing_init(t)
|
||||
|
||||
/**
|
||||
* Macro that enqueues event with its description to the specified
|
||||
* timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_add_step()
|
||||
*/
|
||||
#define PMIX_TIMING_EVENT(x) pmix_timing_add_step( pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* MDESCR: Measurement DESCRiption
|
||||
* Introduce new timing measurement with string description for the specified
|
||||
* timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_descr()
|
||||
*/
|
||||
#define PMIX_TIMING_MDESCR(x) pmix_timing_descr( pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* MSTART_ID: Measurement START by ID.
|
||||
* Marks the beginning of the measurement with ID=id on the
|
||||
* specified timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_start_id()
|
||||
*/
|
||||
#define PMIX_TIMING_MSTART_ID(t, id) pmix_timing_start_id(t, id, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* MSTART: Measurement START
|
||||
* Introduce new timing measurement conjuncted with its start
|
||||
* on the specifyed timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_start_init()
|
||||
*/
|
||||
#define PMIX_TIMING_MSTART(x) pmix_timing_start_init( pmix_timing_prep_ev x, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* MSTOP: STOP Measurement
|
||||
* Finishes the most recent measurement on the specifyed timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_end()
|
||||
*/
|
||||
#define PMIX_TIMING_MSTOP(t) pmix_timing_end(t, -1, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* MSTOP_ID: STOP Measurement with ID=id.
|
||||
* Finishes the measurement with give ID on the specifyed timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_end()
|
||||
*/
|
||||
#define PMIX_TIMING_MSTOP_ID(t, id) pmix_timing_end(t, id, __FUNCTION__, __FILE__, __LINE__)
|
||||
|
||||
/**
|
||||
* MNEXT: start NEXT Measurement
|
||||
* Convinient macro, may be implemented with the sequence of three previously
|
||||
* defined macroses:
|
||||
* - finish current measurement (PMIX_TIMING_MSTOP);
|
||||
* - introduce new timing measurement (PMIX_TIMING_MDESCR);
|
||||
* - starts next measurement (PMIX_TIMING_MSTART_ID)
|
||||
* on the specifyed timing handler;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_start_init()
|
||||
*/
|
||||
#define PMIX_TIMING_MNEXT(x) ( \
|
||||
pmix_timing_end_prep(pmix_timing_prep_ev_end x, \
|
||||
__FUNCTION__, __FILE__, __LINE__ ), \
|
||||
pmix_timing_start_init( pmix_timing_prep_ev x, \
|
||||
__FUNCTION__, __FILE__, __LINE__) \
|
||||
)
|
||||
|
||||
/**
|
||||
* The macro for use in reporting collected events with absolute values;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @param enable flag that enables/disables reporting. Used for fine-grained timing.
|
||||
* @see pmix_timing_report()
|
||||
*/
|
||||
#define PMIX_TIMING_REPORT(enable, t) { \
|
||||
if( enable ) { \
|
||||
pmix_timing_report(t, pmix_timing_output); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* The macro for use in reporting collected events with relative times;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @param enable flag that enables/disables reporting. Used for fine-grained timing.
|
||||
* @see pmix_timing_deltas()
|
||||
*/
|
||||
#define PMIX_TIMING_DELTAS(enable, t) { \
|
||||
if( enable ) { \
|
||||
pmix_timing_deltas(t, pmix_timing_output); \
|
||||
} \
|
||||
}
|
||||
|
||||
/**
|
||||
* Main macro for use in releasing allocated resources;
|
||||
* will be "compiled out" when PMIX is configured without
|
||||
* --enable-timing.
|
||||
*
|
||||
* @see pmix_timing_release()
|
||||
*/
|
||||
#define PMIX_TIMING_RELEASE(t) pmix_timing_release(t)
|
||||
|
||||
#else
|
||||
|
||||
#define PMIX_TIMING_ID(n, r)
|
||||
|
||||
#define PMIX_TIMING_DECLARE(t)
|
||||
|
||||
#define PMIX_TIMING_DECLARE_EXT(x, t)
|
||||
|
||||
#define PMIX_TIMING_INIT(t)
|
||||
|
||||
#define PMIX_TIMING_EVENT(x)
|
||||
|
||||
#define PMIX_TIMING_MDESCR(x)
|
||||
|
||||
#define PMIX_TIMING_MSTART_ID(t, id)
|
||||
|
||||
#define PMIX_TIMING_MSTART(x)
|
||||
|
||||
#define PMIX_TIMING_MSTOP(t)
|
||||
|
||||
#define PMIX_TIMING_MSTOP_ID(t, id)
|
||||
|
||||
#define PMIX_TIMING_MNEXT(x)
|
||||
|
||||
#define PMIX_TIMING_REPORT(enable, t)
|
||||
|
||||
#define PMIX_TIMING_DELTAS(enable, t)
|
||||
|
||||
#define PMIX_TIMING_RELEASE(t)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,61 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
# University Research and Technology
|
||||
# Corporation. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
# of Tennessee Research Foundation. All rights
|
||||
# reserved.
|
||||
# Copyright (c) 2004-2009 High Performance Computing Center Stuttgart,
|
||||
# University of Stuttgart. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved.
|
||||
# Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved.
|
||||
# Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
SUBDIRS = simple
|
||||
|
||||
headers = test_common.h cli_stages.h server_callbacks.h utils.h test_fence.h test_publish.h test_spawn.h test_cd.h test_resolve_peers.h
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_builddir)/src/include -I$(top_builddir)/src/api
|
||||
|
||||
check_PROGRAMS = pmix_test pmix_client pmi_client pmi2_client pmix_regex
|
||||
|
||||
# TESTS = pmix_test
|
||||
|
||||
pmix_test_SOURCES = $(headers) \
|
||||
pmix_test.c test_common.c cli_stages.c server_callbacks.c utils.c
|
||||
pmix_test_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
pmix_test_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
pmi_client_SOURCES = $(headers) \
|
||||
pmi_client.c
|
||||
pmi_client_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
pmi_client_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
pmi2_client_SOURCES = $(headers) \
|
||||
pmi2_client.c
|
||||
pmi2_client_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
pmi2_client_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
pmix_client_SOURCES = $(headers) \
|
||||
pmix_client.c test_fence.c test_common.c test_publish.c test_spawn.c test_cd.c test_resolve_peers.c
|
||||
pmix_client_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
pmix_client_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
pmix_regex_SOURCES = $(headers) \
|
||||
pmix_regex.c test_common.c cli_stages.c utils.c
|
||||
pmix_regex_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
pmix_regex_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
@ -1,269 +0,0 @@
|
||||
/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include "cli_stages.h"
|
||||
|
||||
cli_info_t *cli_info = NULL;
|
||||
int cli_info_cnt = 0;
|
||||
bool test_abort = false;
|
||||
|
||||
int cli_rank(cli_info_t *cli)
|
||||
{
|
||||
int i;
|
||||
for(i=0; i < cli_info_cnt; i++){
|
||||
if( cli == &cli_info[i] ){
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void cli_init(int nprocs, cli_state_t order[])
|
||||
{
|
||||
int n, i;
|
||||
cli_info = malloc( sizeof(cli_info_t) * nprocs);
|
||||
cli_info_cnt = nprocs;
|
||||
|
||||
for (n=0; n < nprocs; n++) {
|
||||
cli_info[n].sd = -1;
|
||||
cli_info[n].ev = NULL;
|
||||
cli_info[n].pid = -1;
|
||||
cli_info[n].state = CLI_UNINIT;
|
||||
PMIX_CONSTRUCT(&(cli_info[n].modex), pmix_list_t);
|
||||
for (i = 0; i < CLI_TERM+1; i++) {
|
||||
cli_info[n].next_state[i] = order[i];
|
||||
}
|
||||
cli_info[n].rank = -1;
|
||||
cli_info[n].ns = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_connect(cli_info_t *cli, int sd, struct event_base * ebase, event_callback_fn callback)
|
||||
{
|
||||
if( CLI_CONNECTED != cli->next_state[cli->state] ){
|
||||
TEST_ERROR(("Rank %d has bad next state: expect %d have %d!",
|
||||
cli_rank(cli), CLI_CONNECTED, cli->next_state[cli->state]));
|
||||
test_abort = true;
|
||||
return;
|
||||
}
|
||||
|
||||
cli->sd = sd;
|
||||
cli->ev = event_new(ebase, sd,
|
||||
EV_READ|EV_PERSIST, callback, cli);
|
||||
event_add(cli->ev,NULL);
|
||||
pmix_usock_set_nonblocking(sd);
|
||||
TEST_VERBOSE(("Connection accepted from rank %d", cli_rank(cli) ));
|
||||
cli->state = CLI_CONNECTED;
|
||||
}
|
||||
|
||||
void cli_finalize(cli_info_t *cli)
|
||||
{
|
||||
if( CLI_FIN != cli->next_state[cli->state] ){
|
||||
TEST_ERROR(("rank %d: bad client next state: expect %d have %d!",
|
||||
cli_rank(cli), CLI_FIN, cli->next_state[cli->state]));
|
||||
test_abort = true;
|
||||
}
|
||||
|
||||
cli->state = CLI_FIN;
|
||||
}
|
||||
|
||||
void cli_disconnect(cli_info_t *cli)
|
||||
{
|
||||
if( CLI_DISCONN != cli->next_state[cli->state] ){
|
||||
TEST_ERROR(("rank %d: bad client next state: expect %d have %d!",
|
||||
cli_rank(cli), CLI_DISCONN, cli->next_state[cli->state]));
|
||||
test_abort = true;
|
||||
}
|
||||
|
||||
if( 0 > cli->sd ){
|
||||
TEST_ERROR(("Bad sd = %d of rank = %d ", cli->sd, cli_rank(cli)));
|
||||
test_abort = true;
|
||||
} else {
|
||||
TEST_VERBOSE(("close sd = %d for rank = %d", cli->sd, cli_rank(cli)));
|
||||
close(cli->sd);
|
||||
cli->sd = -1;
|
||||
}
|
||||
|
||||
if( NULL == cli->ev ){
|
||||
TEST_ERROR(("Bad ev = NULL of rank = %d ", cli->sd, cli_rank(cli)));
|
||||
test_abort = true;
|
||||
} else {
|
||||
TEST_VERBOSE(("remove event of rank %d from event queue", cli_rank(cli)));
|
||||
event_del(cli->ev);
|
||||
event_free(cli->ev);
|
||||
cli->ev = NULL;
|
||||
}
|
||||
|
||||
TEST_VERBOSE(("Destruct modex list for the rank %d", cli_rank(cli)));
|
||||
PMIX_LIST_DESTRUCT(&(cli->modex));
|
||||
|
||||
cli->state = CLI_DISCONN;
|
||||
}
|
||||
|
||||
void cli_terminate(cli_info_t *cli)
|
||||
{
|
||||
if( CLI_TERM != cli->next_state[cli->state] ){
|
||||
TEST_ERROR(("rank %d: bad client next state: expect %d have %d!",
|
||||
cli_rank(cli), CLI_TERM, cli->next_state[cli->state]));
|
||||
test_abort = true;
|
||||
}
|
||||
cli->pid = -1;
|
||||
TEST_VERBOSE(("Client rank = %d terminated", cli_rank(cli)));
|
||||
cli->state = CLI_TERM;
|
||||
if (NULL != cli->ns) {
|
||||
free(cli->ns);
|
||||
}
|
||||
}
|
||||
|
||||
void cli_cleanup(cli_info_t *cli)
|
||||
{
|
||||
if (CLI_TERM < cli->state) {
|
||||
TEST_ERROR(("Bad rank %d state %d", cli_rank(cli), cli->state));
|
||||
test_abort = true;
|
||||
return;
|
||||
}
|
||||
switch( cli->next_state[cli->state] ){
|
||||
case CLI_FORKED:
|
||||
break;
|
||||
case CLI_CONNECTED:
|
||||
/* error - means that process terminated w/o calling finalize */
|
||||
if (!test_abort) {
|
||||
TEST_ERROR(("rank %d with state %d unexpectedly terminated.", cli_rank(cli), cli->state));
|
||||
}
|
||||
cli->state = CLI_TERM;
|
||||
test_abort = true;
|
||||
break;
|
||||
case CLI_FIN:
|
||||
/* error - means that process terminated w/o calling finalize */
|
||||
if (!test_abort) {
|
||||
TEST_ERROR(("rank %d with state %d unexpectedly terminated.", cli_rank(cli), cli->state));
|
||||
}
|
||||
cli_finalize(cli);
|
||||
cli_cleanup(cli);
|
||||
test_abort = true;
|
||||
break;
|
||||
case CLI_DISCONN:
|
||||
cli_disconnect(cli);
|
||||
cli_cleanup(cli);
|
||||
break;
|
||||
case CLI_TERM:
|
||||
cli_terminate(cli);
|
||||
break;
|
||||
default:
|
||||
TEST_ERROR(("Bad rank %d next state %d", cli_rank(cli), cli->next_state[cli->state]));
|
||||
test_abort = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool test_terminated(void)
|
||||
{
|
||||
bool ret = true;
|
||||
int i;
|
||||
|
||||
// All clients should disconnect
|
||||
for(i=0; i < cli_info_cnt; i++){
|
||||
ret = ret && (CLI_TERM <= cli_info[i].state);
|
||||
}
|
||||
return (ret || test_abort);
|
||||
}
|
||||
|
||||
void cli_wait_all(double timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
double start_time, cur_time;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
start_time = tv.tv_sec + 1E-6*tv.tv_usec;
|
||||
cur_time = start_time;
|
||||
|
||||
//TEST_VERBOSE(("Wait for all children to terminate"))
|
||||
|
||||
// Wait for all children to cleanup after the test.
|
||||
while( !test_terminated() && ( timeout >= (cur_time - start_time) ) ){
|
||||
struct timespec ts;
|
||||
int status, i;
|
||||
pid_t pid;
|
||||
while( 0 < (pid = waitpid(-1, &status, WNOHANG) ) ){
|
||||
TEST_VERBOSE(("waitpid = %d", pid));
|
||||
for(i=0; i < cli_info_cnt; i++){
|
||||
if( cli_info[i].pid == pid ){
|
||||
TEST_VERBOSE(("the child with pid = %d has rank = %d\n"
|
||||
"\t\texited = %d, signalled = %d", pid, i,
|
||||
WIFEXITED(status), WIFSIGNALED(status) ));
|
||||
if( WIFEXITED(status) || WIFSIGNALED(status) ){
|
||||
cli_cleanup(&cli_info[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( pid < 0 ){
|
||||
if( errno == ECHILD ){
|
||||
TEST_VERBOSE(("No more children to wait. Happens on the last cli_wait_all call "
|
||||
"which is used to ensure that all children terminated.\n"));
|
||||
break;
|
||||
} else {
|
||||
TEST_ERROR(("waitpid(): %d : %s", errno, strerror(errno)));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000;
|
||||
nanosleep(&ts, NULL);
|
||||
// calculate current timestamp
|
||||
gettimeofday(&tv, NULL);
|
||||
cur_time = tv.tv_sec + 1E-6*tv.tv_usec;
|
||||
}
|
||||
}
|
||||
|
||||
void cli_kill_all(void)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < cli_info_cnt; i++){
|
||||
if( CLI_UNINIT == cli_info[i].state ){
|
||||
TEST_ERROR(("Skip rank %d as it wasn't ever initialized (shouldn't happe)",
|
||||
i));
|
||||
continue;
|
||||
} else if( CLI_TERM <= cli_info[i].state ){
|
||||
TEST_VERBOSE(("Skip rank %d as it was already terminated.", i));
|
||||
continue;
|
||||
|
||||
}
|
||||
TEST_VERBOSE(("Kill rank %d (pid = %d).", i, cli_info[i].pid));
|
||||
kill(cli_info[i].pid, SIGKILL);
|
||||
cli_cleanup(&cli_info[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void errhandler(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
TEST_ERROR(("Error handler with status = %d", status))
|
||||
test_abort = true;
|
||||
}
|
||||
|
||||
void op_callbk(pmix_status_t status,
|
||||
void *cbdata)
|
||||
{
|
||||
TEST_VERBOSE(( "OP CALLBACK CALLED WITH STATUS %d", status));
|
||||
}
|
||||
|
||||
void errhandler_reg_callbk (pmix_status_t status,
|
||||
int errhandler_ref,
|
||||
void *cbdata)
|
||||
{
|
||||
TEST_VERBOSE(("ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%d",
|
||||
status, errhandler_ref));
|
||||
}
|
||||
|
@ -1,173 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "test_common.h"
|
||||
#include "test_fence.h"
|
||||
#include "test_publish.h"
|
||||
#include "test_spawn.h"
|
||||
#include "test_cd.h"
|
||||
#include "test_resolve_peers.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
test_params params;
|
||||
INIT_TEST_PARAMS(params);
|
||||
pmix_proc_t myproc;
|
||||
|
||||
parse_cmd(argc, argv, ¶ms);
|
||||
|
||||
// We don't know rank at this place!
|
||||
TEST_VERBOSE(("Client ns %s rank %d: Start", params.nspace, params.rank));
|
||||
|
||||
/* handle early-fail test case */
|
||||
if (1 == params.early_fail && 0 == params.rank) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
TEST_ERROR(("Client ns %s rank %d: PMIx_Init failed: %d", params.nspace, params.rank, rc));
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (myproc.rank != params.rank) {
|
||||
TEST_ERROR(("Client ns %s Rank returned in PMIx_Init %d does not match to rank from command line %d.", myproc.nspace, myproc.rank, params.rank));
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
||||
if ( NULL != params.prefix && -1 != params.ns_id) {
|
||||
TEST_SET_FILE(params.prefix, params.ns_id, params.rank);
|
||||
}
|
||||
TEST_VERBOSE((" Client ns %s rank %d: PMIx_Init success", myproc.nspace, myproc.rank));
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc,PMIX_UNIV_SIZE,NULL, 0,&val))) {
|
||||
TEST_ERROR(("rank %d: PMIx_Get universe size failed: %d", myproc.rank, rc));
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
||||
if (NULL == val) {
|
||||
TEST_ERROR(("rank %d: PMIx_Get universe size returned NULL value", myproc.rank));
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
||||
if (val->type != PMIX_UINT32 || val->data.uint32 != (uint32_t)params.ns_size ) {
|
||||
TEST_ERROR(("rank %d: Universe size value or type mismatch,"
|
||||
" want %d(%d) get %d(%d)",
|
||||
myproc.rank, params.ns_size, PMIX_UINT32,
|
||||
val->data.integer, val->type));
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
TEST_VERBOSE(("rank %d: Universe size check: PASSED", myproc.rank));
|
||||
|
||||
if( NULL != params.nspace && 0 != strcmp(myproc.nspace, params.nspace) ) {
|
||||
TEST_ERROR(("rank %d: Bad nspace!", myproc.rank));
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (NULL != params.fences) {
|
||||
rc = test_fence(params, myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
FREE_TEST_PARAMS(params);
|
||||
TEST_ERROR(("%s:%d Fence test failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != params.test_job_fence) {
|
||||
rc = test_job_fence(params, myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
FREE_TEST_PARAMS(params);
|
||||
TEST_ERROR(("%s:%d Job fence test failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != params.test_publish) {
|
||||
rc = test_publish_lookup(myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
FREE_TEST_PARAMS(params);
|
||||
TEST_ERROR(("%s:%d Publish/Lookup test failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != params.test_spawn) {
|
||||
rc = test_spawn(myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
FREE_TEST_PARAMS(params);
|
||||
TEST_ERROR(("%s:%d Spawn test failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != params.test_connect) {
|
||||
rc = test_connect_disconnect(myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
FREE_TEST_PARAMS(params);
|
||||
TEST_ERROR(("%s:%d Connect/Disconnect test failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (0 != params.test_resolve_peers) {
|
||||
rc = test_resolve_peers(myproc.nspace, myproc.rank, params);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
FREE_TEST_PARAMS(params);
|
||||
TEST_ERROR(("%s:%d Resolve peers test failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_VERBOSE(("Client ns %s rank %d: PASSED", myproc.nspace, myproc.rank));
|
||||
|
||||
/* finalize us */
|
||||
TEST_VERBOSE(("Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank));
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
TEST_ERROR(("Client ns %s rank %d:PMIx_Finalize failed: %d", myproc.nspace, myproc.rank, rc));
|
||||
} else {
|
||||
TEST_VERBOSE(("Client ns %s rank %d:PMIx_Finalize successfully completed", myproc.nspace, myproc.rank));
|
||||
}
|
||||
|
||||
TEST_OUTPUT_CLEAR(("OK\n"));
|
||||
TEST_CLOSE_FILE();
|
||||
FREE_TEST_PARAMS(params);
|
||||
exit(0);
|
||||
}
|
@ -1,302 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "server_callbacks.h"
|
||||
#include "src/util/argv.h"
|
||||
|
||||
pmix_server_module_t mymodule = {
|
||||
connected,
|
||||
finalized,
|
||||
abort_fn,
|
||||
fencenb_fn,
|
||||
dmodex_fn,
|
||||
publish_fn,
|
||||
lookup_fn,
|
||||
unpublish_fn,
|
||||
spawn_fn,
|
||||
connect_fn,
|
||||
disconnect_fn,
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_modex_data_t data;
|
||||
} pmix_test_data_t;
|
||||
|
||||
static void pcon(pmix_test_data_t *p)
|
||||
{
|
||||
p->data.blob = NULL;
|
||||
p->data.size = 0;
|
||||
}
|
||||
|
||||
static void pdes(pmix_test_data_t *p)
|
||||
{
|
||||
if (NULL != p->data.blob) {
|
||||
free(p->data.blob);
|
||||
}
|
||||
}
|
||||
|
||||
PMIX_CLASS_INSTANCE(pmix_test_data_t,
|
||||
pmix_list_item_t,
|
||||
pcon, pdes);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_info_t data;
|
||||
char *namespace_published;
|
||||
int rank_published;
|
||||
} pmix_test_info_t;
|
||||
|
||||
static void tcon(pmix_test_info_t *p)
|
||||
{
|
||||
PMIX_INFO_CONSTRUCT(&p->data);
|
||||
}
|
||||
|
||||
static void tdes(pmix_test_info_t *p)
|
||||
{
|
||||
PMIX_INFO_DESTRUCT(&p->data);
|
||||
}
|
||||
|
||||
PMIX_CLASS_INSTANCE(pmix_test_info_t,
|
||||
pmix_list_item_t,
|
||||
tcon, tdes);
|
||||
|
||||
pmix_list_t *pmix_test_published_list = NULL;
|
||||
|
||||
static int finalized_count = 0;
|
||||
|
||||
int connected(const pmix_proc_t *proc, void *server_object)
|
||||
{
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int finalized(const pmix_proc_t *proc, void *server_object,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
if( CLI_TERM <= cli_info[proc->rank].state ){
|
||||
TEST_ERROR(("double termination of rank %d", proc->rank));
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
TEST_VERBOSE(("Rank %d terminated", proc->rank));
|
||||
cli_finalize(&cli_info[proc->rank]);
|
||||
finalized_count++;
|
||||
if (finalized_count == cli_info_cnt) {
|
||||
if (NULL != pmix_test_published_list) {
|
||||
PMIX_LIST_RELEASE(pmix_test_published_list);
|
||||
}
|
||||
}
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int abort_fn(const pmix_proc_t *proc, void *server_object,
|
||||
int status, const char msg[],
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
TEST_VERBOSE(("Abort is called with status = %d, msg = %s",
|
||||
status, msg));
|
||||
test_abort = true;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int fencenb_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
char *data, size_t ndata,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
TEST_VERBOSE(("Getting data for %s:%d",
|
||||
procs[0].nspace, procs[0].rank));
|
||||
|
||||
/* In a perfect world, we should wait until
|
||||
* the test servers from all involved procs
|
||||
* respond. We don't have multi-server capability
|
||||
* yet, so we'll just respond right away and
|
||||
* return what we were given */
|
||||
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, data, ndata, cbdata, NULL, NULL);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int dmodex_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
TEST_VERBOSE(("Getting data for %s:%d", proc->nspace, proc->rank));
|
||||
|
||||
/* In a perfect world, we should call another server
|
||||
* to get the data for one of its clients. We don't
|
||||
* have multi-server capability yet, so we'll just
|
||||
* respond right away */
|
||||
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, cbdata, NULL, NULL);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int publish_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
size_t i;
|
||||
int found;
|
||||
pmix_test_info_t *new_info, *old_info;
|
||||
if (NULL == pmix_test_published_list) {
|
||||
pmix_test_published_list = PMIX_NEW(pmix_list_t);
|
||||
}
|
||||
for (i = 0; i < ninfo; i++) {
|
||||
found = 0;
|
||||
PMIX_LIST_FOREACH(old_info, pmix_test_published_list, pmix_test_info_t) {
|
||||
if (!strcmp(old_info->data.key, info[i].key)) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
new_info = PMIX_NEW(pmix_test_info_t);
|
||||
strncpy(new_info->data.key, info[i].key, strlen(info[i].key)+1);
|
||||
pmix_value_xfer(&new_info->data.value, (pmix_value_t*)&info[i].value);
|
||||
new_info->namespace_published = strdup(proc->nspace);
|
||||
new_info->rank_published = proc->rank;
|
||||
pmix_list_append(pmix_test_published_list, &new_info->super);
|
||||
}
|
||||
}
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int lookup_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_lookup_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
size_t i, ndata, ret;
|
||||
pmix_pdata_t *pdata;
|
||||
pmix_test_info_t *tinfo;
|
||||
if (NULL == pmix_test_published_list) {
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
ndata = pmix_argv_count(keys);
|
||||
PMIX_PDATA_CREATE(pdata, ndata);
|
||||
ret = 0;
|
||||
for (i = 0; i < ndata; i++) {
|
||||
PMIX_LIST_FOREACH(tinfo, pmix_test_published_list, pmix_test_info_t) {
|
||||
if (0 == strcmp(tinfo->data.key, keys[i])) {
|
||||
(void)strncpy(pdata[i].proc.nspace, tinfo->namespace_published, PMIX_MAX_NSLEN);
|
||||
pdata[i].proc.rank = tinfo->rank_published;
|
||||
(void)strncpy(pdata[i].key, keys[i], strlen(keys[i])+1);
|
||||
pmix_value_xfer(&pdata[i].value, &tinfo->data.value);
|
||||
ret++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc((ret == ndata) ? PMIX_SUCCESS : PMIX_ERR_NOT_FOUND, pdata, ndata, cbdata);
|
||||
}
|
||||
PMIX_PDATA_FREE(pdata, ndata);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int unpublish_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
size_t i;
|
||||
pmix_test_info_t *iptr, *next;
|
||||
if (NULL == pmix_test_published_list) {
|
||||
return PMIX_ERR_NOT_FOUND;
|
||||
}
|
||||
PMIX_LIST_FOREACH_SAFE(iptr, next, pmix_test_published_list, pmix_test_info_t) {
|
||||
if (1) { // if data posted by this process
|
||||
if (NULL == keys) {
|
||||
pmix_list_remove_item(pmix_test_published_list, &iptr->super);
|
||||
PMIX_RELEASE(iptr);
|
||||
} else {
|
||||
ninfo = pmix_argv_count(keys);
|
||||
for (i = 0; i < ninfo; i++) {
|
||||
if (!strcmp(iptr->data.key, keys[i])) {
|
||||
pmix_list_remove_item(pmix_test_published_list, &iptr->super);
|
||||
PMIX_RELEASE(iptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
pmix_status_t status;
|
||||
pmix_spawn_cbfunc_t cbfunc;
|
||||
void *cbdata;
|
||||
} release_cbdata;
|
||||
|
||||
static void release_cb(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
release_cbdata *cb = (release_cbdata*)cbdata;
|
||||
if (NULL != cb->cbfunc) {
|
||||
cb->cbfunc(cb->status, "foobar", cb->cbdata);
|
||||
}
|
||||
free(cb);
|
||||
}
|
||||
|
||||
int spawn_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
pmix_spawn_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
release_cbdata *cb = malloc(sizeof(release_cbdata));
|
||||
cb->status = PMIX_SUCCESS;
|
||||
cb->cbfunc = cbfunc;
|
||||
cb->cbdata = cbdata;
|
||||
PMIx_server_register_nspace("foobar", napps, NULL, 0, release_cb, (void*)cb);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int connect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
if (NULL != cbfunc) {
|
||||
/* return PMIX_EXISTS here just to ensure we get the correct status on the client */
|
||||
cbfunc(PMIX_EXISTS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int disconnect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PMIX_SERVER_CALLBACK_H
|
||||
#define PMIX_SERVER_CALLBACK_H
|
||||
|
||||
#include "cli_stages.h"
|
||||
|
||||
pmix_status_t connected(const pmix_proc_t *proc, void *server_object);
|
||||
pmix_status_t finalized(const pmix_proc_t *proc, void *server_object,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t abort_fn(const pmix_proc_t *proc,
|
||||
void *server_object,
|
||||
int status, const char msg[],
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
char *data, size_t ndata,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t dmodex_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t publish_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_lookup_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t spawn_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
pmix_spawn_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
extern pmix_server_module_t mymodule;
|
||||
|
||||
#endif
|
@ -1,62 +0,0 @@
|
||||
#
|
||||
# Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
|
||||
# University Research and Technology
|
||||
# Corporation. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The University of Tennessee and The University
|
||||
# of Tennessee Research Foundation. All rights
|
||||
# reserved.
|
||||
# Copyright (c) 2004-2009 High Performance Computing Center Stuttgart,
|
||||
# University of Stuttgart. All rights reserved.
|
||||
# Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2006-2010 Cisco Systems, Inc. All rights reserved.
|
||||
# Copyright (c) 2012-2013 Los Alamos National Security, Inc. All rights reserved.
|
||||
# Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_builddir)/src/include -I$(top_builddir)/include -I$(top_builddir)/include/pmix
|
||||
|
||||
check_PROGRAMS = simptest simpclient simppub simpdyn simpft simpdmodex
|
||||
|
||||
# TESTS = simptest
|
||||
|
||||
simptest_SOURCES = \
|
||||
simptest.c
|
||||
simptest_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
simptest_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
simpclient_SOURCES = \
|
||||
simpclient.c
|
||||
simpclient_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
simpclient_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
simppub_SOURCES = \
|
||||
simppub.c
|
||||
simppub_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
simppub_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
simpdmodex_SOURCES = \
|
||||
simpdmodex.c
|
||||
simpdmodex_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
simpdmodex_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
simpft_SOURCES = \
|
||||
simpft.c
|
||||
simpft_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
simpft_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
||||
|
||||
simpdyn_SOURCES = \
|
||||
simpdyn.c
|
||||
simpdyn_LDFLAGS = $(PMIX_PKG_CONFIG_LDFLAGS)
|
||||
simpdyn_LDADD = \
|
||||
$(top_builddir)/libpmix.la
|
@ -1,160 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/printf.h"
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
char *tmp;
|
||||
pmix_proc_t proc, myproc;
|
||||
uint32_t nprocs, n;
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
exit(rc);
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get universe size failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
pmix_output(0, "Client %s:%d universe size %d", myproc.nspace, myproc.rank, nprocs);
|
||||
|
||||
/* put a few values */
|
||||
(void)asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT32;
|
||||
value.data.uint32 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Store_internal failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT64;
|
||||
value.data.uint64 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_STRING;
|
||||
value.data.string = "1234";
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_REMOTE, tmp, &value))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Commit failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call fence to ensure the data is received */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* check the returned data */
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
for (n=0; n < nprocs; n++) {
|
||||
proc.rank = n;
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, n);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s failed: %d", myproc.nspace, myproc.rank, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
if (PMIX_UINT64 != val->type) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s returned wrong type: %d", myproc.nspace, myproc.rank, tmp, val->type);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
if (1234 != val->data.uint64) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s returned wrong value: %d", myproc.nspace, myproc.rank, tmp, (int)val->data.uint64);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s returned correct", myproc.nspace, myproc.rank, tmp);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-remote", proc.nspace, n);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, tmp, NULL, 0, &val))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s failed: %d", myproc.nspace, myproc.rank, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
if (PMIX_STRING != val->type) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s returned wrong type: %d", myproc.nspace, myproc.rank, tmp, val->type);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
if (0 != strcmp(val->data.string, "1234")) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s returned wrong value: %s", myproc.nspace, myproc.rank, tmp, val->data.string);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s returned correct", myproc.nspace, myproc.rank, tmp);
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
free(tmp);
|
||||
}
|
||||
|
||||
done:
|
||||
/* finalize us */
|
||||
pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(rc);
|
||||
}
|
@ -1,210 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/printf.h"
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
static uint32_t nprocs;
|
||||
static pmix_proc_t myproc;
|
||||
static uint32_t getcount = 0;
|
||||
|
||||
static void opcbfunc(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
bool *active = (bool*)cbdata;
|
||||
|
||||
pmix_output(0, "%s:%d completed fence_nb", myproc.nspace, myproc.rank);
|
||||
*active = false;
|
||||
}
|
||||
|
||||
static void valcbfunc(pmix_status_t status,
|
||||
pmix_value_t *val, void *cbdata)
|
||||
{
|
||||
char *key = (char*)cbdata;
|
||||
|
||||
if (PMIX_SUCCESS == status) {
|
||||
if (NULL != strstr(key, "local")) {
|
||||
if (PMIX_UINT64 != val->type) {
|
||||
pmix_output(0, "%s:%d: PMIx_Get_nb Key %s returned wrong type: %d", myproc.nspace, myproc.rank, key, val->type);
|
||||
goto done;
|
||||
}
|
||||
if (1234 != val->data.uint64) {
|
||||
pmix_output(0, "%s:%d: PMIx_Get_nb Key %s returned wrong value: %d", myproc.nspace, myproc.rank, key, (int)val->data.uint64);
|
||||
goto done;
|
||||
}
|
||||
} else if (NULL != strstr(key, "remote")) {
|
||||
if (PMIX_STRING != val->type) {
|
||||
pmix_output(0, "%s:%d: PMIx_Get_nb Key %s returned wrong type: %d", myproc.nspace, myproc.rank, key, val->type);
|
||||
goto done;
|
||||
}
|
||||
if (0 != strcmp(val->data.string, "1234")) {
|
||||
pmix_output(0, "%s:%d: PMIx_Get_nb Key %s returned wrong value: %s", myproc.nspace, myproc.rank, key, val->data.string);
|
||||
goto done;
|
||||
}
|
||||
} else {
|
||||
pmix_output(0, "%s:%d PMIx_Get_nb returned wrong key: %s", myproc.nspace, myproc.rank, key);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "%s:%d PMIx_Get_nb Key %s returned correctly", myproc.nspace, myproc.rank, key);
|
||||
} else {
|
||||
pmix_output(0, "%s:%d PMIx_Get_nb Key %s failed", myproc.nspace, myproc.rank, key);
|
||||
}
|
||||
done:
|
||||
free(key);
|
||||
getcount++;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
char *tmp;
|
||||
pmix_proc_t proc;
|
||||
uint32_t n, num_gets;
|
||||
bool active;
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
exit(0);
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get universe size failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
pmix_output(0, "Client %s:%d universe size %d", myproc.nspace, myproc.rank, nprocs);
|
||||
|
||||
/* put a few values */
|
||||
(void)asprintf(&tmp, "%s-%d-internal", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT32;
|
||||
value.data.uint32 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Store_internal(&myproc, tmp, &value))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Store_internal failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_UINT64;
|
||||
value.data.uint64 = 1234;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_LOCAL, tmp, &value))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, myproc.rank);
|
||||
value.type = PMIX_STRING;
|
||||
value.data.string = "1234";
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(PMIX_REMOTE, tmp, &value))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Put internal failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* introduce a delay by one rank so we can check what happens
|
||||
* if a "get" is received prior to data being provided */
|
||||
if (0 == myproc.rank) {
|
||||
sleep(2);
|
||||
}
|
||||
|
||||
/* commit the data to the server */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Commit failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* call fence_nb, but don't return any data */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
active = true;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence_nb(&proc, 1, NULL, 0, opcbfunc, &active))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* get the committed data - ask for someone who doesn't exist as well */
|
||||
num_gets = 0;
|
||||
for (n=0; n < nprocs; n++) {
|
||||
(void)asprintf(&tmp, "%s-%d-local", myproc.nspace, n);
|
||||
proc.rank = n;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&proc, tmp,
|
||||
NULL, 0, valcbfunc, tmp))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s failed: %d", myproc.nspace, n, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
++num_gets;
|
||||
(void)asprintf(&tmp, "%s-%d-remote", myproc.nspace, n);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&proc, tmp,
|
||||
NULL, 0, valcbfunc, tmp))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get %s failed: %d", myproc.nspace, n, tmp, rc);
|
||||
goto done;
|
||||
}
|
||||
++num_gets;
|
||||
}
|
||||
|
||||
/* wait for the first fence to finish */
|
||||
PMIX_WAIT_FOR_COMPLETION(active);
|
||||
|
||||
/* wait for all my "get" calls to complete */
|
||||
while (getcount < num_gets) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
/* call fence again so everyone waits before leaving */
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
done:
|
||||
/* finalize us */
|
||||
pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(0);
|
||||
}
|
@ -1,196 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/pmix_environ.h"
|
||||
#include "src/util/printf.h"
|
||||
|
||||
static pmix_proc_t myproc;
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
pmix_proc_t proc;
|
||||
uint32_t nprocs;
|
||||
char nsp2[PMIX_MAX_NSLEN+1];
|
||||
pmix_app_t *app;
|
||||
char hostname[1024];
|
||||
pmix_proc_t *peers;
|
||||
size_t npeers, ntmp=0;
|
||||
char *nodelist;
|
||||
|
||||
gethostname(hostname, 1024);
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
exit(0);
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get universe size failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
pmix_output(0, "Client %s:%d universe size %d", myproc.nspace, myproc.rank, nprocs);
|
||||
|
||||
/* call fence to sync */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* rank=0 calls spawn */
|
||||
if (0 == myproc.rank) {
|
||||
PMIX_APP_CREATE(app, 1);
|
||||
app->cmd = strdup("gumby");
|
||||
app->maxprocs = 2;
|
||||
pmix_argv_append(&app->argc, &app->argv, "gumby");
|
||||
pmix_argv_append(&app->argc, &app->argv, "-n");
|
||||
pmix_argv_append(&app->argc, &app->argv, "2");
|
||||
pmix_setenv("PMIX_ENV_VALUE", "3", true, &app->env);
|
||||
PMIX_INFO_CREATE(app->info, 2);
|
||||
(void)strncpy(app->info[0].key, "DARTH", PMIX_MAX_KEYLEN);
|
||||
app->info[0].value.type = PMIX_INT8;
|
||||
app->info[0].value.data.int8 = 12;
|
||||
(void)strncpy(app->info[1].key, "VADER", PMIX_MAX_KEYLEN);
|
||||
app->info[1].value.type = PMIX_DOUBLE;
|
||||
app->info[1].value.data.dval = 12.34;
|
||||
|
||||
pmix_output(0, "Client ns %s rank %d: calling PMIx_Spawn", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Spawn(NULL, 0, app, 1, nsp2))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Spawn failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
PMIX_APP_FREE(app, 1);
|
||||
|
||||
/* check to see if we got the expected info back */
|
||||
if (0 != strncmp(nsp2, "DYNSPACE", PMIX_MAX_NSLEN)) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Spawn returned incorrect nspace: %s", myproc.nspace, myproc.rank, nsp2);
|
||||
goto done;
|
||||
} else {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Spawn succeeded returning nspace: %s", myproc.nspace, myproc.rank, nsp2);
|
||||
}
|
||||
/* get their universe size */
|
||||
(void)strncpy(proc.nspace, nsp2, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
val = NULL;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_UNIV_SIZE, NULL, 0, &val)) ||
|
||||
NULL == val) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get universe size failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
ntmp = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
pmix_output(0, "Client %s:%d universe %s size %d", myproc.nspace, myproc.rank, nsp2, (int)ntmp);
|
||||
}
|
||||
|
||||
/* just cycle the connect/disconnect functions */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Connect(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Connect failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Connect succeeded", myproc.nspace, myproc.rank);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Disconnect(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Disonnect failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Disconnect succeeded", myproc.nspace, myproc.rank);
|
||||
|
||||
/* finally, test the resolve functions */
|
||||
if (0 == myproc.rank) {
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_peers(hostname, NULL, &peers, &npeers))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers failed for nspace %s: %d", myproc.nspace, myproc.rank, nsp2, rc);
|
||||
goto done;
|
||||
}
|
||||
if ((nprocs+ntmp) != npeers) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers returned incorrect npeers: %d vs %d", myproc.nspace, myproc.rank, (int)(nprocs+ntmp), (int)npeers);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers returned %d npeers", myproc.nspace, myproc.rank, (int)npeers);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_nodes(nsp2, &nodelist))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes failed for nspace %s: %d", myproc.nspace, myproc.rank, nsp2, rc);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes %s", myproc.nspace, myproc.rank, nodelist);
|
||||
} else {
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_peers(hostname, myproc.nspace, &peers, &npeers))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers failed for nspace %s: %d", myproc.nspace, myproc.rank, myproc.nspace, rc);
|
||||
goto done;
|
||||
}
|
||||
if (nprocs != npeers) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers returned incorrect npeers: %d vs %d", myproc.nspace, myproc.rank, nprocs, (int)npeers);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_peers returned %d npeers", myproc.nspace, myproc.rank, (int)npeers);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Resolve_nodes(myproc.nspace, &nodelist))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Resolve_nodes %s", myproc.nspace, myproc.rank, nodelist);
|
||||
}
|
||||
PMIX_PROC_FREE(peers, npeers);
|
||||
free(nodelist);
|
||||
|
||||
done:
|
||||
/* call fence to sync */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* finalize us */
|
||||
pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank);
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(0);
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc. All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "src/class/pmix_object.h"
|
||||
#include "src/buffer_ops/types.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/printf.h"
|
||||
|
||||
static pmix_proc_t myproc;
|
||||
static bool completed;
|
||||
|
||||
static void notification_fn(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
pmix_output(0, "Client %s:%d NOTIFIED with status %d", myproc.nspace, myproc.rank, status);
|
||||
completed = true;
|
||||
}
|
||||
|
||||
static void op_callbk(pmix_status_t status,
|
||||
void *cbdata)
|
||||
{
|
||||
pmix_output(0, "CLIENT: OP CALLBACK CALLED WITH STATUS %d", status);
|
||||
}
|
||||
|
||||
static void errhandler_reg_callbk (pmix_status_t status,
|
||||
int errhandler_ref,
|
||||
void *cbdata)
|
||||
{
|
||||
pmix_output(0, "Client: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%d",
|
||||
status, errhandler_ref);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int rc;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
pmix_proc_t proc;
|
||||
uint32_t nprocs;
|
||||
|
||||
/* init us */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Init(&myproc))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Init failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
exit(0);
|
||||
}
|
||||
pmix_output(0, "Client ns %s rank %d: Running", myproc.nspace, myproc.rank);
|
||||
|
||||
/* get our universe size */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&myproc, PMIX_UNIV_SIZE, NULL, 0, &val))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Get universe size failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
nprocs = val->data.uint32;
|
||||
PMIX_VALUE_RELEASE(val);
|
||||
pmix_output(0, "Client %s:%d universe size %d", myproc.nspace, myproc.rank, nprocs);
|
||||
completed = false;
|
||||
|
||||
/* register our errhandler */
|
||||
PMIx_Register_errhandler(NULL, 0, notification_fn, errhandler_reg_callbk, NULL);
|
||||
|
||||
/* call fence to sync */
|
||||
PMIX_PROC_CONSTRUCT(&proc);
|
||||
(void)strncpy(proc.nspace, myproc.nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = PMIX_RANK_WILDCARD;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Fence(&proc, 1, NULL, 0))) {
|
||||
pmix_output(0, "Client ns %s rank %d: PMIx_Fence failed: %d", myproc.nspace, myproc.rank, rc);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* rank=0 calls abort */
|
||||
if (0 == myproc.rank) {
|
||||
PMIx_Abort(PMIX_ERR_OUT_OF_RESOURCE, "Eat rocks",
|
||||
&proc, 1);
|
||||
pmix_output(0, "Client ns %s rank %d: Abort called", myproc.nspace, myproc.rank);
|
||||
}
|
||||
/* everyone simply waits */
|
||||
while (!completed) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
done:
|
||||
/* finalize us */
|
||||
pmix_output(0, "Client ns %s rank %d: Finalizing", myproc.nspace, myproc.rank);
|
||||
PMIx_Deregister_errhandler(0, op_callbk, NULL);
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Finalize())) {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize failed: %d\n", myproc.nspace, myproc.rank, rc);
|
||||
} else {
|
||||
fprintf(stderr, "Client ns %s rank %d:PMIx_Finalize successfully completed\n", myproc.nspace, myproc.rank);
|
||||
}
|
||||
fflush(stderr);
|
||||
return(0);
|
||||
}
|
@ -1,679 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2004-2010 The Trustees of Indiana University and Indiana
|
||||
* University Research and Technology
|
||||
* Corporation. All rights reserved.
|
||||
* Copyright (c) 2004-2011 The University of Tennessee and The University
|
||||
* of Tennessee Research Foundation. All rights
|
||||
* reserved.
|
||||
* Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
|
||||
* University of Stuttgart. All rights reserved.
|
||||
* Copyright (c) 2004-2005 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2006-2013 Los Alamos National Security, LLC.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2009-2012 Cisco Systems, Inc. All rights reserved.
|
||||
* Copyright (c) 2011 Oak Ridge National Labs. All rights reserved.
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix_server.h>
|
||||
#include <private/types.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include PMIX_EVENT_HEADER
|
||||
|
||||
#include "src/util/pmix_environ.h"
|
||||
#include "src/util/output.h"
|
||||
#include "src/util/printf.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
static pmix_status_t connected(const pmix_proc_t *proc, void *server_object);
|
||||
static pmix_status_t finalized(const pmix_proc_t *proc, void *server_object,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t abort_fn(const pmix_proc_t *proc, void *server_object,
|
||||
int status, const char msg[],
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t fencenb_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
char *data, size_t ndata,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t dmodex_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t publish_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t lookup_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_lookup_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t unpublish_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t spawn_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
pmix_spawn_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t connect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t disconnect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
static pmix_status_t register_event_fn(const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata);
|
||||
|
||||
static pmix_server_module_t mymodule = {
|
||||
connected,
|
||||
finalized,
|
||||
abort_fn,
|
||||
fencenb_fn,
|
||||
dmodex_fn,
|
||||
publish_fn,
|
||||
lookup_fn,
|
||||
unpublish_fn,
|
||||
spawn_fn,
|
||||
connect_fn,
|
||||
disconnect_fn,
|
||||
register_event_fn,
|
||||
NULL
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_pdata_t pdata;
|
||||
} pmix_locdat_t;
|
||||
PMIX_CLASS_INSTANCE(pmix_locdat_t,
|
||||
pmix_list_item_t,
|
||||
NULL, NULL);
|
||||
|
||||
typedef struct {
|
||||
pmix_object_t super;
|
||||
volatile bool active;
|
||||
pmix_proc_t caller;
|
||||
pmix_info_t *info;
|
||||
size_t ninfo;
|
||||
pmix_op_cbfunc_t cbfunc;
|
||||
pmix_spawn_cbfunc_t spcbfunc;
|
||||
void *cbdata;
|
||||
} myxfer_t;
|
||||
static void xfcon(myxfer_t *p)
|
||||
{
|
||||
p->info = NULL;
|
||||
p->ninfo = 0;
|
||||
p->active = true;
|
||||
p->cbfunc = NULL;
|
||||
p->spcbfunc = NULL;
|
||||
p->cbdata = NULL;
|
||||
}
|
||||
static void xfdes(myxfer_t *p)
|
||||
{
|
||||
if (NULL != p->info) {
|
||||
PMIX_INFO_FREE(p->info, p->ninfo);
|
||||
}
|
||||
}
|
||||
PMIX_CLASS_INSTANCE(myxfer_t,
|
||||
pmix_object_t,
|
||||
xfcon, xfdes);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pid_t pid;
|
||||
} wait_tracker_t;
|
||||
PMIX_CLASS_INSTANCE(wait_tracker_t,
|
||||
pmix_list_item_t,
|
||||
NULL, NULL);
|
||||
|
||||
static volatile int wakeup;
|
||||
static pmix_list_t pubdata;
|
||||
static pmix_event_t handler;
|
||||
static pmix_list_t children;
|
||||
|
||||
static void set_namespace(int nprocs, char *ranks, char *nspace,
|
||||
pmix_op_cbfunc_t cbfunc, myxfer_t *x);
|
||||
static void errhandler(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo);
|
||||
static void wait_signal_callback(int fd, short event, void *arg);
|
||||
static void op_callbk(pmix_status_t status, void *cbdata);
|
||||
static void errhandler_reg_callbk (pmix_status_t status,
|
||||
int errhandler_ref,
|
||||
void *cbdata);
|
||||
|
||||
static void opcbfunc(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
myxfer_t *x = (myxfer_t*)cbdata;
|
||||
|
||||
/* release the caller, if necessary */
|
||||
if (NULL != x->cbfunc) {
|
||||
x->cbfunc(PMIX_SUCCESS, x->cbdata);
|
||||
}
|
||||
x->active = false;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char **client_env=NULL;
|
||||
char **client_argv=NULL;
|
||||
char *tmp, **atmp, *executable=NULL;
|
||||
int rc, nprocs=1, n;
|
||||
uid_t myuid;
|
||||
gid_t mygid;
|
||||
pid_t pid;
|
||||
myxfer_t *x;
|
||||
pmix_proc_t proc;
|
||||
wait_tracker_t *child;
|
||||
|
||||
/* smoke test */
|
||||
if (PMIX_SUCCESS != 0) {
|
||||
fprintf(stderr, "ERROR IN COMPUTING CONSTANTS: PMIX_SUCCESS = %d\n", PMIX_SUCCESS);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Testing version %s\n", PMIx_Get_version());
|
||||
|
||||
/* setup the server library */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_server_init(&mymodule, NULL, 0))) {
|
||||
fprintf(stderr, "Init failed with error %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
/* register the errhandler */
|
||||
PMIx_Register_errhandler(NULL, 0, errhandler, errhandler_reg_callbk, NULL);
|
||||
|
||||
/* setup the pub data, in case it is used */
|
||||
PMIX_CONSTRUCT(&pubdata, pmix_list_t);
|
||||
|
||||
/* setup to see sigchld on the forked tests */
|
||||
PMIX_CONSTRUCT(&children, pmix_list_t);
|
||||
event_assign(&handler, pmix_globals.evbase, SIGCHLD,
|
||||
EV_SIGNAL|EV_PERSIST,wait_signal_callback, &handler);
|
||||
event_add(&handler, NULL);
|
||||
|
||||
/* see if we were passed the number of procs to run or
|
||||
* the executable to use */
|
||||
for (n=1; n < (argc-1); n++) {
|
||||
if (0 == strcmp("-n", argv[n]) &&
|
||||
NULL != argv[n+1]) {
|
||||
nprocs = strtol(argv[n+1], NULL, 10);
|
||||
++n; // step over the argument
|
||||
} else if (0 == strcmp("-e", argv[n]) &&
|
||||
NULL != argv[n+1]) {
|
||||
executable = strdup(argv[n+1]);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
if (NULL == executable) {
|
||||
executable = strdup("simpclient");
|
||||
}
|
||||
|
||||
/* we have a single namespace for all clients */
|
||||
atmp = NULL;
|
||||
for (n=0; n < nprocs; n++) {
|
||||
asprintf(&tmp, "%d", n);
|
||||
pmix_argv_append_nosize(&atmp, tmp);
|
||||
free(tmp);
|
||||
}
|
||||
tmp = pmix_argv_join(atmp, ',');
|
||||
x = PMIX_NEW(myxfer_t);
|
||||
set_namespace(nprocs, tmp, "foobar", opcbfunc, x);
|
||||
|
||||
/* set common argv and env */
|
||||
client_env = pmix_argv_copy(environ);
|
||||
pmix_argv_append_nosize(&client_argv, executable);
|
||||
|
||||
wakeup = nprocs;
|
||||
myuid = getuid();
|
||||
mygid = getgid();
|
||||
|
||||
/* if the nspace registration hasn't completed yet,
|
||||
* wait for it here */
|
||||
PMIX_WAIT_FOR_COMPLETION(x->active);
|
||||
free(tmp);
|
||||
PMIX_RELEASE(x);
|
||||
|
||||
/* fork/exec the test */
|
||||
(void)strncpy(proc.nspace, "foobar", PMIX_MAX_NSLEN);
|
||||
for (n = 0; n < nprocs; n++) {
|
||||
proc.rank = n;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_server_setup_fork(&proc, &client_env))) {//n
|
||||
fprintf(stderr, "Server fork setup failed with error %d\n", rc);
|
||||
PMIx_server_finalize();
|
||||
return rc;
|
||||
}
|
||||
x = PMIX_NEW(myxfer_t);
|
||||
if (PMIX_SUCCESS != (rc = PMIx_server_register_client(&proc, myuid, mygid,
|
||||
NULL, opcbfunc, x))) {
|
||||
fprintf(stderr, "Server fork setup failed with error %d\n", rc);
|
||||
PMIx_server_finalize();
|
||||
return rc;
|
||||
}
|
||||
/* don't fork/exec the client until we know it is registered
|
||||
* so we avoid a potential race condition in the server */
|
||||
PMIX_WAIT_FOR_COMPLETION(x->active);
|
||||
PMIX_RELEASE(x);
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
fprintf(stderr, "Fork failed\n");
|
||||
PMIx_server_finalize();
|
||||
return -1;
|
||||
}
|
||||
child = PMIX_NEW(wait_tracker_t);
|
||||
child->pid = pid;
|
||||
pmix_list_append(&children, &child->super);
|
||||
|
||||
if (pid == 0) {
|
||||
execve(executable, client_argv, client_env);
|
||||
/* Does not return */
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* hang around until the client(s) finalize */
|
||||
while (0 < wakeup) {
|
||||
struct timespec ts;
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 100000;
|
||||
nanosleep(&ts, NULL);
|
||||
}
|
||||
pmix_argv_free(client_argv);
|
||||
pmix_argv_free(client_env);
|
||||
|
||||
/* deregister the errhandler */
|
||||
PMIx_Deregister_errhandler(0, op_callbk, NULL);
|
||||
|
||||
/* release any pub data */
|
||||
PMIX_LIST_DESTRUCT(&pubdata);
|
||||
|
||||
/* finalize the server library */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_server_finalize())) {
|
||||
fprintf(stderr, "Finalize failed with error %d\n", rc);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Test finished OK!\n");
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void set_namespace(int nprocs, char *ranks, char *nspace,
|
||||
pmix_op_cbfunc_t cbfunc, myxfer_t *x)
|
||||
{
|
||||
char *regex, *ppn;
|
||||
char hostname[1024];
|
||||
|
||||
gethostname(hostname, 1024);
|
||||
x->ninfo = 6;
|
||||
|
||||
PMIX_INFO_CREATE(x->info, x->ninfo);
|
||||
(void)strncpy(x->info[0].key, PMIX_UNIV_SIZE, PMIX_MAX_KEYLEN);
|
||||
x->info[0].value.type = PMIX_UINT32;
|
||||
x->info[0].value.data.uint32 = nprocs;
|
||||
|
||||
(void)strncpy(x->info[1].key, PMIX_SPAWNED, PMIX_MAX_KEYLEN);
|
||||
x->info[1].value.type = PMIX_UINT32;
|
||||
x->info[1].value.data.uint32 = 0;
|
||||
|
||||
(void)strncpy(x->info[2].key, PMIX_LOCAL_SIZE, PMIX_MAX_KEYLEN);
|
||||
x->info[2].value.type = PMIX_UINT32;
|
||||
x->info[2].value.data.uint32 = nprocs;
|
||||
|
||||
(void)strncpy(x->info[3].key, PMIX_LOCAL_PEERS, PMIX_MAX_KEYLEN);
|
||||
x->info[3].value.type = PMIX_STRING;
|
||||
x->info[3].value.data.string = strdup(ranks);
|
||||
|
||||
PMIx_generate_regex(hostname, ®ex);
|
||||
(void)strncpy(x->info[4].key, PMIX_NODE_MAP, PMIX_MAX_KEYLEN);
|
||||
x->info[4].value.type = PMIX_STRING;
|
||||
x->info[4].value.data.string = regex;
|
||||
|
||||
PMIx_generate_ppn(ranks, &ppn);
|
||||
(void)strncpy(x->info[5].key, PMIX_PROC_MAP, PMIX_MAX_KEYLEN);
|
||||
x->info[5].value.type = PMIX_STRING;
|
||||
x->info[5].value.data.string = ppn;
|
||||
|
||||
PMIx_server_register_nspace(nspace, nprocs, x->info, x->ninfo,
|
||||
cbfunc, x);
|
||||
}
|
||||
|
||||
static void errhandler(pmix_status_t status,
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_info_t info[], size_t ninfo)
|
||||
{
|
||||
pmix_output(0, "SERVER: ERRHANDLER CALLED WITH STATUS %d", status);
|
||||
}
|
||||
|
||||
static void op_callbk(pmix_status_t status,
|
||||
void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: OP CALLBACK CALLED WITH STATUS %d", status);
|
||||
}
|
||||
|
||||
static void errhandler_reg_callbk (pmix_status_t status,
|
||||
int errhandler_ref,
|
||||
void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: ERRHANDLER REGISTRATION CALLBACK CALLED WITH STATUS %d, ref=%d",
|
||||
status, errhandler_ref);
|
||||
}
|
||||
|
||||
static pmix_status_t connected(const pmix_proc_t *proc, void *server_object)
|
||||
{
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
static int finalized(const pmix_proc_t *proc, void *server_object,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: FINALIZED %s:%d",
|
||||
proc->nspace, proc->rank);
|
||||
--wakeup;
|
||||
/* ensure we call the cbfunc so the proc can exit! */
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void abcbfunc(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
myxfer_t *x = (myxfer_t*)cbdata;
|
||||
|
||||
/* be sure to release the caller */
|
||||
if (NULL != x->cbfunc) {
|
||||
x->cbfunc(status, x->cbdata);
|
||||
}
|
||||
PMIX_RELEASE(x);
|
||||
}
|
||||
|
||||
static int abort_fn(const pmix_proc_t *proc,
|
||||
void *server_object,
|
||||
pmix_status_t status, const char msg[],
|
||||
pmix_proc_t procs[], size_t nprocs,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_status_t rc;
|
||||
myxfer_t *x;
|
||||
|
||||
pmix_output(0, "SERVER: ABORT on %s:%d", procs[0].nspace, procs[0].rank);
|
||||
|
||||
/* instead of aborting the specified procs, notify them
|
||||
* (if they have registered their errhandler) */
|
||||
|
||||
/* use the myxfer_t object to ensure we release
|
||||
* the caller when notification has been queued */
|
||||
x = PMIX_NEW(myxfer_t);
|
||||
(void)strncpy(x->caller.nspace, proc->nspace, PMIX_MAX_NSLEN);
|
||||
x->caller.rank = proc->rank;
|
||||
|
||||
PMIX_INFO_CREATE(x->info, 2);
|
||||
(void)strncpy(x->info[0].key, "DARTH", PMIX_MAX_KEYLEN);
|
||||
x->info[0].value.type = PMIX_INT8;
|
||||
x->info[0].value.data.int8 = 12;
|
||||
(void)strncpy(x->info[1].key, "VADER", PMIX_MAX_KEYLEN);
|
||||
x->info[1].value.type = PMIX_DOUBLE;
|
||||
x->info[1].value.data.dval = 12.34;
|
||||
x->cbfunc = cbfunc;
|
||||
x->cbdata = cbdata;
|
||||
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Notify_error(status, procs, nprocs,
|
||||
&x->caller, 1, x->info, 2,
|
||||
abcbfunc, x))) {
|
||||
pmix_output(0, "SERVER: FAILED NOTIFY ERROR %d", (int)rc);
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int fencenb_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
char *data, size_t ndata,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: FENCENB");
|
||||
/* pass the provided data back to each participating proc */
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, data, ndata, cbdata, NULL, NULL);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int dmodex_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_modex_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: DMODEX");
|
||||
|
||||
/* we don't have any data for remote procs as this
|
||||
* test only runs one server - so report accordingly */
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_ERR_NOT_FOUND, NULL, 0, cbdata, NULL, NULL);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int publish_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_locdat_t *p;
|
||||
size_t n;
|
||||
|
||||
pmix_output(0, "SERVER: PUBLISH");
|
||||
|
||||
for (n=0; n < ninfo; n++) {
|
||||
p = PMIX_NEW(pmix_locdat_t);
|
||||
(void)strncpy(p->pdata.proc.nspace, proc->nspace, PMIX_MAX_NSLEN);
|
||||
p->pdata.proc.rank = proc->rank;
|
||||
(void)strncpy(p->pdata.key, info[n].key, PMIX_MAX_KEYLEN);
|
||||
pmix_value_xfer(&p->pdata.value, (pmix_value_t*)&info[n].value);
|
||||
pmix_list_append(&pubdata, &p->super);
|
||||
}
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int lookup_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_lookup_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_locdat_t *p, *p2;
|
||||
pmix_list_t results;
|
||||
size_t i, n;
|
||||
pmix_pdata_t *pd = NULL;
|
||||
pmix_status_t ret = PMIX_ERR_NOT_FOUND;
|
||||
|
||||
pmix_output(0, "SERVER: LOOKUP");
|
||||
|
||||
PMIX_CONSTRUCT(&results, pmix_list_t);
|
||||
|
||||
for (n=0; NULL != keys[n]; n++) {
|
||||
PMIX_LIST_FOREACH(p, &pubdata, pmix_locdat_t) {
|
||||
if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) {
|
||||
p2 = PMIX_NEW(pmix_locdat_t);
|
||||
(void)strncpy(p2->pdata.proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN);
|
||||
p2->pdata.proc.rank = p->pdata.proc.rank;
|
||||
(void)strncpy(p2->pdata.key, p->pdata.key, PMIX_MAX_KEYLEN);
|
||||
pmix_value_xfer(&p2->pdata.value, &p->pdata.value);
|
||||
pmix_list_append(&results, &p2->super);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (0 < (n = pmix_list_get_size(&results))) {
|
||||
ret = PMIX_SUCCESS;
|
||||
PMIX_PDATA_CREATE(pd, n);
|
||||
for (i=0; i < n; i++) {
|
||||
p = (pmix_locdat_t*)pmix_list_remove_first(&results);
|
||||
(void)strncpy(pd[i].proc.nspace, p->pdata.proc.nspace, PMIX_MAX_NSLEN);
|
||||
pd[i].proc.rank = p->pdata.proc.rank;
|
||||
(void)strncpy(pd[i].key, p->pdata.key, PMIX_MAX_KEYLEN);
|
||||
pmix_value_xfer(&pd[i].value, &p->pdata.value);
|
||||
}
|
||||
}
|
||||
PMIX_LIST_DESTRUCT(&results);
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(ret, pd, n, cbdata);
|
||||
}
|
||||
if (0 < n) {
|
||||
PMIX_PDATA_FREE(pd, n);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int unpublish_fn(const pmix_proc_t *proc, char **keys,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_locdat_t *p, *p2;
|
||||
size_t n;
|
||||
|
||||
pmix_output(0, "SERVER: UNPUBLISH");
|
||||
|
||||
for (n=0; NULL != keys[n]; n++) {
|
||||
PMIX_LIST_FOREACH_SAFE(p, p2, &pubdata, pmix_locdat_t) {
|
||||
if (0 == strncmp(keys[n], p->pdata.key, PMIX_MAX_KEYLEN)) {
|
||||
pmix_list_remove_item(&pubdata, &p->super);
|
||||
PMIX_RELEASE(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void spcbfunc(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
myxfer_t *x = (myxfer_t*)cbdata;
|
||||
|
||||
if (NULL != x->spcbfunc) {
|
||||
x->spcbfunc(PMIX_SUCCESS, "DYNSPACE", x->cbdata);
|
||||
}
|
||||
}
|
||||
|
||||
static int spawn_fn(const pmix_proc_t *proc,
|
||||
const pmix_info_t job_info[], size_t ninfo,
|
||||
const pmix_app_t apps[], size_t napps,
|
||||
pmix_spawn_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
myxfer_t *x;
|
||||
|
||||
pmix_output(0, "SERVER: SPAWN");
|
||||
|
||||
/* in practice, we would pass this request to the local
|
||||
* resource manager for launch, and then have that server
|
||||
* execute our callback function. For now, we will fake
|
||||
* the spawn and just pretend */
|
||||
|
||||
/* must register the nspace for the new procs before
|
||||
* we return to the caller */
|
||||
x = PMIX_NEW(myxfer_t);
|
||||
x->spcbfunc = cbfunc;
|
||||
x->cbdata = cbdata;
|
||||
|
||||
set_namespace(2, "0,1", "DYNSPACE", spcbfunc, x);
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int connect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: CONNECT");
|
||||
|
||||
/* in practice, we would pass this request to the local
|
||||
* resource manager for handling */
|
||||
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int disconnect_fn(const pmix_proc_t procs[], size_t nprocs,
|
||||
const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
pmix_output(0, "SERVER: DISCONNECT");
|
||||
|
||||
/* in practice, we would pass this request to the local
|
||||
* resource manager for handling */
|
||||
|
||||
if (NULL != cbfunc) {
|
||||
cbfunc(PMIX_SUCCESS, cbdata);
|
||||
}
|
||||
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static pmix_status_t register_event_fn(const pmix_info_t info[], size_t ninfo,
|
||||
pmix_op_cbfunc_t cbfunc, void *cbdata)
|
||||
{
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static void wait_signal_callback(int fd, short event, void *arg)
|
||||
{
|
||||
pmix_event_t *sig = (pmix_event_t*) arg;
|
||||
int status;
|
||||
pid_t pid;
|
||||
wait_tracker_t *t2;
|
||||
|
||||
if (SIGCHLD != event_get_signal(sig)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* we can have multiple children leave but only get one
|
||||
* sigchild callback, so reap all the waitpids until we
|
||||
* don't get anything valid back */
|
||||
while (1) {
|
||||
pid = waitpid(-1, &status, WNOHANG);
|
||||
if (-1 == pid && EINTR == errno) {
|
||||
/* try it again */
|
||||
continue;
|
||||
}
|
||||
/* if we got garbage, then nothing we can do */
|
||||
if (pid <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* we are already in an event, so it is safe to access the list */
|
||||
PMIX_LIST_FOREACH(t2, &children, wait_tracker_t) {
|
||||
if (pid == t2->pid) {
|
||||
/* found it! */
|
||||
--wakeup;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,540 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include "test_common.h"
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int pmix_test_verbose = 0;
|
||||
|
||||
FILE *file;
|
||||
|
||||
#define OUTPUT_MAX 1024
|
||||
char *pmix_test_output_prepare(const char *fmt, ... )
|
||||
{
|
||||
static char output[OUTPUT_MAX];
|
||||
va_list args;
|
||||
va_start( args, fmt );
|
||||
memset(output, 0, sizeof(output));
|
||||
vsnprintf(output, OUTPUT_MAX - 1, fmt, args);
|
||||
va_end(args);
|
||||
return output;
|
||||
}
|
||||
|
||||
void parse_cmd(int argc, char **argv, test_params *params)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* set output to stderr by default */
|
||||
file = stdout;
|
||||
if( params->nspace != NULL ) {
|
||||
params->nspace = NULL;
|
||||
}
|
||||
|
||||
/* parse user options */
|
||||
for (i=1; i < argc; i++) {
|
||||
if (0 == strcmp(argv[i], "--n") || 0 == strcmp(argv[i], "-n")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->np = strdup(argv[i]);
|
||||
params->nprocs = strtol(argv[i], NULL, 10);
|
||||
if (-1 == params->ns_size) {
|
||||
params->ns_size = params->nprocs;
|
||||
}
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--h") || 0 == strcmp(argv[i], "-h")) {
|
||||
/* print help */
|
||||
fprintf(stderr, "usage: pmix_test [-h] [-e foo] [-b] [-c] [-nb]\n");
|
||||
fprintf(stderr, "\t-n provides information about the job size (for checking purposes)\n");
|
||||
fprintf(stderr, "\t-e foo use foo as test client\n");
|
||||
fprintf(stderr, "\t-v verbose output\n");
|
||||
fprintf(stderr, "\t-t <> set timeout\n");
|
||||
fprintf(stderr, "\t-o out redirect clients logs to file out.<rank>\n");
|
||||
fprintf(stderr, "\t--early-fail force client process with rank 0 to fail before PMIX_Init.\n");
|
||||
fprintf(stderr, "\t--ns-dist n1:n2:n3 register n namespaces (3 in this example) each with ni ranks (n1, n2 or n3).\n");
|
||||
fprintf(stderr, "\t--fence \"[<data_exchange><blocking> | ns0:ranks;ns1:ranks...][...]\" specify fences in different configurations.\n");
|
||||
fprintf(stderr, "\t--use-same-keys relative to the --fence option: put the same keys in the interim between multiple fences.\n");
|
||||
fprintf(stderr, "\t--job-fence test fence inside its own namespace.\n");
|
||||
fprintf(stderr, "\t-c relative to the --job-fence option: fence[_nb] callback shall include all collected data\n");
|
||||
fprintf(stderr, "\t-nb relative to the --job-fence option: use non-blocking fence\n");
|
||||
fprintf(stderr, "\t--noise \"[ns0:ranks;ns1:ranks...]\" add system noise to specified processes.\n");
|
||||
fprintf(stderr, "\t--test-publish test publish/lookup/unpublish api.\n");
|
||||
fprintf(stderr, "\t--test-spawn test spawn api.\n");
|
||||
fprintf(stderr, "\t--test-connect test connect/disconnect api.\n");
|
||||
fprintf(stderr, "\t--test-resolve-peers test resolve_peers api.\n");
|
||||
exit(0);
|
||||
} else if (0 == strcmp(argv[i], "--exec") || 0 == strcmp(argv[i], "-e")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->binary = strdup(argv[i]);
|
||||
}
|
||||
} else if( 0 == strcmp(argv[i], "--verbose") || 0 == strcmp(argv[i],"-v") ){
|
||||
TEST_VERBOSE_ON();
|
||||
params->verbose = 1;
|
||||
} else if (0 == strcmp(argv[i], "--timeout") || 0 == strcmp(argv[i], "-t")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->timeout = atoi(argv[i]);
|
||||
if( params->timeout == 0 ){
|
||||
params->timeout = TEST_DEFAULT_TIMEOUT;
|
||||
}
|
||||
}
|
||||
} else if( 0 == strcmp(argv[i], "-o")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->prefix = strdup(argv[i]);
|
||||
}
|
||||
} else if( 0 == strcmp(argv[i], "-s")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->nspace = strdup(argv[i]);
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--rank") || 0 == strcmp(argv[i], "-r")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->rank = strtol(argv[i], NULL, 10);
|
||||
}
|
||||
} else if( 0 == strcmp(argv[i], "--early-fail") ){
|
||||
params->early_fail = 1;
|
||||
} else if (0 == strcmp(argv[i], "--fence")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->fences = strdup(argv[i]);
|
||||
if (0 != parse_fence(params->fences, 0)) {
|
||||
fprintf(stderr, "Incorrect --fence option format: %s\n", params->fences);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--use-same-keys")) {
|
||||
params->use_same_keys = 1;
|
||||
} else if (0 == strcmp(argv[i], "--job-fence")) {
|
||||
params->test_job_fence = 1;
|
||||
} else if (0 == strcmp(argv[i], "--collect-corrupt")) {
|
||||
params->collect_bad = 1;
|
||||
} else if (0 == strcmp(argv[i], "--collect") || 0 == strcmp(argv[i], "-c")) {
|
||||
params->collect = 1;
|
||||
} else if (0 == strcmp(argv[i], "--non-blocking") || 0 == strcmp(argv[i], "-nb")) {
|
||||
params->nonblocking = 1;
|
||||
} else if (0 == strcmp(argv[i], "--noise")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->noise = strdup(argv[i]);
|
||||
if (0 != parse_noise(params->noise, 0)) {
|
||||
fprintf(stderr, "Incorrect --noise option format: %s\n", params->noise);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--ns-dist")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->ns_dist = strdup(argv[i]);
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--ns-size")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->ns_size = strtol(argv[i], NULL, 10);
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--ns-id")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->ns_id = strtol(argv[i], NULL, 10);
|
||||
}
|
||||
} else if (0 == strcmp(argv[i], "--base-rank")) {
|
||||
i++;
|
||||
if (NULL != argv[i]) {
|
||||
params->base_rank = strtol(argv[i], NULL, 10);
|
||||
}
|
||||
} else if( 0 == strcmp(argv[i], "--test-publish") ){
|
||||
params->test_publish = 1;
|
||||
} else if( 0 == strcmp(argv[i], "--test-spawn") ){
|
||||
params->test_spawn = 1;
|
||||
} else if( 0 == strcmp(argv[i], "--test-connect") ){
|
||||
params->test_connect = 1;
|
||||
} else if( 0 == strcmp(argv[i], "--test-resolve-peers") ){
|
||||
params->test_resolve_peers = 1;
|
||||
}
|
||||
|
||||
else {
|
||||
fprintf(stderr, "unrecognized option: %s\n", argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (NULL == params->binary) {
|
||||
char *basename = NULL;
|
||||
basename = strrchr(argv[0], '/');
|
||||
if (basename) {
|
||||
*basename = '\0';
|
||||
/* pmix_test and pmix_clients are the shell scripts that
|
||||
* make sure that actual binary placed in "./.libs" directory
|
||||
* is properly linked.
|
||||
* after launch pmix_test you'll find the following process:
|
||||
* <pmix-root-dir>/test/.libs/lt-pmix_test
|
||||
*
|
||||
* To launch
|
||||
* <pmix-root-dir>/test/pmix_client
|
||||
* instead of
|
||||
* <pmix-root-dir>/test/.libs/pmix_client
|
||||
* we need to do a step back in directory tree.
|
||||
*/
|
||||
asprintf(¶ms->binary, "%s/../pmix_client", argv[0]);
|
||||
*basename = '/';
|
||||
} else {
|
||||
asprintf(¶ms->binary, "pmix_client");
|
||||
}
|
||||
}
|
||||
|
||||
if( params->collect_bad ){
|
||||
params->collect = params->rank % 2;
|
||||
}
|
||||
|
||||
// Fix rank if running under SLURM
|
||||
if( 0 > params->rank ){
|
||||
char *ranklist = getenv("SLURM_GTIDS");
|
||||
char *rankno = getenv("SLURM_LOCALID");
|
||||
if( NULL != ranklist && NULL != rankno ){
|
||||
char **argv = pmix_argv_split(ranklist, ',');
|
||||
int count = pmix_argv_count(argv);
|
||||
int rankidx = strtoul(rankno, NULL, 10);
|
||||
if( rankidx >= count ){
|
||||
fprintf(stderr, "It feels like we are running under SLURM:\n\t"
|
||||
"SLURM_GTIDS=%s, SLURM_LOCALID=%s\nbut env vars are conflicting\n",
|
||||
ranklist, rankno);
|
||||
exit(1);
|
||||
}
|
||||
params->rank = strtoul(argv[rankidx], NULL, 10);
|
||||
pmix_argv_free(argv);
|
||||
}
|
||||
}
|
||||
|
||||
// Fix namespace if running under SLURM
|
||||
if( NULL == params->nspace ){
|
||||
char *nspace = getenv("PMIX_NAMESPACE");
|
||||
if( NULL != nspace ){
|
||||
params->nspace = strdup(nspace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fcon(fence_desc_t *p)
|
||||
{
|
||||
p->blocking = 0;
|
||||
p->data_exchange = 0;
|
||||
p->participants = PMIX_NEW(pmix_list_t);
|
||||
}
|
||||
|
||||
static void fdes(fence_desc_t *p)
|
||||
{
|
||||
PMIX_LIST_RELEASE(p->participants);
|
||||
}
|
||||
|
||||
PMIX_CLASS_INSTANCE(fence_desc_t,
|
||||
pmix_list_item_t,
|
||||
fcon, fdes);
|
||||
|
||||
PMIX_CLASS_INSTANCE(participant_t,
|
||||
pmix_list_item_t,
|
||||
NULL, NULL);
|
||||
|
||||
static int ns_id = -1;
|
||||
static fence_desc_t *fdesc = NULL;
|
||||
pmix_list_t *participants = NULL;
|
||||
pmix_list_t test_fences;
|
||||
pmix_list_t *noise_range = NULL;
|
||||
|
||||
#define CHECK_STRTOL_VAL(val, str, store) do { \
|
||||
if (0 == val) { \
|
||||
if (0 != strncmp(str, "0", 1)) { \
|
||||
if (!store) { \
|
||||
return 1; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int parse_token(char *str, int step, int store)
|
||||
{
|
||||
char *pch;
|
||||
int count = 0;
|
||||
int remember = -1;
|
||||
int i;
|
||||
int rank;
|
||||
participant_t *proc;
|
||||
|
||||
switch (step) {
|
||||
case 0:
|
||||
if (store) {
|
||||
fdesc = PMIX_NEW(fence_desc_t);
|
||||
participants = fdesc->participants;
|
||||
}
|
||||
pch = strchr(str, '|');
|
||||
if (NULL != pch) {
|
||||
while (pch != str) {
|
||||
if ('d' == *str) {
|
||||
if (store && NULL != fdesc) {
|
||||
fdesc->data_exchange = 1;
|
||||
}
|
||||
} else if ('b' == *str) {
|
||||
if (store && NULL != fdesc) {
|
||||
fdesc->blocking = 1;
|
||||
}
|
||||
} else if (' ' != *str) {
|
||||
if (!store) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
str++;
|
||||
}
|
||||
if (0 < parse_token(pch+1, 1, store)) {
|
||||
if (!store) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (0 < parse_token(str, 1, store)) {
|
||||
if (!store) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (store && NULL != fdesc) {
|
||||
pmix_list_append(&test_fences, &fdesc->super);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (store && NULL == participants) {
|
||||
participants = PMIX_NEW(pmix_list_t);
|
||||
noise_range = participants;
|
||||
}
|
||||
pch = strtok(str, ";");
|
||||
while (NULL != pch) {
|
||||
if (0 < parse_token(pch, 2, store)) {
|
||||
if (!store) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
pch = strtok (NULL, ";");
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
pch = strchr(str, ':');
|
||||
if (NULL != pch) {
|
||||
*pch = '\0';
|
||||
pch++;
|
||||
while (' ' == *str) {
|
||||
str++;
|
||||
}
|
||||
ns_id = (int)(strtol(str, NULL, 10));
|
||||
CHECK_STRTOL_VAL(ns_id, str, store);
|
||||
if (0 < parse_token(pch, 3, store)) {
|
||||
if (!store) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!store) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
while (' ' == *str) {
|
||||
str++;
|
||||
}
|
||||
if ('\0' == *str) {
|
||||
/* all ranks from namespace participate */
|
||||
if (store && NULL != participants) {
|
||||
proc = PMIX_NEW(participant_t);
|
||||
(void)snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id);
|
||||
proc->proc.rank = PMIX_RANK_WILDCARD;
|
||||
pmix_list_append(participants, &proc->super);
|
||||
}
|
||||
}
|
||||
while ('\0' != *str) {
|
||||
if (',' == *str && 0 != count) {
|
||||
*str = '\0';
|
||||
if (-1 != remember) {
|
||||
rank = (int)(strtol(str-count, NULL, 10));
|
||||
CHECK_STRTOL_VAL(rank, str-count, store);
|
||||
for (i = remember; i < rank; i++) {
|
||||
if (store && NULL != participants) {
|
||||
proc = PMIX_NEW(participant_t);
|
||||
(void)snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id);
|
||||
proc->proc.rank = i;
|
||||
pmix_list_append(participants, &proc->super);
|
||||
}
|
||||
}
|
||||
remember = -1;
|
||||
}
|
||||
rank = (int)(strtol(str-count, NULL, 10));
|
||||
CHECK_STRTOL_VAL(rank, str-count, store);
|
||||
if (store && NULL != participants) {
|
||||
proc = PMIX_NEW(participant_t);
|
||||
(void)snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id);
|
||||
proc->proc.rank = rank;
|
||||
pmix_list_append(participants, &proc->super);
|
||||
}
|
||||
count = -1;
|
||||
} else if ('-' == *str && 0 != count) {
|
||||
*str = '\0';
|
||||
remember = (int)(strtol(str-count, NULL, 10));
|
||||
CHECK_STRTOL_VAL(remember, str-count, store);
|
||||
count = -1;
|
||||
}
|
||||
str++;
|
||||
count++;
|
||||
}
|
||||
if (0 != count) {
|
||||
if (-1 != remember) {
|
||||
rank = (int)(strtol(str-count, NULL, 10));
|
||||
CHECK_STRTOL_VAL(rank, str-count, store);
|
||||
for (i = remember; i < rank; i++) {
|
||||
if (store && NULL != participants) {
|
||||
proc = PMIX_NEW(participant_t);
|
||||
(void)snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id);
|
||||
proc->proc.rank = i;
|
||||
pmix_list_append(participants, &proc->super);
|
||||
}
|
||||
}
|
||||
remember = -1;
|
||||
}
|
||||
rank = (int)(strtol(str-count, NULL, 10));
|
||||
CHECK_STRTOL_VAL(rank, str-count, store);
|
||||
if (store && NULL != participants) {
|
||||
proc = PMIX_NEW(participant_t);
|
||||
(void)snprintf(proc->proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, ns_id);
|
||||
proc->proc.rank = rank;
|
||||
pmix_list_append(participants, &proc->super);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Incorrect parsing step.\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_fence(char *fence_param, int store)
|
||||
{
|
||||
int ret = 0;
|
||||
char *tmp = strdup(fence_param);
|
||||
char * pch, *ech;
|
||||
|
||||
pch = strchr(tmp, '[');
|
||||
while (NULL != pch) {
|
||||
pch++;
|
||||
ech = strchr(pch, ']');
|
||||
if (NULL != ech) {
|
||||
*ech = '\0';
|
||||
ech++;
|
||||
ret += parse_token(pch, 0, store);
|
||||
pch = strchr(ech, '[');
|
||||
} else {
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int parse_noise(char *noise_param, int store)
|
||||
{
|
||||
int ret = 0;
|
||||
char *tmp = strdup(noise_param);
|
||||
char * pch, *ech;
|
||||
|
||||
pch = strchr(tmp, '[');
|
||||
if (NULL != pch) {
|
||||
pch++;
|
||||
ech = strchr(pch, ']');
|
||||
if (NULL != ech) {
|
||||
*ech = '\0';
|
||||
ech++;
|
||||
if ('\0' != *ech) {
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = parse_token(pch, 1, store);
|
||||
}
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
free(tmp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_total_ns_number(test_params params)
|
||||
{
|
||||
int num = 0;
|
||||
if (NULL == params.ns_dist) {
|
||||
return 1;
|
||||
} else {
|
||||
char *tmp = strdup(params.ns_dist);
|
||||
char *pch = tmp;
|
||||
while (NULL != pch) {
|
||||
num++;
|
||||
pch = strtok((1 == num ) ? tmp : NULL, ":");
|
||||
}
|
||||
num--;
|
||||
free(tmp);
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
int get_all_ranks_from_namespace(test_params params, char *nspace, pmix_proc_t **ranks, size_t *nranks)
|
||||
{
|
||||
int base_rank = 0;
|
||||
size_t num_ranks = 0;
|
||||
int num = -1;
|
||||
size_t j;
|
||||
if (NULL == params.ns_dist) {
|
||||
*nranks = params.ns_size;
|
||||
PMIX_PROC_CREATE(*ranks, params.ns_size);
|
||||
for (j = 0; j < (size_t)params.ns_size; j++) {
|
||||
(void)strncpy((*ranks)[j].nspace, nspace, PMIX_MAX_NSLEN);
|
||||
(*ranks)[j].rank = j;
|
||||
}
|
||||
} else {
|
||||
char *tmp = strdup(params.ns_dist);
|
||||
char *pch = tmp;
|
||||
int ns_id = (int)strtol(nspace + strlen(TEST_NAMESPACE) + 1, NULL, 10);
|
||||
while (NULL != pch && num != ns_id) {
|
||||
base_rank += num_ranks;
|
||||
pch = strtok((-1 == num ) ? tmp : NULL, ":");
|
||||
if (NULL == pch) {
|
||||
break;
|
||||
}
|
||||
num++;
|
||||
num_ranks = (size_t)strtol(pch, NULL, 10);
|
||||
}
|
||||
if (num == ns_id && 0 != num_ranks) {
|
||||
*nranks = num_ranks;
|
||||
PMIX_PROC_CREATE(*ranks, num_ranks);
|
||||
for (j = 0; j < num_ranks; j++) {
|
||||
(void)strncpy((*ranks)[j].nspace, nspace, PMIX_MAX_NSLEN);
|
||||
(*ranks)[j].rank = base_rank+j;
|
||||
}
|
||||
} else {
|
||||
free(tmp);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
free(tmp);
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
@ -1,197 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Artem Y. Polyakov <artpol84@gmail.com>.
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2015 Research Organization for Information Science
|
||||
* and Technology (RIST). All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TEST_COMMON_H
|
||||
#define TEST_COMMON_H
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix/pmix_common.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "src/class/pmix_list.h"
|
||||
#include "src/util/argv.h"
|
||||
#include "src/usock/usock.h"
|
||||
|
||||
#define TEST_NAMESPACE "smoky_nspace"
|
||||
#define TEST_CREDENTIAL "dummy"
|
||||
|
||||
/* WARNING: pmix_test_output_prepare is currently not threadsafe!
|
||||
* fix it once needed!
|
||||
*/
|
||||
char *pmix_test_output_prepare(const char *fmt,... );
|
||||
extern int pmix_test_verbose;
|
||||
extern FILE *file;
|
||||
|
||||
#define STRIPPED_FILE_NAME (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
|
||||
|
||||
#define TEST_OUTPUT(x) { \
|
||||
fprintf(file,"%s:%s: %s\n",STRIPPED_FILE_NAME, __func__, \
|
||||
pmix_test_output_prepare x ); \
|
||||
fflush(file); \
|
||||
}
|
||||
|
||||
// Write output wightout adding anything to it.
|
||||
// Need for automate tests to receive "OK" string
|
||||
#define TEST_OUTPUT_CLEAR(x) { \
|
||||
fprintf(file, "%s", pmix_test_output_prepare x ); \
|
||||
fflush(file); \
|
||||
}
|
||||
|
||||
// Always write errors to the stderr
|
||||
#define TEST_ERROR(x) { \
|
||||
fprintf(stderr,"ERROR [%s:%d:%s]: %s\n", STRIPPED_FILE_NAME, __LINE__, __func__, \
|
||||
pmix_test_output_prepare x ); \
|
||||
fflush(stderr); \
|
||||
}
|
||||
|
||||
#define TEST_VERBOSE_ON() (pmix_test_verbose = 1)
|
||||
#define TEST_VERBOSE_GET() (pmix_test_verbose)
|
||||
|
||||
#define TEST_VERBOSE(x) { \
|
||||
if( pmix_test_verbose ){ \
|
||||
TEST_OUTPUT(x); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TEST_DEFAULT_TIMEOUT 10
|
||||
#define MAX_DIGIT_LEN 10
|
||||
|
||||
#define TEST_SET_FILE(prefix, ns_id, rank) { \
|
||||
char *fname = malloc( strlen(prefix) + MAX_DIGIT_LEN + 2 ); \
|
||||
sprintf(fname, "%s.%d.%d", prefix, ns_id, rank); \
|
||||
file = fopen(fname, "w"); \
|
||||
free(fname); \
|
||||
if( NULL == file ){ \
|
||||
fprintf(stderr, "Cannot open file %s for writing!", fname); \
|
||||
exit(1); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define TEST_CLOSE_FILE() { \
|
||||
if ( stderr != file ) { \
|
||||
fclose(file); \
|
||||
} \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
char *binary;
|
||||
char *np;
|
||||
char *prefix;
|
||||
char *nspace;
|
||||
uint32_t nprocs;
|
||||
int timeout;
|
||||
int verbose;
|
||||
int rank;
|
||||
int early_fail;
|
||||
int test_job_fence;
|
||||
int collect_bad;
|
||||
int use_same_keys;
|
||||
int collect;
|
||||
int nonblocking;
|
||||
char *fences;
|
||||
char *noise;
|
||||
char *ns_dist;
|
||||
int ns_size;
|
||||
int ns_id;
|
||||
int base_rank;
|
||||
int test_publish;
|
||||
int test_spawn;
|
||||
int test_connect;
|
||||
int test_resolve_peers;
|
||||
} test_params;
|
||||
|
||||
#define INIT_TEST_PARAMS(params) do { \
|
||||
params.nprocs = 1; \
|
||||
params.verbose = 0; \
|
||||
params.rank = -1; \
|
||||
params.base_rank = 0; \
|
||||
params.early_fail = 0; \
|
||||
params.ns_size = -1; \
|
||||
params.ns_id = -1; \
|
||||
params.timeout = TEST_DEFAULT_TIMEOUT; \
|
||||
params.test_job_fence = 0; \
|
||||
params.use_same_keys = 0; \
|
||||
params.collect = 0; \
|
||||
params.collect_bad = 0; \
|
||||
params.nonblocking = 0; \
|
||||
params.test_publish = 0; \
|
||||
params.test_spawn = 0; \
|
||||
params.test_connect = 0; \
|
||||
params.test_resolve_peers = 0; \
|
||||
params.binary = NULL; \
|
||||
params.np = NULL; \
|
||||
params.prefix = NULL; \
|
||||
params.nspace = NULL; \
|
||||
params.fences = NULL; \
|
||||
params.noise = NULL; \
|
||||
params.ns_dist = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define FREE_TEST_PARAMS(params) do { \
|
||||
if (NULL != params.binary) { \
|
||||
free(params.binary); \
|
||||
} \
|
||||
if (NULL != params.np) { \
|
||||
free(params.np); \
|
||||
} \
|
||||
if (NULL != params.prefix) { \
|
||||
free(params.prefix); \
|
||||
} \
|
||||
if (NULL != params.nspace) { \
|
||||
free(params.nspace); \
|
||||
} \
|
||||
if (NULL != params.fences) { \
|
||||
free(params.fences); \
|
||||
} \
|
||||
if (NULL != params.noise) { \
|
||||
free(params.noise); \
|
||||
} \
|
||||
if (NULL != params.ns_dist) { \
|
||||
free(params.ns_dist); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
void parse_cmd(int argc, char **argv, test_params *params);
|
||||
int parse_fence(char *fence_param, int store);
|
||||
int parse_noise(char *noise_param, int store);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
int blocking;
|
||||
int data_exchange;
|
||||
pmix_list_t *participants; // list of participants
|
||||
} fence_desc_t;
|
||||
PMIX_CLASS_DECLARATION(fence_desc_t);
|
||||
|
||||
typedef struct {
|
||||
pmix_list_item_t super;
|
||||
pmix_proc_t proc;
|
||||
} participant_t;
|
||||
PMIX_CLASS_DECLARATION(participant_t);
|
||||
|
||||
extern pmix_list_t test_fences;
|
||||
extern pmix_list_t *noise_range;
|
||||
|
||||
#define NODE_NAME "node1"
|
||||
int get_total_ns_number(test_params params);
|
||||
int get_all_ranks_from_namespace(test_params params, char *nspace, pmix_proc_t **ranks, size_t *nranks);
|
||||
|
||||
#endif // TEST_COMMON_H
|
@ -1,556 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "test_fence.h"
|
||||
#include "src/buffer_ops/buffer_ops.h"
|
||||
|
||||
static void release_cb(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
int *ptr = (int*)cbdata;
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int in_progress;
|
||||
pmix_value_t *kv;
|
||||
int status;
|
||||
} get_cbdata;
|
||||
|
||||
static void get_cb(pmix_status_t status, pmix_value_t *kv, void *cbdata)
|
||||
{
|
||||
get_cbdata *cb = (get_cbdata*)cbdata;
|
||||
if (PMIX_SUCCESS == status) {
|
||||
pmix_value_xfer(cb->kv, kv);
|
||||
}
|
||||
cb->in_progress = 0;
|
||||
cb->status = status;
|
||||
}
|
||||
|
||||
static void add_noise(char *noise_param, char *my_nspace, int my_rank)
|
||||
{
|
||||
bool participate = false;
|
||||
participant_t *p;
|
||||
|
||||
parse_noise(noise_param, 1);
|
||||
if (NULL != noise_range) {
|
||||
PMIX_LIST_FOREACH(p, noise_range, participant_t) {
|
||||
if (0 == strncmp(my_nspace, p->proc.nspace, strlen(my_nspace)) &&
|
||||
(my_rank == p->proc.rank || PMIX_RANK_WILDCARD == p->proc.rank)) {
|
||||
participate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (participate) {
|
||||
sleep(2);
|
||||
TEST_VERBOSE(("I'm %s:%d sleeping\n", my_nspace, my_rank));
|
||||
}
|
||||
PMIX_LIST_RELEASE(noise_range);
|
||||
noise_range = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define SET_KEY(key, fence_num, ind, use_same_keys) do { \
|
||||
if (use_same_keys) { \
|
||||
(void)snprintf(key, sizeof(key)-1, "key-%d", ind); \
|
||||
} else { \
|
||||
(void)snprintf(key, sizeof(key)-1, "key-f%d:%d", fence_num, ind); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
#define PUT(dtype, data, flag, fence_num, ind, use_same_keys) do { \
|
||||
char key[50]; \
|
||||
pmix_value_t value; \
|
||||
SET_KEY(key, fence_num, ind, use_same_keys); \
|
||||
PMIX_VAL_SET(&value, dtype, data); \
|
||||
TEST_VERBOSE(("%s:%d put key %s", my_nspace, my_rank, key)); \
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Put(flag, key, &value))) { \
|
||||
TEST_ERROR(("%s:%d: PMIx_Put key %s failed: %d", my_nspace, my_rank, key, rc)); \
|
||||
rc = PMIX_ERROR; \
|
||||
} \
|
||||
PMIX_VALUE_DESTRUCT(&value); \
|
||||
} while (0);
|
||||
|
||||
#define GET(dtype, data, ns, r, fence_num, ind, use_same_keys, blocking, ok_notfnd) do { \
|
||||
char key[50]; \
|
||||
pmix_value_t *val; \
|
||||
get_cbdata cbdata; \
|
||||
cbdata.status = PMIX_SUCCESS; \
|
||||
pmix_proc_t foobar; \
|
||||
SET_KEY(key, fence_num, ind, use_same_keys); \
|
||||
(void)strncpy(foobar.nspace, ns, PMIX_MAX_NSLEN); \
|
||||
foobar.rank = r; \
|
||||
TEST_VERBOSE(("%s:%d want to get from %s:%d key %s", my_nspace, my_rank, ns, r, key)); \
|
||||
if (blocking) { \
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&foobar, key, NULL, 0, &val))) { \
|
||||
if( !( rc == PMIX_ERR_NOT_FOUND && ok_notfnd ) ){ \
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed: %d from %s:%d, key %s", my_nspace, my_rank, rc, ns, r, key)); \
|
||||
} \
|
||||
rc = PMIX_ERROR; \
|
||||
} \
|
||||
} else { \
|
||||
int count; \
|
||||
cbdata.in_progress = 1; \
|
||||
PMIX_VALUE_CREATE(val, 1); \
|
||||
cbdata.kv = val; \
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get_nb(&foobar, key, NULL, 0, get_cb, (void*)&cbdata))) { \
|
||||
TEST_VERBOSE(("%s:%d: PMIx_Get_nb failed: %d from %s:%d, key=%s", my_nspace, my_rank, rc, ns, r, key)); \
|
||||
rc = PMIX_ERROR; \
|
||||
} else { \
|
||||
count = 0; \
|
||||
while(cbdata.in_progress){ \
|
||||
struct timespec ts; \
|
||||
ts.tv_sec = 0; \
|
||||
ts.tv_nsec = 100; \
|
||||
nanosleep(&ts,NULL); \
|
||||
count++; \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
if (PMIX_SUCCESS == rc) { \
|
||||
if( PMIX_SUCCESS != cbdata.status ){ \
|
||||
if( !( rc == PMIX_ERR_NOT_FOUND && ok_notfnd ) ){ \
|
||||
TEST_VERBOSE(("%s:%d: PMIx_Get_nb failed: %d from %s:%d, key=%s", \
|
||||
my_nspace, my_rank, rc, my_nspace, r)); \
|
||||
} \
|
||||
rc = PMIX_ERROR; \
|
||||
} else if (NULL == val) { \
|
||||
TEST_VERBOSE(("%s:%d: PMIx_Get returned NULL value", my_nspace, my_rank)); \
|
||||
rc = PMIX_ERROR; \
|
||||
} \
|
||||
else if (val->type != PMIX_VAL_TYPE_ ## dtype || PMIX_VAL_CMP(dtype, PMIX_VAL_FIELD_ ## dtype((val)), data)) { \
|
||||
TEST_VERBOSE(("%s:%d: from %s:%d Key %s value or type mismatch," \
|
||||
" want type %d get type %d", \
|
||||
my_nspace, my_rank, ns, r, key, PMIX_VAL_TYPE_ ## dtype, val->type)); \
|
||||
rc = PMIX_ERROR; \
|
||||
} \
|
||||
} \
|
||||
if (PMIX_SUCCESS == rc) { \
|
||||
TEST_VERBOSE(("%s:%d: GET OF %s from %s:%d SUCCEEDED", my_nspace, my_rank, key, ns, r)); \
|
||||
PMIX_VALUE_RELEASE(val); \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define FENCE(blocking, data_ex, pcs, nprocs) do { \
|
||||
if( blocking ){ \
|
||||
pmix_info_t *info = NULL; \
|
||||
size_t ninfo = 0; \
|
||||
if (data_ex) { \
|
||||
bool value = 1; \
|
||||
PMIX_INFO_CREATE(info, 1); \
|
||||
(void)strncpy(info->key, PMIX_COLLECT_DATA, PMIX_MAX_KEYLEN); \
|
||||
pmix_value_load(&info->value, &value, PMIX_BOOL); \
|
||||
ninfo = 1; \
|
||||
} \
|
||||
rc = PMIx_Fence(pcs, nprocs, info, ninfo); \
|
||||
PMIX_INFO_FREE(info, ninfo); \
|
||||
} else { \
|
||||
int in_progress = 1, count; \
|
||||
rc = PMIx_Fence_nb(pcs, nprocs, NULL, 0, release_cb, &in_progress); \
|
||||
if ( PMIX_SUCCESS == rc ) { \
|
||||
count = 0; \
|
||||
while( in_progress ){ \
|
||||
struct timespec ts; \
|
||||
ts.tv_sec = 0; \
|
||||
ts.tv_nsec = 100; \
|
||||
nanosleep(&ts,NULL); \
|
||||
count++; \
|
||||
} \
|
||||
TEST_VERBOSE(("PMIx_Fence_nb(barrier,collect): free time: %lfs", \
|
||||
count*100*1E-9)); \
|
||||
} \
|
||||
} \
|
||||
if (PMIX_SUCCESS == rc) { \
|
||||
TEST_VERBOSE(("%s:%d: Fence successfully completed", \
|
||||
my_nspace, my_rank)); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
int test_fence(test_params params, char *my_nspace, int my_rank)
|
||||
{
|
||||
int len;
|
||||
int rc;
|
||||
size_t i, npcs;
|
||||
fence_desc_t *desc;
|
||||
participant_t *p, *next;
|
||||
pmix_proc_t *pcs;
|
||||
bool participate;
|
||||
int fence_num = 0;
|
||||
char sval[50];
|
||||
int put_ind;
|
||||
|
||||
if (NULL != params.noise) {
|
||||
add_noise(params.noise, my_nspace, my_rank);
|
||||
}
|
||||
|
||||
PMIX_CONSTRUCT(&test_fences, pmix_list_t);
|
||||
parse_fence(params.fences, 1);
|
||||
|
||||
/* cycle thru all the test fence descriptors to find
|
||||
* those that include my nspace/rank */
|
||||
PMIX_LIST_FOREACH(desc, &test_fences, fence_desc_t) {
|
||||
char tmp[256] = {0};
|
||||
len = sprintf(tmp, "fence %d: block = %d de = %d ", fence_num, desc->blocking, desc->data_exchange);
|
||||
participate = false;
|
||||
/* search the participants */
|
||||
PMIX_LIST_FOREACH(p, desc->participants, participant_t) {
|
||||
if (0 == strncmp(my_nspace, p->proc.nspace, strlen(my_nspace)) &&
|
||||
(my_rank == p->proc.rank || PMIX_RANK_WILDCARD == p->proc.rank)) {
|
||||
participate = true;
|
||||
}
|
||||
if (PMIX_RANK_WILDCARD == p->proc.rank) {
|
||||
len += sprintf(tmp+len, "all; ");
|
||||
} else {
|
||||
len += sprintf(tmp+len, "%d,", p->proc.rank);
|
||||
}
|
||||
}
|
||||
TEST_VERBOSE(("%s\n", tmp));
|
||||
if (participate) {
|
||||
/*run fence test on this range */
|
||||
/* first put value (my_ns, my_rank) with key based on fence_num to split results of different fences*/
|
||||
put_ind = 0;
|
||||
(void)snprintf(sval, 50, "%d:%s:%d", fence_num, my_nspace, my_rank);
|
||||
PUT(string, sval, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
|
||||
PUT(int, fence_num+my_rank, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
|
||||
PUT(float, fence_num+1.1, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
|
||||
PUT(uint32_t, fence_num+14, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
|
||||
PUT(uint16_t, fence_num+15, PMIX_GLOBAL, fence_num, put_ind++, params.use_same_keys);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Submit the data */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* setup the fence */
|
||||
npcs = pmix_list_get_size(desc->participants);
|
||||
PMIX_PROC_CREATE(pcs, npcs);
|
||||
i = 0;
|
||||
PMIX_LIST_FOREACH(p, desc->participants, participant_t) {
|
||||
(void)strncpy(pcs[i].nspace, p->proc.nspace, PMIX_MAX_NSLEN);
|
||||
pcs[i].rank = p->proc.rank;
|
||||
i++;
|
||||
}
|
||||
|
||||
/* perform fence */
|
||||
FENCE(desc->blocking, desc->data_exchange, pcs, npcs);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* replace all items in the list with PMIX_RANK_WILDCARD rank by real ranks to get their data. */
|
||||
pmix_proc_t *ranks;
|
||||
size_t nranks;
|
||||
PMIX_LIST_FOREACH_SAFE(p, next, desc->participants, participant_t) {
|
||||
if (-1 == p->proc.rank) {
|
||||
rc = get_all_ranks_from_namespace(params, p->proc.nspace, &ranks, &nranks);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: Can't parse --ns-dist value in order to get ranks for namespace %s", my_nspace, my_rank, p->proc.nspace));
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
pmix_list_remove_item(desc->participants, (pmix_list_item_t*)p);
|
||||
for (i = 0; i < nranks; i++) {
|
||||
participant_t *prt;
|
||||
prt = PMIX_NEW(participant_t);
|
||||
strncpy(prt->proc.nspace, ranks[i].nspace, strlen(ranks[i].nspace)+1);
|
||||
prt->proc.rank = ranks[i].rank;
|
||||
pmix_list_append(desc->participants, &prt->super);
|
||||
}
|
||||
PMIX_PROC_FREE(ranks, nranks);
|
||||
}
|
||||
}
|
||||
|
||||
/* get data from all participating in this fence clients */
|
||||
PMIX_LIST_FOREACH(p, desc->participants, participant_t) {
|
||||
put_ind = 0;
|
||||
snprintf(sval, 50, "%d:%s:%d", fence_num, p->proc.nspace, p->proc.rank);
|
||||
GET(string, sval, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 1, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank));
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
GET(int, fence_num+p->proc.rank, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 0, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank));
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
GET(float, fence_num+1.1, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 1, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank));
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
GET(uint32_t, (uint32_t)fence_num+14, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 0, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank));
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
GET(uint16_t, fence_num+15, p->proc.nspace, p->proc.rank, fence_num, put_ind++, params.use_same_keys, 1, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d) from %s:%d", my_nspace, my_rank, rc, p->proc.nspace, p->proc.rank));
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
/* barrier across participating processes to prevent putting new values with the same key
|
||||
* before finishing data exchange with other processes. */
|
||||
FENCE(1, 0, pcs, npcs);
|
||||
PMIX_PROC_FREE(pcs, npcs);
|
||||
}
|
||||
fence_num++;
|
||||
}
|
||||
|
||||
PMIX_LIST_DESTRUCT(&test_fences);
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
static int get_local_peers(char *my_nspace, int my_rank, int **_peers, int *count)
|
||||
{
|
||||
pmix_value_t *val;
|
||||
int *peers = NULL;
|
||||
char *sptr, *token, *eptr, *str;
|
||||
int npeers;
|
||||
int rc;
|
||||
pmix_proc_t proc;
|
||||
|
||||
(void)strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = my_rank;
|
||||
/* get number of neighbours on this node */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_SIZE, NULL, 0, &val))) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get local peer # failed: %d", my_nspace, my_rank, rc));
|
||||
return rc;
|
||||
}
|
||||
if (NULL == val) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get local peer # returned NULL value", my_nspace, my_rank));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
if (val->type != PMIX_UINT32 ) {
|
||||
TEST_ERROR(("%s:%d: local peer # attribute value type mismatch,"
|
||||
" want %d get %d(%d)",
|
||||
my_nspace, my_rank, PMIX_UINT32, val->type));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
npeers = val->data.uint32;
|
||||
peers = malloc(sizeof(int) * npeers);
|
||||
|
||||
/* get ranks of neighbours on this node */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Get(&proc, PMIX_LOCAL_PEERS, NULL, 0, &val))) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get local peers failed: %d", my_nspace, my_rank, rc));
|
||||
free(peers);
|
||||
return rc;
|
||||
}
|
||||
if (NULL == val) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get local peers returned NULL value", my_nspace, my_rank));
|
||||
free(peers);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
if (val->type != PMIX_STRING ) {
|
||||
TEST_ERROR(("%s:%d: local peers attribute value type mismatch,"
|
||||
" want %d get %d(%d)",
|
||||
my_nspace, my_rank, PMIX_UINT32, val->type));
|
||||
free(peers);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
sptr = NULL;
|
||||
str = val->data.string;
|
||||
do{
|
||||
if( *count > npeers ){
|
||||
TEST_ERROR(("%s:%d: Bad peer ranks number: should be %d, actual %d (%s)",
|
||||
my_nspace, my_rank, npeers, *count, val->data.string));
|
||||
free(peers);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
token = strtok_r(str, ",", &sptr);
|
||||
str = NULL;
|
||||
if( NULL != token ){
|
||||
peers[(*count)++] = strtol(token,&eptr,10);
|
||||
if( *eptr != '\0' ){
|
||||
TEST_ERROR(("%s:%d: Bad peer ranks string", my_nspace, my_rank));
|
||||
free(peers);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
} while( NULL != token );
|
||||
|
||||
if( *count != npeers ){
|
||||
TEST_ERROR(("%s:%d: Bad peer ranks number: should be %d, actual %d (%s)",
|
||||
my_nspace, my_rank, npeers, *count, val->data.string));
|
||||
free(peers);
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
*_peers = peers;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
||||
int test_job_fence(test_params params, char *my_nspace, int my_rank)
|
||||
{
|
||||
int rc;
|
||||
int i, j;
|
||||
char sval[50];
|
||||
int *peers, npeers;
|
||||
pmix_value_t value;
|
||||
pmix_value_t *val = &value;
|
||||
pmix_proc_t proc;
|
||||
|
||||
(void)strncpy(proc.nspace, my_nspace, PMIX_MAX_NSLEN);
|
||||
proc.rank = my_rank;
|
||||
|
||||
for (i=0; i < 3; i++) {
|
||||
PUT(int, 12340 + i, PMIX_LOCAL, 100, i, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
(void)snprintf(sval, 50, "%s:%d", my_nspace, my_rank);
|
||||
PUT(string, sval, PMIX_REMOTE, 101, i, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
PUT(float, (float)12.15 + i, PMIX_GLOBAL, 102, i, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Put failed: %d", my_nspace, my_rank, rc));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* Submit the data */
|
||||
if (PMIX_SUCCESS != (rc = PMIx_Commit())) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Commit failed: %d", my_nspace, my_rank, rc));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
/* Perform a fence if was requested */
|
||||
FENCE(!params.nonblocking, params.collect, NULL, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Fence failed: %d", my_nspace, my_rank, rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (PMIX_SUCCESS != (rc = get_local_peers(my_nspace, my_rank, &peers, &npeers))) {
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
/* Check the predefined output */
|
||||
for (i=0; i < (int)params.ns_size; i++) {
|
||||
|
||||
for (j=0; j < 3; j++) {
|
||||
|
||||
int local = 0, k;
|
||||
for(k=0; k<npeers; k++){
|
||||
if( peers[k] == i+params.base_rank){
|
||||
local = 1;
|
||||
}
|
||||
}
|
||||
if( local ){
|
||||
GET(int, (12340+j), my_nspace, i+params.base_rank, 100, j, 0, 0, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed: %d", my_nspace, my_rank, rc));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
snprintf(sval, 50, "%s:%d", my_nspace, i+params.base_rank);
|
||||
GET(string, sval, my_nspace, i+params.base_rank, 101, j, 0, 1, 1);
|
||||
if (PMIX_SUCCESS == rc && (i+params.base_rank) != my_rank ) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get of remote key on local proc", my_nspace, my_rank));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
} else {
|
||||
GET(int, (12340+j), my_nspace, i+params.base_rank, 100, j, 0, 0, 1);
|
||||
if (PMIX_SUCCESS == rc && (i+params.base_rank) != my_rank) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get of local key on the remote proc", my_nspace, my_rank));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
|
||||
snprintf(sval, 50, "%s:%d", my_nspace, i+params.base_rank);
|
||||
GET(string, sval, my_nspace, i+params.base_rank, 101, j, 0, 1, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d)", my_nspace, my_rank, rc));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
GET(float, (float)12.15 + j, my_nspace, i+params.base_rank, 102, j, 0, 0, 0);
|
||||
if (PMIX_SUCCESS != rc) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get failed (%d)", my_nspace, my_rank, rc));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* ask for a non-existent key */
|
||||
proc.rank = i+params.base_rank;
|
||||
if (PMIX_SUCCESS == (rc = PMIx_Get(&proc, "foobar", NULL, 0, &val))) {
|
||||
TEST_ERROR(("%s:%d: PMIx_Get returned success instead of failure",
|
||||
my_nspace, my_rank));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
if (PMIX_ERR_NOT_FOUND != rc) {
|
||||
TEST_ERROR(("%s:%d [ERROR]: PMIx_Get returned %d instead of not_found",
|
||||
my_nspace, my_rank, rc));
|
||||
}
|
||||
if (NULL != val) {
|
||||
TEST_ERROR(("%s:%d [ERROR]: PMIx_Get did not return NULL value", my_nspace, my_rank));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
TEST_VERBOSE(("%s:%d: rank %d is OK", my_nspace, my_rank, i+params.base_rank));
|
||||
}
|
||||
return PMIX_SUCCESS;
|
||||
}
|
||||
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
int test_publish_lookup(char *my_nspace, int my_rank);
|
@ -1,18 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private/autogen/config.h>
|
||||
#include <pmix.h>
|
||||
|
||||
#include "test_common.h"
|
||||
|
||||
int test_resolve_peers(char *my_nspace, int my_rank, test_params params);
|
@ -1,242 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
* Copyright (c) 2015 Mellanox Technologies, Inc.
|
||||
* All rights reserved.
|
||||
* $COPYRIGHT$
|
||||
*
|
||||
* Additional copyrights may follow
|
||||
*
|
||||
* $HEADER$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "test_common.h"
|
||||
#include "pmix_server.h"
|
||||
#include "cli_stages.h"
|
||||
|
||||
static void release_cb(pmix_status_t status, void *cbdata)
|
||||
{
|
||||
int *ptr = (int*)cbdata;
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
static void fill_seq_ranks_array(size_t nprocs, int base_rank, char **ranks)
|
||||
{
|
||||
uint32_t i;
|
||||
int len = 0, max_ranks_len;
|
||||
if (0 >= nprocs) {
|
||||
return;
|
||||
}
|
||||
max_ranks_len = nprocs * (MAX_DIGIT_LEN+1);
|
||||
*ranks = (char*) malloc(max_ranks_len);
|
||||
for (i = 0; i < nprocs; i++) {
|
||||
len += snprintf(*ranks + len, max_ranks_len-len-1, "%d", i+base_rank);
|
||||
if (i != nprocs-1) {
|
||||
len += snprintf(*ranks + len, max_ranks_len-len-1, "%c", ',');
|
||||
}
|
||||
}
|
||||
if (len >= max_ranks_len-1) {
|
||||
free(*ranks);
|
||||
*ranks = NULL;
|
||||
TEST_ERROR(("Not enough allocated space for global ranks array."));
|
||||
}
|
||||
}
|
||||
|
||||
static void set_namespace(int nprocs, char *ranks, char *name)
|
||||
{
|
||||
size_t ninfo;
|
||||
pmix_info_t *info;
|
||||
ninfo = 6;
|
||||
char *regex, *ppn;
|
||||
|
||||
PMIX_INFO_CREATE(info, ninfo);
|
||||
(void)strncpy(info[0].key, PMIX_UNIV_SIZE, PMIX_MAX_KEYLEN);
|
||||
info[0].value.type = PMIX_UINT32;
|
||||
info[0].value.data.uint32 = nprocs;
|
||||
|
||||
(void)strncpy(info[1].key, PMIX_SPAWNED, PMIX_MAX_KEYLEN);
|
||||
info[1].value.type = PMIX_UINT32;
|
||||
info[1].value.data.uint32 = 0;
|
||||
|
||||
(void)strncpy(info[2].key, PMIX_LOCAL_SIZE, PMIX_MAX_KEYLEN);
|
||||
info[2].value.type = PMIX_UINT32;
|
||||
info[2].value.data.uint32 = nprocs;
|
||||
|
||||
(void)strncpy(info[3].key, PMIX_LOCAL_PEERS, PMIX_MAX_KEYLEN);
|
||||
info[3].value.type = PMIX_STRING;
|
||||
info[3].value.data.string = strdup(ranks);
|
||||
|
||||
PMIx_generate_regex(NODE_NAME, ®ex);
|
||||
(void)strncpy(info[4].key, PMIX_NODE_MAP, PMIX_MAX_KEYLEN);
|
||||
info[4].value.type = PMIX_STRING;
|
||||
info[4].value.data.string = regex;
|
||||
|
||||
PMIx_generate_ppn(ranks, &ppn);
|
||||
(void)strncpy(info[5].key, PMIX_PROC_MAP, PMIX_MAX_KEYLEN);
|
||||
info[5].value.type = PMIX_STRING;
|
||||
info[5].value.data.string = ppn;
|
||||
|
||||
int in_progress = 1, rc;
|
||||
if (PMIX_SUCCESS == (rc = PMIx_server_register_nspace(name, nprocs, info, ninfo, release_cb, &in_progress))) {
|
||||
PMIX_WAIT_FOR_COMPLETION(in_progress);
|
||||
}
|
||||
PMIX_INFO_FREE(info, ninfo);
|
||||
}
|
||||
|
||||
void set_client_argv(test_params *params, char ***argv)
|
||||
{
|
||||
pmix_argv_append_nosize(argv, params->binary);
|
||||
pmix_argv_append_nosize(argv, "-n");
|
||||
if (NULL == params->np) {
|
||||
pmix_argv_append_nosize(argv, "1");
|
||||
} else {
|
||||
pmix_argv_append_nosize(argv, params->np);
|
||||
}
|
||||
if( params->verbose ){
|
||||
pmix_argv_append_nosize(argv, "-v");
|
||||
}
|
||||
if (NULL != params->prefix) {
|
||||
pmix_argv_append_nosize(argv, "-o");
|
||||
pmix_argv_append_nosize(argv, params->prefix);
|
||||
}
|
||||
if( params->early_fail ){
|
||||
pmix_argv_append_nosize(argv, "--early-fail");
|
||||
}
|
||||
if (NULL != params->fences) {
|
||||
pmix_argv_append_nosize(argv, "--fence");
|
||||
pmix_argv_append_nosize(argv, params->fences);
|
||||
if (params->use_same_keys) {
|
||||
pmix_argv_append_nosize(argv, "--use-same-keys");
|
||||
}
|
||||
}
|
||||
if (params->test_job_fence) {
|
||||
pmix_argv_append_nosize(argv, "--job-fence");
|
||||
if (params->nonblocking) {
|
||||
pmix_argv_append_nosize(argv, "-nb");
|
||||
}
|
||||
if (params->collect) {
|
||||
pmix_argv_append_nosize(argv, "-c");
|
||||
}
|
||||
if (params->collect_bad) {
|
||||
pmix_argv_append_nosize(argv, "--collect-corrupt");
|
||||
}
|
||||
}
|
||||
if (NULL != params->noise) {
|
||||
pmix_argv_append_nosize(argv, "--noise");
|
||||
pmix_argv_append_nosize(argv, params->noise);
|
||||
}
|
||||
if (NULL != params->ns_dist) {
|
||||
pmix_argv_append_nosize(argv, "--ns-dist");
|
||||
pmix_argv_append_nosize(argv, params->ns_dist);
|
||||
}
|
||||
if (params->test_publish) {
|
||||
pmix_argv_append_nosize(argv, "--test-publish");
|
||||
}
|
||||
if (params->test_spawn) {
|
||||
pmix_argv_append_nosize(argv, "--test-spawn");
|
||||
}
|
||||
if (params->test_connect) {
|
||||
pmix_argv_append_nosize(argv, "--test-connect");
|
||||
}
|
||||
if (params->test_resolve_peers) {
|
||||
pmix_argv_append_nosize(argv, "--test-resolve-peers");
|
||||
}
|
||||
}
|
||||
|
||||
int launch_clients(int num_procs, char *binary, char *** client_env, char ***base_argv)
|
||||
{
|
||||
int n;
|
||||
uid_t myuid;
|
||||
gid_t mygid;
|
||||
char *ranks = NULL;
|
||||
char digit[MAX_DIGIT_LEN];
|
||||
int rc;
|
||||
static int counter = 0;
|
||||
static int num_ns = 0;
|
||||
pmix_proc_t proc;
|
||||
|
||||
TEST_VERBOSE(("Setting job info"));
|
||||
fill_seq_ranks_array(num_procs, counter, &ranks);
|
||||
if (NULL == ranks) {
|
||||
PMIx_server_finalize();
|
||||
TEST_ERROR(("fill_seq_ranks_array failed"));
|
||||
return PMIX_ERROR;
|
||||
}
|
||||
(void)snprintf(proc.nspace, PMIX_MAX_NSLEN, "%s-%d", TEST_NAMESPACE, num_ns);
|
||||
set_namespace(num_procs, ranks, proc.nspace);
|
||||
if (NULL != ranks) {
|
||||
free(ranks);
|
||||
}
|
||||
|
||||
myuid = getuid();
|
||||
mygid = getgid();
|
||||
|
||||
/* fork/exec the test */
|
||||
for (n = 0; n < num_procs; n++) {
|
||||
proc.rank = counter;
|
||||
if (PMIX_SUCCESS != (rc = PMIx_server_setup_fork(&proc, client_env))) {//n
|
||||
TEST_ERROR(("Server fork setup failed with error %d", rc));
|
||||
PMIx_server_finalize();
|
||||
cli_kill_all();
|
||||
return rc;
|
||||
}
|
||||
if (PMIX_SUCCESS != (rc = PMIx_server_register_client(&proc, myuid, mygid, NULL, NULL, NULL))) {//n
|
||||
TEST_ERROR(("Server fork setup failed with error %d", rc));
|
||||
PMIx_server_finalize();
|
||||
cli_kill_all();
|
||||
return rc;
|
||||
}
|
||||
|
||||
cli_info[counter].pid = fork();
|
||||
if (cli_info[counter].pid < 0) {
|
||||
TEST_ERROR(("Fork failed"));
|
||||
PMIx_server_finalize();
|
||||
cli_kill_all();
|
||||
return -1;
|
||||
}
|
||||
cli_info[counter].rank = counter;//n
|
||||
cli_info[counter].ns = strdup(proc.nspace);
|
||||
|
||||
char **client_argv = pmix_argv_copy(*base_argv);
|
||||
|
||||
/* add two last arguments: -r <rank> */
|
||||
sprintf(digit, "%d", counter);//n
|
||||
pmix_argv_append_nosize(&client_argv, "-r");
|
||||
pmix_argv_append_nosize(&client_argv, digit);
|
||||
|
||||
pmix_argv_append_nosize(&client_argv, "-s");
|
||||
pmix_argv_append_nosize(&client_argv, proc.nspace);
|
||||
|
||||
sprintf(digit, "%d", num_procs);
|
||||
pmix_argv_append_nosize(&client_argv, "--ns-size");
|
||||
pmix_argv_append_nosize(&client_argv, digit);
|
||||
|
||||
sprintf(digit, "%d", num_ns);
|
||||
pmix_argv_append_nosize(&client_argv, "--ns-id");
|
||||
pmix_argv_append_nosize(&client_argv, digit);
|
||||
|
||||
sprintf(digit, "%d", (counter-n));
|
||||
pmix_argv_append_nosize(&client_argv, "--base-rank");
|
||||
pmix_argv_append_nosize(&client_argv, digit);
|
||||
|
||||
if (cli_info[counter].pid == 0) {
|
||||
if( !TEST_VERBOSE_GET() ){
|
||||
// Hide clients stdout
|
||||
// TODO: on some systems stdout is a constant, address this
|
||||
fclose(stdout);
|
||||
stdout = fopen("/dev/null","w");
|
||||
}
|
||||
execve(binary, client_argv, *client_env);
|
||||
/* Does not return */
|
||||
exit(0);
|
||||
}
|
||||
cli_info[counter].state = CLI_FORKED;
|
||||
|
||||
pmix_argv_free(client_argv);
|
||||
|
||||
counter++;
|
||||
}
|
||||
num_ns++;
|
||||
return PMIX_SUCCESS;
|
||||
}
|
53
opal/mca/pmix/pmix114/Makefile.am
Обычный файл
53
opal/mca/pmix/pmix114/Makefile.am
Обычный файл
@ -0,0 +1,53 @@
|
||||
#
|
||||
# Copyright (c) 2014-2016 Intel, Inc. All rights reserved.
|
||||
# Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
|
||||
# Copyright (c) 2015 Research Organization for Information Science
|
||||
# and Technology (RIST). All rights reserved.
|
||||
# $COPYRIGHT$
|
||||
#
|
||||
# Additional copyrights may follow
|
||||
#
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
EXTRA_DIST = autogen.subdirs
|
||||
|
||||
SUBDIRS = pmix
|
||||
|
||||
sources = \
|
||||
pmix1.h \
|
||||
pmix_pmix1_component.c \
|
||||
pmix_pmix1.c \
|
||||
pmix1_client.c \
|
||||
pmix1_server_south.c \
|
||||
pmix1_server_north.c
|
||||
|
||||
# Make the output library in this directory, and name it either
|
||||
# mca_<type>_<name>.la (for DSO builds) or libmca_<type>_<name>.la
|
||||
# (for static builds).
|
||||
|
||||
if MCA_BUILD_opal_pmix_pmix114_DSO
|
||||
component_noinst =
|
||||
component_install = mca_pmix_pmix114.la
|
||||
else
|
||||
component_noinst = libmca_pmix_pmix114.la
|
||||
component_install =
|
||||
endif
|
||||
|
||||
mcacomponentdir = $(opallibdir)
|
||||
mcacomponent_LTLIBRARIES = $(component_install)
|
||||
mca_pmix_pmix114_la_SOURCES = $(sources)
|
||||
mca_pmix_pmix114_la_CFLAGS = $(opal_pmix_pmix114_CFLAGS)
|
||||
mca_pmix_pmix114_la_CPPFLAGS = \
|
||||
-I$(srcdir)/pmix/include $(opal_pmix_pmix114_CPPFLAGS)
|
||||
mca_pmix_pmix114_la_LDFLAGS = -module -avoid-version $(opal_pmix_pmix114_LDFLAGS)
|
||||
mca_pmix_pmix114_la_LIBADD = $(opal_pmix_pmix114_LIBS)
|
||||
mca_pmix_pmix114_la_DEPENDENCIES = $(mca_pmix_pmix114_la_LIBADD)
|
||||
|
||||
noinst_LTLIBRARIES = $(component_noinst)
|
||||
libmca_pmix_pmix114_la_SOURCES =$(sources)
|
||||
libmca_pmix_pmix114_la_CFLAGS = $(opal_pmix_pmix114_CFLAGS)
|
||||
libmca_pmix_pmix114_la_CPPFLAGS = -I$(srcdir)/pmix/include $(opal_pmix_pmix114_CPPFLAGS)
|
||||
libmca_pmix_pmix114_la_LDFLAGS = -module -avoid-version $(opal_pmix_pmix114_LDFLAGS)
|
||||
libmca_pmix_pmix114_la_LIBADD = $(opal_pmix_pmix114_LIBS)
|
||||
libmca_pmix_pmix114_la_DEPENDENCIES = $(mca_pmix_pmix114_la_LIBADD)
|
@ -23,51 +23,51 @@
|
||||
# $HEADER$
|
||||
#
|
||||
|
||||
# MCA_pmix_pmix120_CONFIG([action-if-found], [action-if-not-found])
|
||||
# MCA_pmix_pmix114_CONFIG([action-if-found], [action-if-not-found])
|
||||
# -----------------------------------------------------------
|
||||
AC_DEFUN([MCA_opal_pmix_pmix120_CONFIG],[
|
||||
AC_CONFIG_FILES([opal/mca/pmix/pmix120/Makefile])
|
||||
AC_DEFUN([MCA_opal_pmix_pmix114_CONFIG],[
|
||||
AC_CONFIG_FILES([opal/mca/pmix/pmix114/Makefile])
|
||||
|
||||
OPAL_VAR_SCOPE_PUSH([PMIX_VERSION opal_pmix_pmix120_save_CPPFLAGS opal_pmix_pmix120_save_LDFLAGS opal_pmix_pmix120_save_LIBS opal_pmix_pmix120_basedir opal_pmix_pmix120_save_cflags])
|
||||
OPAL_VAR_SCOPE_PUSH([PMIX_VERSION opal_pmix_pmix114_save_CPPFLAGS opal_pmix_pmix114_save_LDFLAGS opal_pmix_pmix114_save_LIBS opal_pmix_pmix114_basedir opal_pmix_pmix114_save_cflags])
|
||||
|
||||
AS_IF([test "$opal_external_pmix_happy" = "yes"],
|
||||
[AC_MSG_WARN([using an external pmix; disqualifiying this component])
|
||||
opal_pmix_pmix120_happy=0],
|
||||
opal_pmix_pmix114_happy=0],
|
||||
[PMIX_VERSION=
|
||||
opal_pmix_pmix120_basedir=opal/mca/pmix/pmix120
|
||||
opal_pmix_pmix114_basedir=opal/mca/pmix/pmix114
|
||||
|
||||
opal_pmix_pmix120_save_CFLAGS=$CFLAGS
|
||||
opal_pmix_pmix120_save_CPPFLAGS=$CPPFLAGS
|
||||
opal_pmix_pmix120_save_LDFLAGS=$LDFLAGS
|
||||
opal_pmix_pmix120_save_LIBS=$LIBS
|
||||
opal_pmix_pmix114_save_CFLAGS=$CFLAGS
|
||||
opal_pmix_pmix114_save_CPPFLAGS=$CPPFLAGS
|
||||
opal_pmix_pmix114_save_LDFLAGS=$LDFLAGS
|
||||
opal_pmix_pmix114_save_LIBS=$LIBS
|
||||
|
||||
opal_pmix_pmix120_args="--enable-embedded-mode --with-pmix-symbol-prefix=opal_pmix_pmix120_ --disable-visibility --with-libevent-header=\\\"opal/mca/event/$opal_event_base_include\\\" --with-hwloc-header=\\\"$opal_hwloc_base_include\\\""
|
||||
opal_pmix_pmix114_args="--enable-embedded-mode --with-pmix-symbol-prefix=opal_pmix_pmix114_ --disable-visibility --with-libevent-header=\\\"opal/mca/event/$opal_event_base_include\\\" --with-hwloc-header=\\\"$opal_hwloc_base_include\\\""
|
||||
AS_IF([test "$enable_debug" = "yes"],
|
||||
[opal_pmix_pmix120_args="--enable-debug $opal_pmix_pmix120_args"
|
||||
[opal_pmix_pmix114_args="--enable-debug $opal_pmix_pmix114_args"
|
||||
CFLAGS="$OPAL_CFLAGS_BEFORE_PICKY $OPAL_VISIBILITY_CFLAGS -g"],
|
||||
[opal_pmix_pmix120_args="--disable-debug $opal_pmix_pmix120_args"
|
||||
[opal_pmix_pmix114_args="--disable-debug $opal_pmix_pmix114_args"
|
||||
CFLAGS="$OPAL_CFLAGS_BEFORE_PICKY $OPAL_VISIBILITY_CFLAGS"])
|
||||
CPPFLAGS="-I$OPAL_TOP_SRCDIR -I$OPAL_TOP_BUILDDIR -I$OPAL_TOP_SRCDIR/opal/include -I$OPAL_TOP_BUILDDIR/opal/include $CPPFLAGS"
|
||||
|
||||
OPAL_CONFIG_SUBDIR([$opal_pmix_pmix120_basedir/pmix],
|
||||
[$opal_pmix_pmix120_args $opal_subdir_args 'CFLAGS=$CFLAGS' 'CPPFLAGS=$CPPFLAGS'],
|
||||
[opal_pmix_pmix120_happy=1], [opal_pmix_pmix120_happy=0])
|
||||
OPAL_CONFIG_SUBDIR([$opal_pmix_pmix114_basedir/pmix],
|
||||
[$opal_pmix_pmix114_args $opal_subdir_args 'CFLAGS=$CFLAGS' 'CPPFLAGS=$CPPFLAGS'],
|
||||
[opal_pmix_pmix114_happy=1], [opal_pmix_pmix114_happy=0])
|
||||
|
||||
AS_IF([test $opal_pmix_pmix120_happy -eq 1],
|
||||
[PMIX_VERSION="internal v`$srcdir/$opal_pmix_pmix120_basedir/pmix/config/pmix_get_version.sh $srcdir/$opal_pmix_pmix120_basedir/pmix/VERSION`"
|
||||
AS_IF([test $opal_pmix_pmix114_happy -eq 1],
|
||||
[PMIX_VERSION="internal v`$srcdir/$opal_pmix_pmix114_basedir/pmix/config/pmix_get_version.sh $srcdir/$opal_pmix_pmix114_basedir/pmix/VERSION`"
|
||||
# Build flags for our Makefile.am
|
||||
opal_pmix_pmix120_LIBS='$(OPAL_TOP_BUILDDIR)/'"$opal_pmix_pmix120_basedir"'/pmix/libpmix.la'
|
||||
opal_pmix_pmix120_CPPFLAGS='-I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix120/pmix/include/pmix -I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix120/pmix/include -I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix120/pmix -I$(OPAL_TOP_SRCDIR)/opal/mca/pmix/pmix120/pmix'
|
||||
AC_SUBST([opal_pmix_pmix120_LIBS])
|
||||
AC_SUBST([opal_pmix_pmix120_CPPFLAGS])])
|
||||
opal_pmix_pmix114_LIBS='$(OPAL_TOP_BUILDDIR)/'"$opal_pmix_pmix114_basedir"'/pmix/libpmix.la'
|
||||
opal_pmix_pmix114_CPPFLAGS='-I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix114/pmix/include/pmix -I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix114/pmix/include -I$(OPAL_TOP_BUILDDIR)/opal/mca/pmix/pmix114/pmix -I$(OPAL_TOP_SRCDIR)/opal/mca/pmix/pmix114/pmix'
|
||||
AC_SUBST([opal_pmix_pmix114_LIBS])
|
||||
AC_SUBST([opal_pmix_pmix114_CPPFLAGS])])
|
||||
|
||||
CFLAGS=$opal_pmix_pmix120_save_CFLAGS
|
||||
CPPFLAGS=$opal_pmix_pmix120_save_CPPFLAGS
|
||||
LDFLAGS=$opal_pmix_pmix120_save_LDFLAGS
|
||||
LIBS=$opal_pmix_pmix120_save_LIBS
|
||||
CFLAGS=$opal_pmix_pmix114_save_CFLAGS
|
||||
CPPFLAGS=$opal_pmix_pmix114_save_CPPFLAGS
|
||||
LDFLAGS=$opal_pmix_pmix114_save_LDFLAGS
|
||||
LIBS=$opal_pmix_pmix114_save_LIBS
|
||||
])
|
||||
|
||||
AS_IF([test $opal_pmix_pmix120_happy -eq 1],
|
||||
AS_IF([test $opal_pmix_pmix114_happy -eq 1],
|
||||
[$1],
|
||||
[$2])
|
||||
|
@ -42,6 +42,8 @@ man_MANS = \
|
||||
man/man3/pmix_abort.3 \
|
||||
man/man3/pmix_put.3 \
|
||||
man/man3/pmix_commit.3 \
|
||||
man/man3/pmix_fence.3 \
|
||||
man/man3/pmix_get.3 \
|
||||
man/man7/pmix.7 \
|
||||
man/man7/pmix_constants.7
|
||||
|
||||
@ -61,17 +63,22 @@ if PMIX_EMBEDDED_MODE
|
||||
noinst_LTLIBRARIES = libpmix.la
|
||||
libpmix_la_SOURCES = $(headers) $(sources)
|
||||
libpmix_la_LDFLAGS =
|
||||
|
||||
else
|
||||
|
||||
lib_LTLIBRARIES = libpmix.la
|
||||
libpmix_la_SOURCES = $(headers) $(sources)
|
||||
libpmix_la_LDFLAGS = -version-info $(libpmix_so_version)
|
||||
SUBDIRS = . test examples
|
||||
endif
|
||||
|
||||
|
||||
if ! PMIX_EMBEDDED_MODE
|
||||
SUBDIRS = . test
|
||||
if WANT_INSTALL_HEADERS
|
||||
pmixdir = $(pmixincludedir)/$(subdir)
|
||||
nobase_pmix_HEADERS = $(headers)
|
||||
|
||||
else
|
||||
|
||||
noinst_HEADERS = $(headers)
|
||||
endif
|
||||
|
||||
nroff:
|
||||
@ -86,9 +93,7 @@ EXTRA_DIST += README INSTALL VERSION LICENSE autogen.sh \
|
||||
test/test_common.h test/cli_stages.h \
|
||||
test/server_callbacks.h test/test_fence.h \
|
||||
test/test_publish.h test/test_resolve_peers.h \
|
||||
test/test_spawn.h test/utils.h test/test_cd.h \
|
||||
examples/client.c examples/dmodex.c examples/dynamic.c \
|
||||
examples/fault.c examples/pub.c
|
||||
test/test_spawn.h test/utils.h test/test_cd.h
|
||||
|
||||
|
||||
dist-hook:
|
@ -1,4 +1,4 @@
|
||||
Copyright (c) 2015 Intel, Inc. All rights reserved.
|
||||
Copyright (c) 2015-2016 Intel, Inc. All rights reserved.
|
||||
$COPYRIGHT$
|
||||
|
||||
Additional copyrights may follow
|
||||
@ -24,6 +24,15 @@ Master (not on release branches yet)
|
||||
------------------------------------
|
||||
|
||||
|
||||
1.1.3
|
||||
-----
|
||||
- Update the symbol hiding file to cover all symbols
|
||||
- Fix examples and test directory Makefile.am's so
|
||||
the Makefiles are automatically built and the
|
||||
code compiled, but not installed
|
||||
- Do not install the pmix library in embedded use-cases
|
||||
|
||||
|
||||
1.1.2
|
||||
-----
|
||||
- Provide a check for hwloc support - if not found, then
|
@ -3,7 +3,7 @@
|
||||
# Copyright (c) 2011 NVIDIA Corporation. All rights reserved.
|
||||
# Copyright (c) 2013 Mellanox Technologies, Inc.
|
||||
# All rights reserved.
|
||||
# Copyright (c) 2014-2015 Intel, Inc. All rights reserved.
|
||||
# Copyright (c) 2014-2016 Intel, Inc. All rights reserved.
|
||||
|
||||
# This is the VERSION file for PMIx, describing the precise
|
||||
# version of PMIx in this distribution. The various components of
|
||||
@ -15,7 +15,7 @@
|
||||
|
||||
major=1
|
||||
minor=1
|
||||
release=2
|
||||
release=3
|
||||
|
||||
# greek is used for alpha or beta release tags. If it is non-empty,
|
||||
# it will be appended to the version number. It does not have to be
|
||||
@ -23,14 +23,14 @@ release=2
|
||||
# The only requirement is that it must be entirely printable ASCII
|
||||
# characters and have no white space.
|
||||
|
||||
greek=
|
||||
greek=rc1
|
||||
|
||||
# If repo_rev is empty, then the repository version number will be
|
||||
# obtained during "make dist" via the "git describe --tags --always"
|
||||
# command, or with the date (if "git describe" fails) in the form of
|
||||
# "date<date>".
|
||||
|
||||
repo_rev=git17ae5a4
|
||||
repo_rev=git17fb9c5
|
||||
|
||||
# If tarball_version is not empty, it is used as the version string in
|
||||
# the tarball filename, regardless of all other versions listed in
|
||||
@ -44,7 +44,7 @@ tarball_version=
|
||||
|
||||
# The date when this release was created
|
||||
|
||||
date="Dec 12, 2015"
|
||||
date="Apr 14, 2016"
|
||||
|
||||
# The shared library version of each of PMIx's public libraries.
|
||||
# These versions are maintained in accordance with the "Library
|
||||
@ -75,4 +75,4 @@ date="Dec 12, 2015"
|
||||
# Version numbers are described in the Libtool current:revision:age
|
||||
# format.
|
||||
|
||||
libpmix_so_version=2:1:0
|
||||
libpmix_so_version=2:2:0
|
@ -20,6 +20,8 @@ dnl Copyright (c) 2011-2013 NVIDIA Corporation. All rights reserved.
|
||||
dnl Copyright (c) 2013-2015 Intel, Inc. All rights reserved
|
||||
dnl Copyright (c) 2015 Research Organization for Information Science
|
||||
dnl and Technology (RIST). All rights reserved.
|
||||
dnl Copyright (c) 2016 Mellanox Technologies, Inc.
|
||||
dnl All rights reserved.
|
||||
dnl
|
||||
dnl $COPYRIGHT$
|
||||
dnl
|
||||
@ -103,7 +105,7 @@ AC_DEFUN([PMIX_SETUP_CORE],[
|
||||
# becomes the "main" config header file. Any AC-CONFIG-HEADERS
|
||||
# after that (pmix/config.h) will only have selective #defines
|
||||
# replaced, not the entire file.
|
||||
AC_CONFIG_HEADERS(pmix_config_prefix[include/private/autogen/config.h])
|
||||
AC_CONFIG_HEADERS(pmix_config_prefix[src/include/private/autogen/config.h])
|
||||
AC_CONFIG_HEADERS(pmix_config_prefix[include/pmix/autogen/config.h])
|
||||
|
||||
# What prefix are we using?
|
||||
@ -580,7 +582,7 @@ AC_DEFUN([PMIX_SETUP_CORE],[
|
||||
# rather than have successive assignments to these shell
|
||||
# variables, lest the $(foo) names try to get evaluated here.
|
||||
# Yuck!
|
||||
CPPFLAGS='-I$(PMIX_top_srcdir) -I$(PMIX_top_builddir) -I$(PMIX_top_srcdir)/src -I$(PMIX_top_srcdir)/include -I$(PMIX_top_builddir)/include'" $CPPFLAGS"
|
||||
CPPFLAGS='-I$(PMIX_top_builddir) -I$(PMIX_top_srcdir) -I$(PMIX_top_srcdir)/src -I$(PMIX_top_builddir)/include -I$(PMIX_top_srcdir)/include'" $CPPFLAGS"
|
||||
else
|
||||
CPPFLAGS='-I$(PMIX_top_srcdir) -I$(PMIX_top_srcdir)/src -I$(PMIX_top_srcdir)/include'" $CPPFLAGS"
|
||||
fi
|
||||
@ -608,12 +610,15 @@ AC_DEFUN([PMIX_SETUP_CORE],[
|
||||
|
||||
AC_DEFUN([PMIX_DEFINE_ARGS],[
|
||||
# Embedded mode, or standalone?
|
||||
AC_MSG_CHECKING([if embedded mode is enabled])
|
||||
AC_ARG_ENABLE([embedded-mode],
|
||||
[AC_HELP_STRING([--enable-embedded-mode],
|
||||
[Using --enable-embedded-mode causes PMIx to skip a few configure checks and install nothing. It should only be used when building PMIx within the scope of a larger package.])])
|
||||
AS_IF([test ! -z "$enable_embedded_mode" && test "$enable_embedded_mode" = "yes"],
|
||||
[pmix_mode=embedded],
|
||||
[pmix_mode=standalone])
|
||||
[pmix_mode=embedded
|
||||
AC_MSG_RESULT([yes])],
|
||||
[pmix_mode=standalone
|
||||
AC_MSG_RESULT([no])])
|
||||
|
||||
# Change the symbol prefix?
|
||||
AC_ARG_WITH([pmix-symbol-prefix],
|
||||
@ -685,6 +690,22 @@ AC_ARG_ENABLE(debug-symbols,
|
||||
AC_HELP_STRING([--disable-debug-symbols],
|
||||
[Disable adding compiler flags to enable debugging symbols if --enable-debug is specified. For non-debugging builds, this flag has no effect.]))
|
||||
|
||||
#
|
||||
# Do we want to install the internal devel headers?
|
||||
#
|
||||
AC_MSG_CHECKING([if want to install project-internal header files])
|
||||
AC_ARG_WITH(devel-headers,
|
||||
AC_HELP_STRING([--with-devel-headers],
|
||||
[normal PMIx users/applications do not need this (pmix.h and friends are ALWAYS installed). Developer headers are only necessary for authors doing deeper integration (default: disabled).]))
|
||||
if test "$with_devel_headers" = "yes"; then
|
||||
AC_MSG_RESULT([yes])
|
||||
WANT_INSTALL_HEADERS=1
|
||||
else
|
||||
AC_MSG_RESULT([no])
|
||||
WANT_INSTALL_HEADERS=0
|
||||
fi
|
||||
AM_CONDITIONAL(WANT_INSTALL_HEADERS, test "$WANT_INSTALL_HEADERS" = 1)
|
||||
|
||||
#
|
||||
# Do we want the pretty-print stack trace feature?
|
||||
#
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
x
Ссылка в новой задаче
Block a user