Mercurial > hg > vamp-plugin-load-checker
comparison plugincandidates.cpp @ 6:61dbb18f2369
Logging, timeouts
author | Chris Cannam |
---|---|
date | Wed, 13 Apr 2016 18:41:49 +0100 |
parents | 74064d6f5e07 |
children |
comparison
equal
deleted
inserted
replaced
5:74064d6f5e07 | 6:61dbb18f2369 |
---|---|
33 #include <stdexcept> | 33 #include <stdexcept> |
34 #include <iostream> | 34 #include <iostream> |
35 | 35 |
36 #include <QProcess> | 36 #include <QProcess> |
37 #include <QDir> | 37 #include <QDir> |
38 #include <QTime> | |
38 | 39 |
39 #if defined(_WIN32) | 40 #if defined(_WIN32) |
40 #define PLUGIN_GLOB "*.dll" | 41 #define PLUGIN_GLOB "*.dll" |
41 #elif defined(__APPLE__) | 42 #elif defined(__APPLE__) |
42 #define PLUGIN_GLOB "*.dylib *.so" | 43 #define PLUGIN_GLOB "*.dylib *.so" |
45 #endif | 46 #endif |
46 | 47 |
47 using namespace std; | 48 using namespace std; |
48 | 49 |
49 PluginCandidates::PluginCandidates(string helperExecutableName) : | 50 PluginCandidates::PluginCandidates(string helperExecutableName) : |
50 m_helper(helperExecutableName) | 51 m_helper(helperExecutableName), |
51 { | 52 m_logCallback(0) |
53 { | |
54 } | |
55 | |
56 void | |
57 PluginCandidates::setLogCallback(LogCallback *cb) | |
58 { | |
59 m_logCallback = cb; | |
52 } | 60 } |
53 | 61 |
54 vector<string> | 62 vector<string> |
55 PluginCandidates::getCandidateLibrariesFor(string tag) const | 63 PluginCandidates::getCandidateLibrariesFor(string tag) const |
56 { | 64 { |
63 { | 71 { |
64 if (m_failures.find(tag) == m_failures.end()) return {}; | 72 if (m_failures.find(tag) == m_failures.end()) return {}; |
65 else return m_failures.at(tag); | 73 else return m_failures.at(tag); |
66 } | 74 } |
67 | 75 |
76 void | |
77 PluginCandidates::log(string message) | |
78 { | |
79 if (m_logCallback) m_logCallback->log("PluginCandidates: " + message); | |
80 } | |
81 | |
68 vector<string> | 82 vector<string> |
69 PluginCandidates::getLibrariesInPath(vector<string> path) | 83 PluginCandidates::getLibrariesInPath(vector<string> path) |
70 { | 84 { |
71 vector<string> candidates; | 85 vector<string> candidates; |
72 | 86 |
73 for (string dirname: path) { | 87 for (string dirname: path) { |
74 | 88 |
75 //#ifdef DEBUG_PLUGIN_SCAN_AND_INSTANTIATE | 89 log("scanning directory " + dirname + "\n"); |
76 cerr << "getLibrariesInPath: scanning directory " << dirname << endl; | |
77 //#endif | |
78 | 90 |
79 QDir dir(dirname.c_str(), PLUGIN_GLOB, | 91 QDir dir(dirname.c_str(), PLUGIN_GLOB, |
80 QDir::Name | QDir::IgnoreCase, | 92 QDir::Name | QDir::IgnoreCase, |
81 QDir::Files | QDir::Readable); | 93 QDir::Files | QDir::Readable); |
82 | 94 |
109 if (shortfall > 0) { | 121 if (shortfall > 0) { |
110 // Helper bailed out for some reason presumably associated | 122 // Helper bailed out for some reason presumably associated |
111 // with the plugin following the last one it reported | 123 // with the plugin following the last one it reported |
112 // on. Add a failure entry for that one and continue with | 124 // on. Add a failure entry for that one and continue with |
113 // the following ones. | 125 // the following ones. |
114 cerr << "shortfall = " << shortfall << " (of " << remaining.size() << ")" << endl; | 126 string failed = *(remaining.rbegin() + shortfall - 1); |
115 result.push_back("FAILURE|" + | 127 log("helper output ended before result for plugin " + failed + "\n"); |
116 *(remaining.rbegin() + shortfall - 1) + | 128 result.push_back("FAILURE|" + failed + "|Plugin load check failed or timed out"); |
117 "|Plugin load check failed"); | |
118 remaining = vector<string> | 129 remaining = vector<string> |
119 (remaining.rbegin(), remaining.rbegin() + shortfall - 1); | 130 (remaining.rbegin(), remaining.rbegin() + shortfall - 1); |
120 } | 131 } |
121 ++runcount; | 132 ++runcount; |
122 } | 133 } |
126 | 137 |
127 vector<string> | 138 vector<string> |
128 PluginCandidates::runHelper(vector<string> libraries, string descriptor) | 139 PluginCandidates::runHelper(vector<string> libraries, string descriptor) |
129 { | 140 { |
130 vector<string> output; | 141 vector<string> output; |
131 // cerr << "running helper with following library list:" << endl; | 142 |
132 // for (auto &lib: libraries) cerr << lib << endl; | 143 log("running helper with following library list:\n"); |
144 for (auto &lib: libraries) log(lib + "\n"); | |
133 | 145 |
134 QProcess process; | 146 QProcess process; |
135 process.setReadChannel(QProcess::StandardOutput); | 147 process.setReadChannel(QProcess::StandardOutput); |
136 process.setProcessChannelMode(QProcess::ForwardedErrorChannel); | 148 process.setProcessChannelMode(QProcess::ForwardedErrorChannel); |
137 process.start(m_helper.c_str(), { descriptor.c_str() }); | 149 process.start(m_helper.c_str(), { descriptor.c_str() }); |
141 } | 153 } |
142 for (auto &lib: libraries) { | 154 for (auto &lib: libraries) { |
143 process.write(lib.c_str(), lib.size()); | 155 process.write(lib.c_str(), lib.size()); |
144 process.write("\n", 1); | 156 process.write("\n", 1); |
145 } | 157 } |
158 | |
159 QTime t; | |
160 t.start(); | |
161 int timeout = 3000; // ms | |
146 | 162 |
147 int buflen = 4096; | 163 int buflen = 4096; |
148 bool done = false; | 164 bool done = false; |
149 | 165 |
150 while (!done) { | 166 while (!done) { |
153 if (linelen > 0) { | 169 if (linelen > 0) { |
154 output.push_back(buf); | 170 output.push_back(buf); |
155 done = (output.size() == libraries.size()); | 171 done = (output.size() == libraries.size()); |
156 } else if (linelen < 0) { | 172 } else if (linelen < 0) { |
157 // error case | 173 // error case |
174 log("received error code while reading from helper\n"); | |
158 done = true; | 175 done = true; |
159 } else { | 176 } else { |
160 // no error, but no line read (could just be between | 177 // no error, but no line read (could just be between |
161 // lines, or could be eof) | 178 // lines, or could be eof) |
162 done = (process.state() == QProcess::NotRunning); | 179 done = (process.state() == QProcess::NotRunning); |
163 if (!done) process.waitForReadyRead(100); | 180 if (!done) { |
181 if (t.elapsed() > timeout) { | |
182 // this is purely an emergency measure | |
183 log("timeout: helper took too long, killing it\n"); | |
184 process.kill(); | |
185 done = true; | |
186 } else { | |
187 process.waitForReadyRead(200); | |
188 } | |
189 } | |
164 } | 190 } |
165 } | 191 } |
166 | 192 |
167 if (process.state() != QProcess::NotRunning) { | 193 if (process.state() != QProcess::NotRunning) { |
168 process.close(); | 194 process.close(); |
177 { | 203 { |
178 for (auto &r: result) { | 204 for (auto &r: result) { |
179 | 205 |
180 QString s(r.c_str()); | 206 QString s(r.c_str()); |
181 QStringList bits = s.split("|"); | 207 QStringList bits = s.split("|"); |
208 | |
209 log("read output line from helper: " + r); | |
210 | |
182 if (bits.size() < 2 || bits.size() > 3) { | 211 if (bits.size() < 2 || bits.size() > 3) { |
183 cerr << "Invalid helper output line: \"" << r << "\"" << endl; | 212 log("invalid output line (wrong number of |-separated fields)\n"); |
184 continue; | 213 continue; |
185 } | 214 } |
186 | 215 |
187 string status = bits[0].toStdString(); | 216 string status = bits[0].toStdString(); |
188 | 217 |
197 | 226 |
198 } else if (status == "FAILURE") { | 227 } else if (status == "FAILURE") { |
199 m_failures[tag].push_back({ library, message }); | 228 m_failures[tag].push_back({ library, message }); |
200 | 229 |
201 } else { | 230 } else { |
202 cerr << "Unexpected status " << status | 231 log("unexpected status \"" + status + "\" in output line\n"); |
203 << " in helper output line: \"" << r << "\"" << endl; | 232 } |
204 } | 233 } |
205 } | 234 } |
206 } | 235 |
207 |