How does JUCE protect the VST3 hosting application from crashing when it scans VST3 plugins?
Some plugins seem to crash my Windows app while JUCE is scanning VST3 plugins.
Occasionally the whole OS (Windows) is required to restart so the application can be started again after such a crash had occured during VST3 plugin scanning.
Any ideas what could be causing such behavior?
How to protect the application properly in case plugin crashes during scanning?
Plugins are normally loaded in the same process as the host application, therefore when they crash they also crash the host application. A common trick to avoid this is to load the plugins in a separate process while scanning them. If this process crashes you can detect the plugin that caused the crash, blacklist it, and avoid scanning the same plugin next time while keeping the host application running. The AudioPluginHost allows scanning out of process, it might be worth looking there for an example. Some hosts also do this when loading a plugin in general however this will have some impact on latency/performance.
Take a look at how this is implemented in the AudioPluginHost for an example.
The PluginScannerSubprocess can be found in HostStartup.cpp, and is responsible for scanning plugin paths that are sent to it by the coordinating process, and replying with an XML PluginDescription for each plugin that was scanned successfully.
The CustomPluginScanner that runs the plugin scan in the coordinating process can be found in MainHostWindow.cpp.
ChildProcessWorker and ChildProcessCoordinator handle crash detection automatically. The Worker sends a ping message back to the Coordinator periodically; if the ping isn’t received, then the Worker is assumed to have crashed.
Is the ping sent only after each plugin’s scan finishes, or is there some way to send it several times while the scanning of single plugin is happening? I assume this is not possible?
What if the plugin takes a long time to scan, longer than the ping frequency is?
I assume scanning a plugin takes as long as it would when the end user loads the plugin into the application? So if the plugin by default loads a gigabyte of samples, it might take a long time, thus the failed ping might indicate a false failure?
Wait. Do I read the code and JUCE documentation right, that we’re not talking about a thread created by the application, but actually a real whole different instance of the same executable file/application, which gets started up with ChildProcessWorker::initialiseFromCommandLine() ?
So the main application starts up a second version of it self, using commandline parameters for the second instance of itself to indicate that it should be in the “plugin scanning mode” instead of what it does normally?
Then these two separate instances of the executable communicate with each other using the InterprocessConnection? This way if plugin scan crashes something, it’s going to be the second instance of the application, and the crash is protected by operating system itself?
So what’s keeping the ping alive only up until the second application crashes? If the application crashes, does the operating system halt all the threads created by the crashing application? Does it work like this:
MainApp → Starts up PluginScanApp.
PluginScanApp → Creates a thread which pings periodically MainApp.
PluginScanApp crashes —> The pinging thread is also automatically halted by the operating system.
Now MainApp stops receiving the ping and knows for sure that something went horribly wrong and can react accordingly?
Yes. As mentioned, a thread is part of an existing process, so all threads from the same process can crash the process.
That’s the reason for a separate process (not thread). and as mentioned here the process running the plug-in has multiple threads (one that pings to avoid plug-in code that might block).
Also, any plug-in running in it can also make its own threads of course.
OK, now it’s starting to make sense what’s going on.
Are there any downsides between these two alternative approaches to which process is responsible for figuring out the VST3 file names that will be scanned:
Plugin scanner process figures out the exact filenames and does the scanning.
Main application figures out the exact filenames and sends them to the scanner.
As far as I can see, nothing can crash when figuring out the filenames, as they’re not scanned in any way at that point. So it’s probably OK to do it in either process, regarding which one works best for the application in question?