xmrig-minimized-dll/src/3rdparty/hwloc/src/components.c
2020-05-22 20:47:12 +07:00

1087 lines
30 KiB
C

/*
* Copyright © 2009-2020 Inria. All rights reserved.
* Copyright © 2012 Université Bordeaux
* See COPYING in top-level directory.
*/
#include "private/autogen/config.h"
#include "hwloc.h"
#include "private/private.h"
#include "private/xml.h"
#include "private/misc.h"
#define HWLOC_COMPONENT_STOP_NAME "stop"
#define HWLOC_COMPONENT_EXCLUDE_CHAR '-'
#define HWLOC_COMPONENT_SEPS ","
#define HWLOC_COMPONENT_PHASESEP_CHAR ':'
/* list of all registered discovery components, sorted by priority, higher priority first.
* noos is last because its priority is 0.
* others' priority is 10.
*/
static struct hwloc_disc_component * hwloc_disc_components = NULL;
static unsigned hwloc_components_users = 0; /* first one initializes, last ones destroys */
static int hwloc_components_verbose = 0;
#ifdef HWLOC_HAVE_PLUGINS
static int hwloc_plugins_verbose = 0;
static const char * hwloc_plugins_blacklist = NULL;
#endif
/* hwloc_components_mutex serializes:
* - loading/unloading plugins, and modifications of the hwloc_plugins list
* - calls to ltdl, including in hwloc_check_plugin_namespace()
* - registration of components with hwloc_disc_component_register()
* and hwloc_xml_callbacks_register()
*/
#ifdef HWLOC_WIN_SYS
/* Basic mutex on top of InterlockedCompareExchange() on windows,
* Far from perfect, but easy to maintain, and way enough given that this code will never be needed for real. */
#include <windows.h>
static LONG hwloc_components_mutex = 0;
#define HWLOC_COMPONENTS_LOCK() do { \
while (InterlockedCompareExchange(&hwloc_components_mutex, 1, 0) != 0) \
SwitchToThread(); \
} while (0)
#define HWLOC_COMPONENTS_UNLOCK() do { \
assert(hwloc_components_mutex == 1); \
hwloc_components_mutex = 0; \
} while (0)
#elif defined HWLOC_HAVE_PTHREAD_MUTEX
/* pthread mutex if available (except on windows) */
#include <pthread.h>
static pthread_mutex_t hwloc_components_mutex = PTHREAD_MUTEX_INITIALIZER;
#define HWLOC_COMPONENTS_LOCK() pthread_mutex_lock(&hwloc_components_mutex)
#define HWLOC_COMPONENTS_UNLOCK() pthread_mutex_unlock(&hwloc_components_mutex)
#else /* HWLOC_WIN_SYS || HWLOC_HAVE_PTHREAD_MUTEX */
#error No mutex implementation available
#endif
#ifdef HWLOC_HAVE_PLUGINS
#ifdef HWLOC_HAVE_LTDL
/* ltdl-based plugin load */
#include <ltdl.h>
typedef lt_dlhandle hwloc_dlhandle;
#define hwloc_dlinit lt_dlinit
#define hwloc_dlexit lt_dlexit
#define hwloc_dlopenext lt_dlopenext
#define hwloc_dlclose lt_dlclose
#define hwloc_dlerror lt_dlerror
#define hwloc_dlsym lt_dlsym
#define hwloc_dlforeachfile lt_dlforeachfile
#else /* !HWLOC_HAVE_LTDL */
/* no-ltdl plugin load relies on less portable libdl */
#include <dlfcn.h>
typedef void * hwloc_dlhandle;
static __hwloc_inline int hwloc_dlinit(void) { return 0; }
static __hwloc_inline int hwloc_dlexit(void) { return 0; }
#define hwloc_dlclose dlclose
#define hwloc_dlerror dlerror
#define hwloc_dlsym dlsym
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
static hwloc_dlhandle hwloc_dlopenext(const char *_filename)
{
hwloc_dlhandle handle;
char *filename = NULL;
(void) asprintf(&filename, "%s.so", _filename);
if (!filename)
return NULL;
handle = dlopen(filename, RTLD_NOW|RTLD_LOCAL);
free(filename);
return handle;
}
static int
hwloc_dlforeachfile(const char *_paths,
int (*func)(const char *filename, void *data),
void *data)
{
char *paths = NULL, *path;
paths = strdup(_paths);
if (!paths)
return -1;
path = paths;
while (*path) {
char *colon;
DIR *dir;
struct dirent *dirent;
colon = strchr(path, ':');
if (colon)
*colon = '\0';
if (hwloc_plugins_verbose)
fprintf(stderr, " Looking under %s\n", path);
dir = opendir(path);
if (!dir)
goto next;
while ((dirent = readdir(dir)) != NULL) {
char *abs_name, *suffix;
struct stat stbuf;
int err;
err = asprintf(&abs_name, "%s/%s", path, dirent->d_name);
if (err < 0)
continue;
err = stat(abs_name, &stbuf);
if (err < 0) {
free(abs_name);
continue;
}
if (!S_ISREG(stbuf.st_mode)) {
free(abs_name);
continue;
}
/* Only keep .so files, and remove that suffix to get the component basename */
suffix = strrchr(abs_name, '.');
if (!suffix || strcmp(suffix, ".so")) {
free(abs_name);
continue;
}
*suffix = '\0';
err = func(abs_name, data);
if (err) {
free(abs_name);
continue;
}
free(abs_name);
}
closedir(dir);
next:
if (!colon)
break;
path = colon+1;
}
free(paths);
return 0;
}
#endif /* !HWLOC_HAVE_LTDL */
/* array of pointers to dynamically loaded plugins */
static struct hwloc__plugin_desc {
char *name;
struct hwloc_component *component;
char *filename;
hwloc_dlhandle handle;
struct hwloc__plugin_desc *next;
} *hwloc_plugins = NULL;
static int
hwloc__dlforeach_cb(const char *filename, void *_data __hwloc_attribute_unused)
{
const char *basename;
hwloc_dlhandle handle;
struct hwloc_component *component;
struct hwloc__plugin_desc *desc, **prevdesc;
char *componentsymbolname;
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin dlforeach found `%s'\n", filename);
basename = strrchr(filename, '/');
if (!basename)
basename = filename;
else
basename++;
if (hwloc_plugins_blacklist && strstr(hwloc_plugins_blacklist, basename)) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin `%s' is blacklisted in the environment\n", basename);
goto out;
}
/* dlopen and get the component structure */
handle = hwloc_dlopenext(filename);
if (!handle) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Failed to load plugin: %s\n", hwloc_dlerror());
goto out;
}
componentsymbolname = malloc(strlen(basename)+10+1);
if (!componentsymbolname) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Failed to allocation component `%s' symbol\n",
basename);
goto out_with_handle;
}
sprintf(componentsymbolname, "%s_component", basename);
component = hwloc_dlsym(handle, componentsymbolname);
if (!component) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Failed to find component symbol `%s'\n",
componentsymbolname);
free(componentsymbolname);
goto out_with_handle;
}
if (component->abi != HWLOC_COMPONENT_ABI) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin symbol ABI %u instead of %d\n",
component->abi, HWLOC_COMPONENT_ABI);
free(componentsymbolname);
goto out_with_handle;
}
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin contains expected symbol `%s'\n",
componentsymbolname);
free(componentsymbolname);
if (HWLOC_COMPONENT_TYPE_DISC == component->type) {
if (strncmp(basename, "hwloc_", 6)) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin name `%s' doesn't match its type DISCOVERY\n", basename);
goto out_with_handle;
}
} else if (HWLOC_COMPONENT_TYPE_XML == component->type) {
if (strncmp(basename, "hwloc_xml_", 10)) {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin name `%s' doesn't match its type XML\n", basename);
goto out_with_handle;
}
} else {
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin name `%s' has invalid type %u\n",
basename, (unsigned) component->type);
goto out_with_handle;
}
/* allocate a plugin_desc and queue it */
desc = malloc(sizeof(*desc));
if (!desc)
goto out_with_handle;
desc->name = strdup(basename);
desc->filename = strdup(filename);
desc->component = component;
desc->handle = handle;
desc->next = NULL;
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin descriptor `%s' ready\n", basename);
/* append to the list */
prevdesc = &hwloc_plugins;
while (*prevdesc)
prevdesc = &((*prevdesc)->next);
*prevdesc = desc;
if (hwloc_plugins_verbose)
fprintf(stderr, "Plugin descriptor `%s' queued\n", basename);
return 0;
out_with_handle:
hwloc_dlclose(handle);
out:
return 0;
}
static void
hwloc_plugins_exit(void)
{
struct hwloc__plugin_desc *desc, *next;
if (hwloc_plugins_verbose)
fprintf(stderr, "Closing all plugins\n");
desc = hwloc_plugins;
while (desc) {
next = desc->next;
hwloc_dlclose(desc->handle);
free(desc->name);
free(desc->filename);
free(desc);
desc = next;
}
hwloc_plugins = NULL;
hwloc_dlexit();
}
static int
hwloc_plugins_init(void)
{
const char *verboseenv;
const char *path = HWLOC_PLUGINS_PATH;
const char *env;
int err;
verboseenv = getenv("HWLOC_PLUGINS_VERBOSE");
hwloc_plugins_verbose = verboseenv ? atoi(verboseenv) : 0;
hwloc_plugins_blacklist = getenv("HWLOC_PLUGINS_BLACKLIST");
err = hwloc_dlinit();
if (err)
goto out;
env = getenv("HWLOC_PLUGINS_PATH");
if (env)
path = env;
hwloc_plugins = NULL;
if (hwloc_plugins_verbose)
fprintf(stderr, "Starting plugin dlforeach in %s\n", path);
err = hwloc_dlforeachfile(path, hwloc__dlforeach_cb, NULL);
if (err)
goto out_with_init;
return 0;
out_with_init:
hwloc_plugins_exit();
out:
return -1;
}
#endif /* HWLOC_HAVE_PLUGINS */
static int
hwloc_disc_component_register(struct hwloc_disc_component *component,
const char *filename)
{
struct hwloc_disc_component **prev;
/* check that the component name is valid */
if (!strcmp(component->name, HWLOC_COMPONENT_STOP_NAME)) {
if (hwloc_components_verbose)
fprintf(stderr, "Cannot register discovery component with reserved name `" HWLOC_COMPONENT_STOP_NAME "'\n");
return -1;
}
if (strchr(component->name, HWLOC_COMPONENT_EXCLUDE_CHAR)
|| strchr(component->name, HWLOC_COMPONENT_PHASESEP_CHAR)
|| strcspn(component->name, HWLOC_COMPONENT_SEPS) != strlen(component->name)) {
if (hwloc_components_verbose)
fprintf(stderr, "Cannot register discovery component with name `%s' containing reserved characters `%c" HWLOC_COMPONENT_SEPS "'\n",
component->name, HWLOC_COMPONENT_EXCLUDE_CHAR);
return -1;
}
/* check that the component phases are valid */
if (!component->phases
|| (component->phases != HWLOC_DISC_PHASE_GLOBAL
&& component->phases & ~(HWLOC_DISC_PHASE_CPU
|HWLOC_DISC_PHASE_MEMORY
|HWLOC_DISC_PHASE_PCI
|HWLOC_DISC_PHASE_IO
|HWLOC_DISC_PHASE_MISC
|HWLOC_DISC_PHASE_ANNOTATE
|HWLOC_DISC_PHASE_TWEAK))) {
fprintf(stderr, "Cannot register discovery component `%s' with invalid phases 0x%x\n",
component->name, component->phases);
return -1;
}
prev = &hwloc_disc_components;
while (NULL != *prev) {
if (!strcmp((*prev)->name, component->name)) {
/* if two components have the same name, only keep the highest priority one */
if ((*prev)->priority < component->priority) {
/* drop the existing component */
if (hwloc_components_verbose)
fprintf(stderr, "Dropping previously registered discovery component `%s', priority %u lower than new one %u\n",
(*prev)->name, (*prev)->priority, component->priority);
*prev = (*prev)->next;
} else {
/* drop the new one */
if (hwloc_components_verbose)
fprintf(stderr, "Ignoring new discovery component `%s', priority %u lower than previously registered one %u\n",
component->name, component->priority, (*prev)->priority);
return -1;
}
}
prev = &((*prev)->next);
}
if (hwloc_components_verbose)
fprintf(stderr, "Registered discovery component `%s' phases 0x%x with priority %u (%s%s)\n",
component->name, component->phases, component->priority,
filename ? "from plugin " : "statically build", filename ? filename : "");
prev = &hwloc_disc_components;
while (NULL != *prev) {
if ((*prev)->priority < component->priority)
break;
prev = &((*prev)->next);
}
component->next = *prev;
*prev = component;
return 0;
}
#include "static-components.h"
static void (**hwloc_component_finalize_cbs)(unsigned long);
static unsigned hwloc_component_finalize_cb_count;
void
hwloc_components_init(void)
{
#ifdef HWLOC_HAVE_PLUGINS
struct hwloc__plugin_desc *desc;
#endif
const char *verboseenv;
unsigned i;
HWLOC_COMPONENTS_LOCK();
assert((unsigned) -1 != hwloc_components_users);
if (0 != hwloc_components_users++) {
HWLOC_COMPONENTS_UNLOCK();
return;
}
verboseenv = getenv("HWLOC_COMPONENTS_VERBOSE");
hwloc_components_verbose = verboseenv ? atoi(verboseenv) : 0;
#ifdef HWLOC_HAVE_PLUGINS
hwloc_plugins_init();
#endif
hwloc_component_finalize_cbs = NULL;
hwloc_component_finalize_cb_count = 0;
/* count the max number of finalize callbacks */
for(i=0; NULL != hwloc_static_components[i]; i++)
hwloc_component_finalize_cb_count++;
#ifdef HWLOC_HAVE_PLUGINS
for(desc = hwloc_plugins; NULL != desc; desc = desc->next)
hwloc_component_finalize_cb_count++;
#endif
if (hwloc_component_finalize_cb_count) {
hwloc_component_finalize_cbs = calloc(hwloc_component_finalize_cb_count,
sizeof(*hwloc_component_finalize_cbs));
assert(hwloc_component_finalize_cbs);
/* forget that max number and recompute the real one below */
hwloc_component_finalize_cb_count = 0;
}
/* hwloc_static_components is created by configure in static-components.h */
for(i=0; NULL != hwloc_static_components[i]; i++) {
if (hwloc_static_components[i]->flags) {
fprintf(stderr, "Ignoring static component with invalid flags %lx\n",
hwloc_static_components[i]->flags);
continue;
}
/* initialize the component */
if (hwloc_static_components[i]->init && hwloc_static_components[i]->init(0) < 0) {
if (hwloc_components_verbose)
fprintf(stderr, "Ignoring static component, failed to initialize\n");
continue;
}
/* queue ->finalize() callback if any */
if (hwloc_static_components[i]->finalize)
hwloc_component_finalize_cbs[hwloc_component_finalize_cb_count++] = hwloc_static_components[i]->finalize;
/* register for real now */
if (HWLOC_COMPONENT_TYPE_DISC == hwloc_static_components[i]->type)
hwloc_disc_component_register(hwloc_static_components[i]->data, NULL);
else if (HWLOC_COMPONENT_TYPE_XML == hwloc_static_components[i]->type)
hwloc_xml_callbacks_register(hwloc_static_components[i]->data);
else
assert(0);
}
/* dynamic plugins */
#ifdef HWLOC_HAVE_PLUGINS
for(desc = hwloc_plugins; NULL != desc; desc = desc->next) {
if (desc->component->flags) {
fprintf(stderr, "Ignoring plugin `%s' component with invalid flags %lx\n",
desc->name, desc->component->flags);
continue;
}
/* initialize the component */
if (desc->component->init && desc->component->init(0) < 0) {
if (hwloc_components_verbose)
fprintf(stderr, "Ignoring plugin `%s', failed to initialize\n", desc->name);
continue;
}
/* queue ->finalize() callback if any */
if (desc->component->finalize)
hwloc_component_finalize_cbs[hwloc_component_finalize_cb_count++] = desc->component->finalize;
/* register for real now */
if (HWLOC_COMPONENT_TYPE_DISC == desc->component->type)
hwloc_disc_component_register(desc->component->data, desc->filename);
else if (HWLOC_COMPONENT_TYPE_XML == desc->component->type)
hwloc_xml_callbacks_register(desc->component->data);
else
assert(0);
}
#endif
HWLOC_COMPONENTS_UNLOCK();
}
void
hwloc_topology_components_init(struct hwloc_topology *topology)
{
topology->nr_blacklisted_components = 0;
topology->blacklisted_components = NULL;
topology->backends = NULL;
topology->backend_phases = 0;
topology->backend_excluded_phases = 0;
}
/* look for name among components, ignoring things after `:' */
static struct hwloc_disc_component *
hwloc_disc_component_find(const char *name, const char **endp)
{
struct hwloc_disc_component *comp;
size_t length;
const char *end = strchr(name, HWLOC_COMPONENT_PHASESEP_CHAR);
if (end) {
length = end-name;
if (endp)
*endp = end+1;
} else {
length = strlen(name);
if (endp)
*endp = NULL;
}
comp = hwloc_disc_components;
while (NULL != comp) {
if (!strncmp(name, comp->name, length))
return comp;
comp = comp->next;
}
return NULL;
}
static unsigned
hwloc_phases_from_string(const char *s)
{
if (!s)
return ~0U;
if (s[0]<'0' || s[0]>'9') {
if (!strcasecmp(s, "global"))
return HWLOC_DISC_PHASE_GLOBAL;
else if (!strcasecmp(s, "cpu"))
return HWLOC_DISC_PHASE_CPU;
if (!strcasecmp(s, "memory"))
return HWLOC_DISC_PHASE_MEMORY;
if (!strcasecmp(s, "pci"))
return HWLOC_DISC_PHASE_PCI;
if (!strcasecmp(s, "io"))
return HWLOC_DISC_PHASE_IO;
if (!strcasecmp(s, "misc"))
return HWLOC_DISC_PHASE_MISC;
if (!strcasecmp(s, "annotate"))
return HWLOC_DISC_PHASE_ANNOTATE;
if (!strcasecmp(s, "tweak"))
return HWLOC_DISC_PHASE_TWEAK;
return 0;
}
return (unsigned) strtoul(s, NULL, 0);
}
static int
hwloc_disc_component_blacklist_one(struct hwloc_topology *topology,
const char *name)
{
struct hwloc_topology_forced_component_s *blacklisted;
struct hwloc_disc_component *comp;
unsigned phases;
unsigned i;
if (!strcmp(name, "linuxpci") || !strcmp(name, "linuxio")) {
/* replace linuxpci and linuxio with linux (with IO phases)
* for backward compatibility with pre-v2.0 and v2.0 respectively */
if (hwloc_components_verbose)
fprintf(stderr, "Replacing deprecated component `%s' with `linux' IO phases in blacklisting\n", name);
comp = hwloc_disc_component_find("linux", NULL);
phases = HWLOC_DISC_PHASE_PCI | HWLOC_DISC_PHASE_IO | HWLOC_DISC_PHASE_MISC | HWLOC_DISC_PHASE_ANNOTATE;
} else {
/* normal lookup */
const char *end;
comp = hwloc_disc_component_find(name, &end);
phases = hwloc_phases_from_string(end);
}
if (!comp) {
errno = EINVAL;
return -1;
}
if (hwloc_components_verbose)
fprintf(stderr, "Blacklisting component `%s` phases 0x%x\n", comp->name, phases);
for(i=0; i<topology->nr_blacklisted_components; i++) {
if (topology->blacklisted_components[i].component == comp) {
topology->blacklisted_components[i].phases |= phases;
return 0;
}
}
blacklisted = realloc(topology->blacklisted_components, (topology->nr_blacklisted_components+1)*sizeof(*blacklisted));
if (!blacklisted)
return -1;
blacklisted[topology->nr_blacklisted_components].component = comp;
blacklisted[topology->nr_blacklisted_components].phases = phases;
topology->blacklisted_components = blacklisted;
topology->nr_blacklisted_components++;
return 0;
}
int
hwloc_topology_set_components(struct hwloc_topology *topology,
unsigned long flags,
const char *name)
{
if (topology->is_loaded) {
errno = EBUSY;
return -1;
}
if (flags & ~HWLOC_TOPOLOGY_COMPONENTS_FLAG_BLACKLIST) {
errno = EINVAL;
return -1;
}
/* this flag is strictly required for now */
if (flags != HWLOC_TOPOLOGY_COMPONENTS_FLAG_BLACKLIST) {
errno = EINVAL;
return -1;
}
if (!strncmp(name, "all", 3) && name[3] == HWLOC_COMPONENT_PHASESEP_CHAR) {
topology->backend_excluded_phases = hwloc_phases_from_string(name+4);
return 0;
}
return hwloc_disc_component_blacklist_one(topology, name);
}
/* used by set_xml(), set_synthetic(), ... environment variables, ... to force the first backend */
int
hwloc_disc_component_force_enable(struct hwloc_topology *topology,
int envvar_forced,
const char *name,
const void *data1, const void *data2, const void *data3)
{
struct hwloc_disc_component *comp;
struct hwloc_backend *backend;
if (topology->is_loaded) {
errno = EBUSY;
return -1;
}
comp = hwloc_disc_component_find(name, NULL);
if (!comp) {
errno = ENOSYS;
return -1;
}
backend = comp->instantiate(topology, comp, 0U /* force-enabled don't get any phase blacklisting */,
data1, data2, data3);
if (backend) {
int err;
backend->envvar_forced = envvar_forced;
if (topology->backends)
hwloc_backends_disable_all(topology);
err = hwloc_backend_enable(backend);
if (comp->phases == HWLOC_DISC_PHASE_GLOBAL) {
char *env = getenv("HWLOC_ANNOTATE_GLOBAL_COMPONENTS");
if (env && atoi(env))
topology->backend_excluded_phases &= ~HWLOC_DISC_PHASE_ANNOTATE;
}
return err;
} else
return -1;
}
static int
hwloc_disc_component_try_enable(struct hwloc_topology *topology,
struct hwloc_disc_component *comp,
int envvar_forced,
unsigned blacklisted_phases)
{
struct hwloc_backend *backend;
if (!(comp->phases & ~(topology->backend_excluded_phases | blacklisted_phases))) {
/* all this backend phases are already excluded, exclude the backend entirely */
if (hwloc_components_verbose)
/* do not warn if envvar_forced since system-wide HWLOC_COMPONENTS must be silently ignored after set_xml() etc.
*/
fprintf(stderr, "Excluding discovery component `%s' phases 0x%x, conflicts with excludes 0x%x\n",
comp->name, comp->phases, topology->backend_excluded_phases);
return -1;
}
backend = comp->instantiate(topology, comp, topology->backend_excluded_phases | blacklisted_phases,
NULL, NULL, NULL);
if (!backend) {
if (hwloc_components_verbose || envvar_forced)
fprintf(stderr, "Failed to instantiate discovery component `%s'\n", comp->name);
return -1;
}
backend->phases &= ~blacklisted_phases;
backend->envvar_forced = envvar_forced;
return hwloc_backend_enable(backend);
}
void
hwloc_disc_components_enable_others(struct hwloc_topology *topology)
{
struct hwloc_disc_component *comp;
struct hwloc_backend *backend;
int tryall = 1;
const char *_env;
char *env; /* we'll to modify the env value, so duplicate it */
unsigned i;
_env = getenv("HWLOC_COMPONENTS");
env = _env ? strdup(_env) : NULL;
/* blacklist disabled components */
if (env) {
char *curenv = env;
size_t s;
while (*curenv) {
s = strcspn(curenv, HWLOC_COMPONENT_SEPS);
if (s) {
char c;
if (curenv[0] != HWLOC_COMPONENT_EXCLUDE_CHAR)
goto nextname;
/* save the last char and replace with \0 */
c = curenv[s];
curenv[s] = '\0';
/* blacklist it, and just ignore failures to allocate */
hwloc_disc_component_blacklist_one(topology, curenv+1);
/* remove that blacklisted name from the string */
for(i=0; i<s; i++)
curenv[i] = *HWLOC_COMPONENT_SEPS;
/* restore chars (the second loop below needs env to be unmodified) */
curenv[s] = c;
}
nextname:
curenv += s;
if (*curenv)
/* Skip comma */
curenv++;
}
}
/* enable explicitly listed components */
if (env) {
char *curenv = env;
size_t s;
while (*curenv) {
s = strcspn(curenv, HWLOC_COMPONENT_SEPS);
if (s) {
char c;
const char *name;
if (!strncmp(curenv, HWLOC_COMPONENT_STOP_NAME, s)) {
tryall = 0;
break;
}
/* save the last char and replace with \0 */
c = curenv[s];
curenv[s] = '\0';
name = curenv;
if (!strcmp(name, "linuxpci") || !strcmp(name, "linuxio")) {
if (hwloc_components_verbose)
fprintf(stderr, "Replacing deprecated component `%s' with `linux' in envvar forcing\n", name);
name = "linux";
}
comp = hwloc_disc_component_find(name, NULL /* we enable the entire component, phases must be blacklisted separately */);
if (comp) {
unsigned blacklisted_phases = 0U;
for(i=0; i<topology->nr_blacklisted_components; i++)
if (comp == topology->blacklisted_components[i].component) {
blacklisted_phases = topology->blacklisted_components[i].phases;
break;
}
if (comp->phases & ~blacklisted_phases)
hwloc_disc_component_try_enable(topology, comp, 1 /* envvar forced */, blacklisted_phases);
} else {
fprintf(stderr, "Cannot find discovery component `%s'\n", name);
}
/* restore chars (the second loop below needs env to be unmodified) */
curenv[s] = c;
}
curenv += s;
if (*curenv)
/* Skip comma */
curenv++;
}
}
/* env is still the same, the above loop didn't modify it */
/* now enable remaining components (except the explicitly '-'-listed ones) */
if (tryall) {
comp = hwloc_disc_components;
while (NULL != comp) {
unsigned blacklisted_phases = 0U;
if (!comp->enabled_by_default)
goto nextcomp;
/* check if this component was blacklisted by the application */
for(i=0; i<topology->nr_blacklisted_components; i++)
if (comp == topology->blacklisted_components[i].component) {
blacklisted_phases = topology->blacklisted_components[i].phases;
break;
}
if (!(comp->phases & ~blacklisted_phases)) {
if (hwloc_components_verbose)
fprintf(stderr, "Excluding blacklisted discovery component `%s' phases 0x%x\n",
comp->name, comp->phases);
goto nextcomp;
}
hwloc_disc_component_try_enable(topology, comp, 0 /* defaults, not envvar forced */, blacklisted_phases);
nextcomp:
comp = comp->next;
}
}
if (hwloc_components_verbose) {
/* print a summary */
int first = 1;
backend = topology->backends;
fprintf(stderr, "Final list of enabled discovery components: ");
while (backend != NULL) {
fprintf(stderr, "%s%s(0x%x)", first ? "" : ",", backend->component->name, backend->phases);
backend = backend->next;
first = 0;
}
fprintf(stderr, "\n");
}
free(env);
}
void
hwloc_components_fini(void)
{
unsigned i;
HWLOC_COMPONENTS_LOCK();
assert(0 != hwloc_components_users);
if (0 != --hwloc_components_users) {
HWLOC_COMPONENTS_UNLOCK();
return;
}
for(i=0; i<hwloc_component_finalize_cb_count; i++)
hwloc_component_finalize_cbs[hwloc_component_finalize_cb_count-i-1](0);
free(hwloc_component_finalize_cbs);
hwloc_component_finalize_cbs = NULL;
hwloc_component_finalize_cb_count = 0;
/* no need to unlink/free the list of components, they'll be unloaded below */
hwloc_disc_components = NULL;
hwloc_xml_callbacks_reset();
#ifdef HWLOC_HAVE_PLUGINS
hwloc_plugins_exit();
#endif
HWLOC_COMPONENTS_UNLOCK();
}
struct hwloc_backend *
hwloc_backend_alloc(struct hwloc_topology *topology,
struct hwloc_disc_component *component)
{
struct hwloc_backend * backend = malloc(sizeof(*backend));
if (!backend) {
errno = ENOMEM;
return NULL;
}
backend->component = component;
backend->topology = topology;
/* filter-out component phases that are excluded */
backend->phases = component->phases & ~topology->backend_excluded_phases;
if (backend->phases != component->phases && hwloc_components_verbose)
fprintf(stderr, "Trying discovery component `%s' with phases 0x%x instead of 0x%x\n",
component->name, backend->phases, component->phases);
backend->flags = 0;
backend->discover = NULL;
backend->get_pci_busid_cpuset = NULL;
backend->disable = NULL;
backend->is_thissystem = -1;
backend->next = NULL;
backend->envvar_forced = 0;
return backend;
}
static void
hwloc_backend_disable(struct hwloc_backend *backend)
{
if (backend->disable)
backend->disable(backend);
free(backend);
}
int
hwloc_backend_enable(struct hwloc_backend *backend)
{
struct hwloc_topology *topology = backend->topology;
struct hwloc_backend **pprev;
/* check backend flags */
if (backend->flags) {
fprintf(stderr, "Cannot enable discovery component `%s' phases 0x%x with unknown flags %lx\n",
backend->component->name, backend->component->phases, backend->flags);
return -1;
}
/* make sure we didn't already enable this backend, we don't want duplicates */
pprev = &topology->backends;
while (NULL != *pprev) {
if ((*pprev)->component == backend->component) {
if (hwloc_components_verbose)
fprintf(stderr, "Cannot enable discovery component `%s' phases 0x%x twice\n",
backend->component->name, backend->component->phases);
hwloc_backend_disable(backend);
errno = EBUSY;
return -1;
}
pprev = &((*pprev)->next);
}
if (hwloc_components_verbose)
fprintf(stderr, "Enabling discovery component `%s' with phases 0x%x (among 0x%x)\n",
backend->component->name, backend->phases, backend->component->phases);
/* enqueue at the end */
pprev = &topology->backends;
while (NULL != *pprev)
pprev = &((*pprev)->next);
backend->next = *pprev;
*pprev = backend;
topology->backend_phases |= backend->component->phases;
topology->backend_excluded_phases |= backend->component->excluded_phases;
return 0;
}
void
hwloc_backends_is_thissystem(struct hwloc_topology *topology)
{
struct hwloc_backend *backend;
const char *local_env;
/*
* If the application changed the backend with set_foo(),
* it may use set_flags() update the is_thissystem flag here.
* If it changes the backend with environment variables below,
* it may use HWLOC_THISSYSTEM envvar below as well.
*/
topology->is_thissystem = 1;
/* apply thissystem from normally-given backends (envvar_forced=0, either set_foo() or defaults) */
backend = topology->backends;
while (backend != NULL) {
if (backend->envvar_forced == 0 && backend->is_thissystem != -1) {
assert(backend->is_thissystem == 0);
topology->is_thissystem = 0;
}
backend = backend->next;
}
/* override set_foo() with flags */
if (topology->flags & HWLOC_TOPOLOGY_FLAG_IS_THISSYSTEM)
topology->is_thissystem = 1;
/* now apply envvar-forced backend (envvar_forced=1) */
backend = topology->backends;
while (backend != NULL) {
if (backend->envvar_forced == 1 && backend->is_thissystem != -1) {
assert(backend->is_thissystem == 0);
topology->is_thissystem = 0;
}
backend = backend->next;
}
/* override with envvar-given flag */
local_env = getenv("HWLOC_THISSYSTEM");
if (local_env)
topology->is_thissystem = atoi(local_env);
}
void
hwloc_backends_find_callbacks(struct hwloc_topology *topology)
{
struct hwloc_backend *backend = topology->backends;
/* use the first backend's get_pci_busid_cpuset callback */
topology->get_pci_busid_cpuset_backend = NULL;
while (backend != NULL) {
if (backend->get_pci_busid_cpuset) {
topology->get_pci_busid_cpuset_backend = backend;
return;
}
backend = backend->next;
}
return;
}
void
hwloc_backends_disable_all(struct hwloc_topology *topology)
{
struct hwloc_backend *backend;
while (NULL != (backend = topology->backends)) {
struct hwloc_backend *next = backend->next;
if (hwloc_components_verbose)
fprintf(stderr, "Disabling discovery component `%s'\n",
backend->component->name);
hwloc_backend_disable(backend);
topology->backends = next;
}
topology->backends = NULL;
topology->backend_excluded_phases = 0;
}
void
hwloc_topology_components_fini(struct hwloc_topology *topology)
{
/* hwloc_backends_disable_all() must have been called earlier */
assert(!topology->backends);
free(topology->blacklisted_components);
}