1
1

Roll to PMIx 1.1.4rc1 and remove the PMIx 1.2.0 directory as the community has decided to not do that release version. This incorporates a number of bug fixes that have been identified and repaired in the PMIx and OMPI code bases. Also includes several minor corrections to the PMIx code so it now supports run-thru without hanging on collectives involving a process that exits

Этот коммит содержится в:
Ralph Castain 2016-04-14 21:09:11 -07:00
родитель 3245428e82
Коммит 449ec41532
385 изменённых файлов: 2984 добавлений и 51123 удалений

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, &params);
// 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, &regex);
(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(&params->binary, "%s/../pmix_client", argv[0]);
*basename = '/';
} else {
asprintf(&params->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, &regex);
(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 Обычный файл
Просмотреть файл

@ -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?
#

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше