Addition of module registration code; initial port to LAMX framework
This commit was SVN r464.
Этот коммит содержится в:
родитель
ee58c030ba
Коммит
64b07daedb
@ -9,13 +9,23 @@ noinst_LTLIBRARIES = libmca_lam_base.la
|
||||
# Source code files
|
||||
|
||||
headers = \
|
||||
mca_lam_param.h \
|
||||
module_exchange.h
|
||||
mca_base_close.h \
|
||||
mca_base_module_compare.h \
|
||||
mca_base_open.h \
|
||||
mca_base_param.h \
|
||||
mca_base_module_exchange.h
|
||||
|
||||
# Library
|
||||
|
||||
libmca_lam_base_la_SOURCES = \
|
||||
mca_lam_param.c
|
||||
$(headers) \
|
||||
mca_base_close.c \
|
||||
mca_base_cmd_line.c \
|
||||
mca_base_module_compare.c \
|
||||
mca_base_module_find.c \
|
||||
mca_base_module_registry.c \
|
||||
mca_base_open.c \
|
||||
mca_base_param.c
|
||||
|
||||
|
||||
# Conditionally install the header files
|
||||
|
72
src/mca/lam/base/base.h
Обычный файл
72
src/mca/lam/base/base.h
Обычный файл
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#ifndef MCA_LAM_BASE_H
|
||||
#define MCA_LAM_BASE_H
|
||||
|
||||
#include "mca/ltdl.h"
|
||||
|
||||
/*
|
||||
* These units are large enough to warrant their own .h files
|
||||
*/
|
||||
#include "mca/lam/base/mca_base_param.h"
|
||||
#include "mca/lam/base/mca_base_module_exchange.h"
|
||||
|
||||
|
||||
/*
|
||||
* Public variables
|
||||
*/
|
||||
extern int mca_base_param_module_path;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Public functions
|
||||
*/
|
||||
#if defined(c_plusplus) || defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* mca_base_open.c */
|
||||
|
||||
int mca_base_open(void);
|
||||
|
||||
/* mca_base_close.c */
|
||||
|
||||
int mca_base_close(void);
|
||||
|
||||
/* mca_base_cmd_line.c */
|
||||
|
||||
int mca_base_cmd_line_setup(lam_cmd_line_t *cmd);
|
||||
int mca_base_cmd_line_process_args(lam_cmd_line_t *cmd);
|
||||
int mca_base_cmd_line_process_arg(const char *param, const char *value);
|
||||
|
||||
/* mca_base_module_compare.c */
|
||||
|
||||
int mca_base_module_compare(mca_base_module_priority_t *a,
|
||||
mca_base_module_priority_t *b);
|
||||
|
||||
/* mca_base_module_find.c */
|
||||
|
||||
int mca_base_module_find(const char *directory, const char *type,
|
||||
mca_base_module_t *static_modules[],
|
||||
lam_list_t *found_modules);
|
||||
|
||||
/* mca_base_module_register.c */
|
||||
|
||||
int mca_base_module_registry_init(void);
|
||||
int mca_base_module_registry_retain(char *type, lt_dlhandle module_handle,
|
||||
mca_base_module_t *module_struct);
|
||||
int mca_base_module_registry_link(const char *src_type,
|
||||
const char *src_name,
|
||||
const char *depend_type,
|
||||
const char *depend_name);
|
||||
void mca_base_module_registry_release(mca_base_module_t *module);
|
||||
void mca_base_module_registry_finalize(void);
|
||||
|
||||
#if defined(c_plusplus) || defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MCA_LAM_BASE_H */
|
28
src/mca/lam/base/mca_base_close.c
Обычный файл
28
src/mca/lam/base/mca_base_close.c
Обычный файл
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include "lam_config.h"
|
||||
|
||||
#include "lam/util/output.h"
|
||||
#include "mca/mca.h"
|
||||
#include "mca/lam/base/base.h"
|
||||
|
||||
|
||||
/*
|
||||
* Main MCA shutdown.
|
||||
*/
|
||||
int mca_base_close(void)
|
||||
{
|
||||
/* Clear out all the registered MCA params */
|
||||
|
||||
mca_base_param_finalize();
|
||||
|
||||
/* Close down the module registry */
|
||||
|
||||
mca_base_module_registry_finalize();
|
||||
|
||||
/* All done */
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
117
src/mca/lam/base/mca_base_cmd_line.c
Обычный файл
117
src/mca/lam/base/mca_base_cmd_line.c
Обычный файл
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include "lam_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "lam/constants.h"
|
||||
#include "lam/mem/malloc.h"
|
||||
#include "lam/util/cmd_line.h"
|
||||
#include "lam/util/argv.h"
|
||||
#include "mca/lam/base/base.h"
|
||||
|
||||
|
||||
/*
|
||||
* Private variables
|
||||
*/
|
||||
static int mca_param_argc = 0;
|
||||
static char **mca_param_argv = NULL;
|
||||
static int mca_value_argc = 0;
|
||||
static char **mca_value_argv = NULL;
|
||||
|
||||
|
||||
/*
|
||||
* Add -mca to the possible command line options list
|
||||
*/
|
||||
int
|
||||
mca_base_cmd_line_setup(lam_cmd_line_t *cmd)
|
||||
{
|
||||
return lam_cmd_line_set_opt(cmd, "m", "mca", 2,
|
||||
"General mechanism to pass MCA parameters");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Look for and handle any -mca options on the command line
|
||||
*/
|
||||
int
|
||||
mca_base_cmd_line_process_args(lam_cmd_line_t *cmd)
|
||||
{
|
||||
int i, num_insts;
|
||||
char *buf = 0;
|
||||
int buflen = 0;
|
||||
|
||||
/* If no "-mca" parameters were given, just return */
|
||||
|
||||
if (!lam_cmd_line_is_taken(cmd, "mca"))
|
||||
return LAM_SUCCESS;
|
||||
|
||||
/* Otherwise, assemble them into an argc/argv */
|
||||
|
||||
num_insts = lam_cmd_line_get_ninsts(cmd, "mca");
|
||||
for (i = 0; i < num_insts; ++i)
|
||||
mca_base_cmd_line_process_arg(lam_cmd_line_get_param(cmd, "mca", i, 0),
|
||||
lam_cmd_line_get_param(cmd, "mca", i, 1));
|
||||
|
||||
/* Now put that argc/argv in the environment */
|
||||
|
||||
if (NULL == mca_param_argv)
|
||||
return LAM_SUCCESS;
|
||||
|
||||
/* Loop through all the -mca args that we've gotten and make env
|
||||
vars of the form LAM_MPI_MCA_*=value. This is a memory leak, but
|
||||
that's how putenv works. :-( */
|
||||
|
||||
for (i = 0; NULL != mca_param_argv[i]; ++i) {
|
||||
buflen = strlen(mca_param_argv[i]) + strlen(mca_value_argv[i]) + 32;
|
||||
buf = LAM_MALLOC(buflen);
|
||||
if (NULL == buf)
|
||||
return LAM_ERR_OUT_OF_RESOURCE;
|
||||
|
||||
snprintf(buf, buflen, "LAM_MPI_MCA_%s=%s", mca_param_argv[i],
|
||||
mca_value_argv[i]);
|
||||
putenv(buf);
|
||||
}
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Process a single MCA argument. Done as a separate function so that
|
||||
* top-level applications can directly invoke this to effect MCA
|
||||
* command line arguments.
|
||||
*/
|
||||
int
|
||||
mca_base_cmd_line_process_arg(const char *param, const char *value)
|
||||
{
|
||||
int i, len;
|
||||
char *new_str;
|
||||
|
||||
/* Look to see if we've already got an -mca argument for the same
|
||||
param. Check against the list of MCA param's that we've already
|
||||
saved arguments for. */
|
||||
|
||||
for (i = 0; NULL != mca_param_argv && NULL != mca_param_argv[i]; ++i) {
|
||||
if (0 == strcmp(param, mca_param_argv[i])) {
|
||||
len = strlen(value) + strlen(mca_param_argv[i]);
|
||||
new_str = LAM_MALLOC(len);
|
||||
snprintf(new_str, len, "%s,%s", mca_value_argv[i], value);
|
||||
LAM_FREE(mca_value_argv[i]);
|
||||
mca_value_argv[i] = new_str;
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't already have an value for the same param, save this
|
||||
one away */
|
||||
|
||||
lam_argv_add(&mca_param_argc, &mca_param_argv, param);
|
||||
lam_argv_add(&mca_value_argc, &mca_value_argv, value);
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
68
src/mca/lam/base/mca_base_module_compare.c
Обычный файл
68
src/mca/lam/base/mca_base_module_compare.c
Обычный файл
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include "lam_config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "mca/mca.h"
|
||||
#include "mca/lam/base/base.h"
|
||||
|
||||
|
||||
/*
|
||||
* Function for comparing two mca_base_module_priorit_t structs so
|
||||
* that we can build prioritized LIST's of them. This assumed that
|
||||
* the types of the modules are the same. Sort first by priority,
|
||||
* second by module name, third by module version.
|
||||
*
|
||||
* Note that we acutally want a *reverse* ordering here -- the al_*
|
||||
* functions will put "smaller" items at the head, and "larger" items
|
||||
* at the tail. Since we want the highest priority at the head, it
|
||||
* may help the gentle reader to consider this an inverse comparison.
|
||||
* :-)
|
||||
*/
|
||||
int mca_base_module_compare(mca_base_module_priority_t *a,
|
||||
mca_base_module_priority_t *b)
|
||||
{
|
||||
int val;
|
||||
|
||||
/* First, compare the priorties */
|
||||
|
||||
if (a->lsm_priority > b->lsm_priority)
|
||||
return -1;
|
||||
else if (a->lsm_priority < b->lsm_priority)
|
||||
return 1;
|
||||
else {
|
||||
mca_base_module_t *aa = a->lsm_module;
|
||||
mca_base_module_t *bb = b->lsm_module;
|
||||
|
||||
/* The priorities were equal, so compare the names */
|
||||
|
||||
val = strncmp(aa->mca_module_name, bb->mca_module_name,
|
||||
MCA_BASE_MAX_MODULE_NAME_LEN);
|
||||
if (val != 0)
|
||||
return -val;
|
||||
|
||||
/* The names were equal, so compare the versions */
|
||||
|
||||
if (aa->mca_module_major_version > bb->mca_module_major_version)
|
||||
return -1;
|
||||
else if (aa->mca_module_major_version < bb->mca_module_major_version)
|
||||
return 1;
|
||||
|
||||
else if (aa->mca_module_minor_version > bb->mca_module_minor_version)
|
||||
return -1;
|
||||
else if (aa->mca_module_minor_version < bb->mca_module_minor_version)
|
||||
return 1;
|
||||
|
||||
else if (aa->mca_module_release_version > bb->mca_module_release_version)
|
||||
return -1;
|
||||
else if (aa->mca_module_release_version < bb->mca_module_release_version)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* They're equal */
|
||||
|
||||
return 0;
|
||||
}
|
641
src/mca/lam/base/mca_base_module_find.c
Обычный файл
641
src/mca/lam/base/mca_base_module_find.c
Обычный файл
@ -0,0 +1,641 @@
|
||||
/*
|
||||
* $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);
|
||||
}
|
290
src/mca/lam/base/mca_base_module_registry.c
Обычный файл
290
src/mca/lam/base/mca_base_module_registry.c
Обычный файл
@ -0,0 +1,290 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include "lam_config.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
/* Ensure to get the right <ltdl.h> */
|
||||
#include "mca/ltdl.h"
|
||||
|
||||
#include "lam/constants.h"
|
||||
#include "lam/lfc/list.h"
|
||||
#include "mca/mca.h"
|
||||
#include "mca/lam/base/base.h"
|
||||
|
||||
|
||||
/*
|
||||
* Private types
|
||||
*/
|
||||
struct registry_item_t {
|
||||
lam_list_item_t super;
|
||||
|
||||
char ri_type[MCA_BASE_MAX_TYPE_NAME_LEN];
|
||||
lt_dlhandle ri_dlhandle;
|
||||
mca_base_module_t *ri_module_struct;
|
||||
int ri_refcount;
|
||||
lam_list_t ri_dependencies;
|
||||
};
|
||||
typedef struct registry_item_t registry_item_t;
|
||||
|
||||
struct dependency_item_t {
|
||||
lam_list_item_t super;
|
||||
|
||||
registry_item_t *di_registry_entry;
|
||||
};
|
||||
typedef struct dependency_item_t dependency_item_t;
|
||||
|
||||
|
||||
/*
|
||||
* Private variables
|
||||
*/
|
||||
static bool initialized = false;
|
||||
static lam_list_t registry;
|
||||
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static registry_item_t *find_module(const char *type, const char *name);
|
||||
static int link_items(registry_item_t *src, registry_item_t *depend);
|
||||
static void release_registry_item(registry_item_t *ri);
|
||||
|
||||
|
||||
/*
|
||||
* Initialize the registry
|
||||
*/
|
||||
int mca_base_module_registry_init(void)
|
||||
{
|
||||
/* Initialized libltdl */
|
||||
|
||||
if (lt_dlinit() != 0)
|
||||
return LAM_ERR_OUT_OF_RESOURCE;
|
||||
|
||||
/* Setup internal structures */
|
||||
|
||||
if (!initialized) {
|
||||
lam_list_init(®istry);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/* All done */
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Add a newly-opened dyanmic module to the registry of open modules.
|
||||
* The module's type, handle, and public struct are saved.
|
||||
*/
|
||||
int mca_base_module_registry_retain(char *type, lt_dlhandle module_handle,
|
||||
mca_base_module_t *module_struct)
|
||||
{
|
||||
registry_item_t *ri;
|
||||
|
||||
/* Allocate a new registry item */
|
||||
|
||||
ri = LAM_MALLOC(sizeof(registry_item_t));
|
||||
if (NULL == ri)
|
||||
return LAM_ERR_OUT_OF_RESOURCE;
|
||||
|
||||
/* Initialize the registry item */
|
||||
|
||||
lam_list_item_init((lam_list_item_t *) ri);
|
||||
strcpy(ri->ri_type, type);
|
||||
ri->ri_dlhandle = module_handle;
|
||||
ri->ri_module_struct = module_struct;
|
||||
ri->ri_refcount = 1;
|
||||
lam_list_init(&ri->ri_dependencies);
|
||||
|
||||
/* Append the new item to the registry */
|
||||
|
||||
lam_list_append(®istry, (lam_list_item_t *) ri);
|
||||
|
||||
/* All done */
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create a dependency from one module entry to another
|
||||
*/
|
||||
int mca_base_module_registry_link(const char *src_type,
|
||||
const char *src_name,
|
||||
const char *depend_type,
|
||||
const char *depend_name)
|
||||
{
|
||||
registry_item_t *src, *depend;
|
||||
|
||||
/* Look up the two modules */
|
||||
|
||||
src = find_module(src_type, src_name);
|
||||
if (NULL == src)
|
||||
return LAM_ERR_BAD_PARAM;
|
||||
depend = find_module(depend_type, depend_name);
|
||||
if (NULL == depend)
|
||||
return LAM_ERR_BAD_PARAM;
|
||||
|
||||
/* Link them */
|
||||
|
||||
return link_items(src, depend);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If it's in the registr, close a specified module and remove it from
|
||||
* the registry.
|
||||
*/
|
||||
void mca_base_module_registry_release(mca_base_module_t *module)
|
||||
{
|
||||
registry_item_t *ri = find_module(module->mca_type_name,
|
||||
module->mca_module_name);
|
||||
if (NULL != ri)
|
||||
release_registry_item(ri);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finalize the registry -- close everything that's still open.
|
||||
*/
|
||||
void mca_base_module_registry_finalize(void)
|
||||
{
|
||||
lam_list_item_t *item;
|
||||
registry_item_t *ri;
|
||||
bool changed;
|
||||
|
||||
if (initialized) {
|
||||
|
||||
/* Have to be slightly careful about this because of dependencies,
|
||||
particularly on OS's where it matters (i.e., closing a module
|
||||
that is depended on by other modules 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 modules 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 {
|
||||
changed = false;
|
||||
for (item = lam_list_get_first(®istry);
|
||||
lam_list_get_last(®istry) != item && changed;
|
||||
item = lam_list_get_next(item)) {
|
||||
ri = (registry_item_t *) ri;
|
||||
|
||||
if (ri->ri_refcount == 1) {
|
||||
release_registry_item(ri);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} while (lam_list_get_size(®istry) > 0 && changed);
|
||||
lam_list_destroy(®istry);
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/* Close down libltdl */
|
||||
|
||||
lt_dlexit();
|
||||
}
|
||||
|
||||
|
||||
static registry_item_t *find_module(const char *type, const char *name)
|
||||
{
|
||||
lam_list_item_t *item;
|
||||
registry_item_t *ri;
|
||||
|
||||
for (item = lam_list_get_first(®istry);
|
||||
lam_list_get_last(®istry) != item;
|
||||
item = lam_list_get_next(item)) {
|
||||
ri = (registry_item_t *) ri;
|
||||
if (0 == strcmp(ri->ri_type, type) &&
|
||||
0 == strcmp(ri->ri_module_struct->mca_module_name, name))
|
||||
return ri;
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int link_items(registry_item_t *src, registry_item_t *depend)
|
||||
{
|
||||
dependency_item_t *di;
|
||||
|
||||
/* Bozo check */
|
||||
|
||||
if (NULL == src || NULL == depend)
|
||||
return LAM_ERR_BAD_PARAM;
|
||||
|
||||
/* Make a new depedency item */
|
||||
|
||||
di = LAM_MALLOC(sizeof(dependency_item_t));
|
||||
if (NULL == di)
|
||||
return LAM_ERR_OUT_OF_RESOURCE;
|
||||
|
||||
/* Initialize the new dependency item */
|
||||
|
||||
lam_list_item_init((lam_list_item_t *) di);
|
||||
di->di_registry_entry = depend;
|
||||
|
||||
/* Add it to the dependency list on the source registry entry */
|
||||
|
||||
lam_list_append(&src->ri_dependencies, (lam_list_item_t *) di);
|
||||
|
||||
/* Increment the refcount in the dependency */
|
||||
|
||||
++src->ri_refcount;
|
||||
|
||||
/* All done */
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void release_registry_item(registry_item_t *ri)
|
||||
{
|
||||
dependency_item_t *di;
|
||||
lam_list_item_t *item;
|
||||
|
||||
/* Bozo check */
|
||||
|
||||
if (NULL == ri)
|
||||
return;
|
||||
|
||||
/* Decrement this module's refcount. If zero, close and free it. */
|
||||
|
||||
--ri->ri_refcount;
|
||||
if (0 == ri->ri_refcount) {
|
||||
lt_dlclose(ri->ri_dlhandle);
|
||||
|
||||
/* Now go release/close (at a minimum: decrement the refcount) any
|
||||
dependencies of this module */
|
||||
|
||||
for (item = lam_list_remove_first(&ri->ri_dependencies);
|
||||
NULL != item;
|
||||
item = lam_list_remove_first(&ri->ri_dependencies)) {
|
||||
di = (dependency_item_t *) item;
|
||||
--di->di_registry_entry->ri_refcount;
|
||||
LAM_FREE(di);
|
||||
}
|
||||
|
||||
/* It should be obvious, but I'll state it anyway because it bit
|
||||
me during debugging: after the dlclose(), the mca_base_module_t
|
||||
pointer is no longer valid because it has [potentially] been
|
||||
unloaded from memory. So don't try to use it. :-) */
|
||||
|
||||
lam_list_destroy(&di->di_registry_entry->ri_dependencies);
|
||||
lam_list_remove_item(®istry, (lam_list_item_t *) ri);
|
||||
LAM_FREE(ri);
|
||||
}
|
||||
}
|
138
src/mca/lam/base/mca_base_open.c
Обычный файл
138
src/mca/lam/base/mca_base_open.c
Обычный файл
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
#include "lam_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#include "lam/mem/malloc.h"
|
||||
#include "lam/util/output.h"
|
||||
#include "mca/mca.h"
|
||||
#include "mca/lam/base/base.h"
|
||||
|
||||
|
||||
/*
|
||||
* Public variables
|
||||
*/
|
||||
int mca_base_param_module_path = -1;
|
||||
|
||||
|
||||
/*
|
||||
* Private functions
|
||||
*/
|
||||
static void set_defaults(lam_output_stream_t *lds);
|
||||
static void parse_verbose(char *e, lam_output_stream_t *lds);
|
||||
|
||||
|
||||
/*
|
||||
* Main MCA initialization.
|
||||
*/
|
||||
int mca_base_open(void)
|
||||
{
|
||||
int param_index;
|
||||
char *value;
|
||||
lam_output_stream_t lds;
|
||||
|
||||
/* Register some params */
|
||||
|
||||
param_index = mca_base_param_register_string("base", NULL, "verbose",
|
||||
"verbose", NULL);
|
||||
param_index = mca_base_param_register_string("base", NULL, "module_path",
|
||||
"module_path", NULL);
|
||||
|
||||
/* What verbosity level do we want? */
|
||||
|
||||
mca_base_param_lookup_string(param_index, &value);
|
||||
memset(&lds, 0, sizeof(lds));
|
||||
parse_verbose(value, &lds);
|
||||
|
||||
set_defaults(&lds);
|
||||
lam_output_reopen(0, &lds);
|
||||
lam_output_verbose(0, 5, " Opening");
|
||||
|
||||
/* Open up the module registry */
|
||||
|
||||
return mca_base_module_registry_init();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Set sane default values for the lds
|
||||
*/
|
||||
static void set_defaults(lam_output_stream_t *lds)
|
||||
{
|
||||
/* Load up defaults */
|
||||
|
||||
lds->lds_is_debugging = false;
|
||||
lds->lds_verbose_level = 0;
|
||||
lds->lds_want_syslog = false;
|
||||
lds->lds_syslog_priority = LOG_INFO;
|
||||
lds->lds_syslog_ident = "lam";
|
||||
lds->lds_want_stdout = false;
|
||||
lds->lds_want_file = false;
|
||||
lds->lds_want_file_append = false;
|
||||
lds->lds_file_suffix = NULL;
|
||||
lds->lds_file_suffix = "mca.txt";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Parse the value of an environment variable describing verbosity
|
||||
*/
|
||||
static void parse_verbose(char *e, lam_output_stream_t *lds)
|
||||
{
|
||||
char *edup = strdup(e);
|
||||
char *ptr = edup, *next;
|
||||
|
||||
/* Now parse the environment variable */
|
||||
|
||||
while (NULL != ptr && strlen(ptr) > 0) {
|
||||
next = strchr(ptr, ',');
|
||||
if (NULL != next)
|
||||
*next = '\0';
|
||||
|
||||
if (0 == strcasecmp(ptr, "syslog"))
|
||||
lds->lds_want_syslog = true;
|
||||
else if (strncasecmp(ptr, "syslogpri:", 10) == 0) {
|
||||
lds->lds_want_syslog = true;
|
||||
if (strcasecmp(ptr + 10, "notice") == 0)
|
||||
lds->lds_syslog_priority = LOG_NOTICE;
|
||||
else if (strcasecmp(ptr + 10, "INFO") == 0)
|
||||
lds->lds_syslog_priority = LOG_INFO;
|
||||
else if (strcasecmp(ptr + 10, "DEBUG") == 0)
|
||||
lds->lds_syslog_priority = LOG_DEBUG;
|
||||
} else if (strncasecmp(ptr, "syslogid:", 9) == 0) {
|
||||
lds->lds_want_syslog = true;
|
||||
lds->lds_syslog_ident = ptr + 9;
|
||||
}
|
||||
|
||||
else if (strcasecmp(ptr, "stdout") == 0)
|
||||
lds->lds_want_stdout = true;
|
||||
else if (strcasecmp(ptr, "stderr") == 0)
|
||||
lds->lds_want_stderr = true;
|
||||
|
||||
else if (strcasecmp(ptr, "file") == 0)
|
||||
lds->lds_want_file = true;
|
||||
else if (strncasecmp(ptr, "file:", 5) == 0) {
|
||||
lds->lds_want_file = true;
|
||||
lds->lds_file_suffix = ptr + 5;
|
||||
} else if (strcasecmp(ptr, "fileappend") == 0) {
|
||||
lds->lds_want_file = true;
|
||||
lds->lds_want_file_append = 1;
|
||||
|
||||
} else if (strncasecmp(ptr, "level", 5) == 0) {
|
||||
lds->lds_verbose_level = 0;
|
||||
if (ptr[5] == ':')
|
||||
lds->lds_verbose_level = atoi(ptr + 6);
|
||||
}
|
||||
|
||||
if (NULL == next)
|
||||
break;
|
||||
ptr = next + 1;
|
||||
}
|
||||
|
||||
LAM_FREE(edup);
|
||||
}
|
496
src/mca/lam/base/mca_base_param.c
Обычный файл
496
src/mca/lam/base/mca_base_param.c
Обычный файл
@ -0,0 +1,496 @@
|
||||
/*
|
||||
* $HEADER$
|
||||
*/
|
||||
|
||||
/** @file **/
|
||||
|
||||
#include "lam_config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "lam/constants.h"
|
||||
#include "lam/lfc/array.h"
|
||||
#include "lam/mem/malloc.h"
|
||||
#include "mca/mca.h"
|
||||
#include "mca/lam/base/mca_base_param.h"
|
||||
|
||||
|
||||
typedef enum {
|
||||
MCA_BASE_PARAM_TYPE_INT,
|
||||
MCA_BASE_PARAM_TYPE_STRING,
|
||||
|
||||
MCA_BASE_PARAM_TYPE_MAX
|
||||
} mca_base_param_type_t;
|
||||
|
||||
struct mca_base_param_t {
|
||||
lam_array_item_t super;
|
||||
|
||||
mca_base_param_type_t mbp_type;
|
||||
char *mbp_type_name;
|
||||
char *mbp_module_name;
|
||||
char *mbp_param_name;
|
||||
char *mbp_full_name;
|
||||
|
||||
int mbp_keyval;
|
||||
char *mbp_env_var_name;
|
||||
|
||||
mca_base_param_storage_t mbp_default_value;
|
||||
};
|
||||
typedef struct mca_base_param_t mca_base_param_t;
|
||||
|
||||
|
||||
/*
|
||||
* local variables
|
||||
*/
|
||||
static lam_array_t mca_base_params;
|
||||
static char *mca_prefix = "LAM_MPI_MCA_";
|
||||
static bool initialized = false;
|
||||
|
||||
|
||||
/*
|
||||
* local functions
|
||||
*/
|
||||
static int param_register(const char *type_name, const char *module_name, const char *param_name,
|
||||
const char *mca_param_name,
|
||||
mca_base_param_type_t type,
|
||||
mca_base_param_storage_t *default_value);
|
||||
static bool param_lookup(int index, mca_base_param_storage_t *storage);
|
||||
static int param_compare(const void *a, const void *b);
|
||||
static void param_free(mca_base_param_t *p);
|
||||
|
||||
|
||||
/**
|
||||
* Register an integer MCA parameter.
|
||||
*
|
||||
* @param type_name The MCA type (string).
|
||||
* @param module_name The name of the module (string).
|
||||
* @param param_name The name of the parameter being registered (string).
|
||||
* @param mca_param_name If NULL, the user-visible name of the
|
||||
* parameter is {type_name}_{module_name}_{param_name}. If this
|
||||
* parameter is non-NULL, it is used instead of the default name.
|
||||
* @param default_value The value that is used for this parameter if
|
||||
* the user does not supply one.
|
||||
*
|
||||
* @retval LAM_ERROR Upon failure to register the parameter.
|
||||
* @retval index Index value that can be used with
|
||||
* mca_base_param_lookup_int() to retrieve the value of the parameter.
|
||||
*
|
||||
* This function registers an integer MCA parameter and associates it
|
||||
* with a specific module.
|
||||
*
|
||||
* In most cases, mca_param_name should be NULL. Only in rare cases
|
||||
* is it necessary (or advisable) to override the default name.
|
||||
*/
|
||||
int mca_base_param_register_int(const char *type_name, const char *module_name,
|
||||
const char *param_name,
|
||||
const char *mca_param_name,
|
||||
int default_value)
|
||||
{
|
||||
mca_base_param_storage_t storage;
|
||||
|
||||
storage.intval = default_value;
|
||||
return param_register(type_name, module_name, param_name, mca_param_name,
|
||||
MCA_BASE_PARAM_TYPE_INT, &storage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a string MCA parameter.
|
||||
*
|
||||
* @param type_name The MCA type (string).
|
||||
* @param module_name The name of the module (string).
|
||||
* @param param_name The name of the parameter being registered (string).
|
||||
* @param mca_param_name If NULL, the user-visible name of the
|
||||
* parameter is {type_name}_{module_name}_{param_name}. If this
|
||||
* parameter is non-NULL, it is used instead of the default name.
|
||||
* @param default_value The value that is used for this parameter if
|
||||
* the user does not supply one.
|
||||
*
|
||||
* @retval LAM_ERROR Upon failure to register the parameter.
|
||||
* @retval index Index value that can be used with
|
||||
* mca_base_param_lookup_string() to retrieve the value of the
|
||||
* parameter.
|
||||
*
|
||||
* This function registers an string MCA parameter and associates it
|
||||
* with a specific module.
|
||||
*
|
||||
* In most cases, mca_param_name should be NULL. Only in rare cases
|
||||
* is it necessary (or advisable) to override the default name.
|
||||
*/
|
||||
int mca_base_param_register_string(const char *type_name,
|
||||
const char *module_name,
|
||||
const char *param_name,
|
||||
const char *mca_param_name,
|
||||
const char *default_value)
|
||||
{
|
||||
mca_base_param_storage_t storage;
|
||||
storage.stringval = strdup(default_value);
|
||||
return param_register(type_name, module_name, param_name, mca_param_name,
|
||||
MCA_BASE_PARAM_TYPE_STRING, &storage);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up an integer MCA parameter.
|
||||
*
|
||||
* @param index Index previous returned from
|
||||
* mca_base_param_register_int().
|
||||
* @param value Pointer to int where the parameter value will be
|
||||
* stored.
|
||||
*
|
||||
* @retvalue LAM_ERROR Upon failure. The contents of value are
|
||||
* undefined.
|
||||
* @retvalue LAM_SUCCESS Upon success. value will be filled with the
|
||||
* parameter's current value.
|
||||
*
|
||||
* The value of a specific MCA parameter can be looked up using the
|
||||
* return value from mca_base_param_register_int().
|
||||
*/
|
||||
int mca_base_param_lookup_int(int index, int *value)
|
||||
{
|
||||
mca_base_param_storage_t storage;
|
||||
|
||||
if (param_lookup(index, &storage)) {
|
||||
*value = storage.intval;
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
return LAM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Look up a string MCA parameter.
|
||||
*
|
||||
* @param index Index previous returned from
|
||||
* mca_base_param_register_string().
|
||||
* @param value Pointer to (char *) where the parameter value will be
|
||||
* stored.
|
||||
*
|
||||
* @retvalue LAM_ERROR Upon failure. The contents of value are
|
||||
* undefined.
|
||||
* @retvalue LAM_SUCCESS Upon success. value will be filled with the
|
||||
* parameter's current value.
|
||||
*
|
||||
* The value of a specific MCA parameter can be looked up using the
|
||||
* return value from mca_base_param_register_string().
|
||||
*/
|
||||
int mca_base_param_lookup_string(int index, char **value)
|
||||
{
|
||||
mca_base_param_storage_t storage;
|
||||
|
||||
if (param_lookup(index, &storage)) {
|
||||
*value = storage.stringval;
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
return LAM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the index for an MCA parameter based on its names.
|
||||
*
|
||||
* @param type_name Name of the type containing the parameter.
|
||||
* @param module_name Name of the module containing the parameter.
|
||||
* @param param_name Name of the parameter.
|
||||
*
|
||||
* @retval LAM_ERROR If the parameter was not found.
|
||||
* @retval index If the parameter was found.
|
||||
*
|
||||
* It is not always convenient to widely propagate a parameter's index
|
||||
* value, or it may be necessary to look up the parameter from a
|
||||
* different module -- where it is not possible to have the return
|
||||
* value from mca_base_param_register_int() or
|
||||
* mca_base_param_register_string(). This function can be used to
|
||||
* look up the index of any registered parameter. The returned index
|
||||
* can be used with mca_base_param_lookup_int() and
|
||||
* mca_base_param_lookup_string().
|
||||
*/
|
||||
int mca_base_param_find(const char *type_name, const char *module_name,
|
||||
const char *param_name)
|
||||
{
|
||||
size_t i, size;
|
||||
mca_base_param_t **array;
|
||||
|
||||
/* Check for bozo cases */
|
||||
|
||||
if (!initialized)
|
||||
return LAM_ERROR;
|
||||
if (NULL == type_name || NULL == param_name)
|
||||
return LAM_ERROR;
|
||||
|
||||
/* Loop through looking for a parameter of a given
|
||||
type/module/param */
|
||||
|
||||
array = (mca_base_param_t**) lam_arr_get_c_array(&mca_base_params, &size);
|
||||
for (i = 0; i < size; ++i) {
|
||||
if (0 == strcmp(type_name, array[i]->mbp_type_name) &&
|
||||
((NULL == module_name && NULL == array[i]->mbp_module_name) ||
|
||||
(NULL != module_name && NULL != array[i]->mbp_module_name &&
|
||||
0 == strcmp(module_name, array[i]->mbp_module_name))) &&
|
||||
0 == strcmp(param_name, array[i]->mbp_param_name))
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Didn't find it */
|
||||
|
||||
return LAM_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Shut down the MCA parameter system (normally only invoked by the
|
||||
* MCA framework itself).
|
||||
*
|
||||
* @returns LAM_SUCCESS This function never fails.
|
||||
*
|
||||
* This function shuts down the MCA parameter registry and frees all
|
||||
* associated memory. No other mca_base_param*() functions can be
|
||||
* invoked after this function.
|
||||
*
|
||||
* This function is normally only invoked by the MCA framework itself
|
||||
* when the process is shutting down (e.g., during MPI_FINALIZE). It
|
||||
* is only documented here for completeness.
|
||||
*/
|
||||
int mca_base_param_finalize(void)
|
||||
{
|
||||
size_t i, size;
|
||||
mca_base_param_t **array;
|
||||
|
||||
if (initialized) {
|
||||
array = (mca_base_param_t**) lam_arr_get_c_array(&mca_base_params, &size);
|
||||
for (i = 0; i < size; ++i)
|
||||
param_free(array[i]);
|
||||
|
||||
lam_arr_destroy(&mca_base_params);
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
return LAM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
static int param_register(const char *type_name, const char *module_name,
|
||||
const char *param_name, const char *mca_param_name,
|
||||
mca_base_param_type_t type,
|
||||
mca_base_param_storage_t *default_value)
|
||||
{
|
||||
size_t i, len;
|
||||
mca_base_param_t param, **array;
|
||||
|
||||
/* Initialize the array if it has never been initialized */
|
||||
|
||||
if (!initialized) {
|
||||
lam_arr_init(&mca_base_params);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
/* Create a parameter entry. If a keyval is to be used, it will be
|
||||
registered elsewhere. We simply assign -1 here. */
|
||||
|
||||
param.mbp_type = type;
|
||||
param.mbp_keyval = -1;
|
||||
|
||||
param.mbp_type_name = strdup(type_name);
|
||||
if (NULL == param.mbp_type_name)
|
||||
return LAM_ERROR;
|
||||
if (NULL != module_name) {
|
||||
param.mbp_module_name = strdup(module_name);
|
||||
if (NULL == param.mbp_module_name) {
|
||||
LAM_FREE(param.mbp_type_name);
|
||||
return LAM_ERROR;
|
||||
}
|
||||
} else
|
||||
param.mbp_module_name = NULL;
|
||||
if (param_name != NULL) {
|
||||
param.mbp_param_name = strdup(param_name);
|
||||
if (NULL == param.mbp_param_name) {
|
||||
LAM_FREE(param.mbp_type_name);
|
||||
LAM_FREE(param.mbp_module_name);
|
||||
return LAM_ERROR;
|
||||
}
|
||||
} else
|
||||
param.mbp_param_name = NULL;
|
||||
|
||||
/* The full parameter name may have been specified by the caller.
|
||||
If it was, use that (only for backwards compatability).
|
||||
Otherwise, derive it from the type, module, and parameter
|
||||
name. */
|
||||
|
||||
param.mbp_env_var_name = NULL;
|
||||
if (MCA_BASE_PARAM_INFO != mca_param_name && NULL != mca_param_name) {
|
||||
param.mbp_full_name = strdup(mca_param_name);
|
||||
} else {
|
||||
len = 16 + strlen(type_name);
|
||||
|
||||
if (NULL != module_name)
|
||||
len += strlen(module_name);
|
||||
if (NULL != param_name)
|
||||
len += strlen(param_name);
|
||||
|
||||
param.mbp_full_name = LAM_MALLOC(len);
|
||||
if (NULL != param.mbp_full_name) {
|
||||
LAM_FREE(param.mbp_type_name);
|
||||
LAM_FREE(param.mbp_module_name);
|
||||
LAM_FREE(param.mbp_param_name);
|
||||
return LAM_ERROR;
|
||||
}
|
||||
strncpy(param.mbp_full_name, type_name, len);
|
||||
|
||||
if (NULL != module_name) {
|
||||
strcat(param.mbp_full_name, "_");
|
||||
strcat(param.mbp_full_name, module_name);
|
||||
}
|
||||
if (NULL != param_name) {
|
||||
strcat(param.mbp_full_name, "_");
|
||||
strcat(param.mbp_full_name, param_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* If mca_param_name isn't MCA_BASE_PARAM_INFO, then it's a
|
||||
lookup-able value. So amcagn the environment variable name as
|
||||
well. */
|
||||
|
||||
if (MCA_BASE_PARAM_INFO != mca_param_name) {
|
||||
len = strlen(param.mbp_full_name) + strlen(mca_prefix) + 16;
|
||||
param.mbp_env_var_name = LAM_MALLOC(len);
|
||||
if (NULL == param.mbp_env_var_name) {
|
||||
LAM_FREE(param.mbp_full_name);
|
||||
LAM_FREE(param.mbp_type_name);
|
||||
LAM_FREE(param.mbp_module_name);
|
||||
LAM_FREE(param.mbp_param_name);
|
||||
return LAM_ERROR;
|
||||
}
|
||||
snprintf(param.mbp_env_var_name, len, "%s%s", mca_prefix,
|
||||
param.mbp_full_name);
|
||||
}
|
||||
|
||||
/* Figure out the default value */
|
||||
|
||||
if (NULL != default_value) {
|
||||
if (MCA_BASE_PARAM_TYPE_STRING == param.mbp_type &&
|
||||
NULL != default_value->stringval)
|
||||
param.mbp_default_value.stringval = strdup(default_value->stringval);
|
||||
else
|
||||
param.mbp_default_value = *default_value;
|
||||
} else
|
||||
memset(¶m.mbp_default_value, 0, sizeof(param.mbp_default_value));
|
||||
|
||||
/* See if this entry is already in the Array */
|
||||
|
||||
array = (mca_base_param_t**) lam_arr_get_c_array(&mca_base_params, &len);
|
||||
for (i = 0; i < len; ++i)
|
||||
if (param_compare(¶m, array[i]) == 0) {
|
||||
|
||||
/* Copy in the new default value to the old entry */
|
||||
|
||||
if (MCA_BASE_PARAM_TYPE_STRING == array[i]->mbp_type &&
|
||||
NULL != array[i]->mbp_default_value.stringval)
|
||||
LAM_FREE(array[i]->mbp_default_value.stringval);
|
||||
if (MCA_BASE_PARAM_TYPE_STRING == param.mbp_type &&
|
||||
NULL != param.mbp_default_value.stringval)
|
||||
array[i]->mbp_default_value.stringval =
|
||||
strdup(param.mbp_default_value.stringval);
|
||||
|
||||
param_free(¶m);
|
||||
return i;
|
||||
}
|
||||
|
||||
/* Add it to the array */
|
||||
|
||||
if (!lam_arr_append_item(&mca_base_params, (lam_object_t*) ¶m))
|
||||
return LAM_ERROR;
|
||||
return lam_arr_get_size(&mca_base_params) - 1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* DO NOT MODIFY THIS FUNCTION WITHOUT ALSO MODIFYING mca_mpi_param.c!
|
||||
*
|
||||
* This function appears in liblam. Because of unix linker semantics,
|
||||
* it's simply easier to essentially duplicate this function in libmpi
|
||||
* because in libmpi, we need to lookup on a keyval before looking in
|
||||
* the environment. The logic is simpler if we just duplicate/alter
|
||||
* the code in mca_mpi_param.c rather than try to make this a) public,
|
||||
* and b) more general (to accomodate looking up keyvals while not
|
||||
* linking to MPI_Comm_get_attr() in libmpi).
|
||||
*/
|
||||
static bool param_lookup(int index, mca_base_param_storage_t *storage)
|
||||
{
|
||||
size_t size;
|
||||
char *env;
|
||||
mca_base_param_t *p;
|
||||
|
||||
/* Lookup the index and see if it's valid */
|
||||
|
||||
if (!initialized)
|
||||
return false;
|
||||
if (lam_arr_get_size(&mca_base_params) < index)
|
||||
return false;
|
||||
p = ((mca_base_param_t*) lam_arr_get_c_array(&mca_base_params,
|
||||
&size)) + index;
|
||||
|
||||
/* We either don't have a keyval or didn't find it. So look in the
|
||||
environment. */
|
||||
|
||||
if (NULL != p->mbp_env_var_name &&
|
||||
NULL != (env = getenv(p->mbp_env_var_name))) {
|
||||
if (MCA_BASE_PARAM_TYPE_INT == p->mbp_type)
|
||||
storage->intval = atoi(env);
|
||||
else if (MCA_BASE_PARAM_TYPE_STRING == p->mbp_type)
|
||||
storage->stringval = strdup(env);
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Didn't find it; use the default value. */
|
||||
|
||||
switch (p->mbp_type) {
|
||||
case MCA_BASE_PARAM_TYPE_INT:
|
||||
storage->intval = p->mbp_default_value.intval;
|
||||
break;
|
||||
|
||||
case MCA_BASE_PARAM_TYPE_STRING:
|
||||
storage->stringval = p->mbp_default_value.stringval;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
/* All done */
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static int param_compare(const void *a, const void *b)
|
||||
{
|
||||
const mca_base_param_t *aa = (const mca_base_param_t*) a;
|
||||
const mca_base_param_t *bb = (const mca_base_param_t*) b;
|
||||
|
||||
return strcmp(aa->mbp_full_name, bb->mbp_full_name);
|
||||
}
|
||||
|
||||
|
||||
static void param_free(mca_base_param_t *p)
|
||||
{
|
||||
if (NULL != p->mbp_type_name)
|
||||
LAM_FREE(p->mbp_type_name);
|
||||
if (NULL != p->mbp_module_name)
|
||||
LAM_FREE(p->mbp_module_name);
|
||||
if (NULL != p->mbp_param_name)
|
||||
LAM_FREE(p->mbp_param_name);
|
||||
if (NULL != p->mbp_env_var_name)
|
||||
LAM_FREE(p->mbp_env_var_name);
|
||||
if (NULL != p->mbp_full_name)
|
||||
LAM_FREE(p->mbp_full_name);
|
||||
if (MCA_BASE_PARAM_TYPE_STRING == p->mbp_type &&
|
||||
NULL != p->mbp_default_value.stringval)
|
||||
LAM_FREE(p->mbp_default_value.stringval);
|
||||
}
|
Загрузка…
x
Ссылка в новой задаче
Block a user