1
1

dlopen: simple dl component based on POSIX dlopen

Works on systems with dlopen (e.g., Linux and OS X).  It requires
dlfcn.h and libdl, which many systems have installed by default.
Этот коммит содержится в:
Jeff Squyres 2015-02-18 10:23:59 -08:00
родитель e81c070ef0
Коммит 7d340c0c26
5 изменённых файлов: 509 добавлений и 0 удалений

23
opal/mca/dl/dlopen/Makefile.am Обычный файл
Просмотреть файл

@ -0,0 +1,23 @@
#
# Copyright (c) 2004-2010 The Trustees of Indiana University.
# All rights reserved.
# Copyright (c) 2014-2015 Cisco Systems, Inc. All rights reserved.
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
sources = \
dl_dlopen.h \
dl_dlopen_component.c \
dl_dlopen_module.c
# This component will only ever be built statically -- never as a DSO.
noinst_LTLIBRARIES = libmca_dl_dlopen.la
libmca_dl_dlopen_la_SOURCES = $(sources)
libmca_dl_dlopen_la_LDFLAGS = -module -avoid-version
libmca_dl_dlopen_la_LIBS = $(opal_dl_dlopen_LIBS)

55
opal/mca/dl/dlopen/configure.m4 Обычный файл
Просмотреть файл

@ -0,0 +1,55 @@
# -*- shell-script -*-
#
# Copyright (c) 2009-2015 Cisco Systems, Inc. All rights reserved.
#
# $COPYRIGHT$
#
# Additional copyrights may follow
#
# $HEADER$
#
AC_DEFUN([MCA_opal_dl_dlopen_PRIORITY], [80])
#
# Force this component to compile in static-only mode
#
AC_DEFUN([MCA_opal_dl_dlopen_COMPILE_MODE], [
AC_MSG_CHECKING([for MCA component $2:$3 compile mode])
$4="static"
AC_MSG_RESULT([$$4])
])
# MCA_dl_dlopen_CONFIG([action-if-can-compile],
# [action-if-cant-compile])
# ------------------------------------------------
AC_DEFUN([MCA_opal_dl_dlopen_CONFIG],[
AC_CONFIG_FILES([opal/mca/dl/dlopen/Makefile])
dnl This is effectively a back-door for Open MPI developers to
dnl force the use of the libltdl dl component.
AC_ARG_ENABLE([dl-dlopen],
[AS_HELP_STRING([--disable-dl-dlopen],
[Disable the "dlopen" DL component (and probably force the use of the "libltdl" DL component). This option should really only be used by Open MPI developers. You are probably actually looking for the "--disable-dlopen" option, which disables all dlopen-like functionality from Open MPI.])
])
opal_dl_dlopen_happy=no
AS_IF([test "$enable_dl_dlopen" != "no"],
[OPAL_CHECK_PACKAGE([opal_dl_dlopen],
[dlfcn.h],
[dl],
[dlopen],
[],
[],
[],
[opal_dl_dlopen_happy=yes],
[opal_dl_dlopen_happy=no])
])
AS_IF([test "$opal_dl_dlopen_happy" = "yes"],
[opal_dl_dlopen_ADD_LIBS=$opal_dl_dlopen_LIBS
$1],
[$2])
AC_SUBST(opal_dl_dlopen_LIBS)
])

40
opal/mca/dl/dlopen/dl_dlopen.h Обычный файл
Просмотреть файл

@ -0,0 +1,40 @@
/*
* Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#ifndef OPAL_DL_DLOPEN
#define OPAL_DL_DLOPEN
#include "opal_config.h"
#include "opal/mca/dl/dl.h"
OPAL_DECLSPEC extern opal_dl_base_module_t opal_dl_dlopen_module;
/*
* Dynamic library handles generated by this component.
*
* If we're debugging, keep a copy of the name of the file we've opened.
*/
struct opal_dl_handle_t {
void *dlopen_handle;
#if OPAL_ENABLE_DEBUG
void *filename;
#endif
};
typedef struct {
opal_dl_base_component_t base;
char *filename_suffixes_mca_storage;
char **filename_suffixes;
} opal_dl_dlopen_component_t;
OPAL_DECLSPEC extern opal_dl_dlopen_component_t mca_dl_dlopen_component;
#endif /* OPAL_DL_DLOPEN */

128
opal/mca/dl/dlopen/dl_dlopen_component.c Обычный файл
Просмотреть файл

