Mercurial > hg > svcore
comparison transform/ModelTransformerFactory.cpp @ 1727:8efce64dd85e
Fix potential deadlock when notifying a handler that more models are [not] available
author | Chris Cannam |
---|---|
date | Thu, 20 Jun 2019 11:09:36 +0100 |
parents | b17fb3a4560c |
children | fe3f7f8df3a3 |
comparison
equal
deleted
inserted
replaced
1726:d7ae9bfb015e | 1727:8efce64dd85e |
---|---|
30 | 30 |
31 #include <vamp-hostsdk/PluginHostAdapter.h> | 31 #include <vamp-hostsdk/PluginHostAdapter.h> |
32 | 32 |
33 #include <iostream> | 33 #include <iostream> |
34 #include <set> | 34 #include <set> |
35 #include <map> | |
35 | 36 |
36 #include <QRegExp> | 37 #include <QRegExp> |
37 #include <QMutexLocker> | 38 #include <QMutexLocker> |
38 | 39 |
39 using std::vector; | 40 using std::vector; |
41 using std::set; | |
42 using std::map; | |
40 | 43 |
41 ModelTransformerFactory * | 44 ModelTransformerFactory * |
42 ModelTransformerFactory::m_instance = new ModelTransformerFactory; | 45 ModelTransformerFactory::m_instance = new ModelTransformerFactory; |
43 | 46 |
44 ModelTransformerFactory * | 47 ModelTransformerFactory * |
51 { | 54 { |
52 } | 55 } |
53 | 56 |
54 ModelTransformer::Input | 57 ModelTransformer::Input |
55 ModelTransformerFactory::getConfigurationForTransform(Transform &transform, | 58 ModelTransformerFactory::getConfigurationForTransform(Transform &transform, |
56 const std::vector<Model *> &candidateInputModels, | 59 const vector<Model *> &candidateInputModels, |
57 Model *defaultInputModel, | 60 Model *defaultInputModel, |
58 AudioPlaySource *source, | 61 AudioPlaySource *source, |
59 sv_frame_t startFrame, | 62 sv_frame_t startFrame, |
60 sv_frame_t duration, | 63 sv_frame_t duration, |
61 UserConfigurator *configurator) | 64 UserConfigurator *configurator) |
258 } | 261 } |
259 | 262 |
260 void | 263 void |
261 ModelTransformerFactory::transformerFinished() | 264 ModelTransformerFactory::transformerFinished() |
262 { | 265 { |
263 QMutexLocker locker(&m_mutex); | |
264 | |
265 QObject *s = sender(); | 266 QObject *s = sender(); |
266 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s); | 267 ModelTransformer *transformer = dynamic_cast<ModelTransformer *>(s); |
267 | 268 |
268 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl; | 269 // SVDEBUG << "ModelTransformerFactory::transformerFinished(" << transformer << ")" << endl; |
269 | 270 |
270 if (!transformer) { | 271 if (!transformer) { |
271 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl; | 272 cerr << "WARNING: ModelTransformerFactory::transformerFinished: sender is not a transformer" << endl; |
272 return; | 273 return; |
273 } | 274 } |
274 | 275 |
276 m_mutex.lock(); | |
277 | |
275 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) { | 278 if (m_runningTransformers.find(transformer) == m_runningTransformers.end()) { |
276 cerr << "WARNING: ModelTransformerFactory::transformerFinished(" | 279 cerr << "WARNING: ModelTransformerFactory::transformerFinished(" |
277 << transformer | 280 << transformer |
278 << "): I have no record of this transformer running!" | 281 << "): I have no record of this transformer running!" |
279 << endl; | 282 << endl; |
280 } | 283 } |
281 | 284 |
282 m_runningTransformers.erase(transformer); | 285 m_runningTransformers.erase(transformer); |
283 | 286 |
287 map<AdditionalModelHandler *, vector<Model *>> toNotifyOfMore; | |
288 vector<AdditionalModelHandler *> toNotifyOfNoMore; | |
289 | |
284 if (m_handlers.find(transformer) != m_handlers.end()) { | 290 if (m_handlers.find(transformer) != m_handlers.end()) { |
285 if (transformer->willHaveAdditionalOutputModels()) { | 291 if (transformer->willHaveAdditionalOutputModels()) { |
286 vector<Model *> mm = transformer->detachAdditionalOutputModels(); | 292 vector<Model *> mm = transformer->detachAdditionalOutputModels(); |
287 m_handlers[transformer]->moreModelsAvailable(mm); | 293 toNotifyOfMore[m_handlers[transformer]] = mm; |
288 } else { | 294 } else { |
289 m_handlers[transformer]->noMoreModelsAvailable(); | 295 toNotifyOfNoMore.push_back(m_handlers[transformer]); |
290 } | 296 } |
291 m_handlers.erase(transformer); | 297 m_handlers.erase(transformer); |
292 } | 298 } |
293 | 299 |
300 m_mutex.unlock(); | |
301 | |
302 // These calls have to be made without the mutex held, as they may | |
303 // ultimately call back on us (e.g. we have one baroque situation | |
304 // where this could trigger a command to create a layer, which | |
305 // triggers the command history to clip the stack, which deletes a | |
306 // spare old model, which calls back on our modelAboutToBeDeleted) | |
307 | |
308 for (const auto &i: toNotifyOfMore) { | |
309 i.first->moreModelsAvailable(i.second); | |
310 } | |
311 for (AdditionalModelHandler *handler: toNotifyOfNoMore) { | |
312 handler->noMoreModelsAvailable(); | |
313 } | |
314 | |
294 if (transformer->isAbandoned()) { | 315 if (transformer->isAbandoned()) { |
295 if (transformer->getMessage() != "") { | 316 if (transformer->getMessage() != "") { |
296 emit transformFailed("", transformer->getMessage()); | 317 emit transformFailed("", transformer->getMessage()); |
297 } | 318 } |
298 } | 319 } |