/* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil -*- */ /* * 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) 2008-2015 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2008 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2015 Research Organization for Information Science * and Technology (RIST). All rights reserved. * Copyright (c) 2014-2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) 2019 Triad National Security, LLC. All rights * reserved. * Copyright (c) 2020 Google, LLC. All rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ #include "opal_config.h" #include #include #include #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_NETDB_H # include #endif #include "opal/class/opal_list.h" #include "opal/constants.h" #include "opal/mca/base/base.h" #include "opal/mca/base/mca_base_alias.h" #include "opal/mca/base/mca_base_component_repository.h" #include "opal/mca/dl/base/base.h" #include "opal/mca/installdirs/installdirs.h" #include "opal/mca/mca.h" #include "opal/runtime/opal.h" #include "opal/util/argv.h" #include "opal/util/opal_environ.h" #include "opal/util/output.h" #include "opal/util/show_help.h" #if OPAL_HAVE_DL_SUPPORT /* * Private functions */ static void find_dyn_components(const char *path, mca_base_framework_t *framework, const char **names, bool include_mode); #endif /* OPAL_HAVE_DL_SUPPORT */ static int component_find_check(mca_base_framework_t *framework, char **requested_component_names); /* * Dummy structure for casting for open_only logic */ struct mca_base_open_only_dummy_component_t { /** MCA base component */ mca_base_component_t version; /** MCA base data */ mca_base_component_data_t data; }; typedef struct mca_base_open_only_dummy_component_t mca_base_open_only_dummy_component_t; static char negate[] = "^"; static bool use_component(const mca_base_framework_t *framework, const bool include_mode, const char **requested_component_names, const char *component_name); /* * Function to find as many components of a given type as possible. This * includes statically-linked in components as well as opening up a * directory and looking for shared-library MCA components of the * appropriate type (load them if available). * * Return one consolidated array of (mca_base_component_t*) pointing to all * available components. */ int mca_base_component_find(const char *directory, mca_base_framework_t *framework, bool ignore_requested, bool open_dso_components) { const mca_base_component_t **static_components = framework->framework_static_components; char **requested_component_names = NULL; mca_base_component_list_item_t *cli; bool include_mode = true; int ret; if (!ignore_requested) { ret = mca_base_component_parse_requested(framework->framework_selection, &include_mode, &requested_component_names); if (OPAL_SUCCESS != ret) { return ret; } } /* Find all the components that were statically linked in */ if (static_components) { for (int i = 0; NULL != static_components[i]; ++i) { if (use_component(framework, include_mode, (const char **) requested_component_names, static_components[i]->mca_component_name)) { cli = OBJ_NEW(mca_base_component_list_item_t); if (NULL == cli) { ret = OPAL_ERR_OUT_OF_RESOURCE; goto component_find_out; } cli->cli_component = static_components[i]; opal_list_append(&framework->framework_components, (opal_list_item_t *) cli); } } } #if OPAL_HAVE_DL_SUPPORT /* Find any available dynamic components in the specified directory */ if (open_dso_components && !mca_base_component_disable_dlopen) { find_dyn_components(directory, framework, (const char **) requested_component_names, include_mode); } else { opal_output_verbose(MCA_BASE_VERBOSE_INFO, 0, "mca: base: component_find: dso loading for %s MCA components disabled", framework->framework_name); } #endif if (include_mode) { ret = component_find_check(framework, requested_component_names); } else { ret = OPAL_SUCCESS; } component_find_out: if (NULL != requested_component_names) { opal_argv_free(requested_component_names); } /* All done */ return ret; } int mca_base_component_find_finalize(void) { return OPAL_SUCCESS; } int mca_base_components_filter(mca_base_framework_t *framework, uint32_t filter_flags) { opal_list_t *components = &framework->framework_components; int output_id = framework->framework_output; mca_base_component_list_item_t *cli, *next; char **requested_component_names = NULL; bool include_mode, can_use; int ret; assert(NULL != components); if (0 == filter_flags && NULL == framework->framework_selection) { return OPAL_SUCCESS; } ret = mca_base_component_parse_requested(framework->framework_selection, &include_mode, &requested_component_names); if (OPAL_SUCCESS != ret) { return ret; } OPAL_LIST_FOREACH_SAFE (cli, next, components, mca_base_component_list_item_t) { const mca_base_component_t *component = cli->cli_component; mca_base_open_only_dummy_component_t *dummy = (mca_base_open_only_dummy_component_t *) cli->cli_component; can_use = use_component(framework, include_mode, (const char **) requested_component_names, cli->cli_component->mca_component_name); if (!can_use || (filter_flags & dummy->data.param_field) != filter_flags) { if (can_use && (filter_flags & MCA_BASE_METADATA_PARAM_CHECKPOINT) && !(MCA_BASE_METADATA_PARAM_CHECKPOINT & dummy->data.param_field)) { opal_output_verbose(MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: components_filter: " "(%s) Component %s is *NOT* Checkpointable - Disabled", component->reserved, component->mca_component_name); } opal_list_remove_item(components, &cli->super); mca_base_component_unload(component, output_id); OBJ_RELEASE(cli); } else if (filter_flags & MCA_BASE_METADATA_PARAM_CHECKPOINT) { opal_output_verbose(MCA_BASE_VERBOSE_COMPONENT, output_id, "mca: base: components_filter: " "(%s) Component %s is Checkpointable", component->reserved, component->mca_component_name); } } if (include_mode) { ret = component_find_check(framework, requested_component_names); } else { ret = OPAL_SUCCESS; } if (NULL != requested_component_names) { opal_argv_free(requested_component_names); } return ret; } #if OPAL_HAVE_DL_SUPPORT /* * Open up all directories in a given path and search for components of * the specified type (and possibly of a given name). * * Note that we use our own path iteration functionality because we * need to look at companion .ompi_info files in the same directory as * the library to generate dependencies, etc. */ static void find_dyn_components(const char *path, mca_base_framework_t *framework, const char **names, bool include_mode) { mca_base_component_repository_item_t *ri; opal_list_t *dy_components; int ret; if (NULL != path) { ret = mca_base_component_repository_add(path); if (OPAL_SUCCESS != ret) { return; } } ret = mca_base_component_repository_get_components(framework, &dy_components); if (OPAL_SUCCESS != ret) { return; } /* Iterate through the repository and find components that can be included */ OPAL_LIST_FOREACH (ri, dy_components, mca_base_component_repository_item_t) { if (use_component(framework, include_mode, names, ri->ri_name)) { mca_base_component_repository_open(framework, ri); } } } #endif /* OPAL_HAVE_DL_SUPPORT */ static bool component_in_list(const char **requested_component_names, const char *component_name) { for (int i = 0; requested_component_names[i]; ++i) { if (strcmp(component_name, requested_component_names[i]) == 0) { return true; } } return false; } static bool use_component(const mca_base_framework_t *framework, const bool include_mode, const char **requested_component_names, const char *component_name) { /* * If no selection is specified then we use all components * we can find. */ if (NULL == requested_component_names) { return true; } bool found = component_in_list(requested_component_names, component_name); if (!found) { const mca_base_alias_t *alias = mca_base_alias_lookup(framework->framework_project, framework->framework_name, component_name); if (alias) { OPAL_LIST_FOREACH_DECL (alias_item, &alias->component_aliases, mca_base_alias_item_t) { found = component_in_list(requested_component_names, alias_item->component_alias); if (found) { break; } } } } /* * include_mode found | use * --------------------+------ * 0 0 | true * 0 1 | false * 1 0 | false * 1 1 | true * * -> inverted xor * As xor is a binary operator let's implement it manually before * a compiler screws it up. */ return (include_mode && found) || !(include_mode || found); } /* Ensure that *all* requested components exist. Print a warning and abort if they do not. */ static int component_find_check(mca_base_framework_t *framework, char **requested_component_names) { opal_list_t *components = &framework->framework_components; if (NULL == requested_component_names) { return OPAL_SUCCESS; } for (int i = 0; requested_component_names[i]; ++i) { bool found = false; OPAL_LIST_FOREACH_DECL (cli, components, mca_base_component_list_item_t) { if (0 == strcmp(requested_component_names[i], cli->cli_component->mca_component_name)) { found = true; break; } const mca_base_alias_t *alias = mca_base_alias_lookup(framework->framework_project, framework->framework_name, cli->cli_component ->mca_component_name); if (alias) { OPAL_LIST_FOREACH_DECL (alias_item, &alias->component_aliases, mca_base_alias_item_t) { if (0 == strcmp(requested_component_names[i], alias_item->component_alias)) { found = true; break; } } if (found) { break; } } } if (!found) { const char *h; h = opal_gethostname(); opal_show_help("help-mca-base.txt", "find-available:not-valid", true, h, framework->framework_name, requested_component_names[i]); return OPAL_ERR_NOT_FOUND; } } return OPAL_SUCCESS; } int mca_base_component_parse_requested(const char *requested, bool *include_mode, char ***requested_component_names) { const char *requested_orig = requested; *requested_component_names = NULL; *include_mode = true; /* See if the user requested anything */ if (NULL == requested || 0 == strlen(requested)) { return OPAL_SUCCESS; } /* Are we including or excluding? We only allow the negate character to be the *first* character of the value (but be nice and allow any number of negate characters in the beginning). */ *include_mode = requested[0] != negate[0]; /* skip over all negate symbols at the beginning */ requested += strspn(requested, negate); /* Double check to ensure that the user did not specify the negate character anywhere else in the value. */ if (NULL != strstr(requested, negate)) { opal_show_help("help-mca-base.txt", "framework-param:too-many-negates", true, requested_orig); return OPAL_ERROR; } /* Split up the value into individual component names */ *requested_component_names = opal_argv_split(requested, ','); /* All done */ return OPAL_SUCCESS; }