diff --git a/contrib/test_jenkins.sh b/contrib/test_jenkins.sh index fcea43dd50a..dc0bd75e59e 100755 --- a/contrib/test_jenkins.sh +++ b/contrib/test_jenkins.sh @@ -847,6 +847,10 @@ test_ucs_dlopen() { # Make sure UCM is not unloaded echo "==== Running UCS dlopen test with memhooks ====" ./test/apps/test_ucs_dlopen + + # Test global config list integrity after loading/unloading of UCT + echo "==== Running test_dlopen_cfg_print ====" + ./test/apps/test_dlopen_cfg_print } test_ucp_dlopen() { diff --git a/src/ucs/config/parser.h b/src/ucs/config/parser.h index 3801bf2130f..c3b0cd4079d 100644 --- a/src/ucs/config/parser.h +++ b/src/ucs/config/parser.h @@ -90,14 +90,19 @@ typedef struct ucs_config_bw_spec { #define UCS_CONFIG_REGISTER_TABLE(_fields, _name, _prefix, _type) \ + static ucs_config_global_list_entry_t _fields##_config_entry; \ UCS_STATIC_INIT { \ + ucs_config_global_list_entry_t *entry = &_fields##_config_entry; \ extern ucs_list_link_t ucs_config_global_list; \ - static ucs_config_global_list_entry_t entry; \ - entry.fields = _fields; \ - entry.name = _name; \ - entry.prefix = _prefix; \ - entry.size = sizeof(_type); \ - ucs_list_add_tail(&ucs_config_global_list, &entry.list); \ + entry->fields = _fields; \ + entry->name = _name; \ + entry->prefix = _prefix; \ + entry->size = sizeof(_type); \ + ucs_list_add_tail(&ucs_config_global_list, &entry->list); \ + } \ + \ + UCS_STATIC_CLEANUP { \ + ucs_list_del(&_fields##_config_entry.list); \ } diff --git a/test/apps/Makefile.am b/test/apps/Makefile.am index cd47c5534b4..c6258b6471e 100644 --- a/test/apps/Makefile.am +++ b/test/apps/Makefile.am @@ -13,7 +13,8 @@ endif noinst_PROGRAMS = \ test_ucp_dlopen \ test_ucs_dlopen \ - test_link_map + test_link_map \ + test_dlopen_cfg_print objdir = $(shell sed -n -e 's/^objdir=\(.*\)$$/\1/p' $(LIBTOOL)) @@ -34,6 +35,13 @@ test_link_map_CPPFLAGS = $(BASE_CPPFLAGS) test_link_map_CFLAGS = $(BASE_CFLAGS) test_link_map_LDADD = -ldl $(top_builddir)/src/ucp/libucp.la +test_dlopen_cfg_print_SOURCES = test_dlopen_cfg_print.c +test_dlopen_cfg_print_CPPFLAGS = $(BASE_CPPFLAGS) -g \ + -DUCS_LIB_PATH=$(abs_top_builddir)/src/ucs/$(objdir)/libucs.so \ + -DUCT_LIB_PATH=$(abs_top_builddir)/src/uct/$(objdir)/libuct.so +test_dlopen_cfg_print_CFLAGS = $(BASE_CFLAGS) +test_dlopen_cfg_print_LDADD = -ldl + if HAVE_TCMALLOC noinst_PROGRAMS += test_tcmalloc test_tcmalloc_SOURCES = test_tcmalloc.c diff --git a/test/apps/test_dlopen_cfg_print.c b/test/apps/test_dlopen_cfg_print.c new file mode 100644 index 00000000000..21e6c402fef --- /dev/null +++ b/test/apps/test_dlopen_cfg_print.c @@ -0,0 +1,54 @@ +/** + * Copyright (C) Mellanox Technologies Ltd. 2019. ALL RIGHTS RESERVED. + * + * See file LICENSE for terms. + */ + +#include +#include +#include + +#define _QUOTE(x) #x +#define QUOTE(x) _QUOTE(x) + + +static void* do_dlopen_or_exit(const char *filename) +{ + void *handle; + + (void)dlerror(); + printf("opening '%s'\n", filename); + handle = dlopen(filename, RTLD_LAZY); + if (handle == NULL) { + fprintf(stderr, "failed to open %s: %s\n", filename, + dlerror()); + exit(1); + } + + return handle; +} + +int main(int argc, char **argv) +{ + const char *ucs_filename = QUOTE(UCS_LIB_PATH); + const char *uct_filename = QUOTE(UCT_LIB_PATH); + void *ucs_handle, *uct_handle; + int i; + + /* unload and reload uct while ucs is loaded + * would fail if uct global vars are kept on global lists in ucs */ + ucs_handle = do_dlopen_or_exit(ucs_filename); + for (i = 0; i < 2; ++i) { + uct_handle = do_dlopen_or_exit(uct_filename); + dlclose(uct_handle); + } + + /* print all config table, to force going over the global list in ucs */ + void (*print_all_opts)(FILE*, int) = + dlsym(ucs_handle, "ucs_config_parser_print_all_opts"); + print_all_opts(stdout, 0); + dlclose(ucs_handle); + + printf("done\n"); + return 0; +}