# HG changeset patch
# User Chris Cannam
# Date 1452521936 0
# Node ID d57f9344db19b1508397ac4563415f74178fa457
# Parent 0f90a357cb2ac9fe749700ddd25db248f35c781b
Check for plugin loadability before trying to load in the main process (POSIX only so far)
diff -r 0f90a357cb2a -r d57f9344db19 plugin/FeatureExtractionPluginFactory.cpp
--- 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
+FeatureExtractionPluginFactory::winnowPluginCandidates(vector candidates)
+{
+ vector good, bad;
+ vector 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 = "Failed to load plugins
Failed to load one or more plugin libraries:\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("- %1 (%2)
\n")
+ .arg(bad[i])
+ .arg(m);
+ }
+ warningMessage += "
";
+ cerr << warningMessage; //!!! for now!
+ }
+ return good;
+}
+
+vector
FeatureExtractionPluginFactory::getPluginIdentifiers()
{
Profiler profiler("FeatureExtractionPluginFactory::getPluginIdentifiers");
vector rv;
- vector candidates = getPluginCandidateFiles();
-
+ vector candidates = winnowPluginCandidates(getPluginCandidateFiles());
+
for (QString soname : candidates) {
#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE
diff -r 0f90a357cb2a -r d57f9344db19 plugin/FeatureExtractionPluginFactory.h
--- 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 m_handleMap;
-
+
std::vector getPluginCandidateFiles();
+ std::vector winnowPluginCandidates(std::vector candidates);
void generateTaxonomy();
};
diff -r 0f90a357cb2a -r d57f9344db19 system/System.cpp
--- 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
+#include
+
+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
diff -r 0f90a357cb2a -r d57f9344db19 system/System.h
--- 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
#ifndef M_PI