Mercurial > hg > svcore
changeset 1165:d57f9344db19
Check for plugin loadability before trying to load in the main process (POSIX only so far)
author | Chris Cannam |
---|---|
date | Mon, 11 Jan 2016 14:18:56 +0000 |
parents | 0f90a357cb2a |
children | 4607603c46d0 |
files | plugin/FeatureExtractionPluginFactory.cpp plugin/FeatureExtractionPluginFactory.h system/System.cpp system/System.h |
diffstat | 4 files changed, 126 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/plugin/FeatureExtractionPluginFactory.cpp Fri Jan 08 15:39:12 2016 +0000 +++ b/plugin/FeatureExtractionPluginFactory.cpp Mon Jan 11 14:18:56 2016 +0000 @@ -136,13 +136,59 @@ } vector<QString> +FeatureExtractionPluginFactory::winnowPluginCandidates(vector<QString> candidates) +{ + vector<QString> good, bad; + vector<PluginLoadStatus> badStatuses; + + for (QString c: candidates) { + + PluginLoadStatus status = + TestPluginLoadability(c, "vampGetPluginDescriptor"); + + if (status == PluginLoadOK) { + good.push_back(c); + } else if (status == UnknownPluginLoadStatus) { + cerr << "WARNING: Unknown load status for plugin candidate \"" + << c << "\", continuing" << endl; + good.push_back(c); + } else { + bad.push_back(c); + badStatuses.push_back(status); + } + } + + if (!bad.empty()) { + QString warningMessage = "<b>Failed to load plugins</b></p>Failed to load one or more plugin libraries:</p><ul>\n"; + for (int i = 0; i < bad.size(); ++i) { + QString m; + if (badStatuses[i] == PluginLoadFailedToLoadLibrary) { + m = "Failed to load library"; + } else if (badStatuses[i] == PluginLoadFailedToFindDescriptor) { + m = "Failed to query plugins from library after loading"; + } else if (badStatuses[i] == PluginLoadFailedElsewhere) { + m = "Unknown failure"; + } else { + m = "Success: internal error?"; + } + warningMessage += QString("<li>%1 (%2)</li>\n") + .arg(bad[i]) + .arg(m); + } + warningMessage += "</ul>"; + cerr << warningMessage; //!!! for now! + } + return good; +} + +vector<QString> FeatureExtractionPluginFactory::getPluginIdentifiers() { Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers"); vector<QString> rv; - vector<QString> candidates = getPluginCandidateFiles(); - + vector<QString> candidates = winnowPluginCandidates(getPluginCandidateFiles()); + for (QString soname : candidates) { #ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
--- a/plugin/FeatureExtractionPluginFactory.h Fri Jan 08 15:39:12 2016 +0000 +++ b/plugin/FeatureExtractionPluginFactory.h Mon Jan 11 14:18:56 2016 +0000 @@ -57,8 +57,9 @@ friend class PluginDeletionNotifyAdapter; void pluginDeleted(Vamp::Plugin *); std::map<Vamp::Plugin *, void *> m_handleMap; - + std::vector<QString> getPluginCandidateFiles(); + std::vector<QString> winnowPluginCandidates(std::vector<QString> candidates); void generateTaxonomy(); };
--- a/system/System.cpp Fri Jan 08 15:39:12 2016 +0000 +++ b/system/System.cpp Mon Jan 11 14:18:56 2016 +0000 @@ -325,3 +325,64 @@ double princarg(double a) { return mod(a + M_PI, -2 * M_PI) + M_PI; } float princargf(float a) { return float(princarg(a)); } +#ifndef _WIN32 + +#include <unistd.h> +#include <sys/wait.h> + +PluginLoadStatus +TestPluginLoadability(QString soname, QString descriptorFn) +{ + //!!! This is POSIX only, no equivalent on Windows, where we'll + //!!! have to do something completely different + + pid_t pid = fork(); + + if (pid < 0) { + return UnknownPluginLoadStatus; // fork failed + } + + if (pid == 0) { // the child process + + void *handle = DLOPEN(soname, RTLD_NOW | RTLD_LOCAL); + if (!handle) { + cerr << "isPluginLibraryLoadable: Failed to open plugin library \"" + << soname << "\": " << dlerror() << "\n"; + cerr << "exiting with status 1" << endl; + exit(1); + } + + void *fn = DLSYM(handle, descriptorFn.toLocal8Bit().data()); + if (!fn) { + cerr << "isPluginLibraryLoadable: Failed to find plugin descriptor function \"" << descriptorFn << "\" in library \"" << soname << "\": " << dlerror() << "\n"; + exit(2); + } + + exit(0); + + } else { // the parent process + + int status = 0; + + do { + waitpid(pid, &status, 0); + } while (WIFSTOPPED(status)); + + if (WIFEXITED(status)) { + switch (WEXITSTATUS(status)) { + case 0: return PluginLoadOK; // success + case 1: return PluginLoadFailedToLoadLibrary; + case 2: return PluginLoadFailedToFindDescriptor; + default: return PluginLoadFailedElsewhere; + } + } + + if (WIFSIGNALED(status)) { + return PluginLoadFailedElsewhere; + } + + return UnknownPluginLoadStatus; + } +} + +#endif
--- a/system/System.h Fri Jan 08 15:39:12 2016 +0000 +++ b/system/System.h Mon Jan 11 14:18:56 2016 +0000 @@ -154,6 +154,21 @@ extern void StoreStartupLocale(); extern void RestoreStartupLocale(); +enum PluginLoadStatus { + UnknownPluginLoadStatus, + PluginLoadOK, + PluginLoadFailedToLoadLibrary, + PluginLoadFailedToFindDescriptor, + PluginLoadFailedElsewhere +}; + +// Check whether a plugin library is loadable without crashing (may +// need to spawn an external process to do it). Descriptor fn is the +// name of a LADSPA/DSSI/Vamp-style descriptor function to try +// calling; may be an empty string if the plugin doesn't follow that +// convention. +PluginLoadStatus TestPluginLoadability(QString soname, QString descriptorFn); + #include <cmath> #ifndef M_PI