1
1

mca/base: update the way dynamic components are handled

This commit is a rework of the component repository. The changes
included in this commit are:

 - Remove the component dependency code based off .ompi_info
   files. This code is legacy code dating back 10 years that and is no
   longer used.

 - Move the plugin scanning code to the component repository. New
   calls have been added to add new scanning paths, query available
   components, and dlopen/load components.

 - Pass the framework down to mca_base_component_find/filter. Eventually
   the framework structure will be used to further validate components
   before they are used.

 - Add support to the MCA framework system to disable scanning for
   dlopened components on open (support already existed in
   register). This is really only relevant to installdirs as it has no
   register function and no DSO components.

Signed-off-by: Nathan Hjelm <hjelmn@lanl.gov>
Этот коммит содержится в:
Nathan Hjelm 2015-04-08 12:00:13 -06:00
родитель eb56117405
Коммит c954f457d9
12 изменённых файлов: 573 добавлений и 1115 удалений

Просмотреть файл

@ -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);

Просмотреть файл

@ -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 @@ component_find_out:
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);
}
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);
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;
mca_base_component_repository_item_t *ri;
opal_list_t *dy_components;
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 (NULL != path) {
ret = mca_base_component_repository_add (path);
if (OPAL_SUCCESS != ret) {
return;
}
}
/* 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;
ret = mca_base_component_repository_get_components (framework, &dy_components);
if (OPAL_SUCCESS != ret) {
return;
}
/* 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;
/* 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);
}
}
/* 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;
}
/* 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;
}
}
/* 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;
}
}

Просмотреть файл

@ -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,17 +59,149 @@ static bool initialized = false;
#if OPAL_HAVE_DL_SUPPORT
static opal_list_t repository;
static opal_hash_table_t mca_base_component_repository;
/* two-level macro for stringifying a number */
#define STRINGIFYX(x) #x
#define STRINGIFY(x) STRINGIFYX(x)
/*
* 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 int process_repository_item (const char *filename, void *data)
{
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;
}
/* check if the plugin has the appropriate prefix */
if (0 != strncmp (base, "mca_", 4)) {
free (base);
return OPAL_SUCCESS;
}
/* 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;
}
/* 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;
}
}
/* 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;
}
}
ri = OBJ_NEW(mca_base_component_repository_item_t);
if (NULL == ri) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
ri->ri_base = base;
ri->ri_path = strdup (filename);
if (NULL == ri->ri_path) {
OBJ_RELEASE(ri);
return OPAL_ERR_OUT_OF_RESOURCE;
}
/* 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->ri_name[MCA_BASE_MAX_TYPE_NAME_LEN] = '\0';
strncpy (ri->ri_name, name, MCA_BASE_MAX_COMPONENT_NAME_LEN);
opal_list_append (component_list, &ri->super);
return OPAL_SUCCESS;
}
static int file_exists(const char *filename, const char *ext)
{
char *final;
int ret;
if (NULL == ext) {
return access (filename, F_OK) == 0;
}
ret = asprintf(&final, "%s.%s", filename, ext);
if (0 > ret || NULL == final) {
return 0;
}
ret = access (final, F_OK);
free(final);
return (0 == ret);
}
#endif /* OPAL_HAVE_DL_SUPPORT */
int mca_base_component_repository_add (const char *path)
{
#if OPAL_HAVE_DL_SUPPORT
char *path_to_use = NULL, *dir, *ctx;
const char sep[] = {OPAL_ENV_SEP, '\0'};
if (NULL == path) {
/* nothing to do */
return OPAL_SUCCESS;
}
path_to_use = strdup (path);
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)));
#endif /* OPAL_HAVE_DL_SUPPORT */
return OPAL_SUCCESS;
}
/*
* Initialize the repository
@ -105,7 +222,19 @@ int mca_base_component_repository_init(void)
}
opal_dl_base_select();
OBJ_CONSTRUCT(&repository, opal_list_t);
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;
}
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
initialized = true;
@ -116,279 +245,282 @@ int mca_base_component_repository_init(void)
return OPAL_SUCCESS;
}
/*
* 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)
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
repository_item_t *ri;
/* Allocate a new repository item */
ri = OBJ_NEW(repository_item_t);
if (NULL == ri) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
/* Initialize the repository item */
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;
/* Append the new item to the repository */
opal_list_append(&repository, (opal_list_item_t *) ri);
/* All done */
return OPAL_SUCCESS;
#else
return OPAL_ERR_NOT_SUPPORTED;
return opal_hash_table_get_value_ptr (&mca_base_component_repository, framework->framework_name,
strlen (framework->framework_name), (void **) framework_components);
#endif
}
/*
* Bump up the refcount on a component
*/
int mca_base_component_repository_retain_component(const char *type,
const char *name)
{
#if OPAL_HAVE_DL_SUPPORT
repository_item_t *ri = find_component(type, name);
if (NULL != ri) {
OBJ_RETAIN(ri);
return OPAL_SUCCESS;
}
return OPAL_ERR_NOT_FOUND;
#else
return OPAL_ERR_NOT_SUPPORTED;
#endif
}
static void mca_base_component_repository_release_internal (mca_base_component_repository_item_t *ri) {
int group_id;
/*
* 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;
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);
}
/* 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;
}
/* Link them */
return link_items(src, depend);
#else
return OPAL_ERR_NOT_SUPPORTED;
#endif
/* Close the component (and potentially unload it from memory */
if (ri->ri_dlhandle) {
opal_dl_close(ri->ri_dlhandle);
ri->ri_dlhandle = NULL;
}
}
/*
* If it's in the repository, close a specified component and remove
* it from the repository.
*/
void mca_base_component_repository_release(const mca_base_component_t *component)
{
#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);
mca_base_component_repository_item_t *ri;
opal_list_t *component_list;
int ret;
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;
}
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;
}
}
}
#endif
}
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;
}
}
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;
}
mitem->cli_component = ri->ri_component_struct;
opal_list_append (&framework->framework_components, &mitem->super);
return OPAL_SUCCESS;
}
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;
}
/* 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;
}
/* Successfully opened the component; now find the public struct.
Malloc out enough space for it. */
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;
} while (0);
if (mitem) {
OBJ_RELEASE(mitem);
}
if (struct_name) {
free (struct_name);
}
opal_dl_close (ri->ri_dlhandle);
ri->ri_dlhandle = NULL;
return ret;
#else
/* no dlopen support */
return OPAL_ERR_NOT_SUPPORTED;
#endif
}
/*
* 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;
#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.
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). */
do {
OPAL_LIST_FOREACH_SAFE(ri, next, &repository, repository_item_t) {
OBJ_RELEASE(ri);
}
} while (opal_list_get_size(&repository) > 0);
(void) mca_base_framework_close(&opal_dl_base_framework);
#endif
if (!initialized) {
return;
}
initialized = false;
}
#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);
}
(void) mca_base_framework_close(&opal_dl_base_framework);
OBJ_DESTRUCT(&mca_base_component_repository);
#endif
}
#if OPAL_HAVE_DL_SUPPORT
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;
}
}
/* Not found */
return NULL;
}
static int link_items(repository_item_t *src, repository_item_t *depend)
{
dependency_item_t *di;
/* Bozo check */
if (NULL == src || NULL == depend) {
return OPAL_ERR_BAD_PARAM;
}
/* Make a new depedency item */
di = OBJ_NEW(dependency_item_t);
if (NULL == di) {
return OPAL_ERR_OUT_OF_RESOURCE;
}
/* Initialize the new dependency item */
di->di_repository_entry = depend;
/* Add it to the dependency list on the source repository entry */
opal_list_append(&src->ri_dependencies, (opal_list_item_t *) di);
/* Increment the refcount in the dependency */
OBJ_RETAIN(depend);
/* All done */
return OPAL_SUCCESS;
}
/*
* Basic sentinel values, and construct the inner list
*/
static void ri_constructor(opal_object_t *obj)
static void ri_constructor (mca_base_component_repository_item_t *ri)
{
repository_item_t *ri = (repository_item_t *) obj;
memset(ri->ri_type, 0, sizeof(ri->ri_type));
ri->ri_dlhandle = NULL;
ri->ri_component_struct = NULL;
OBJ_CONSTRUCT(&ri->ri_dependencies, opal_list_t);
memset(ri->ri_type, 0, sizeof(ri->ri_type));
ri->ri_dlhandle = NULL;
ri->ri_component_struct = NULL;
ri->ri_path = NULL;
}
/*
* Close a component
* Close a component
*/
static void ri_destructor(opal_object_t *obj)
static void ri_destructor (mca_base_component_repository_item_t *ri)
{
repository_item_t *ri = (repository_item_t *) obj;
opal_list_item_t *item;
int group_id;
/* dlclose the component if it is still open */
mca_base_component_repository_release_internal (ri);
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);
}
/* 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. :-) */
/* Close the component (and potentially unload it from memory */
opal_dl_close(ri->ri_dlhandle);
if (ri->ri_path) {
free (ri->ri_path);
}
/* 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. :-) */
/* Now go release/close (at a minimum: decrement the refcount) any
dependencies of this component */
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);
}
/*
* Basic sentinel values
*/
static void di_constructor(opal_object_t *obj)
{
dependency_item_t *di = (dependency_item_t *) obj;
di->di_repository_entry = NULL;
}
/*
* When a dependency item is released, go release the repository entry
* that it points to
*/
static void di_destructor(opal_object_t *obj)
{
dependency_item_t *di = (dependency_item_t *) obj;
OBJ_RELEASE(di->di_repository_entry);
if (ri->ri_base) {
free (ri->ri_base);
}
}
#endif /* OPAL_HAVE_DL_SUPPORT */

Просмотреть файл

@ -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_retain(char *type,
opal_dl_handle_t *component_handle,
const mca_base_component_t *component_struct);
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_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);
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);
END_C_DECLS
#endif /* MCA_BASE_COMPONENT_REPOSITORY_H */

Просмотреть файл

@ -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)

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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 */

Просмотреть файл

@ -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;

Просмотреть файл

@ -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;

Просмотреть файл

@ -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);

Просмотреть файл

@ -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();

Просмотреть файл

@ -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
*/