@ -0,0 +1,128 @@
/*
* Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include "opal/constants.h"
#include "opal/mca/dl/dl.h"
#include "opal/util/argv.h"
#include "dl_dlopen.h"
/*
* Public string showing the sysinfo ompi_linux component version number
*/
const char *opal_dl_dlopen_component_version_string =
"OPAL dl dlopen MCA component version " OPAL_VERSION;
/*
* Local functions
*/
static int dlopen_component_register(void);
static int dlopen_component_open(void);
static int dlopen_component_close(void);
static int dlopen_component_query(mca_base_module_t **module, int *priority);
/*
* Instantiate the public struct with all of our public information
* and pointers to our public functions in it
*/
opal_dl_dlopen_component_t mca_dl_dlopen_component = {
/* Fill in the mca_dl_base_component_t */
.base = {
/* First, the mca_component_t struct containing meta information
about the component itself */
.base_version = {
OPAL_DL_BASE_VERSION_1_0_0,
/* Component name and version */
"dlopen",
OPAL_MAJOR_VERSION,
OPAL_MINOR_VERSION,
OPAL_RELEASE_VERSION,
/* Component functions */
.mca_register_component_params = dlopen_component_register,
.mca_open_component = dlopen_component_open,
.mca_close_component = dlopen_component_close,
.mca_query_component = dlopen_component_query,
},
.base_data = {
/* The component is checkpoint ready */
MCA_BASE_METADATA_PARAM_CHECKPOINT
},
/* The dl framework members */
.priority = 80
},
/* Now fill in the dlopen component-specific members */
.filename_suffixes_mca_storage = ".so,.dylib,.dll,.sl",
.filename_suffixes = NULL
};
static int dlopen_component_register(void)
{
int ret;
ret =
mca_base_component_var_register(&mca_dl_dlopen_component.base.base_version,
"filename_suffixes",
"Comma-delimited list of filename suffixes that the dlopen component will try",
MCA_BASE_VAR_TYPE_STRING,
NULL,
0,
MCA_BASE_VAR_FLAG_SETTABLE,
OPAL_INFO_LVL_5,
MCA_BASE_VAR_SCOPE_LOCAL,
&mca_dl_dlopen_component.filename_suffixes_mca_storage);
if (ret < 0) {
return ret;
}
mca_dl_dlopen_component.filename_suffixes =
opal_argv_split(mca_dl_dlopen_component.filename_suffixes_mca_storage,
',');
return OPAL_SUCCESS;
}
static int dlopen_component_open(void)
{
return OPAL_SUCCESS;
}
static int dlopen_component_close(void)
{
if (NULL != mca_dl_dlopen_component.filename_suffixes) {
opal_argv_free(mca_dl_dlopen_component.filename_suffixes);
mca_dl_dlopen_component.filename_suffixes = NULL;
}
return OPAL_SUCCESS;
}
static int dlopen_component_query(mca_base_module_t **module, int *priority)
{
/* The priority value is somewhat meaningless here; by
opal/mca/dl/configure.m4, there's at most one component
available. */
*priority = mca_dl_dlopen_component.base.priority;
*module = &opal_dl_dlopen_module.super;
return OPAL_SUCCESS;
}

263
opal/mca/dl/dlopen/dl_dlopen_module.c Обычный файл
Просмотреть файл

