642 строки
18 KiB
C
642 строки
18 KiB
C
|
/*
|
||
|
* $HEADER$
|
||
|
*/
|
||
|
|
||
|
#include "lam_config.h"
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
/* Ensure to get the right <ltdl.h> */
|
||
|
#include "mca/ltdl.h"
|
||
|
|
||
|
#include "lam/constants.h"
|
||
|
#include "lam/util/output.h"
|
||
|
#include "lam/lfc/list.h"
|
||
|
#include "mca/mca.h"
|
||
|
#include "mca/lam/base/base.h"
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Private types
|
||
|
*/
|
||
|
typedef enum module_status {
|
||
|
UNVISITED,
|
||
|
FAILED_TO_LOAD,
|
||
|
CHECKING_CYCLE,
|
||
|
LOADED,
|
||
|
|
||
|
STATUS_MAX
|
||
|
} module_status_t;
|
||
|
|
||
|
struct module_file_item_t {
|
||
|
lam_list_item_t super;
|
||
|
|
||
|
char type[MCA_BASE_MAX_TYPE_NAME_LEN];
|
||
|
char name[MCA_BASE_MAX_MODULE_NAME_LEN];
|
||
|
char basename[LAM_PATH_MAX];
|
||
|
char filename[LAM_PATH_MAX];
|
||
|
module_status_t status;
|
||
|
};
|
||
|
typedef struct module_file_item_t module_file_item_t;
|
||
|
|
||
|
struct dependency_item_t {
|
||
|
lam_list_item_t super;
|
||
|
|
||
|
module_file_item_t *di_module_file_item;
|
||
|
};
|
||
|
typedef struct dependency_item_t dependency_item_t;
|
||
|
|
||
|
struct ltfn_data_holder_t {
|
||
|
char type[MCA_BASE_MAX_TYPE_NAME_LEN];
|
||
|
char name[MCA_BASE_MAX_MODULE_NAME_LEN];
|
||
|
};
|
||
|
typedef struct ltfn_data_holder_t ltfn_data_holder_t;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Private functions
|
||
|
*/
|
||
|
static void find_dyn_modules(const char *path, const char *type,
|
||
|
const char *name, lam_list_t *found_modules);
|
||
|
static int save_filename(const char *filename, lt_ptr data);
|
||
|
static int open_module(module_file_item_t *target_file,
|
||
|
lam_list_t *found_modules);
|
||
|
static int check_laminfo(module_file_item_t *target_file,
|
||
|
lam_list_t *dependencies,
|
||
|
lam_list_t *found_modules);
|
||
|
static int check_dependency(char *line, module_file_item_t *target_file,
|
||
|
lam_list_t *dependencies,
|
||
|
lam_list_t *found_modules);
|
||
|
static void free_dependency_list(lam_list_t *dependencies);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Private variables
|
||
|
*/
|
||
|
static const char *laminfo_suffix = ".laminfo";
|
||
|
static const char *key_dependency = "dependency=";
|
||
|
static const char module_template[] = "mca_%s_";
|
||
|
static lam_list_t found_files;
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Function to find as many modules of a given type as possible. This
|
||
|
* includes statically-linked in modules as well as opening up a
|
||
|
* directory and looking for shared-library MCA modules of the
|
||
|
* appropriate type (load them if available).
|
||
|
*
|
||
|
* Return one consolidated array of (mca_base_module_t*) pointing to all
|
||
|
* available modules.
|
||
|
*/
|
||
|
int mca_base_module_find(const char *directory, const char *type,
|
||
|
mca_base_module_t *static_modules[],
|
||
|
lam_list_t *found_modules)
|
||
|
{
|
||
|
int i;
|
||
|
mca_base_module_list_item_t *item;
|
||
|
|
||
|
/* Find all the modules that were statically linked in */
|
||
|
|
||
|
lam_list_init(found_modules);
|
||
|
for (i = 0; NULL != static_modules[i]; ++i) {
|
||
|
item = LAM_MALLOC(sizeof(mca_base_module_list_item_t));
|
||
|
if (NULL == item) {
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
lam_list_item_init((lam_list_item_t *) item);
|
||
|
item->mli_module = static_modules[i];
|
||
|
lam_list_append(found_modules, (lam_list_item_t *) item);
|
||
|
}
|
||
|
|
||
|
/* Find any available dynamic modules in the specified directory */
|
||
|
|
||
|
find_dyn_modules(directory, type, NULL, found_modules);
|
||
|
|
||
|
/* All done */
|
||
|
|
||
|
return LAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Open up all directories in a given path and search for modules of
|
||
|
* the specified type (and possibly of a given name).
|
||
|
*
|
||
|
* Note that we use our own path iteration functionality (vs. ltdl's
|
||
|
* lt_dladdsearchdir() functionality) because we need to look at
|
||
|
* companion .laminfo files in the same directory as the library to
|
||
|
* generate dependencies, etc. If we use the plain lt_dlopen()
|
||
|
* functionality, we would not get the directory name of the file
|
||
|
* finally opened in recursive dependency traversals.
|
||
|
*/
|
||
|
static void find_dyn_modules(const char *path, const char *type,
|
||
|
const char *name, lam_list_t *found_modules)
|
||
|
{
|
||
|
ltfn_data_holder_t params;
|
||
|
char *path_to_use, *dir, *end;
|
||
|
module_file_item_t *file;
|
||
|
lam_list_item_t *cur;
|
||
|
|
||
|
strcpy(params.type, type);
|
||
|
strcpy(params.name, name);
|
||
|
|
||
|
if (NULL == name) {
|
||
|
lam_output_verbose(0, 40, " looking for all dynamic %s MCA modules",
|
||
|
type, NULL);
|
||
|
} else {
|
||
|
lam_output_verbose(0, 40,
|
||
|
" looking for dynamic %s MCA module named \"%s\"",
|
||
|
type, name, NULL);
|
||
|
}
|
||
|
|
||
|
/* If directory is NULL, iterate over the set of directories
|
||
|
specified by the MCA param mca_base_module_path. If path is not
|
||
|
NULL, then use that as the path. */
|
||
|
|
||
|
if (NULL == path) {
|
||
|
mca_base_param_lookup_string(mca_base_param_module_path, &dir);
|
||
|
path_to_use = strdup(dir);
|
||
|
}
|
||
|
if (NULL == path) {
|
||
|
path_to_use = strdup(path);
|
||
|
}
|
||
|
|
||
|
/* Iterate over all the files in the directories in the path and
|
||
|
make a master array of all the matching filenames that we
|
||
|
find. */
|
||
|
|
||
|
lam_list_init(&found_files);
|
||
|
dir = path_to_use;
|
||
|
do {
|
||
|
end = strchr(dir, ':');
|
||
|
if (NULL != end) {
|
||
|
*end = '\0';
|
||
|
}
|
||
|
if (0 != lt_dlforeachfile(dir, save_filename, ¶ms)) {
|
||
|
break;
|
||
|
}
|
||
|
dir = end + 1;
|
||
|
} while (NULL != end);
|
||
|
|
||
|
/* Iterate through all the filenames that we found. Since one
|
||
|
module 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 = lam_list_get_first(&found_files);
|
||
|
lam_list_get_end(&found_files) != cur;
|
||
|
cur = lam_list_get_next(cur)) {
|
||
|
file = (module_file_item_t *) cur;
|
||
|
if (UNVISITED == file->status)
|
||
|
open_module(file, found_modules);
|
||
|
}
|
||
|
|
||
|
/* So now we have a final list of loaded modules. We can free all
|
||
|
the file information. */
|
||
|
|
||
|
for (cur = lam_list_get_first(&found_files);
|
||
|
lam_list_get_end(&found_files) != cur; ) {
|
||
|
file = (module_file_item_t *) cur;
|
||
|
cur = lam_list_get_next(cur);
|
||
|
LAM_FREE(file);
|
||
|
lam_list_remove_first(&found_files);
|
||
|
}
|
||
|
|
||
|
/* All done */
|
||
|
|
||
|
lam_list_destroy(&found_files);
|
||
|
LAM_FREE(path_to_use);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Given a filename, see if it appears to be of the proper filename
|
||
|
* format. If so, save it in the array so that we can process it
|
||
|
* later.
|
||
|
*/
|
||
|
static int save_filename(const char *filename, lt_ptr data)
|
||
|
{
|
||
|
int len, prefix_len, total_len;
|
||
|
char *prefix;
|
||
|
const char *basename;
|
||
|
module_file_item_t *module_file;
|
||
|
ltfn_data_holder_t *params = (ltfn_data_holder_t *) data;
|
||
|
|
||
|
/* Check to see if the file is named what we expect it to be
|
||
|
named */
|
||
|
|
||
|
len = sizeof(module_template) + strlen(params->type) + 32;
|
||
|
if (NULL != params->name) {
|
||
|
len += strlen(params->name);
|
||
|
}
|
||
|
prefix = LAM_MALLOC(len);
|
||
|
snprintf(prefix, len, module_template, params->type);
|
||
|
prefix_len = strlen(prefix);
|
||
|
if (NULL != params->name) {
|
||
|
strcat(prefix, params->name);
|
||
|
}
|
||
|
total_len = strlen(prefix);
|
||
|
|
||
|
basename = strrchr(filename, '/');
|
||
|
if (NULL == basename) {
|
||
|
basename = filename;
|
||
|
} else {
|
||
|
basename += 1;
|
||
|
}
|
||
|
|
||
|
if (0 != strncmp(basename, prefix, total_len)) {
|
||
|
LAM_FREE(prefix);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Save all the info and put it in the list of found modules */
|
||
|
|
||
|
module_file = LAM_MALLOC(sizeof(module_file_item_t));
|
||
|
if (NULL == module_file) {
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
lam_list_item_init((lam_list_item_t *) module_file);
|
||
|
strcpy(module_file->type, params->type);
|
||
|
strcpy(module_file->name, basename + prefix_len);
|
||
|
strcpy(module_file->basename, basename);
|
||
|
strcpy(module_file->filename, filename);
|
||
|
module_file->status = UNVISITED;
|
||
|
lam_list_append(&found_files, (lam_list_item_t *) module_file);
|
||
|
|
||
|
/* All done */
|
||
|
|
||
|
LAM_FREE(prefix);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Open a module, chasing down its dependencies first, if possible.
|
||
|
*/
|
||
|
static int open_module(module_file_item_t *target_file,
|
||
|
lam_list_t *found_modules)
|
||
|
{
|
||
|
int len;
|
||
|
lt_dlhandle module_handle;
|
||
|
mca_base_module_t *module_struct;
|
||
|
char *struct_name;
|
||
|
lam_list_t dependencies;
|
||
|
lam_list_item_t *cur;
|
||
|
mca_base_module_list_item_t *mitem;
|
||
|
dependency_item_t *ditem;
|
||
|
|
||
|
lam_output_verbose(0, 40, " examining dyanmic %s MCA module \"%s\"",
|
||
|
target_file->type, target_file->name, NULL);
|
||
|
lam_output_verbose(0, 40, " %s", target_file->filename, NULL);
|
||
|
|
||
|
/* Was this module already loaded (e.g., via dependency)? */
|
||
|
|
||
|
if (LOADED == target_file->status) {
|
||
|
lam_output_verbose(0, 40, " already loaded (ignored)", NULL);
|
||
|
return LAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
/* Ensure that this module 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 module.
|
||
|
Hence, returning LAM_ERR_PARAM indicates that the *file* failed
|
||
|
to load, not the module. */
|
||
|
|
||
|
for (cur = lam_list_get_first(found_modules);
|
||
|
lam_list_get_end(found_modules) != cur;
|
||
|
cur = lam_list_get_next(cur)) {
|
||
|
mitem = (mca_base_module_list_item_t *) cur;
|
||
|
if (0 == strcmp(mitem->mli_module->mca_type_name, target_file->type) &&
|
||
|
0 == strcmp(mitem->mli_module->mca_module_name, target_file->name)) {
|
||
|
lam_output_verbose(0, 40, " already loaded (ignored)", NULL);
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
return LAM_ERR_BAD_PARAM;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Look at see if this module has any dependencies. If so, load
|
||
|
them. If we can't load them, then this module must also fail to
|
||
|
load. */
|
||
|
|
||
|
lam_list_init(&dependencies);
|
||
|
if (0 != check_laminfo(target_file, &dependencies, found_modules)) {
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
free_dependency_list(&dependencies);
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
|
||
|
/* Now try to load the module */
|
||
|
|
||
|
module_handle = lt_dlopenext(target_file->filename);
|
||
|
if (NULL == module_handle) {
|
||
|
lam_output_verbose(0, 40, " unable to open: %s (ignored)",
|
||
|
lt_dlerror(), NULL);
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
free_dependency_list(&dependencies);
|
||
|
return LAM_ERR_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
/* Successfully opened the module; now find the public struct.
|
||
|
Malloc out enough space for it. */
|
||
|
|
||
|
len = strlen(target_file->type) + strlen(target_file->name) + 32;
|
||
|
struct_name = LAM_MALLOC(len);
|
||
|
if (NULL == struct_name) {
|
||
|
lt_dlclose(module_handle);
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
free_dependency_list(&dependencies);
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
snprintf(struct_name, len, "mca_%s_%s_module", target_file->type,
|
||
|
target_file->name);
|
||
|
|
||
|
mitem = LAM_MALLOC(sizeof(mca_base_module_list_item_t));
|
||
|
if (NULL == mitem) {
|
||
|
LAM_FREE(struct_name);
|
||
|
lt_dlclose(module_handle);
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
free_dependency_list(&dependencies);
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
lam_list_item_init((lam_list_item_t *) mitem);
|
||
|
|
||
|
module_struct = lt_dlsym(module_handle, struct_name);
|
||
|
if (NULL == module_struct) {
|
||
|
lam_output_verbose(0, 40, " \"%s\" does not appear to be a valid "
|
||
|
"%s MCA dynamic module (ignored)",
|
||
|
target_file->basename, target_file->type, NULL);
|
||
|
LAM_FREE(mitem);
|
||
|
LAM_FREE(struct_name);
|
||
|
lt_dlclose(module_handle);
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
free_dependency_list(&dependencies);
|
||
|
return LAM_ERR_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
/* We found the public struct. Save it, and register this module to
|
||
|
be closed later. */
|
||
|
|
||
|
mitem->mli_module = module_struct;
|
||
|
lam_list_append(found_modules, (lam_list_item_t *) mitem);
|
||
|
mca_base_module_registry_retain(target_file->type, module_handle,
|
||
|
module_struct);
|
||
|
|
||
|
/* Now that that's all done, link all the dependencies in to this
|
||
|
module's registry entry */
|
||
|
|
||
|
for (cur = lam_list_remove_first(&dependencies);
|
||
|
NULL != cur;
|
||
|
cur = lam_list_remove_first(&dependencies)) {
|
||
|
ditem = (dependency_item_t *) cur;
|
||
|
mca_base_module_registry_link(target_file->type,
|
||
|
target_file->name,
|
||
|
ditem->di_module_file_item->type,
|
||
|
ditem->di_module_file_item->name);
|
||
|
LAM_FREE(ditem);
|
||
|
}
|
||
|
lam_list_destroy(&dependencies);
|
||
|
|
||
|
lam_output_verbose(0, 40, " opened dynamic %s MCA module \"%s\"",
|
||
|
target_file->type, target_file->name, NULL);
|
||
|
target_file->status = LOADED;
|
||
|
|
||
|
/* All done */
|
||
|
|
||
|
LAM_FREE(struct_name);
|
||
|
return LAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* For a given filename, see if there exists a filename.laminfo, which
|
||
|
* lists dependencies that must be loaded before this module is
|
||
|
* loaded. If we find this file, try to load those modules first.
|
||
|
*
|
||
|
* Detect dependency cycles and error out.
|
||
|
*/
|
||
|
static int check_laminfo(module_file_item_t *target_file,
|
||
|
lam_list_t *dependencies, lam_list_t *found_modules)
|
||
|
{
|
||
|
int len;
|
||
|
FILE *fp;
|
||
|
char *depname;
|
||
|
char buffer[BUFSIZ], *p;
|
||
|
|
||
|
/* Form the filename */
|
||
|
|
||
|
len = strlen(target_file->filename) + strlen(laminfo_suffix) + 16;
|
||
|
depname = LAM_MALLOC(len);
|
||
|
if (NULL == depname)
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
snprintf(depname, len, "%s%s", target_file->filename, laminfo_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"))) {
|
||
|
LAM_FREE(depname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* Otherwise, loop reading the lines in the file and trying to load
|
||
|
them. Return failure upon the first module that fails to
|
||
|
load. */
|
||
|
|
||
|
lam_output_verbose(0, 40, " opening laminfo file: %s", depname, NULL);
|
||
|
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 (LAM_SUCCESS != check_dependency(p + strlen(key_dependency),
|
||
|
target_file, dependencies,
|
||
|
found_modules)) {
|
||
|
fclose(fp);
|
||
|
LAM_FREE(depname);
|
||
|
|
||
|
/* We can leave any successfully loaded dependencies; we might
|
||
|
need them again later. But free the dependency list for
|
||
|
this module, 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 module. So free the dependency
|
||
|
list. */
|
||
|
|
||
|
free_dependency_list(dependencies);
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
lam_output_verbose(0, 40, " laminfo file closed (%s)",
|
||
|
target_file->basename, NULL);
|
||
|
|
||
|
/* All done -- all depenencies satisfied */
|
||
|
|
||
|
fclose(fp);
|
||
|
LAM_FREE(depname);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* A DEPENDENCY key was found in the laminfo file. Chase it down: see
|
||
|
* if we've already got such a module loaded, or go try to load it if
|
||
|
* it's not already loaded.
|
||
|
*/
|
||
|
static int check_dependency(char *line, module_file_item_t *target_file,
|
||
|
lam_list_t *dependencies,
|
||
|
lam_list_t *found_modules)
|
||
|
{
|
||
|
bool happiness;
|
||
|
char buffer[BUFSIZ];
|
||
|
char *type, *name;
|
||
|
module_file_item_t *mitem;
|
||
|
dependency_item_t *ditem;
|
||
|
lam_list_item_t *cur;
|
||
|
|
||
|
/* Ensure that this was a valid dependency statement */
|
||
|
|
||
|
type = line;
|
||
|
name = strchr(line, ':');
|
||
|
if (NULL == name)
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
*name = '\0';
|
||
|
++name;
|
||
|
|
||
|
/* Form the name of the module to compare to */
|
||
|
|
||
|
if (strlen(type) + strlen(name) + 32 >= BUFSIZ) {
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
snprintf(buffer, BUFSIZ, module_template, type);
|
||
|
strcat(buffer, name);
|
||
|
|
||
|
/* Traverse down the list of files that we have, and see if we can
|
||
|
find it */
|
||
|
|
||
|
target_file->status = CHECKING_CYCLE;
|
||
|
for (happiness = false, cur = lam_list_get_first(&found_files);
|
||
|
lam_list_get_last(&found_files) != cur;
|
||
|
cur = lam_list_get_next(cur)) {
|
||
|
mitem = (module_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) {
|
||
|
lam_output_verbose(0, 40,
|
||
|
" module depends on itself (ignored dependency)",
|
||
|
NULL);
|
||
|
happiness = true;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* If it's loaded, great -- we're done (no need to check that
|
||
|
dependency sub-tree) */
|
||
|
|
||
|
else if (LOADED == mitem->status) {
|
||
|
lam_output_verbose(0, 40, " dependency has already been loaded (%s)",
|
||
|
mitem->basename, NULL);
|
||
|
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) {
|
||
|
lam_output_verbose(0, 40, " dependency previously failed to load (%s)",
|
||
|
mitem->basename, NULL);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* If we hit a cycle, return badness */
|
||
|
|
||
|
else if (CHECKING_CYCLE == mitem->status) {
|
||
|
lam_output_verbose(0, 40, " found cycle! (%s)",
|
||
|
mitem->basename, NULL);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Otherwise, this dependency has not been looked at yet. Go try
|
||
|
to load it. */
|
||
|
|
||
|
else if (UNVISITED == mitem->status) {
|
||
|
lam_output_verbose(0, 40, " loading dependency (%s)",
|
||
|
mitem->basename, NULL);
|
||
|
if (LAM_SUCCESS == open_module(target_file, found_modules)) {
|
||
|
happiness = true;
|
||
|
} else {
|
||
|
lam_output_verbose(0, 40, " dependency failed to load (%s)",
|
||
|
mitem->basename, NULL);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Did we find the dependency? */
|
||
|
|
||
|
if (!happiness) {
|
||
|
target_file->status = FAILED_TO_LOAD;
|
||
|
return LAM_ERR_BAD_PARAM;
|
||
|
}
|
||
|
|
||
|
/* The dependency loaded properly. Increment its refcount so that
|
||
|
it doesn't get unloaded before we get unloaded. */
|
||
|
|
||
|
ditem = LAM_MALLOC(sizeof(dependency_item_t));
|
||
|
if (NULL == ditem) {
|
||
|
return LAM_ERR_OUT_OF_RESOURCE;
|
||
|
}
|
||
|
cur = (lam_list_item_t *) ditem;
|
||
|
lam_list_item_init(cur);
|
||
|
lam_list_append(dependencies, cur);
|
||
|
|
||
|
/* All done -- all depenencies satisfied */
|
||
|
|
||
|
return LAM_SUCCESS;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Free a dependency list
|
||
|
*/
|
||
|
static void free_dependency_list(lam_list_t *dependencies)
|
||
|
{
|
||
|
lam_list_item_t *item;
|
||
|
|
||
|
for (item = lam_list_remove_first(dependencies);
|
||
|
NULL != item;
|
||
|
item = lam_list_remove_first(dependencies)) {
|
||
|
LAM_FREE(item);
|
||
|
}
|
||
|
lam_list_destroy(dependencies);
|
||
|
}
|