diff --git a/opal/mca/base/base.h b/opal/mca/base/base.h index 3ba82cb1024..936f72684b9 100644 --- a/opal/mca/base/base.h +++ b/opal/mca/base/base.h @@ -145,11 +145,8 @@ OPAL_DECLSPEC char * mca_base_component_to_string(const mca_base_component_t *a) /* mca_base_component_find.c */ -OPAL_DECLSPEC int mca_base_component_find(const char *directory, const char *type, - const mca_base_component_t *static_components[], - const char *requested_components, - opal_list_t *found_components, - bool open_dso_components); +OPAL_DECLSPEC int mca_base_component_find (const char *directory, mca_base_framework_t *framework, + bool ignore_requested, bool open_dso_components); /** * Parse the requested component string and return an opal_argv of the requested @@ -176,8 +173,7 @@ int mca_base_component_parse_requested (const char *requested, bool *include_mod * This function closes and releases any components that do not match the filter_name and * filter flags. */ -OPAL_DECLSPEC int mca_base_components_filter (const char *framework_name, opal_list_t *components, int output_id, - const char *filter_names, uint32_t filter_flags); +OPAL_DECLSPEC int mca_base_components_filter (mca_base_framework_t *framework, uint32_t filter_flags); diff --git a/opal/mca/base/mca_base_component_find.c b/opal/mca/base/mca_base_component_find.c index a1e7f1b928d..67e6d14853c 100644 --- a/opal/mca/base/mca_base_component_find.c +++ b/opal/mca/base/mca_base_component_find.c @@ -55,75 +55,16 @@ #include "opal/constants.h" #include "opal/mca/dl/base/base.h" - -#if OPAL_HAVE_DL_SUPPORT -/* - * Private types; only necessary when we're dlopening components. - */ -typedef enum component_status { - UNVISITED, - FAILED_TO_LOAD, - CHECKING_CYCLE, - LOADED, - - STATUS_MAX -} component_status_t; - -struct component_file_item_t { - opal_list_item_t super; - - char type[MCA_BASE_MAX_TYPE_NAME_LEN + 1]; - char name[MCA_BASE_MAX_COMPONENT_NAME_LEN + 1]; - char basename[OPAL_PATH_MAX + 1]; - char filename[OPAL_PATH_MAX + 1]; - component_status_t status; -}; -typedef struct component_file_item_t component_file_item_t; - -static OBJ_CLASS_INSTANCE(component_file_item_t, opal_list_item_t, NULL, NULL); - -struct dependency_item_t { - opal_list_item_t super; - - component_file_item_t *di_component_file_item; -}; -typedef struct dependency_item_t dependency_item_t; - -static OBJ_CLASS_INSTANCE(dependency_item_t, opal_list_item_t, NULL, NULL); - -#endif /* OPAL_HAVE_DL_SUPPORT */ - - #if OPAL_HAVE_DL_SUPPORT /* * Private functions */ -static void find_dyn_components(const char *path, const char *type, - const char **names, bool include_mode, - opal_list_t *found_components); -static int save_filename(const char *filename, void *data); -static int open_component(component_file_item_t *target_file, - opal_list_t *found_components); -static int check_opal_info(component_file_item_t *target_file, - opal_list_t *dependencies, - opal_list_t *found_components); -static int check_dependency(char *line, component_file_item_t *target_file, - opal_list_t *dependencies, - opal_list_t *found_components); -static void free_dependency_list(opal_list_t *dependencies); +static void find_dyn_components(const char *path, mca_base_framework_t *framework, + const char **names, bool include_mode); -/* - * Private variables - */ -static const char *opal_info_suffix = ".ompi_info"; -static const char *key_dependency = "dependency="; -static const char component_template[] = "mca_%s_"; -static opal_list_t found_files; -static char **found_filenames = NULL; -static char *last_path_to_use = NULL; #endif /* OPAL_HAVE_DL_SUPPORT */ -static int component_find_check (const char *framework_name, char **requested_component_names, opal_list_t *components); +static int component_find_check (mca_base_framework_t *framework, char **requested_component_names); /* * Dummy structure for casting for open_only logic @@ -152,55 +93,54 @@ static bool use_component(const bool include_mode, * Return one consolidated array of (mca_base_component_t*) pointing to all * available components. */ -int mca_base_component_find(const char *directory, const char *type, - const mca_base_component_t *static_components[], - const char *requested_components, - opal_list_t *found_components, - bool open_dso_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; - int i, ret; + bool include_mode = true; + int ret; - ret = mca_base_component_parse_requested (requested_components, &include_mode, - &requested_component_names); - if (OPAL_SUCCESS != ret) { - return 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 */ - OBJ_CONSTRUCT(found_components, opal_list_t); - for (i = 0; NULL != static_components && - NULL != static_components[i]; ++i) { - if ( use_component(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; + if (static_components) { + for (int i = 0 ; NULL != static_components[i]; ++i) { + if ( use_component(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); } - cli->cli_component = static_components[i]; - opal_list_append(found_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, type, - (const char**)requested_component_names, - include_mode, found_components); + find_dyn_components(directory, framework, (const char**)requested_component_names, + include_mode); } else { opal_output_verbose(40, 0, "mca: base: component_find: dso loading for %s MCA components disabled", - type); + framework->framework_name); } #endif if (include_mode) { - ret = component_find_check (type, requested_component_names, found_components); + ret = component_find_check (framework, requested_component_names); } else { ret = OPAL_SUCCESS; } @@ -218,22 +158,13 @@ int mca_base_component_find(const char *directory, const char *type, int mca_base_component_find_finalize(void) { -#if OPAL_HAVE_DL_SUPPORT - if (NULL != found_filenames) { - opal_argv_free(found_filenames); - found_filenames = NULL; - } - if (NULL != last_path_to_use) { - free(last_path_to_use); - last_path_to_use = NULL; - } -#endif return OPAL_SUCCESS; } -int mca_base_components_filter (const char *framework_name, opal_list_t *components, int output_id, - const char *filter_names, uint32_t filter_flags) +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; @@ -241,12 +172,12 @@ int mca_base_components_filter (const char *framework_name, opal_list_t *compone assert (NULL != components); - if (0 == filter_flags && NULL == filter_names) { + if (0 == filter_flags && NULL == framework->framework_selection) { return OPAL_SUCCESS; } - ret = mca_base_component_parse_requested (filter_names, &include_mode, - &requested_component_names); + ret = mca_base_component_parse_requested (framework->framework_selection, &include_mode, + &requested_component_names); if (OPAL_SUCCESS != ret) { return ret; } @@ -284,7 +215,7 @@ int mca_base_components_filter (const char *framework_name, opal_list_t *compone } if (include_mode) { - ret = component_find_check (framework_name, requested_component_names, components); + ret = component_find_check (framework, requested_component_names); } else { ret = OPAL_SUCCESS; } @@ -306,625 +237,31 @@ int mca_base_components_filter (const char *framework_name, opal_list_t *compone * 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, const char *type_name, - const char **names, bool include_mode, - opal_list_t *found_components) +static void find_dyn_components(const char *path, mca_base_framework_t *framework, + const char **names, bool include_mode) { - int i, len; - char *path_to_use = NULL, *dir, *end; - component_file_item_t *file; - opal_list_item_t *cur; - char prefix[32 + MCA_BASE_MAX_TYPE_NAME_LEN], *basename; - - /* If path is NULL, iterate over the set of directories specified by - the MCA param mca_base_component_path. If path is not NULL, then - use that as the path. */ - - if (NULL == path) { - if (NULL != mca_base_component_path) { - path_to_use = strdup (mca_base_component_path); - } else { - /* If there's no path, then there's nothing to search -- we're - done */ - return; - } - } else { - path_to_use = strdup(path); - } - if (NULL == path_to_use) { - /* out of memory */ - return; - } - - /* If we haven't done so already, iterate over all the files in - the directories in the path and make a master array of all the - matching filenames that we find. Save the filenames in an - argv-style array. Re-scan do this if the mca_component_path - has changed. */ - if (NULL == found_filenames || - (NULL != last_path_to_use && - 0 != strcmp(path_to_use, last_path_to_use))) { - if (NULL != found_filenames) { - opal_argv_free(found_filenames); - found_filenames = NULL; - free(last_path_to_use); - last_path_to_use = NULL; - } - if (NULL == last_path_to_use) { - last_path_to_use = strdup(path_to_use); - } + mca_base_component_repository_item_t *ri; + opal_list_t *dy_components; + int ret; - dir = path_to_use; - if (NULL != dir) { - do { - end = strchr(dir, OPAL_ENV_SEP); - if (NULL != end) { - *end = '\0'; - } - if ((0 == strcmp(dir, "USER_DEFAULT") || - 0 == strcmp(dir, "USR_DEFAULT")) - && NULL != mca_base_user_default_path) { - if (0 != opal_dl_foreachfile(mca_base_user_default_path, - save_filename, NULL)) { - break; - } - } else if (0 == strcmp(dir, "SYS_DEFAULT") || - 0 == strcmp(dir, "SYSTEM_DEFAULT")) { - if (0 != opal_dl_foreachfile(mca_base_system_default_path, - save_filename, NULL)) { - break; - } - } else { - if (0 != opal_dl_foreachfile(dir, save_filename, NULL)) { - break; - } - } - dir = end + 1; - } while (NULL != end); - } - } - - /* Look through the list of found files and find those that match - the desired framework name */ - snprintf(prefix, sizeof(prefix) - 1, component_template, type_name); - len = strlen(prefix); - OBJ_CONSTRUCT(&found_files, opal_list_t); - for (i = 0; NULL != found_filenames && NULL != found_filenames[i]; ++i) { - basename = strrchr(found_filenames[i], '/'); - if (NULL == basename) { - basename = found_filenames[i]; - } else { - basename += 1; - } - - if (0 != strncmp(basename, prefix, len)) { - continue; - } - - /* We found a match; save all the relevant details in the - found_files list */ - file = OBJ_NEW(component_file_item_t); - if (NULL == file) { - free(path_to_use); + if (NULL != path) { + ret = mca_base_component_repository_add (path); + if (OPAL_SUCCESS != ret) { return; } - strncpy(file->type, type_name, MCA_BASE_MAX_TYPE_NAME_LEN); - file->type[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0'; - strncpy(file->name, basename + len, MCA_BASE_MAX_COMPONENT_NAME_LEN); - file->name[MCA_BASE_MAX_COMPONENT_NAME_LEN] = '\0'; - strncpy(file->basename, basename, OPAL_PATH_MAX); - file->basename[OPAL_PATH_MAX] = '\0'; - strncpy(file->filename, found_filenames[i], OPAL_PATH_MAX); - file->filename[OPAL_PATH_MAX] = '\0'; - file->status = UNVISITED; - - opal_list_append(&found_files, (opal_list_item_t *) - file); - } - - /* Iterate through all the filenames that we found that matched - the framework we were looking for. Since one component may - [try to] call another to be loaded, only try to load the - UNVISITED files. Also, ignore the return code -- basically, - give every file one chance to try to load. If they load, - great. If not, great. */ - for (cur = opal_list_get_first(&found_files); - opal_list_get_end(&found_files) != cur; - cur = opal_list_get_next(cur)) { - file = (component_file_item_t *) cur; - - if( UNVISITED == file->status ) { - bool op = true; - file->status = CHECKING_CYCLE; - - op = use_component(include_mode, names, file->name); - if( true == op ) { - open_component(file, found_components); - } - } - } - - /* So now we have a final list of loaded components. We can free all - the file information. */ - for (cur = opal_list_remove_first(&found_files); - NULL != cur; - cur = opal_list_remove_first(&found_files)) { - OBJ_RELEASE(cur); - } - OBJ_DESTRUCT(&found_files); - - /* All done, now let's cleanup */ - free(path_to_use); -} - - -/* - * Blindly save all filenames into an argv-style list. This function - * is the callback from lt_dlforeachfile(). - */ -static int save_filename(const char *filename, void *data) -{ - opal_argv_append_nosize(&found_filenames, filename); - return 0; -} - - -static int file_exists(const char *filename, const char *ext) -{ - char *final; - struct stat buf; - int ret; - - if (NULL != ext) { - asprintf(&final, "%s.%s", filename, ext); - } else { - final = strdup(filename); - } - if (NULL == final) { - return 0; } - ret = stat(final, &buf); - free(final); - return (0 == ret ? 1 : 0); -} - - -/* - * Open a component, chasing down its dependencies first, if possible. - */ -static int open_component(component_file_item_t *target_file, - opal_list_t *found_components) -{ - opal_dl_handle_t *component_handle; - mca_base_component_t *component_struct; - char *struct_name; - opal_list_t dependencies; - opal_list_item_t *cur; - mca_base_component_list_item_t *mitem; - dependency_item_t *ditem; - size_t len; - int vl; - - opal_output_verbose(40, 0, "mca: base: component_find: examining dyanmic %s MCA component \"%s\"", - target_file->type, target_file->name); - opal_output_verbose(40, 0, "mca: base: component_find: %s", target_file->filename); - - vl = mca_base_component_show_load_errors ? 0 : 40; - - /* Was this component already loaded (e.g., via dependency)? */ - - if (LOADED == target_file->status) { - opal_output_verbose(40, 0, "mca: base: component_find: already loaded (ignored)"); - return OPAL_SUCCESS; - } - - /* Ensure that this component is not already loaded (should only happen - if it was statically loaded). It's an error if it's already - loaded because we're evaluating this file -- not this component. - Hence, returning OPAL_ERR_PARAM indicates that the *file* failed - to load, not the component. */ - - for (cur = opal_list_get_first(found_components); - opal_list_get_end(found_components) != cur; - cur = opal_list_get_next(cur)) { - mitem = (mca_base_component_list_item_t *) cur; - if (0 == strcmp(mitem->cli_component->mca_type_name, target_file->type) && - 0 == strcmp(mitem->cli_component->mca_component_name, target_file->name)) { - opal_output_verbose(40, 0, "mca: base: component_find: already loaded (ignored)"); - target_file->status = FAILED_TO_LOAD; - return OPAL_ERR_BAD_PARAM; - } - } - - /* Look at see if this component has any dependencies. If so, load - them. If we can't load them, then this component must also fail to - load. */ - OBJ_CONSTRUCT(&dependencies, opal_list_t); - if (0 != check_opal_info(target_file, &dependencies, found_components)) { - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_OUT_OF_RESOURCE; - } - - /* Now try to load the component */ - - char *err_msg; - if (OPAL_SUCCESS != - opal_dl_open(target_file->filename, true, false, &component_handle, - &err_msg)) { - if (NULL != err_msg) { - err_msg = strdup(err_msg); - } else { - err_msg = strdup("opal_dl_open() error message was NULL!"); - } - /* Because libltdl erroneously says "file not found" for any - type of error -- which is especially misleading when the file - is actually there but cannot be opened for some other reason - (e.g., missing symbol) -- do some simple huersitics and if - the file [probably] does exist, print a slightly better error - message. */ - if (0 == strcmp("file not found", err_msg) && - (file_exists(target_file->filename, "lo") || - file_exists(target_file->filename, "so") || - file_exists(target_file->filename, "dylib") || - file_exists(target_file->filename, "dll"))) { - free(err_msg); - err_msg = strdup("perhaps a missing symbol, or compiled for a different version of Open MPI?"); - } - opal_output_verbose(vl, 0, "mca: base: component_find: unable to open %s: %s (ignored)", - target_file->filename, err_msg); - free(err_msg); - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_BAD_PARAM; - } - - /* Successfully opened the component; now find the public struct. - Malloc out enough space for it. */ - - len = strlen(target_file->type) + strlen(target_file->name) + 32; - struct_name = (char*)malloc(len); - if (NULL == struct_name) { - opal_dl_close(component_handle); - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_OUT_OF_RESOURCE; - } - snprintf(struct_name, len, "mca_%s_%s_component", target_file->type, - target_file->name); - - mitem = OBJ_NEW(mca_base_component_list_item_t); - if (NULL == mitem) { - free(struct_name); - opal_dl_close(component_handle); - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_OUT_OF_RESOURCE; - } - - if (OPAL_SUCCESS != opal_dl_lookup(component_handle, struct_name, - (void**) &component_struct, &err_msg) || - NULL == component_struct) { - if (NULL == err_msg) { - err_msg = "opal_dl_loookup() error message was NULL!"; - } - opal_output_verbose(vl, 0, "mca: base: component_find: \"%s\" does not appear to be a valid " - "%s MCA dynamic component (ignored): %s", - target_file->basename, target_file->type, err_msg); - free(mitem); - free(struct_name); - opal_dl_close(component_handle); - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_BAD_PARAM; - } - - /* We found the public struct. Make sure its MCA major.minor - version is the same as ours. */ - if (!(MCA_BASE_VERSION_MAJOR == component_struct->mca_major_version && - MCA_BASE_VERSION_MINOR == component_struct->mca_minor_version)) { - opal_output_verbose(vl, 0, "mca: base: component_find: %s \"%s\" uses an MCA interface that is not recognized (component MCA v%d.%d.%d != supported MCA v%d.%d.%d) -- ignored", - target_file->type, target_file->basename, - component_struct->mca_major_version, - component_struct->mca_minor_version, - component_struct->mca_release_version, - MCA_BASE_VERSION_MAJOR, - MCA_BASE_VERSION_MINOR, - MCA_BASE_VERSION_RELEASE); - free(mitem); - free(struct_name); - opal_dl_close(component_handle); - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_BAD_PARAM; - } - - /* Also check that the component struct framework and component - names match the expected names from the filename */ - if (0 != strcmp(component_struct->mca_type_name, target_file->type) || - 0 != strcmp(component_struct->mca_component_name, target_file->name)) { - opal_output_verbose(vl, 0, "Component file data does not match filename: %s (%s / %s) != %s %s -- ignored", - target_file->filename, target_file->type, target_file->name, - component_struct->mca_type_name, - component_struct->mca_component_name); - free(mitem); - free(struct_name); - opal_dl_close(component_handle); - target_file->status = FAILED_TO_LOAD; - free_dependency_list(&dependencies); - return OPAL_ERR_BAD_PARAM; - } - - /* Alles gut. Save the component struct, and register this - component to be closed later. */ - - mitem->cli_component = component_struct; - opal_list_append(found_components, (opal_list_item_t *) mitem); - mca_base_component_repository_retain(target_file->type, component_handle, - component_struct); - - /* Now that that's all done, link all the dependencies in to this - component's repository entry */ - - for (cur = opal_list_remove_first(&dependencies); - NULL != cur; - cur = opal_list_remove_first(&dependencies)) { - ditem = (dependency_item_t *) cur; - mca_base_component_repository_link(target_file->type, - target_file->name, - ditem->di_component_file_item->type, - ditem->di_component_file_item->name); - OBJ_RELEASE(ditem); - } - OBJ_DESTRUCT(&dependencies); - - opal_output_verbose(40, 0, "mca: base: component_find: opened dynamic %s MCA component \"%s\"", - target_file->type, target_file->name); - target_file->status = LOADED; - - /* All done */ - - free(struct_name); - return OPAL_SUCCESS; -} - - -/* - * For a given filename, see if there exists a filename.ompi_info, which - * lists dependencies that must be loaded before this component is - * loaded. If we find this file, try to load those components first. - * - * Detect dependency cycles and error out. - */ -static int check_opal_info(component_file_item_t *target_file, - opal_list_t *dependencies, - opal_list_t *found_components) -{ - size_t len; - FILE *fp; - char *depname; - char buffer[BUFSIZ], *p; - - /* Form the filename */ - - len = strlen(target_file->filename) + strlen(opal_info_suffix) + 16; - depname = (char*)malloc(len); - if (NULL == depname) - return OPAL_ERR_OUT_OF_RESOURCE; - snprintf(depname, len, "%s%s", target_file->filename, opal_info_suffix); - - /* Try to open the file. If there's no file, return success (i.e., - there are no dependencies). */ - - if (NULL == (fp = fopen(depname, "r"))) { - free(depname); - return 0; - } - - /* Otherwise, loop reading the lines in the file and trying to load - them. Return failure upon the first component that fails to - load. */ - - opal_output_verbose(40, 0, "mca: base: component_find: opening .ompi_info file: %s", depname); - while (NULL != fgets(buffer, BUFSIZ, fp)) { - - /* Perl chomp */ - - buffer[BUFSIZ - 1] = '\0'; - len = strlen(buffer); - if ('\n' == buffer[len - 1]) - buffer[len - 1] = '\0'; - - /* Ignore emtpy lines and lines beginning with "#" or "//" */ - - for (p = buffer; '\0' != p; ++p) - if (!isspace(*p)) - break; - - if ('\0' == *p) - continue; - else if (*p == '#' || ('/' == *p && '/' == *(p + 1))) - continue; - - /* Is it a dependency? */ - - else if (0 == strncasecmp(p, key_dependency, strlen(key_dependency))) { - if (OPAL_SUCCESS != check_dependency(p + strlen(key_dependency), - target_file, dependencies, - found_components)) { - fclose(fp); - free(depname); - - /* We can leave any successfully loaded dependencies; we might - need them again later. But free the dependency list for - this component, because since [at least] one of them didn't - load, we have to pretend like all of them didn't load and - disallow loading this component. So free the dependency - list. */ - - free_dependency_list(dependencies); - return OPAL_ERR_OUT_OF_RESOURCE; - } - } - } - opal_output_verbose(40, 0, "mca: base: component_find: ompi_info file closed (%s)", - target_file->basename); - - /* All done -- all depenencies satisfied */ - - fclose(fp); - free(depname); - return 0; -} - - -/* - * A DEPENDENCY key was found in the ompi_info file. Chase it down: see - * if we've already got such a component loaded, or go try to load it if - * it's not already loaded. - */ -static int check_dependency(char *line, component_file_item_t *target_file, - opal_list_t *dependencies, - opal_list_t *found_components) -{ - bool happiness; - char buffer[BUFSIZ]; - char *type, *name; - int len; - component_file_item_t *mitem; - dependency_item_t *ditem; - opal_list_item_t *cur; - - /* Ensure that this was a valid dependency statement */ - - type = line; - name = strchr(line, OPAL_ENV_SEP); - if (NULL == name) { - return OPAL_ERR_OUT_OF_RESOURCE; - } - *name = '\0'; - ++name; - - /* Form the name of the component to compare to */ - - if (strlen(type) + strlen(name) + 32 >= BUFSIZ) { - target_file->status = FAILED_TO_LOAD; - return OPAL_ERR_OUT_OF_RESOURCE; - } - snprintf(buffer, BUFSIZ, component_template, type); - len = strlen(buffer); - strncat(buffer, name, BUFSIZ - len); - - /* Traverse down the list of files that we have, and see if we can - find it */ - - mitem = NULL; - target_file->status = CHECKING_CYCLE; - for (happiness = false, cur = opal_list_get_first(&found_files); - opal_list_get_end(&found_files) != cur; - cur = opal_list_get_next(cur)) { - mitem = (component_file_item_t *) cur; - - /* Compare the name to the basename */ - - if (0 != strcmp(mitem->basename, buffer)) - continue; - - /* Catch the bozo dependency on itself */ - - else if (mitem == target_file) { - opal_output_verbose(40, 0, - "mca: base: component_find: component depends on itself (ignored dependency)"); - happiness = true; - break; - } - - /* If it's loaded, great -- we're done (no need to check that - dependency sub-tree) */ - - else if (LOADED == mitem->status) { - opal_output_verbose(40, 0, "mca: base: component_find: dependency has already been loaded (%s)", - mitem->basename); - happiness = true; - break; - } - - /* If it's specifically not loaded (i.e., there was some kind of - error when we tried to load it), then we cannot meet the - dependencies. */ - - else if (FAILED_TO_LOAD == mitem->status) { - opal_output_verbose(40, 0, "mca: base: component_find: dependency previously failed to load (%s)", - mitem->basename); - break; - } - - /* If we hit a cycle, return badness */ - - else if (CHECKING_CYCLE == mitem->status) { - opal_output_verbose(40, 0, "mca: base: component_find: found cycle! (%s)", - mitem->basename); - break; + ret = mca_base_component_repository_get_components (framework, &dy_components); + if (OPAL_SUCCESS != ret) { + return; } - /* Otherwise, this dependency has not been looked at yet. Go try - to load it. */ - - else if (UNVISITED == mitem->status) { - opal_output_verbose(40, 0, "mca: base: component_find: loading dependency (%s)", - mitem->basename); - if (OPAL_SUCCESS == open_component(target_file, found_components)) { - happiness = true; - } else { - opal_output_verbose(40, 0, "mca: base: component_find: dependency failed to load (%s)", - mitem->basename); - } - break; + /* 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(include_mode, names, ri->ri_name)) { + mca_base_component_repository_open (framework, ri); + } } - } - - /* Did we find the dependency? */ - - if (!happiness) { - target_file->status = FAILED_TO_LOAD; - return OPAL_ERR_BAD_PARAM; - } - - /* The dependency loaded properly. Increment its refcount so that - it doesn't get unloaded before we get unloaded. The (NULL != - mitem) check is somewhat redundant -- we won't be here in this - function unless there's dependencies to check, but a) it's safer - to double check, and b) it fixes a compiler warning. :-) */ - - if (NULL != mitem) { - ditem = OBJ_NEW(dependency_item_t); - if (NULL == ditem) { - return OPAL_ERR_OUT_OF_RESOURCE; - } - ditem->di_component_file_item = mitem; - opal_list_append(dependencies, (opal_list_item_t*) ditem); - } - - /* All done -- all depenencies satisfied */ - - return OPAL_SUCCESS; -} - - -/* - * Free a dependency list - */ -static void free_dependency_list(opal_list_t *dependencies) -{ - opal_list_item_t *item; - - for (item = opal_list_remove_first(dependencies); - NULL != item; - item = opal_list_remove_first(dependencies)) { - OBJ_RELEASE(item); - } - OBJ_DESTRUCT(dependencies); } #endif /* OPAL_HAVE_DL_SUPPORT */ @@ -970,13 +307,16 @@ static bool use_component(const bool include_mode, /* Ensure that *all* requested components exist. Print a warning and abort if they do not. */ -static int component_find_check (const char *framework_name, char **requested_component_names, opal_list_t *components) +static int component_find_check (mca_base_framework_t *framework, char **requested_component_names) { + opal_list_t *components = &framework->framework_components; mca_base_component_list_item_t *cli; - int i; - for (i = 0; NULL != requested_component_names && - NULL != requested_component_names[i]; ++i) { + if (NULL == requested_component_names) { + return OPAL_SUCCESS; + } + + for (int i = 0; NULL != requested_component_names[i]; ++i) { bool found = false; OPAL_LIST_FOREACH(cli, components, mca_base_component_list_item_t) { @@ -992,7 +332,7 @@ static int component_find_check (const char *framework_name, char **requested_co gethostname(h, sizeof(h)); opal_show_help("help-mca-base.txt", "find-available:not-valid", true, - h, framework_name, requested_component_names[i]); + h, framework->framework_name, requested_component_names[i]); return OPAL_ERR_NOT_FOUND; } } diff --git a/opal/mca/base/mca_base_component_repository.c b/opal/mca/base/mca_base_component_repository.c index d04799e01ce..74b9dde59ca 100644 --- a/opal/mca/base/mca_base_component_repository.c +++ b/opal/mca/base/mca_base_component_repository.c @@ -1,3 +1,4 @@ +/* -*- 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 @@ -10,6 +11,8 @@ * 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) 2015 Los Alamos National Security, LLC. All rights + * reserved. * $COPYRIGHT$ * * Additional copyrights may follow @@ -32,36 +35,18 @@ #include "opal/mca/base/mca_base_component_repository.h" #include "opal/mca/dl/base/base.h" #include "opal/constants.h" +#include "opal/class/opal_hash_table.h" +#include "opal/util/basename.h" #if OPAL_HAVE_DL_SUPPORT /* * Private types */ -struct repository_item_t { - opal_list_item_t super; - - char ri_type[MCA_BASE_MAX_TYPE_NAME_LEN + 1]; - opal_dl_handle_t *ri_dlhandle; - const mca_base_component_t *ri_component_struct; - opal_list_t ri_dependencies; -}; -typedef struct repository_item_t repository_item_t; -static void ri_constructor(opal_object_t *obj); -static void ri_destructor(opal_object_t *obj); -static OBJ_CLASS_INSTANCE(repository_item_t, opal_list_item_t, - ri_constructor, ri_destructor); - -struct dependency_item_t { - opal_list_item_t super; - - repository_item_t *di_repository_entry; -}; -typedef struct dependency_item_t dependency_item_t; -static void di_constructor(opal_object_t *obj); -static void di_destructor(opal_object_t *obj); -static OBJ_CLASS_INSTANCE(dependency_item_t, opal_list_item_t, - di_constructor, di_destructor); +static void ri_constructor(mca_base_component_repository_item_t *ri); +static void ri_destructor(mca_base_component_repository_item_t *ri); +OBJ_CLASS_INSTANCE(mca_base_component_repository_item_t, opal_list_item_t, + ri_constructor, ri_destructor); #endif /* OPAL_HAVE_DL_SUPPORT */ @@ -74,321 +59,468 @@ static bool initialized = false; #if OPAL_HAVE_DL_SUPPORT -static opal_list_t repository; - - -/* - * Private functions - */ -static repository_item_t *find_component(const char *type, const char *name); -static int link_items(repository_item_t *src, repository_item_t *depend); +static opal_hash_table_t mca_base_component_repository; -#endif /* OPAL_HAVE_DL_SUPPORT */ +/* two-level macro for stringifying a number */ +#define STRINGIFYX(x) #x +#define STRINGIFY(x) STRINGIFYX(x) - -/* - * Initialize the repository - */ -int mca_base_component_repository_init(void) +static int process_repository_item (const char *filename, void *data) { - /* Setup internal structures */ - - if (!initialized) { -#if OPAL_HAVE_DL_SUPPORT + char name[MCA_BASE_MAX_COMPONENT_NAME_LEN + 1]; + char type[MCA_BASE_MAX_TYPE_NAME_LEN + 1]; + mca_base_component_repository_item_t *ri; + opal_list_t *component_list; + char *base; + int ret; + + base = opal_basename (filename); + if (NULL == base) { + return OPAL_ERROR; + } - /* Initialize the dl framework */ - int ret = mca_base_framework_open(&opal_dl_base_framework, 0); - if (OPAL_SUCCESS != ret) { - opal_output(0, "%s %d:%s failed -- process will likely abort (open the dl framework returned %d instead of OPAL_SUCCESS)\n", - __FILE__, __LINE__, __func__, ret); - return ret; + /* check if the plugin has the appropriate prefix */ + if (0 != strncmp (base, "mca_", 4)) { + free (base); + return OPAL_SUCCESS; } - opal_dl_base_select(); - OBJ_CONSTRUCT(&repository, opal_list_t); -#endif + /* read framework and component names. framework names may not include an _ + * but component names may */ + ret = sscanf (base, "mca_%" STRINGIFY(MCA_BASE_MAX_TYPE_NAME_LEN) "[^_]_%" + STRINGIFY(MCA_BASE_MAX_COMPONENT_NAME_LEN) "s", type, name); + if (0 > ret) { + /* does not patch the expected template. skip */ + return OPAL_SUCCESS; + } - initialized = true; - } + /* lookup the associated framework list and create if it doesn't already exist */ + ret = opal_hash_table_get_value_ptr (&mca_base_component_repository, type, + strlen (type), (void **) &component_list); + if (OPAL_SUCCESS != ret) { + component_list = OBJ_NEW(opal_list_t); + if (NULL == component_list) { + free (base); + /* OOM. nothing to do but fail */ + return OPAL_ERR_OUT_OF_RESOURCE; + } + + ret = opal_hash_table_set_value_ptr (&mca_base_component_repository, type, + strlen (type), (void *) component_list); + if (OPAL_SUCCESS != ret) { + free (base); + OBJ_RELEASE(component_list); + return ret; + } + } - /* All done */ + /* check for duplicate components */ + OPAL_LIST_FOREACH(ri, component_list, mca_base_component_repository_item_t) { + if (0 == strcmp (ri->ri_name, name)) { + /* already scanned this component */ + free (base); + return OPAL_SUCCESS; + } + } - return OPAL_SUCCESS; -} + ri = OBJ_NEW(mca_base_component_repository_item_t); + if (NULL == ri) { + return OPAL_ERR_OUT_OF_RESOURCE; + } + ri->ri_base = base; -/* - * Add a newly-opened dyanmic component to the repository of open - * components. The component's type, handle, and public struct are - * saved. - */ -int mca_base_component_repository_retain(char *type, - opal_dl_handle_t *component_handle, - const mca_base_component_t *component_struct) -{ -#if OPAL_HAVE_DL_SUPPORT - repository_item_t *ri; + ri->ri_path = strdup (filename); + if (NULL == ri->ri_path) { + OBJ_RELEASE(ri); + return OPAL_ERR_OUT_OF_RESOURCE; + } - /* Allocate a new repository item */ + /* strncpy does not guarantee a \0 */ + ri->ri_type[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0'; + strncpy (ri->ri_type, type, MCA_BASE_MAX_TYPE_NAME_LEN); - ri = OBJ_NEW(repository_item_t); - if (NULL == ri) { - return OPAL_ERR_OUT_OF_RESOURCE; - } + ri->ri_name[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0'; + strncpy (ri->ri_name, name, MCA_BASE_MAX_COMPONENT_NAME_LEN); - /* Initialize the repository item */ + opal_list_append (component_list, &ri->super); - strncpy(ri->ri_type, type, MCA_BASE_MAX_TYPE_NAME_LEN); - ri->ri_type[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0'; - ri->ri_dlhandle = component_handle; - ri->ri_component_struct = component_struct; + return OPAL_SUCCESS; +} - /* Append the new item to the repository */ +static int file_exists(const char *filename, const char *ext) +{ + char *final; + int ret; - opal_list_append(&repository, (opal_list_item_t *) ri); + if (NULL == ext) { + return access (filename, F_OK) == 0; + } - /* All done */ + ret = asprintf(&final, "%s.%s", filename, ext); + if (0 > ret || NULL == final) { + return 0; + } - return OPAL_SUCCESS; -#else - return OPAL_ERR_NOT_SUPPORTED; -#endif + ret = access (final, F_OK); + free(final); + return (0 == ret); } +#endif /* OPAL_HAVE_DL_SUPPORT */ -/* - * Bump up the refcount on a component - */ -int mca_base_component_repository_retain_component(const char *type, - const char *name) +int mca_base_component_repository_add (const char *path) { #if OPAL_HAVE_DL_SUPPORT - repository_item_t *ri = find_component(type, name); - if (NULL != ri) { - OBJ_RETAIN(ri); + char *path_to_use = NULL, *dir, *ctx; + const char sep[] = {OPAL_ENV_SEP, '\0'}; + + if (NULL == path) { + /* nothing to do */ return OPAL_SUCCESS; } - return OPAL_ERR_NOT_FOUND; -#else - return OPAL_ERR_NOT_SUPPORTED; -#endif -} + path_to_use = strdup (path); -/* - * Create a dependency from one component entry to another - */ -int mca_base_component_repository_link(const char *src_type, - const char *src_name, - const char *depend_type, - const char *depend_name) -{ -#if OPAL_HAVE_DL_SUPPORT - repository_item_t *src, *depend; - - /* Look up the two components */ - - src = find_component(src_type, src_name); - if (NULL == src) { - return OPAL_ERR_BAD_PARAM; - } - depend = find_component(depend_type, depend_name); - if (NULL == depend) { - return OPAL_ERR_BAD_PARAM; - } + dir = strtok_r (path_to_use, sep, &ctx); + do { + if ((0 == strcmp(dir, "USER_DEFAULT") || 0 == strcmp(dir, "USR_DEFAULT")) + && NULL != mca_base_user_default_path) { + dir = mca_base_user_default_path; + } else if (0 == strcmp(dir, "SYS_DEFAULT") || + 0 == strcmp(dir, "SYSTEM_DEFAULT")) { + dir = mca_base_system_default_path; + } + + if (0 != opal_dl_foreachfile(dir, process_repository_item, NULL)) { + break; + } + } while (NULL != (dir = strtok_r (NULL, sep, &ctx))); - /* Link them */ +#endif /* OPAL_HAVE_DL_SUPPORT */ - return link_items(src, depend); -#else - return OPAL_ERR_NOT_SUPPORTED; -#endif + return OPAL_SUCCESS; } /* - * If it's in the repository, close a specified component and remove - * it from the repository. + * Initialize the repository */ -void mca_base_component_repository_release(const mca_base_component_t *component) +int mca_base_component_repository_init(void) { + /* Setup internal structures */ + + if (!initialized) { #if OPAL_HAVE_DL_SUPPORT - if (initialized) { - repository_item_t *ri = find_component(component->mca_type_name, - component->mca_component_name); - if (NULL != ri) { - OBJ_RELEASE(ri); + + /* Initialize the dl framework */ + int ret = mca_base_framework_open(&opal_dl_base_framework, 0); + if (OPAL_SUCCESS != ret) { + opal_output(0, "%s %d:%s failed -- process will likely abort (open the dl framework returned %d instead of OPAL_SUCCESS)\n", + __FILE__, __LINE__, __func__, ret); + return ret; } - } -#endif -} + opal_dl_base_select(); + OBJ_CONSTRUCT(&mca_base_component_repository, opal_hash_table_t); + ret = opal_hash_table_init (&mca_base_component_repository, 128); + if (OPAL_SUCCESS != ret) { + mca_base_framework_close (&opal_dl_base_framework); + return ret; + } -/* - * Finalize the repository -- close everything that's still open. - */ -void mca_base_component_repository_finalize(void) -{ -#if OPAL_HAVE_DL_SUPPORT - repository_item_t *ri, *next; + ret = mca_base_component_repository_add (mca_base_component_path); + if (OPAL_SUCCESS != ret) { + OBJ_DESTRUCT(&mca_base_component_repository); + mca_base_framework_close (&opal_dl_base_framework); + return ret; + } #endif - if (initialized) { -#if OPAL_HAVE_DL_SUPPORT - - /* Have to be slightly careful about this because of dependencies, - particularly on OS's where it matters (i.e., closing a - component that is depended on by other components actually - causes missing symbols because the OS actually does unload it - from memory!), such as OS X. + initialized = true; + } - So instead of just blindly closing everything, we have iterate - over the array of open components releasing everything with a - refcount of 1 -- skip anything with a refcount of more than 1. - Repeat this procedure until either we have nothing open or we - made one full pass and no refcounts went to 1 (which is - technically an error). */ + /* All done */ - do { - OPAL_LIST_FOREACH_SAFE(ri, next, &repository, repository_item_t) { - OBJ_RELEASE(ri); - } - } while (opal_list_get_size(&repository) > 0); + return OPAL_SUCCESS; +} - (void) mca_base_framework_close(&opal_dl_base_framework); +int mca_base_component_repository_get_components (mca_base_framework_t *framework, + opal_list_t **framework_components) +{ + *framework_components = NULL; +#if OPAL_HAVE_DL_SUPPORT + return opal_hash_table_get_value_ptr (&mca_base_component_repository, framework->framework_name, + strlen (framework->framework_name), (void **) framework_components); #endif - - initialized = false; - } + return OPAL_ERR_NOT_FOUND; } -#if OPAL_HAVE_DL_SUPPORT +static void mca_base_component_repository_release_internal (mca_base_component_repository_item_t *ri) { + int group_id; -static repository_item_t *find_component(const char *type, const char *name) -{ - opal_list_item_t *item; - repository_item_t *ri; - - for (item = opal_list_get_first(&repository); - opal_list_get_end(&repository) != item; - item = opal_list_get_next(item)) { - ri = (repository_item_t *) item; - if (0 == strcmp(ri->ri_type, type) && - 0 == strcmp(ri->ri_component_struct->mca_component_name, name)) { - return ri; + group_id = mca_base_var_group_find (NULL, ri->ri_type, ri->ri_name); + if (0 <= group_id) { + /* ensure all variables are deregistered before we dlclose the component */ + mca_base_var_group_deregister (group_id); } - } - - /* Not found */ - return NULL; + /* Close the component (and potentially unload it from memory */ + if (ri->ri_dlhandle) { + opal_dl_close(ri->ri_dlhandle); + ri->ri_dlhandle = NULL; + } } - -static int link_items(repository_item_t *src, repository_item_t *depend) +void mca_base_component_repository_release(const mca_base_component_t *component) { - dependency_item_t *di; + mca_base_component_repository_item_t *ri; + opal_list_t *component_list; + int ret; - /* Bozo check */ + ret = opal_hash_table_get_value_ptr (&mca_base_component_repository, component->mca_type_name, + strlen (component->mca_type_name), (void **) &component_list); + if (OPAL_SUCCESS != ret) { + /* component does not exist in the repository */ + return; + } - if (NULL == src || NULL == depend) { - return OPAL_ERR_BAD_PARAM; - } + OPAL_LIST_FOREACH(ri, component_list, mca_base_component_repository_item_t) { + if (0 == strcmp (ri->ri_name, component->mca_component_name)) { + /* go ahead and dlclose the component if it is open */ + mca_base_component_repository_release_internal (ri); + break; + } + } +} - /* Make a new depedency item */ - di = OBJ_NEW(dependency_item_t); - if (NULL == di) { - return OPAL_ERR_OUT_OF_RESOURCE; - } +int mca_base_component_repository_open (mca_base_framework_t *framework, + mca_base_component_repository_item_t *ri) +{ +#if OPAL_HAVE_DL_SUPPORT + mca_base_component_t *component_struct; + mca_base_component_list_item_t *mitem = NULL; + char *struct_name = NULL; + int vl, ret; + + opal_output_verbose(40, 0, "mca_base_component_repository_open: examining dynamic %s MCA component \"%s\" at path %s", + ri->ri_type, ri->ri_name, ri->ri_path); + + vl = mca_base_component_show_load_errors ? 0 : 40; + + /* Ensure that this component is not already loaded (should only happen + if it was statically loaded). It's an error if it's already + loaded because we're evaluating this file -- not this component. + Hence, returning OPAL_ERR_PARAM indicates that the *file* failed + to load, not the component. */ + + OPAL_LIST_FOREACH(mitem, &framework->framework_components, mca_base_component_list_item_t) { + if (0 == strcmp(mitem->cli_component->mca_component_name, ri->ri_name)) { + opal_output_verbose(40, 0, "mca_base_component_repository_open: already loaded (ignored)"); + return OPAL_ERR_BAD_PARAM; + } + } - /* Initialize the new dependency item */ + if (NULL != ri->ri_dlhandle) { + opal_output_verbose(40, 0, "mca_base_component_repository_open: already loaded. returning cached component"); + mitem = OBJ_NEW(mca_base_component_list_item_t); + if (NULL == mitem) { + return OPAL_ERR_OUT_OF_RESOURCE; + } - di->di_repository_entry = depend; + mitem->cli_component = ri->ri_component_struct; + opal_list_append (&framework->framework_components, &mitem->super); - /* Add it to the dependency list on the source repository entry */ + return OPAL_SUCCESS; + } - opal_list_append(&src->ri_dependencies, (opal_list_item_t *) di); + if (0 != strcmp (ri->ri_type, framework->framework_name)) { + /* shouldn't happen. attempting to open a component belonging to + * another framework. if this happens it is likely a MCA base + * bug so assert */ + assert (0); + return OPAL_ERR_NOT_SUPPORTED; + } - /* Increment the refcount in the dependency */ + /* Now try to load the component */ + + char *err_msg = NULL; + if (OPAL_SUCCESS != opal_dl_open(ri->ri_path, true, false, &ri->ri_dlhandle, &err_msg)) { + if (NULL == err_msg) { + err_msg = "opal_dl_open() error message was NULL!"; + } + /* Because libltdl erroneously says "file not found" for any + type of error -- which is especially misleading when the file + is actually there but cannot be opened for some other reason + (e.g., missing symbol) -- do some simple huersitics and if + the file [probably] does exist, print a slightly better error + message. */ + if (0 == strcasecmp("file not found", err_msg) && + (file_exists(ri->ri_path, "lo") || + file_exists(ri->ri_path, "so") || + file_exists(ri->ri_path, "dylib") || + file_exists(ri->ri_path, "dll"))) { + err_msg = "perhaps a missing symbol, or compiled for a different version of Open MPI?"; + } + opal_output_verbose(vl, 0, "mca_base_component_repository_open: unable to open %s: %s (ignored)", + ri->ri_base, err_msg); + return OPAL_ERR_BAD_PARAM; + } - OBJ_RETAIN(depend); + /* Successfully opened the component; now find the public struct. + Malloc out enough space for it. */ - /* All done */ + do { + ret = asprintf (&struct_name, "mca_%s_%s_component", ri->ri_type, ri->ri_name); + if (0 > ret) { + ret = OPAL_ERR_OUT_OF_RESOURCE; + break; + } + + mitem = OBJ_NEW(mca_base_component_list_item_t); + if (NULL == mitem) { + ret = OPAL_ERR_OUT_OF_RESOURCE; + break; + } + + err_msg = NULL; + ret = opal_dl_lookup(ri->ri_dlhandle, struct_name, (void**) &component_struct, &err_msg); + if (OPAL_SUCCESS != ret || NULL == component_struct) { + if (NULL == err_msg) { + err_msg = "opal_dl_loookup() error message was NULL!"; + } + opal_output_verbose(vl, 0, "mca_base_component_repository_open: \"%s\" does not appear to be a valid " + "%s MCA dynamic component (ignored): %s. ret %d", ri->ri_base, ri->ri_type, err_msg, ret); + + ret = OPAL_ERR_BAD_PARAM; + break; + } + + /* done with the structure name */ + free (struct_name); + + /* We found the public struct. Make sure its MCA major.minor + version is the same as ours. TODO -- add checks for project version (from framework) */ + if (!(MCA_BASE_VERSION_MAJOR == component_struct->mca_major_version && + MCA_BASE_VERSION_MINOR == component_struct->mca_minor_version)) { + opal_output_verbose(vl, 0, "mca_base_component_repository_open: %s \"%s\" uses an MCA interface that is " + "not recognized (component MCA v%d.%d.%d != supported MCA v%d.%d.%d) -- ignored", + ri->ri_type, ri->ri_path, component_struct->mca_major_version, + component_struct->mca_minor_version, component_struct->mca_release_version, + MCA_BASE_VERSION_MAJOR, MCA_BASE_VERSION_MINOR, MCA_BASE_VERSION_RELEASE); + ret = OPAL_ERR_BAD_PARAM; + break; + } + + /* Also check that the component struct framework and component + names match the expected names from the filename */ + if (0 != strcmp(component_struct->mca_type_name, ri->ri_type) || + 0 != strcmp(component_struct->mca_component_name, ri->ri_name)) { + opal_output_verbose(vl, 0, "Component file data does not match filename: %s (%s / %s) != %s %s -- ignored", + ri->ri_path, ri->ri_type, ri->ri_name, + component_struct->mca_type_name, + component_struct->mca_component_name); + ret = OPAL_ERR_BAD_PARAM; + break; + } + + /* Alles gut. Save the component struct, and register this + component to be closed later. */ + + ri->ri_component_struct = mitem->cli_component = component_struct; + opal_list_append(&framework->framework_components, &mitem->super); + + opal_output_verbose(40, 0, "mca_base_component_repository_open: opened dynamic %s MCA component \"%s\"", + ri->ri_type, ri->ri_name); - return OPAL_SUCCESS; -} + return OPAL_SUCCESS; + } while (0); + if (mitem) { + OBJ_RELEASE(mitem); + } -/* - * Basic sentinel values, and construct the inner list - */ -static void ri_constructor(opal_object_t *obj) -{ - repository_item_t *ri = (repository_item_t *) obj; + if (struct_name) { + free (struct_name); + } - memset(ri->ri_type, 0, sizeof(ri->ri_type)); - ri->ri_dlhandle = NULL; - ri->ri_component_struct = NULL; + opal_dl_close (ri->ri_dlhandle); + ri->ri_dlhandle = NULL; - OBJ_CONSTRUCT(&ri->ri_dependencies, opal_list_t); -} + return ret; +#else + /* no dlopen support */ + return OPAL_ERR_NOT_SUPPORTED; +#endif +} /* - * Close a component + * Finalize the repository -- close everything that's still open. */ -static void ri_destructor(opal_object_t *obj) +void mca_base_component_repository_finalize(void) { - repository_item_t *ri = (repository_item_t *) obj; - opal_list_item_t *item; - int group_id; - - group_id = mca_base_var_group_find (NULL, ri->ri_type, - ri->ri_component_struct->mca_component_name); - if (0 <= group_id) { - mca_base_var_group_deregister (group_id); - } - - /* Close the component (and potentially unload it from memory */ - opal_dl_close(ri->ri_dlhandle); + if (!initialized) { + return; + } - /* It should be obvious, but I'll state it anyway because it bit me - during debugging: after the dlclose(), the mca_base_component_t - pointer is no longer valid because it has [potentially] been - unloaded from memory. So don't try to use it. :-) */ + initialized = false; - /* Now go release/close (at a minimum: decrement the refcount) any - dependencies of this component */ +#if OPAL_HAVE_DL_SUPPORT + opal_list_t *component_list; + void *node, *key; + size_t key_size; + int ret; + + ret = opal_hash_table_get_first_key_ptr (&mca_base_component_repository, &key, &key_size, + (void **) &component_list, &node); + while (OPAL_SUCCESS == ret) { + OPAL_LIST_RELEASE(component_list); + ret = opal_hash_table_get_next_key_ptr (&mca_base_component_repository, &key, + &key_size, (void **) &component_list, + node, &node); + } - while (NULL != (item = opal_list_remove_first(&ri->ri_dependencies))) { - OBJ_RELEASE(item); - } - OBJ_DESTRUCT(&ri->ri_dependencies); - opal_list_remove_item(&repository, (opal_list_item_t *) ri); + (void) mca_base_framework_close(&opal_dl_base_framework); + OBJ_DESTRUCT(&mca_base_component_repository); +#endif } +#if OPAL_HAVE_DL_SUPPORT /* - * Basic sentinel values + * Basic sentinel values, and construct the inner list */ -static void di_constructor(opal_object_t *obj) +static void ri_constructor (mca_base_component_repository_item_t *ri) { - dependency_item_t *di = (dependency_item_t *) obj; - - di->di_repository_entry = NULL; + memset(ri->ri_type, 0, sizeof(ri->ri_type)); + ri->ri_dlhandle = NULL; + ri->ri_component_struct = NULL; + ri->ri_path = NULL; } /* - * When a dependency item is released, go release the repository entry - * that it points to + * Close a component */ -static void di_destructor(opal_object_t *obj) +static void ri_destructor (mca_base_component_repository_item_t *ri) { - dependency_item_t *di = (dependency_item_t *) obj; + /* dlclose the component if it is still open */ + mca_base_component_repository_release_internal (ri); + + /* It should be obvious, but I'll state it anyway because it bit me + during debugging: after the dlclose(), the mca_base_component_t + pointer is no longer valid because it has [potentially] been + unloaded from memory. So don't try to use it. :-) */ - OBJ_RELEASE(di->di_repository_entry); + if (ri->ri_path) { + free (ri->ri_path); + } + + if (ri->ri_base) { + free (ri->ri_base); + } } #endif /* OPAL_HAVE_DL_SUPPORT */ diff --git a/opal/mca/base/mca_base_component_repository.h b/opal/mca/base/mca_base_component_repository.h index fba02334207..8ba27f1da93 100644 --- a/opal/mca/base/mca_base_component_repository.h +++ b/opal/mca/base/mca_base_component_repository.h @@ -17,6 +17,19 @@ * $HEADER$ */ +/** + * @file mca_base_component_repository.h + * + * This file provide the external interface to our base component + * module. Most of the components that depend on it, will use the + * retain_component() function to increase the reference count on a + * particular component (as opposed to the retain() function, which is + * internal to the opal/mca/base). But it's convenient to have all + * the functions exported from one header file rather than to separate + * retain_component() and retain() into two separate header files + * (i.e., have a separate header file just for retain()). + */ + #ifndef MCA_BASE_COMPONENT_REPOSITORY_H #define MCA_BASE_COMPONENT_REPOSITORY_H @@ -26,31 +39,71 @@ #include "opal/mca/dl/base/base.h" BEGIN_C_DECLS +struct mca_base_component_repository_item_t { + opal_list_item_t super; - OPAL_DECLSPEC int mca_base_component_repository_init(void); + char ri_type[MCA_BASE_MAX_TYPE_NAME_LEN + 1]; + char ri_name[MCA_BASE_MAX_COMPONENT_NAME_LEN + 1]; -/* This file provide the external interface to our base component - * module. Most of the components that depend on it, will use the - * retain_component() function to increase the reference count on a - * particular component (as opposed to the retain() function, which is - * internal to the opal/mca/base). But it's convenient to have all - * the functions exported from one header file rather than to separate - * retain_component() and retain() into two separate header files - * (i.e., have a separate header file just for retain()). + char *ri_path; + char *ri_base; + + opal_dl_handle_t *ri_dlhandle; + const mca_base_component_t *ri_component_struct; +}; +typedef struct mca_base_component_repository_item_t mca_base_component_repository_item_t; + +OBJ_CLASS_DECLARATION(mca_base_component_repository_item_t); + +/** + * @brief initialize the component repository + * + * This function must be called before any frameworks are registered or + * opened. It is responsible for setting up the repository of dynamically + * loaded components. The initial search path is taken from the + * mca_base_component_path MCA parameter. mca_base_open () is a + * prerequisite call as it registers the mca_base_component_path parameter. + */ +OPAL_DECLSPEC int mca_base_component_repository_init(void); + +/** + * @brief add search path for dynamically loaded components + * + * @param[in] path delimited list of search paths to add + */ +OPAL_DECLSPEC int mca_base_component_repository_add (const char *path); + + +/** + * @brief return the list of components that match a given framework + * + * @param[in] framework framework to match + * @param[out] framework_components components that match this framework + * + * The list returned in {framework_components} is owned by the component + * repository and CAN NOT be modified by the caller. */ - OPAL_DECLSPEC int mca_base_component_repository_retain(char *type, - opal_dl_handle_t *component_handle, - const mca_base_component_t *component_struct); - - OPAL_DECLSPEC int mca_base_component_repository_retain_component(const char *type, - const char *name); - OPAL_DECLSPEC int mca_base_component_repository_link(const char *src_type, - const char *src_name, - const char *depend_type, - const char *depend_name); - OPAL_DECLSPEC void mca_base_component_repository_release(const mca_base_component_t *component); - OPAL_DECLSPEC void mca_base_component_repository_finalize(void); - +OPAL_DECLSPEC int mca_base_component_repository_get_components (mca_base_framework_t *framework, + opal_list_t **framework_components); + +/** + * @brief finalize the mca component repository + */ +OPAL_DECLSPEC void mca_base_component_repository_finalize(void); + +/** + * @brief open the repository item and add it to the framework's component + * list + * + * @param[in] framework framework that matches the component + * @param[in] ri dynamic component to open + */ +int mca_base_component_repository_open (mca_base_framework_t *framework, + mca_base_component_repository_item_t *ri); + + +void mca_base_component_repository_release(const mca_base_component_t *component); + END_C_DECLS #endif /* MCA_BASE_COMPONENT_REPOSITORY_H */ diff --git a/opal/mca/base/mca_base_components_close.c b/opal/mca/base/mca_base_components_close.c index 294b4e5e742..232b0a38b34 100644 --- a/opal/mca/base/mca_base_components_close.c +++ b/opal/mca/base/mca_base_components_close.c @@ -44,7 +44,7 @@ void mca_base_component_unload (const mca_base_component_t *component, int outpu mca_base_var_group_deregister (ret); } - mca_base_component_repository_release((mca_base_component_t *) component); + mca_base_component_repository_release (component); } void mca_base_component_close (const mca_base_component_t *component, int output_id) diff --git a/opal/mca/base/mca_base_components_open.c b/opal/mca/base/mca_base_components_open.c index 59a1e7b4514..76475333003 100644 --- a/opal/mca/base/mca_base_components_open.c +++ b/opal/mca/base/mca_base_components_open.c @@ -11,7 +11,7 @@ * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2012 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2011-2013 Los Alamos National Security, LLC. + * Copyright (c) 2011-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2014 Hochschule Esslingen. All rights reserved. * $COPYRIGHT$ @@ -56,11 +56,9 @@ int mca_base_framework_components_open (mca_base_framework_t *framework, { /* Open flags are not used at this time. Suppress compiler warning. */ if (flags & MCA_BASE_OPEN_FIND_COMPONENTS) { + bool open_dso_components = !(flags & MCA_BASE_OPEN_STATIC_ONLY); /* Find and load requested components */ - int ret = mca_base_component_find(NULL, framework->framework_name, - framework->framework_static_components, - framework->framework_selection, - &framework->framework_components, true); + int ret = mca_base_component_find(NULL, framework, false, open_dso_components); if (OPAL_SUCCESS != ret) { return ret; } @@ -70,53 +68,6 @@ int mca_base_framework_components_open (mca_base_framework_t *framework, return open_components (framework); } -int mca_base_components_open (const char *type_name, int output_id, - const mca_base_component_t **static_components, - opal_list_t *components_available, - bool open_dso_components) -{ - /* create a dummy framework -- this leaks -- i know -- but it is temporary */ - mca_base_register_flag_t register_flags; - mca_base_framework_t *dummy_framework; - opal_list_item_t *item; - int ret; - - dummy_framework = calloc (1, sizeof(*dummy_framework)); - - dummy_framework->framework_static_components = static_components; - dummy_framework->framework_output = output_id; - dummy_framework->framework_name = strdup(type_name); - - if (open_dso_components) { - register_flags = MCA_BASE_REGISTER_STATIC_ONLY; - } else { - register_flags = MCA_BASE_REGISTER_DEFAULT; - } - - ret = mca_base_framework_components_register (dummy_framework, register_flags); - if (OPAL_SUCCESS != ret) { - free (dummy_framework); - return ret; - } - - ret = mca_base_framework_components_open (dummy_framework, 0); - if (OPAL_SUCCESS != ret) { - (void) mca_base_framework_components_close (dummy_framework, NULL); - free (dummy_framework); - return ret; - } - - OBJ_CONSTRUCT(components_available, opal_list_t); - - while (NULL != (item = opal_list_remove_first(&dummy_framework->framework_components))) { - opal_list_append(components_available, item); - } - - OBJ_DESTRUCT(&dummy_framework->framework_components); - - return OPAL_SUCCESS; -} - /* * Traverse the entire list of found components (a list of * mca_base_component_t instances). If the requested_component_names @@ -152,16 +103,13 @@ static int open_components(mca_base_framework_t *framework) /* If mca_base_framework_register_components was called with the MCA_BASE_COMPONENTS_ALL flag we need to trim down and close any extra components we do not want open */ - ret = mca_base_components_filter (framework->framework_name, &framework->framework_components, - framework->framework_output, framework->framework_selection, - open_only_flags); + ret = mca_base_components_filter (framework, open_only_flags); if (OPAL_SUCCESS != ret) { return ret; } /* Announce */ - opal_output_verbose(10, output_id, - "mca: base: components_open: opening %s components", + opal_output_verbose(10, output_id, "mca: base: components_open: opening %s components", framework->framework_name); /* Traverse the list of components */ diff --git a/opal/mca/base/mca_base_components_register.c b/opal/mca/base/mca_base_components_register.c index 7c7743ac22c..54a06b29660 100644 --- a/opal/mca/base/mca_base_components_register.c +++ b/opal/mca/base/mca_base_components_register.c @@ -11,7 +11,7 @@ * Copyright (c) 2004-2005 The Regents of the University of California. * All rights reserved. * Copyright (c) 2008-2012 Cisco Systems, Inc. All rights reserved. - * Copyright (c) 2011-2013 Los Alamos National Security, LLC. + * Copyright (c) 2011-2015 Los Alamos National Security, LLC. * All rights reserved. * $COPYRIGHT$ * @@ -39,8 +39,7 @@ /* * Local functions */ -static int register_components(const char *project_name, const char *type_name, - int output_id, opal_list_t *src, opal_list_t *dest); +static int register_components(mca_base_framework_t *framework); /** * Function for finding and opening either all MCA components, or the * one that was specifically requested via a MCA parameter. @@ -50,28 +49,16 @@ int mca_base_framework_components_register (mca_base_framework_t *framework, { bool open_dso_components = !(flags & MCA_BASE_REGISTER_STATIC_ONLY); bool ignore_requested = !!(flags & MCA_BASE_REGISTER_ALL); - opal_list_t components_found; int ret; /* Find and load requested components */ - ret = mca_base_component_find(NULL, framework->framework_name, - framework->framework_static_components, - ignore_requested ? NULL : framework->framework_selection, - &components_found, open_dso_components); - + ret = mca_base_component_find(NULL, framework, ignore_requested, open_dso_components); if (OPAL_SUCCESS != ret) { return ret; } /* Register all remaining components */ - ret = register_components(framework->framework_project, framework->framework_name, - framework->framework_output, &components_found, - &framework->framework_components); - - OBJ_DESTRUCT(&components_found); - - /* All done */ - return ret; + return register_components(framework); } /* @@ -81,24 +68,21 @@ int mca_base_framework_components_register (mca_base_framework_t *framework, * components is in the requested_components_array, try to open it. * If it opens, add it to the components_available list. */ -static int register_components(const char *project_name, const char *type_name, - int output_id, opal_list_t *src, opal_list_t *dest) +static int register_components(mca_base_framework_t *framework) { int ret; - opal_list_item_t *item; mca_base_component_t *component; - mca_base_component_list_item_t *cli; + mca_base_component_list_item_t *cli, *next; + int output_id = framework->framework_output; /* Announce */ opal_output_verbose(10, output_id, - "mca: base: components_register: registering %s components", - type_name); + "mca: base: components_register: registering framework %s components", + framework->framework_name); /* Traverse the list of found components */ - OBJ_CONSTRUCT(dest, opal_list_t); - while (NULL != (item = opal_list_remove_first (src))) { - cli = (mca_base_component_list_item_t *) item; + OPAL_LIST_FOREACH_SAFE(cli, next, &framework->framework_components, mca_base_component_list_item_t) { component = (mca_base_component_t *)cli->cli_component; opal_output_verbose(10, output_id, @@ -142,7 +126,7 @@ static int register_components(const char *project_name, const char *type_name, component->mca_component_name); } - mca_base_component_unload (component, output_id); + opal_list_remove_item (&framework->framework_components, &cli->super); /* Release this list item */ OBJ_RELEASE(cli); @@ -168,8 +152,6 @@ static int register_components(const char *project_name, const char *type_name, 0, MCA_BASE_VAR_FLAG_DEFAULT_ONLY | MCA_BASE_VAR_FLAG_INTERNAL, OPAL_INFO_LVL_9, MCA_BASE_VAR_SCOPE_CONSTANT, &component->mca_component_release_version); - - opal_list_append(dest, item); } /* All done */ diff --git a/opal/mca/base/mca_base_framework.c b/opal/mca/base/mca_base_framework.c index 18c55517fc1..039e7421e44 100644 --- a/opal/mca/base/mca_base_framework.c +++ b/opal/mca/base/mca_base_framework.c @@ -65,6 +65,8 @@ int mca_base_framework_register (struct mca_base_framework_t *framework, return OPAL_SUCCESS; } + OBJ_CONSTRUCT(&framework->framework_components, opal_list_t); + if (framework->framework_flags & MCA_BASE_FRAMEWORK_FLAG_NO_DSO) { flags |= MCA_BASE_REGISTER_STATIC_ONLY; } @@ -147,6 +149,10 @@ int mca_base_framework_open (struct mca_base_framework_t *framework, if (MCA_BASE_FRAMEWORK_FLAG_NOREGISTER & framework->framework_flags) { flags |= MCA_BASE_OPEN_FIND_COMPONENTS; + + if (MCA_BASE_FRAMEWORK_FLAG_NO_DSO & framework->framework_flags) { + flags |= MCA_BASE_OPEN_STATIC_ONLY; + } } /* lock all of this frameworks's variables */ @@ -221,6 +227,8 @@ int mca_base_framework_close (struct mca_base_framework_t *framework) { framework->framework_flags &= ~(MCA_BASE_FRAMEWORK_FLAG_REGISTERED | MCA_BASE_FRAMEWORK_FLAG_OPEN); + OBJ_DESTRUCT(&framework->framework_components); + framework_close_output (framework); return ret; diff --git a/opal/mca/base/mca_base_framework.h b/opal/mca/base/mca_base_framework.h index bfc78ec12ff..43aa36a731c 100644 --- a/opal/mca/base/mca_base_framework.h +++ b/opal/mca/base/mca_base_framework.h @@ -29,11 +29,13 @@ enum mca_base_register_flag_t { typedef enum mca_base_register_flag_t mca_base_register_flag_t; enum mca_base_open_flag_t { - MCA_BASE_OPEN_DEFAULT = 0, + MCA_BASE_OPEN_DEFAULT = 0, /** Find components in mca_base_components_find. Used by mca_base_framework_open() when NOREGISTER is specified by the framework */ - MCA_BASE_OPEN_FIND_COMPONENTS = 1 + MCA_BASE_OPEN_FIND_COMPONENTS = 1, + /** Do not open DSO components */ + MCA_BASE_OPEN_STATIC_ONLY = 2, }; typedef enum mca_base_open_flag_t mca_base_open_flag_t; diff --git a/opal/mca/installdirs/base/installdirs_base_components.c b/opal/mca/installdirs/base/installdirs_base_components.c index 33a92db135d..0df268d3dc5 100644 --- a/opal/mca/installdirs/base/installdirs_base_components.c +++ b/opal/mca/installdirs/base/installdirs_base_components.c @@ -171,4 +171,4 @@ opal_installdirs_base_close(void) /* Declare the installdirs framework */ MCA_BASE_FRAMEWORK_DECLARE(opal, installdirs, NULL, NULL, opal_installdirs_base_open, opal_installdirs_base_close, mca_installdirs_base_static_components, - MCA_BASE_FRAMEWORK_FLAG_NOREGISTER); + MCA_BASE_FRAMEWORK_FLAG_NOREGISTER | MCA_BASE_FRAMEWORK_FLAG_NO_DSO); diff --git a/opal/runtime/opal_finalize.c b/opal/runtime/opal_finalize.c index b6d67bd075e..50d1932a7ff 100644 --- a/opal/runtime/opal_finalize.c +++ b/opal/runtime/opal_finalize.c @@ -10,7 +10,7 @@ * 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) 2010-2013 Los Alamos National Security, LLC. + * Copyright (c) 2010-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2013-2015 Intel, Inc. All rights reserved * $COPYRIGHT$ @@ -160,9 +160,6 @@ opal_finalize(void) /* close the sec framework */ (void) mca_base_framework_close(&opal_sec_base_framework); - /* finalize the mca */ - mca_base_close(); - /* finalize util code */ opal_finalize_util(); diff --git a/opal/runtime/opal_init.c b/opal/runtime/opal_init.c index 89d6600590d..d351799b84e 100644 --- a/opal/runtime/opal_init.c +++ b/opal/runtime/opal_init.c @@ -13,7 +13,7 @@ * Copyright (c) 2007-2012 Cisco Systems, Inc. All rights reserved. * Copyright (c) 2007 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2009 Oak Ridge National Labs. All rights reserved. - * Copyright (c) 2010-2013 Los Alamos National Security, LLC. + * Copyright (c) 2010-2015 Los Alamos National Security, LLC. * All rights reserved. * Copyright (c) 2013-2014 Intel, Inc. All rights reserved * Copyright (c) 2015 Research Organization for Information Science @@ -354,6 +354,12 @@ opal_init_util(int* pargc, char*** pargv) goto return_error; } + /* initialize the mca */ + if (OPAL_SUCCESS != (ret = mca_base_open())) { + error = "mca_base_open"; + goto return_error; + } + return OPAL_SUCCESS; return_error: @@ -384,12 +390,6 @@ opal_init(int* pargc, char*** pargv) return ret; } - /* initialize the mca */ - if (OPAL_SUCCESS != (ret = mca_base_open())) { - error = "mca_base_open"; - goto return_error; - } - /* open hwloc - since this is a static framework, no * select is required */