@ -0,0 +1,263 @@
/*
* Copyright (c) 2015 Cisco Systems, Inc. All rights reserved.
* $COPYRIGHT$
*
* Additional copyrights may follow
*
* $HEADER$
*/
#include "opal_config.h"
#include <stdlib.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include "opal/constants.h"
#include "opal/mca/dl/dl.h"
#include "opal/util/argv.h"
#include "dl_dlopen.h"
/*
* Trivial helper function to avoid replicating code
*/
static void do_dlopen(const char *fname, int flags,
void **handle, char **err_msg)
{
assert(fname);
assert(handle);
*handle = dlopen(fname, flags);
if (NULL != err_msg) {
if (NULL != *handle) {
*err_msg = NULL;
} else {
*err_msg = dlerror();
}
}
}
static int dlopen_open(const char *fname, bool use_ext, bool private_namespace,
opal_dl_handle_t **handle, char **err_msg)
{
assert(fname);
assert(handle);
*handle = NULL;
/* Setup the dlopen flags */
int flags = RTLD_LAZY;
if (private_namespace) {
flags |= RTLD_LOCAL;
} else {
flags |= RTLD_GLOBAL;
}
/* If the caller wants to use filename extensions, loop through
them */
void *local_handle = NULL;
if (use_ext) {
int i;
char *ext;
for (i = 0, ext = mca_dl_dlopen_component.filename_suffixes[i];
NULL != ext;
ext = mca_dl_dlopen_component.filename_suffixes[++i]) {
char *name;
asprintf(&name, "%s%s", fname, ext);
if (NULL == name) {
return OPAL_ERR_IN_ERRNO;
}
/* Does the file exist? */
struct stat buf;
if (stat(name, &buf) < 0) {
free(name);
if (NULL != err_msg) {
*err_msg = "File not found";
}
continue;
}
/* Yes, the file exists -- try to dlopen it. If we can't
dlopen it, bail. */
do_dlopen(name, flags, &local_handle, err_msg);
free(name);
break;
}
}
/* Otherwise, the caller does not want to use filename extensions,
so just use the single filename that the caller provided */
else {
do_dlopen(fname, flags, &local_handle, err_msg);
}
if (NULL != local_handle) {
*handle = calloc(1, sizeof(opal_dl_handle_t));
(*handle)->dlopen_handle = local_handle;
#if OPAL_ENABLE_DEBUG
(*handle)->filename = strdup(fname);
#endif
}
return (NULL != local_handle) ? OPAL_SUCCESS : OPAL_ERROR;
}
static int dlopen_lookup(opal_dl_handle_t *handle, const char *symbol,
void **ptr, char **err_msg)
{
assert(handle);
assert(handle->dlopen_handle);
assert(symbol);
assert(ptr);
*ptr = dlsym(handle->dlopen_handle, symbol);
if (NULL != *ptr) {
return OPAL_SUCCESS;
}
if (NULL != err_msg) {
*err_msg = dlerror();
}
return OPAL_ERROR;
}
static int dlopen_close(opal_dl_handle_t *handle)
{
assert(handle);
int ret;
ret = dlclose(handle->dlopen_handle);
#if OPAL_ENABLE_DEBUG
free(handle->filename);
#endif
free(handle);
return ret;
}
/*
* Scan all the files in a directory (or path) and invoke a callback
* on each one.
*/
static int dlopen_foreachfile(const char *search_path,
int (*func)(const char *filename, void *data),
void *data)
{
int ret;
DIR *dp = NULL;
char **dirs = NULL;
char **good_files = NULL;
dirs = opal_argv_split(search_path, OPAL_ENV_SEP);
for (int i = 0; NULL != dirs[i]; ++i) {
dp = opendir(dirs[i]);
if (NULL == dp) {
return OPAL_ERR_IN_ERRNO;
}
struct dirent *de;
while (NULL != (de = readdir(dp))) {
/* Make the absolute path name */
char *abs_name = NULL;
asprintf(&abs_name, "%s/%s", dirs[i], de->d_name);
if (NULL == abs_name) {
ret = OPAL_ERR_IN_ERRNO;
goto error;
}
/* Stat the file */
struct stat buf;
if (stat(abs_name, &buf) < 0) {
free(abs_name);
ret = OPAL_ERR_IN_ERRNO;
goto error;
}
/* Skip if not a file */
if (!S_ISREG(buf.st_mode)) {
free(abs_name);
continue;
}
/* Find the suffix */
char *ptr = strrchr(abs_name, '.');
if (NULL != ptr) {
/* Skip libtool files */
if (strcmp(ptr, ".la") == 0 ||
strcmp(ptr, ".lo") == 0) {
continue;
}
*ptr = '\0';
}
/* Have we already found this file? Or already found a
file with the same basename (but different suffix)? */
if (NULL != good_files) {
for (int j = 0; NULL != good_files[j]; ++j) {
if (strcmp(good_files[j], abs_name) == 0) {
free(abs_name);
continue;
}
}
}
opal_argv_append_nosize(&good_files, abs_name);
free(abs_name);
}
}
closedir(dp);
dp = NULL;
/* Invoke the callback on all the found files */
if (NULL != good_files) {
for (int i = 0; NULL != good_files[i]; ++i) {
ret = func(good_files[i], data);
if (OPAL_SUCCESS != ret) {
goto error;
}
}
}
ret = OPAL_SUCCESS;
error:
if (NULL != dp) {
closedir(dp);
}
if (NULL != dirs) {
opal_argv_free(dirs);
}
if (NULL != good_files) {
opal_argv_free(good_files);
}
return ret;
}
/*
* Module definition
*/
opal_dl_base_module_t opal_dl_dlopen_module = {
.open = dlopen_open,
.lookup = dlopen_lookup,
.close = dlopen_close,
.foreachfile = dlopen_foreachfile
};