From 2ed9438116b496d04a7afa90307929553c89a89b Mon Sep 17 00:00:00 2001 From: Nathan Hjelm Date: Tue, 24 Sep 2024 13:49:24 -0600 Subject: [PATCH] mca/base: add a new MCA variable type for include lists It is not uncommon in Open MPI to register a string variable to allow specifying an exclude or exclude list (every framework registers one). Given this common patten it is worthwhile to formalize an MCA include list variable type: MCA_BASE_VAR_TYPE_INCLUDE_LIST. Variables of this type use a new opal object (mca_base_var_include_list_t) that stores and argv-style array and an exclude- list flag. To register an include list variable the caller must first either OBJ_CONSTRUCT the object or allocate it with OBJ_NEW. Variables of this type are exposed as strings to MPI_T. Signed-off-by: Nathan Hjelm --- configure.ac | 1 + ompi/mpi/tool/cvar_read.c | 12 ++ ompi/mpi/tool/mpit_common.c | 2 + opal/mca/base/mca_base_var.c | 123 ++++++++++++++--- opal/mca/base/mca_base_var.h | 46 +++++++ test/Makefile.am | 3 +- test/mca/Makefile.am | 41 ++++++ test/mca/mca_var.c | 256 +++++++++++++++++++++++++++++++++++ 8 files changed, 461 insertions(+), 23 deletions(-) create mode 100644 test/mca/Makefile.am create mode 100644 test/mca/mca_var.c diff --git a/configure.ac b/configure.ac index 2057a103712..5cd5ef821c0 100644 --- a/configure.ac +++ b/configure.ac @@ -1505,6 +1505,7 @@ AC_CONFIG_FILES([ test/asm/Makefile test/datatype/Makefile test/class/Makefile + test/mca/Makefile test/mpool/Makefile test/support/Makefile test/threads/Makefile diff --git a/ompi/mpi/tool/cvar_read.c b/ompi/mpi/tool/cvar_read.c index b46db2c99c4..a49885a20a1 100644 --- a/ompi/mpi/tool/cvar_read.c +++ b/ompi/mpi/tool/cvar_read.c @@ -10,6 +10,7 @@ * reserved. * Copyright (c) 2021 Amazon.com, Inc. or its affiliates. All Rights * reserved. + * Copyright (c) 2024 Google, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -88,6 +89,17 @@ int MPI_T_cvar_read (MPI_T_cvar_handle handle, void *buf) } break; + case MCA_BASE_VAR_TYPE_INCLUDE_LIST: { + char *tmp = mca_base_var_string_value (handle->var->mbv_index); + if (strlen(tmp) == 0) { + ((char *)buf)[0] = '\0'; + } else { + strcpy ((char *) buf, tmp); + free (tmp); + } + + break; + } default: rc = MPI_T_ERR_INVALID; } diff --git a/ompi/mpi/tool/mpit_common.c b/ompi/mpi/tool/mpit_common.c index e47da814f7a..f7b63bc1db7 100644 --- a/ompi/mpi/tool/mpit_common.c +++ b/ompi/mpi/tool/mpit_common.c @@ -8,6 +8,7 @@ * Copyright (c) 2020 The University of Tennessee and The University * of Tennessee Research Foundation. All rights * reserved. + * Copyright (c) 2024 Google, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -56,6 +57,7 @@ static MPI_Datatype mca_to_mpi_datatypes[MCA_BASE_VAR_TYPE_MAX] = { [MCA_BASE_VAR_TYPE_UINT32_T] = MPI_UINT32_T, [MCA_BASE_VAR_TYPE_INT64_T] = MPI_INT64_T, [MCA_BASE_VAR_TYPE_UINT64_T] = MPI_UINT64_T, + [MCA_BASE_VAR_TYPE_INCLUDE_LIST] = MPI_CHAR, }; int ompit_var_type_to_datatype (mca_base_var_type_t type, MPI_Datatype *datatype) diff --git a/opal/mca/base/mca_base_var.c b/opal/mca/base/mca_base_var.c index b9860c6ed1e..d13944493a3 100644 --- a/opal/mca/base/mca_base_var.c +++ b/opal/mca/base/mca_base_var.c @@ -20,7 +20,7 @@ * Copyright (c) 2018 Amazon.com, Inc. or its affiliates. All Rights reserved. * Copyright (c) 2018 Triad National Security, LLC. All rights * reserved. - * Copyright (c) 2020 Google, LLC. All rights reserved. + * Copyright (c) 2020-2024 Google, LLC. All rights reserved. * Copyright (c) 2021 Nanook Consulting. All rights reserved. * Copyright (c) 2022 Computer Architecture and VLSI Systems (CARV) * Laboratory, ICS Forth. All rights reserved. @@ -138,6 +138,11 @@ static void fv_constructor(mca_base_var_file_value_t *p); static void fv_destructor(mca_base_var_file_value_t *p); OBJ_CLASS_INSTANCE(mca_base_var_file_value_t, opal_list_item_t, fv_constructor, fv_destructor); +static void include_list_contructor(mca_base_var_include_list_t *p); +static void include_list_destructor(mca_base_var_include_list_t *p); +OBJ_CLASS_INSTANCE(mca_base_var_include_list_t, opal_object_t, include_list_contructor, + include_list_destructor); + static const char *mca_base_var_source_file(const mca_base_var_t *var) { mca_base_var_file_value_t *fv = (mca_base_var_file_value_t *) var->mbv_file_value; @@ -766,6 +771,9 @@ static int var_set_from_string(mca_base_var_t *var, char *src) case MCA_BASE_VAR_TYPE_VERSION_STRING: var_set_string(var, src); break; + case MCA_BASE_VAR_TYPE_INCLUDE_LIST: + mca_base_var_parse_include_list(src, &var->mbv_storage->ilistval); + break; case MCA_BASE_VAR_TYPE_MAX: return OPAL_ERROR; } @@ -803,11 +811,13 @@ int mca_base_var_set_value(int vari, const void *value, size_t size, mca_base_va } } - if (MCA_BASE_VAR_TYPE_STRING != var->mbv_type - && MCA_BASE_VAR_TYPE_VERSION_STRING != var->mbv_type) { - memmove(var->mbv_storage, value, ompi_var_type_sizes[var->mbv_type]); + if (MCA_BASE_VAR_TYPE_STRING == var->mbv_type || + MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) { + ret = var_set_string(var, (char *) value); + } else if (MCA_BASE_VAR_TYPE_INCLUDE_LIST == var->mbv_type) { + ret = mca_base_var_parse_include_list((char *) value, &var->mbv_storage->ilistval); } else { - var_set_string(var, (char *) value); + memmove(var->mbv_storage, value, ompi_var_type_sizes[var->mbv_type]); } var->mbv_source = source; @@ -817,7 +827,7 @@ int mca_base_var_set_value(int vari, const void *value, size_t size, mca_base_va var->mbv_source_file = append_filename_to_list(source_file); } - return OPAL_SUCCESS; + return ret; } /* @@ -847,11 +857,12 @@ int mca_base_var_deregister(int vari) } /* Release the current value if it is a string. */ - if ((MCA_BASE_VAR_TYPE_STRING == var->mbv_type - || MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) - && var->mbv_storage->stringval) { + if (MCA_BASE_VAR_TYPE_STRING == var->mbv_type + || MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) { free(var->mbv_storage->stringval); var->mbv_storage->stringval = NULL; + } else if (MCA_BASE_VAR_TYPE_INCLUDE_LIST == var->mbv_type) { + OBJ_DESTRUCT(&var->mbv_storage->ilistval); } else { OPAL_MCA_VAR_MBV_ENUMERATOR_FREE(var->mbv_enumerator); } @@ -1046,9 +1057,11 @@ int mca_base_var_build_env(char ***env, int *num_env, bool internal) continue; } - if ((MCA_BASE_VAR_TYPE_STRING == var->mbv_type + if (((MCA_BASE_VAR_TYPE_STRING == var->mbv_type || MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) - && NULL == var->mbv_storage->stringval) { + && NULL == var->mbv_storage->stringval) || + (MCA_BASE_VAR_TYPE_INCLUDE_LIST == var->mbv_type && + NULL == var->mbv_storage->ilistval.items)) { continue; } @@ -1331,7 +1344,11 @@ static int register_variable(const char *project_name, const char *framework_nam align = OPAL_ALIGNMENT_DOUBLE; break; case MCA_BASE_VAR_TYPE_VERSION_STRING: + /* fall through */ case MCA_BASE_VAR_TYPE_STRING: + /* fall through */ + case MCA_BASE_VAR_TYPE_INCLUDE_LIST: + /* fall through */ default: align = 0; break; @@ -1533,6 +1550,9 @@ int mca_base_var_register(const char *project_name, const char *framework_name, assert(NULL == enumerator || (MCA_BASE_VAR_TYPE_INT == type || MCA_BASE_VAR_TYPE_UNSIGNED_INT == type)); + + assert(MCA_BASE_VAR_TYPE_INCLUDE_LIST != type || ((mca_base_var_include_list_t *) storage)->super.obj_reference_count > 0); + ret = register_variable(project_name, framework_name, component_name, variable_name, description, type, enumerator, bind, flags, info_lvl, scope, -1, storage); @@ -1855,25 +1875,26 @@ static void var_constructor(mca_base_var_t *var) */ static void var_destructor(mca_base_var_t *var) { - if ((MCA_BASE_VAR_TYPE_STRING == var->mbv_type - || MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) - && NULL != var->mbv_storage && NULL != var->mbv_storage->stringval) { - free(var->mbv_storage->stringval); - var->mbv_storage->stringval = NULL; + if (NULL != var->mbv_storage) { + if (MCA_BASE_VAR_TYPE_STRING == var->mbv_type + || MCA_BASE_VAR_TYPE_VERSION_STRING == var->mbv_type) { + free(var->mbv_storage->stringval); + var->mbv_storage->stringval = NULL; + } else if (MCA_BASE_VAR_TYPE_INCLUDE_LIST == var->mbv_type) { + OBJ_DESTRUCT(&var->mbv_storage->ilistval); + } + + var->mbv_storage = NULL; } /* don't release the boolean enumerator */ OPAL_MCA_VAR_MBV_ENUMERATOR_FREE(var->mbv_enumerator); - if (NULL != var->mbv_long_name) { - free(var->mbv_long_name); - } + free(var->mbv_long_name); var->mbv_full_name = NULL; var->mbv_variable_name = NULL; - if (NULL != var->mbv_description) { - free(var->mbv_description); - } + free(var->mbv_description); /* Destroy the synonym array */ OBJ_DESTRUCT(&var->mbv_synonyms); @@ -1994,6 +2015,19 @@ static int var_value_string(mca_base_var_t *var, char **value_string) case MCA_BASE_VAR_TYPE_DOUBLE: ret = opal_asprintf(value_string, "%lf", value->lfval); break; + case MCA_BASE_VAR_TYPE_INCLUDE_LIST: + if (NULL == value->ilistval.items) { + *value_string = strdup(""); + } else { + char *tmp = opal_argv_join(value->ilistval.items, ','); + if (value->ilistval.is_exclude) { + ret = opal_asprintf(value_string, "^%s", tmp); + free(tmp); + } else { + *value_string = tmp; + } + } + break; default: ret = -1; break; @@ -2014,6 +2048,20 @@ static int var_value_string(mca_base_var_t *var, char **value_string) return ret; } +char *mca_base_var_string_value(int vari) +{ + char *tmp = NULL; + mca_base_var_t *var; + + int ret = var_get(vari, &var, false); + if (OPAL_SUCCESS != ret) { + return NULL; + } + + (void) var_value_string(var, &tmp); + return tmp; +} + int mca_base_var_check_exclusive(const char *project, const char *type_a, const char *component_a, const char *param_a, const char *type_b, const char *component_b, const char *param_b) @@ -2290,3 +2338,34 @@ int mca_base_var_dump(int vari, char ***out, mca_base_var_dump_type_t output_typ return OPAL_SUCCESS; } + +static void include_list_contructor(mca_base_var_include_list_t *p) +{ + p->items = NULL; + p->is_exclude = false; +} + +static void include_list_destructor(mca_base_var_include_list_t *p) +{ + opal_argv_free(p->items); + include_list_contructor(p); +} + +int mca_base_var_parse_include_list(const char *value, mca_base_var_include_list_t *result) +{ + /* release any current value and set to defaults */ + include_list_destructor(result); + + if (NULL == value || 0 == strlen(value)) { + return OPAL_SUCCESS; + } + + if ('^' == value[0]) { + result->is_exclude = true; + ++value; + } + + result->items = opal_argv_split(value, ','); + return OPAL_SUCCESS; +} + diff --git a/opal/mca/base/mca_base_var.h b/opal/mca/base/mca_base_var.h index 5f6e4ced3f1..8326122e708 100644 --- a/opal/mca/base/mca_base_var.h +++ b/opal/mca/base/mca_base_var.h @@ -19,6 +19,7 @@ * reserved. * Copyright (c) 2022 Computer Architecture and VLSI Systems (CARV) * Laboratory, ICS Forth. All rights reserved. + * Copyright (c) 2024 Google, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -106,6 +107,10 @@ typedef enum { MCA_BASE_VAR_TYPE_INT64_T, /** The variable is of type uint64_t */ MCA_BASE_VAR_TYPE_UINT64_T, + /** The variable is an include list. Must be OBJ_CONSTRUCTed before + * registration to be valid. The destuction is automatic when the + * variable is deregistered. */ + MCA_BASE_VAR_TYPE_INCLUDE_LIST, /** Maximum variable type. */ MCA_BASE_VAR_TYPE_MAX @@ -212,6 +217,22 @@ typedef enum { MCA_BASE_VAR_FLAG_DEF_UNSET = 0x0080, } mca_base_var_flag_t; +/** + * An include list. These are strings of the form: + * foo,bar,baz (include) + * ^foo,bar,baz (exclude) + */ +struct mca_base_var_include_list { + opal_object_t super; + /** argv array of items */ + char **items; + /** is this an exclude list */ + bool is_exclude; +}; +typedef struct mca_base_var_include_list mca_base_var_include_list_t; + +OPAL_DECLSPEC OBJ_CLASS_DECLARATION(mca_base_var_include_list_t); + /** * Types for MCA parameters. */ @@ -242,6 +263,8 @@ typedef union { size_t sizetval; /** double value */ double lfval; + /** include/exclude list */ + mca_base_var_include_list_t ilistval; } mca_base_var_storage_t; /** @@ -718,6 +741,29 @@ typedef enum { */ OPAL_DECLSPEC int mca_base_var_dump(int vari, char ***out, mca_base_var_dump_type_t output_type); +/** + * Get a string representation of a variable. + * + * @param[in] vari Variable index + * + * This function returns the string representation of the variable or NULL if an + * error occurs. It is the caller's responsibility to free the string. + */ +OPAL_DECLSPEC char *mca_base_var_string_value(int vari); + +/** + * Parse an include list. + * + * @param[in] value Include list string + * @param[out] result Parsed include/exclude list (must already be OBJ_CONSTRUCTed) + * + * In Open MPI include lists are a comma-seperated list of things that can be negated + * by prefixing the list with a ^. Example: self,vader,ugni or ^tcp,ofi. This method + * fills in the mca_base_var_include_list_t struct with an argv array of items and + * a boolean indicating whether this is an exclude list or not. + */ +OPAL_DECLSPEC int mca_base_var_parse_include_list(const char *value, mca_base_var_include_list_t *result); + #define MCA_COMPILETIME_VER "print_compiletime_version" #define MCA_RUNTIME_VER "print_runtime_version" diff --git a/test/Makefile.am b/test/Makefile.am index b3fd5f2f32c..44bb246575c 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -14,6 +14,7 @@ # Copyright (c) 2015-2016 Research Organization for Information Science # and Technology (RIST). All rights reserved. # Copyright (c) 2017 IBM Corporation. All rights reserved. +# Copyright (c) 2024 Google, LLC. All rights reserved. # $COPYRIGHT$ # # Additional copyrights may follow @@ -22,7 +23,7 @@ # # support needs to be first for dependencies -SUBDIRS = support asm class threads datatype util mpool +SUBDIRS = support asm class threads datatype util mpool mca if PROJECT_OMPI SUBDIRS += monitoring spc endif diff --git a/test/mca/Makefile.am b/test/mca/Makefile.am new file mode 100644 index 00000000000..f66ac617618 --- /dev/null +++ b/test/mca/Makefile.am @@ -0,0 +1,41 @@ +# -*- makefile -*- +# +# 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) 2010-2015 Cisco Systems, Inc. All rights reserved. +# Copyright (c) 2014 Research Organization for Information Science +# and Technology (RIST). All rights reserved. +# Copyright (c) 2016 IBM Corporation. All rights reserved. +# Copyright (c) 2024 Google, LLC. All rights reserved. +# $COPYRIGHT$ +# +# Additional copyrights may follow +# +# $HEADER$ +# + +AM_CPPFLAGS="-I$(top_srcdir)/test/support" + +check_PROGRAMS = mca_var + +TESTS = $(check_PROGRAMS) + +mca_var_SOURCES = mca_var.c +mca_var_LDADD = \ + $(top_builddir)/opal/lib@OPAL_LIB_NAME@.la \ + $(top_builddir)/test/support/libsupport.a +mca_var_DEPENDENCIES = $(mca_var_LDADD) + +clean-local: + rm -f mca_var + +distclean-local: + rm -rf *.dSYM .deps .libs *.log *.txt *.o *.trs $(check_PROGRAMS) Makefile diff --git a/test/mca/mca_var.c b/test/mca/mca_var.c new file mode 100644 index 00000000000..18e22bffcc0 --- /dev/null +++ b/test/mca/mca_var.c @@ -0,0 +1,256 @@ +/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ +/* + * Copyright (c) 2024 Google, LLC. All rights reserved. + * $COPYRIGHT$ + * + * Additional copyrights may follow + * + * $HEADER$ + */ + +#include "opal_config.h" +#include + +#include "opal/mca/base/mca_base_var.h" +#include "opal/util/argv.h" +#include "opal/constants.h" +#include "opal/runtime/opal.h" +#include "support.h" + +/* + * Data type used for testing + */ +typedef struct test_data { + /* link list data structure */ + opal_list_item_t ll_element; + /* test data */ + size_t data; +} test_data_t; + +OBJ_CLASS_INSTANCE(test_data_t, opal_list_item_t, NULL, NULL); + +#define TEST_ASSERT(cond, failure_string) \ + if (!(cond)) { \ + test_failure(failure_string); \ + return test_finalize(); \ + } + +#define TEST_EXPECT(cond, failure_string) \ + if (cond) { \ + test_pass(); \ + } else { \ + test_failure(failure_string); \ + } + +static void test_pass(void) { + fprintf (stderr, "PASS\n"); + test_success(); +} + +static char *string_var; +static mca_base_var_include_list_t include_list_var; + +static int test_string_variable(void) +{ + test_init("mca_var string"); + + unsetenv("OMPI_MCA_test_component_test_string"); + + fprintf (stderr, "Testing string MCA variables....\n"); + + fprintf (stderr, " Testing string variable creation: "); + + const char *kProjectName = "openmpi"; + const char *kFrameworkName = "test"; + const char *kComponentName = "component"; + const char *kTestVarName = "test_string"; + + char *test_string1 = "test_string1"; + string_var = test_string1; + int ret = mca_base_var_register(kProjectName, kFrameworkName, kComponentName, kTestVarName, + "String variable for test", MCA_BASE_VAR_TYPE_STRING, + /*enumerator=*/NULL, /*bind=*/0, MCA_BASE_VAR_FLAG_SETTABLE, + OPAL_INFO_LVL_1, MCA_BASE_VAR_SCOPE_LOCAL, &string_var); + TEST_ASSERT(ret >= 0, "could not create variable"); + + int vari = mca_base_var_find(kProjectName, kFrameworkName, kComponentName, kTestVarName); + TEST_ASSERT(vari >= 0, "variable register but not found"); + TEST_ASSERT(ret == vari, "mca_base_var_register did not return the correct variable index"); + + test_pass(); + + fprintf (stderr, " Testing string variable storage: "); + TEST_ASSERT(string_var != test_string1, "set value did not re-allocate string"); + ret = test_verify_str(test_string1, string_var); + if (1 == ret) { + test_pass(); + } + + fprintf (stderr, " Testing mca_base_var_set_value: "); + + const char *kTestString2 = "test_string2"; + ret = mca_base_var_set_value(vari, kTestString2, /*size=*/0, MCA_BASE_VAR_SOURCE_SET, + /*source_file=*/NULL); + ret = test_verify_int(OPAL_SUCCESS, ret); + if (ret == 1) { + fprintf (stderr, "PASS\n"); + } + + fprintf (stderr, " Retesting string variable storage: "); + TEST_ASSERT(string_var != kTestString2, "set value did not re-allocate string"); + ret = test_verify_str(kTestString2, string_var); + if (1 == ret) { + fprintf (stderr, "PASS\n"); + } + + fprintf (stderr, " Testing de-registration: "); + ret = mca_base_var_deregister(vari); + TEST_ASSERT(OPAL_SUCCESS == ret, "deregistration failed"); + fprintf (stderr, "PASS\n"); + TEST_ASSERT(string_var == NULL, "deregistration did not nullify the storage"); + + return test_finalize(); +} + +static void check_include_list_contents(const char *check_str, const char *value, const mca_base_var_include_list_t *include_list) +{ + bool is_exclude = false; + + if ('^' == value[0]) { + is_exclude = true; + ++value; + } + + fprintf (stderr, " Checking %s list contents: ", check_str); + char **list = opal_argv_split(value, ','); + bool contents_match = true; + for (int i = 0 ; list[i] != NULL ; ++i) { + if ((NULL == include_list->items[i] || 0 != strcasecmp(list[i], include_list->items[i])) || + (list[i+1] == NULL && include_list->items[i+1] != NULL)) { + contents_match = false; + break; + } + } + TEST_EXPECT(contents_match, "contents do not match"); + + fprintf (stderr, " Checking %s include/exclude: ", check_str); + TEST_EXPECT(is_exclude == include_list->is_exclude, "list type not correctly identified"); +} + +static int test_mca_base_var_parse_include_list(void) +{ + test_init("mca_base_var_parse_include_list"); + + fprintf (stderr, "Testing mca_base_var_parse_include_list....\n"); + + fprintf (stderr, " Test mca_base_var_include_list_t construction: "); + + OBJ_CONSTRUCT(&include_list_var, mca_base_var_include_list_t); + if (NULL != include_list_var.items || include_list_var.is_exclude == true) { + OBJ_DESTRUCT(&include_list_var); + test_failure("incorrectly initial state"); + return test_finalize(); + } else { + test_pass(); + } + + fprintf (stderr, " Test parsing an exclude list: "); + char *exclude_list = "^foo,baz"; + int ret = mca_base_var_parse_include_list(exclude_list, &include_list_var); + TEST_EXPECT(ret == OPAL_SUCCESS, ""); + check_include_list_contents("exclude", exclude_list, &include_list_var); + + fprintf (stderr, " Test parsing an include list: "); + char *include_list = "foo,bar,baz"; + ret = mca_base_var_parse_include_list(include_list, &include_list_var); + TEST_EXPECT(ret == OPAL_SUCCESS, ""); + check_include_list_contents("include", include_list, &include_list_var); + + fprintf (stderr, " Test mca_base_var_include_list_t destruction: "); + OBJ_DESTRUCT(&include_list_var); + if (NULL != include_list_var.items || include_list_var.is_exclude == true) { + test_failure("incorrect state after destruct"); + } else { + test_pass(); + } + + return test_finalize(); +} + +static int test_include_list_variable(void) +{ + test_init("include/exclude list MCA variables..."); + + unsetenv("OMPI_MCA_test_component_test_include_list"); + + fprintf (stderr, "Testing include list MCA variables....\n"); + + const char *kProjectName = "openmpi"; + const char *kFrameworkName = "test"; + const char *kComponentName = "component"; + const char *kTestVarName = "test_list"; + + OBJ_CONSTRUCT(&include_list_var, mca_base_var_include_list_t); + char *exclude_list = "^foo,baz"; + int ret = mca_base_var_parse_include_list(exclude_list, &include_list_var); + if (OPAL_SUCCESS != ret) { + test_failure("error setting initial value"); + return test_finalize(); + } + + fprintf (stderr, " Testing include list variable creation: "); + + ret = mca_base_var_register(kProjectName, kFrameworkName, kComponentName, kTestVarName, + "String variable for test", MCA_BASE_VAR_TYPE_INCLUDE_LIST, + /*enumerator=*/NULL, /*bind=*/0, MCA_BASE_VAR_FLAG_SETTABLE, + OPAL_INFO_LVL_1, MCA_BASE_VAR_SCOPE_LOCAL, &include_list_var); + TEST_ASSERT(ret >= 0, "could not create variable"); + + int vari = mca_base_var_find(kProjectName, kFrameworkName, kComponentName, kTestVarName); + TEST_ASSERT(vari >= 0, "variable register but not found"); + TEST_ASSERT(ret == vari, "mca_base_var_register did not return the correct variable index"); + + test_pass(); + + check_include_list_contents("exclude", exclude_list, &include_list_var); + + fprintf (stderr, " Testing mca_base_var_set_value: "); + + char *include_list = "foo,bar,baz"; + ret = mca_base_var_set_value(vari, include_list, /*size=*/0, MCA_BASE_VAR_SOURCE_SET, + /*source_file=*/NULL); + ret = test_verify_int(OPAL_SUCCESS, ret); + if (ret == 1) { + fprintf (stderr, "PASS\n"); + } + + check_include_list_contents("include", include_list, &include_list_var); + + fprintf (stderr, " Testing de-registration: "); + ret = mca_base_var_deregister(vari); + TEST_ASSERT(OPAL_SUCCESS == ret, "deregistration failed"); + test_pass(); + + fprintf (stderr, " Testing post-deregistration state: "); + TEST_ASSERT(include_list_var.items == NULL, "deregistration did not nullify the storage"); + test_pass(); + + return test_finalize(); +} + +int main(int argc, char *argv[]) +{ + int ret = opal_init_util(&argc, &argv); + if (OPAL_SUCCESS != ret) { + fprintf (stderr, "could not initialize opal"); + exit(1); + } + + test_string_variable(); + test_mca_base_var_parse_include_list(); + test_include_list_variable(); + + opal_finalize_util(); + + return ret; +}