mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
PluginListComponent: Wait for current scan to complete before calling owner.scanFinished()
I observed a deadlock when scanning AU plugins in-process in the AudioPluginHost, and then clicking the "cancel" button in the scan progress alert window. The cause of the deadlock seems to be that JUCE uses async messages to create and destroy AU plugins on the main thread. When running a plugin scanner on a background thread, it was possible to end up in a situation where the background thread was waiting on the message thread to process a create/destroy message; and, at the same time, the main thread was blocked waiting for all scan jobs to complete. This seemed to happen because scanFinished() was called directly from the Scanner's timerCallback as soon as the progress window was cancelled, even if there was still a scan in progress at that point. To avoid the deadlock, we now wait until the current scan has completely finished before allowing the timerCallback to call scanFinished(). If no scan is in progress, then the main thread can safely destroy the scanner ThreadPool without needing to wait at that point.
This commit is contained in:
parent
dc890c69c2
commit
5c34248d00
1 changed files with 15 additions and 9 deletions
|
|
@ -218,6 +218,12 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
enum Flags
|
||||
{
|
||||
stopRequested = 1 << 0, // Set to indicate to the background scanner that it should stop asap
|
||||
finished = 1 << 1, // Set by the scanner to indicate that it's done
|
||||
};
|
||||
|
||||
PluginListComponent& owner;
|
||||
AudioPluginFormat& formatToScan;
|
||||
StringArray filesOrIdentifiersToScan;
|
||||
|
|
@ -229,7 +235,7 @@ private:
|
|||
double progress = 0;
|
||||
const int numThreads;
|
||||
bool allowAsync, timerReentrancyCheck = false;
|
||||
std::atomic<bool> finished { false };
|
||||
std::atomic<int> flags { 0 };
|
||||
std::unique_ptr<ThreadPool> pool;
|
||||
std::set<String> initiallyBlacklistedFiles;
|
||||
ScopedMessageBox messageBox;
|
||||
|
|
@ -315,7 +321,10 @@ private:
|
|||
|
||||
progressWindow.addButton (TRANS ("Cancel"), 0, KeyPress (KeyPress::escapeKey));
|
||||
progressWindow.addProgressBarComponent (progress);
|
||||
progressWindow.enterModalState();
|
||||
progressWindow.enterModalState (true, ModalCallbackFunction::create ([this] (auto)
|
||||
{
|
||||
flags |= stopRequested;
|
||||
}));
|
||||
|
||||
if (numThreads > 0)
|
||||
{
|
||||
|
|
@ -357,10 +366,7 @@ private:
|
|||
startTimer (20);
|
||||
}
|
||||
|
||||
if (! progressWindow.isCurrentlyModal())
|
||||
finished = true;
|
||||
|
||||
if (finished)
|
||||
if ((flags & finished) != 0)
|
||||
finishedScan();
|
||||
else
|
||||
progressWindow.setMessage (TRANS ("Testing") + ":\n\n" + pluginBeingScanned);
|
||||
|
|
@ -368,16 +374,16 @@ private:
|
|||
|
||||
bool doNextScan()
|
||||
{
|
||||
if (scanner->scanNextFile (true, pluginBeingScanned))
|
||||
if ((flags & stopRequested) == 0 && scanner->scanNextFile (true, pluginBeingScanned))
|
||||
return true;
|
||||
|
||||
finished = true;
|
||||
flags |= finished;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct ScanJob final : public ThreadPoolJob
|
||||
{
|
||||
ScanJob (Scanner& s) : ThreadPoolJob ("pluginscan"), scanner (s) {}
|
||||
explicit ScanJob (Scanner& s) : ThreadPoolJob ("pluginscan"), scanner (s) {}
|
||||
|
||||
JobStatus runJob() override
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue