Browse Source

Plugin scanning: ability to use multiple threads

tags/2021-05-28
jules 12 years ago
parent
commit
6810038dea
6 changed files with 93 additions and 54 deletions
  1. +12
    -7
      modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp
  2. +1
    -0
      modules/juce_audio_processors/scanning/juce_KnownPluginList.h
  3. +30
    -22
      modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp
  4. +2
    -1
      modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h
  5. +43
    -21
      modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp
  6. +5
    -3
      modules/juce_audio_processors/scanning/juce_PluginListComponent.h

+ 12
- 7
modules/juce_audio_processors/scanning/juce_KnownPluginList.cpp View File

@@ -126,6 +126,8 @@ bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier,
OwnedArray <PluginDescription>& typesFound, OwnedArray <PluginDescription>& typesFound,
AudioPluginFormat& format) AudioPluginFormat& format)
{ {
const ScopedLock sl (scanLock);
if (dontRescanIfAlreadyInList if (dontRescanIfAlreadyInList
&& getTypeForFile (fileOrIdentifier) != nullptr) && getTypeForFile (fileOrIdentifier) != nullptr)
{ {
@@ -153,14 +155,17 @@ bool KnownPluginList::scanAndAddFile (const String& fileOrIdentifier,
OwnedArray <PluginDescription> found; OwnedArray <PluginDescription> found;
if (scanner != nullptr)
{ {
if (! scanner->findPluginTypesFor (format, found, fileOrIdentifier))
addToBlacklist (fileOrIdentifier);
}
else
{
format.findAllTypesForFile (found, fileOrIdentifier);
const ScopedUnlock sl (scanLock);
if (scanner != nullptr)
{
if (! scanner->findPluginTypesFor (format, found, fileOrIdentifier))
addToBlacklist (fileOrIdentifier);
}
else
{
format.findAllTypesForFile (found, fileOrIdentifier);
}
} }
for (int i = 0; i < found.size(); ++i) for (int i = 0; i < found.size(); ++i)


+ 1
- 0
modules/juce_audio_processors/scanning/juce_KnownPluginList.h View File

@@ -201,6 +201,7 @@ private:
OwnedArray <PluginDescription> types; OwnedArray <PluginDescription> types;
StringArray blacklist; StringArray blacklist;
ScopedPointer<CustomScanner> scanner; ScopedPointer<CustomScanner> scanner;
CriticalSection scanLock;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList)
}; };


+ 30
- 22
modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.cpp View File

@@ -39,7 +39,6 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo,
: list (listToAddTo), : list (listToAddTo),
format (formatToLookFor), format (formatToLookFor),
deadMansPedalFile (deadMansPedal), deadMansPedalFile (deadMansPedal),
nextIndex (0),
progress (0) progress (0)
{ {
directoriesToSearch.removeRedundantPaths(); directoriesToSearch.removeRedundantPaths();
@@ -60,6 +59,7 @@ PluginDirectoryScanner::PluginDirectoryScanner (KnownPluginList& listToAddTo,
} }
applyBlacklistingsFromDeadMansPedal (listToAddTo, deadMansPedalFile); applyBlacklistingsFromDeadMansPedal (listToAddTo, deadMansPedalFile);
nextIndex.set (filesOrIdentifiersToScan.size());
} }
PluginDirectoryScanner::~PluginDirectoryScanner() PluginDirectoryScanner::~PluginDirectoryScanner()
@@ -69,43 +69,51 @@ PluginDirectoryScanner::~PluginDirectoryScanner()
//============================================================================== //==============================================================================
String PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const String PluginDirectoryScanner::getNextPluginFileThatWillBeScanned() const
{ {
return format.getNameOfPluginFromIdentifier (filesOrIdentifiersToScan [nextIndex]);
return format.getNameOfPluginFromIdentifier (filesOrIdentifiersToScan [nextIndex.get() - 1]);
}
void PluginDirectoryScanner::updateProgress()
{
progress = (1.0f - nextIndex.get() / (float) filesOrIdentifiersToScan.size());
} }
bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList) bool PluginDirectoryScanner::scanNextFile (const bool dontRescanIfAlreadyInList)
{ {
String file (filesOrIdentifiersToScan [nextIndex]);
const int index = --nextIndex;
if (file.isNotEmpty() && ! list.isListingUpToDate (file))
if (index >= 0)
{ {
OwnedArray <PluginDescription> typesFound;
String file (filesOrIdentifiersToScan [index]);
// Add this plugin to the end of the dead-man's pedal list in case it crashes...
StringArray crashedPlugins (readDeadMansPedalFile (deadMansPedalFile));
crashedPlugins.removeString (file);
crashedPlugins.add (file);
setDeadMansPedalFile (crashedPlugins);
if (file.isNotEmpty() && ! list.isListingUpToDate (file))
{
OwnedArray <PluginDescription> typesFound;
list.scanAndAddFile (file, dontRescanIfAlreadyInList, typesFound, format);
// Add this plugin to the end of the dead-man's pedal list in case it crashes...
StringArray crashedPlugins (readDeadMansPedalFile (deadMansPedalFile));
crashedPlugins.removeString (file);
crashedPlugins.add (file);
setDeadMansPedalFile (crashedPlugins);
// Managed to load without crashing, so remove it from the dead-man's-pedal..
crashedPlugins.removeString (file);
setDeadMansPedalFile (crashedPlugins);
list.scanAndAddFile (file, dontRescanIfAlreadyInList, typesFound, format);
if (typesFound.size() == 0 && ! list.getBlacklistedFiles().contains (file))
failedFiles.add (file);
// Managed to load without crashing, so remove it from the dead-man's-pedal..
crashedPlugins.removeString (file);
setDeadMansPedalFile (crashedPlugins);
if (typesFound.size() == 0 && ! list.getBlacklistedFiles().contains (file))
failedFiles.add (file);
}
} }
return skipNextFile();
updateProgress();
return index > 0;
} }
bool PluginDirectoryScanner::skipNextFile() bool PluginDirectoryScanner::skipNextFile()
{ {
if (nextIndex >= filesOrIdentifiersToScan.size())
return false;
progress = ++nextIndex / (float) filesOrIdentifiersToScan.size();
return nextIndex < filesOrIdentifiersToScan.size();
updateProgress();
return --nextIndex > 0;
} }
void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents) void PluginDirectoryScanner::setDeadMansPedalFile (const StringArray& newContents)


