/* * 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 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 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 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 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 #include #include #include 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; inr_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; inr_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; inr_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; icomponent = 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); }