+ 2
- 1
modules/juce_audio_processors/scanning/juce_PluginDirectoryScanner.h View File

@@ -115,9 +115,10 @@ private:
StringArray filesOrIdentifiersToScan; StringArray filesOrIdentifiersToScan;
File deadMansPedalFile; File deadMansPedalFile;
StringArray failedFiles; StringArray failedFiles;
int nextIndex;
Atomic<int> nextIndex;
float progress; float progress;
void updateProgress();
void setDeadMansPedalFile (const StringArray& newContents); void setDeadMansPedalFile (const StringArray& newContents);
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginDirectoryScanner) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginDirectoryScanner)


+ 43
- 21
modules/juce_audio_processors/scanning/juce_PluginListComponent.cpp View File

@@ -32,7 +32,7 @@ PluginListComponent::PluginListComponent (AudioPluginFormatManager& manager,
deadMansPedalFile (deadMansPedal), deadMansPedalFile (deadMansPedal),
optionsButton ("Options..."), optionsButton ("Options..."),
propertiesToUse (properties), propertiesToUse (properties),
scanOnBackgroundThread (false)
numThreads (0)
{ {
listBox.setModel (this); listBox.setModel (this);
addAndMakeVisible (&listBox); addAndMakeVisible (&listBox);
@@ -60,9 +60,9 @@ void PluginListComponent::setOptionsButtonText (const String& newText)
resized(); resized();
} }
void PluginListComponent::setScansOnMessageThread (bool useMessageThread) noexcept
void PluginListComponent::setNumberOfThreadsForScanning (int num)
{ {
scanOnBackgroundThread = ! useMessageThread;
numThreads = num;
} }
void PluginListComponent::resized() void PluginListComponent::resized()
@@ -244,20 +244,18 @@ void PluginListComponent::filesDropped (const StringArray& files, int, int)
} }
//============================================================================== //==============================================================================
class PluginListComponent::Scanner : private Timer,
private Thread
class PluginListComponent::Scanner : private Timer
{ {
public: public:
Scanner (PluginListComponent& plc, Scanner (PluginListComponent& plc,
AudioPluginFormat& format, AudioPluginFormat& format,
PropertiesFile* properties, PropertiesFile* properties,
bool useThread)
: Thread ("plugin_scan"),
owner (plc), formatToScan (format), propertiesToUse (properties),
int threads)
: owner (plc), formatToScan (format), propertiesToUse (properties),
pathChooserWindow (TRANS("Select folders to scan..."), String::empty, AlertWindow::NoIcon), pathChooserWindow (TRANS("Select folders to scan..."), String::empty, AlertWindow::NoIcon),
progressWindow (TRANS("Scanning for plug-ins..."), progressWindow (TRANS("Scanning for plug-ins..."),
TRANS("Searching for all possible plug-in files..."), AlertWindow::NoIcon), TRANS("Searching for all possible plug-in files..."), AlertWindow::NoIcon),
progress (0.0), shouldUseThread (useThread), finished (false)
progress (0.0), numThreads (threads), finished (false)
{ {
FileSearchPath path (formatToScan.getDefaultLocationsToSearch()); FileSearchPath path (formatToScan.getDefaultLocationsToSearch());
@@ -285,7 +283,11 @@ public:
~Scanner() ~Scanner()
{ {
stopThread (10000);
if (pool != nullptr)
{
pool->removeAllJobs (true, 60000);
pool = nullptr;
}
} }
private: private:
@@ -317,8 +319,13 @@ private:
progressWindow.addProgressBarComponent (progress); progressWindow.addProgressBarComponent (progress);
progressWindow.enterModalState(); progressWindow.enterModalState();
if (shouldUseThread)
startThread();
if (numThreads > 0)
{
pool = new ThreadPool (numThreads);
for (int i = numThreads; --i >= 0;)
pool->addJob (new ScanJob (*this), true);
}
startTimer (20); startTimer (20);
} }
@@ -331,7 +338,7 @@ private:
void timerCallback() void timerCallback()
{ {
if (! isThreadRunning())
if (pool == nullptr)
{ {
if (doNextScan()) if (doNextScan())
startTimer (20); startTimer (20);
@@ -346,12 +353,6 @@ private:
progressWindow.setMessage (progressMessage); progressWindow.setMessage (progressMessage);
} }
void run()
{
while (doNextScan() && ! threadShouldExit())
{}
}
bool doNextScan() bool doNextScan()
{ {
progressMessage = TRANS("Testing:\n\n") + scanner->getNextPluginFileThatWillBeScanned(); progressMessage = TRANS("Testing:\n\n") + scanner->getNextPluginFileThatWillBeScanned();
@@ -374,15 +375,36 @@ private:
FileSearchPathListComponent pathList; FileSearchPathListComponent pathList;
String progressMessage; String progressMessage;
double progress; double progress;
bool shouldUseThread, finished;
int numThreads;
bool finished;
ScopedPointer<ThreadPool> pool;
struct ScanJob : public ThreadPoolJob
{
ScanJob (Scanner& s) : ThreadPoolJob ("pluginscan"), scanner (s) {}
JobStatus runJob()
{
while (scanner.doNextScan() && ! shouldExit())
{}
return jobHasFinished;
}
Scanner& scanner;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScanJob)
};
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Scanner) JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Scanner)
}; };
void PluginListComponent::scanFor (AudioPluginFormat* format) void PluginListComponent::scanFor (AudioPluginFormat* format)
{ {
if (format != nullptr) if (format != nullptr)
currentScanner = new Scanner (*this, *format, propertiesToUse, scanOnBackgroundThread);
currentScanner = new Scanner (*this, *format, propertiesToUse, numThreads);
} }
void PluginListComponent::scanFinished (const StringArray& failedFiles) void PluginListComponent::scanFinished (const StringArray& failedFiles)


+ 5
- 3
modules/juce_audio_processors/scanning/juce_PluginListComponent.h View File

@@ -61,8 +61,10 @@ public:
/** Changes the text in the panel's button. */ /** Changes the text in the panel's button. */
void setOptionsButtonText (const String& newText); void setOptionsButtonText (const String& newText);
/** Chooses whether to use the message thread or a background thread for scanning. */
void setScansOnMessageThread (bool useMessageThread) noexcept;
/** Sets how many threads to simultaneously scan for plugins.
If this is 0, then all scanning happens on the message thread (this is the default)
*/
void setNumberOfThreadsForScanning (int numThreads);
//============================================================================== //==============================================================================
/** @internal */ /** @internal */
@@ -86,7 +88,7 @@ private:
ListBox listBox; ListBox listBox;
TextButton optionsButton; TextButton optionsButton;
PropertiesFile* propertiesToUse; PropertiesFile* propertiesToUse;
bool scanOnBackgroundThread;
int numThreads;
class Scanner; class Scanner;
friend class Scanner; friend class Scanner;


Loading…
Cancel
Save