Run events async and centralized for group hosts

At a 30 fps rate with a limit on the number of window messages per
frame. This is somehow needed for Melda plugins, as they otherwise
dispatch tiemr messages indefinitely after opening a second editor with
seemingly no way around it.

With this and some refactoring #15 should be almost done.
This commit is contained in:
Robbert van der Helm
2020-05-26 12:09:27 +02:00
parent 16fce5577d
commit 198807a15a
4 changed files with 122 additions and 64 deletions
+55 -9
View File
@@ -27,6 +27,13 @@
// path operation will thrown an encoding related error
namespace fs = boost::filesystem;
using namespace std::literals::chrono_literals;
/**
* The delay between calls to the event loop at a more than cinematic 30 fps.
*/
constexpr std::chrono::duration event_loop_interval = 1000ms / 30;
/**
* Listen on the specified endpoint if no process is already listening there,
* otherwise throw. This is needed to handle these three situations:
@@ -98,6 +105,7 @@ GroupBridge::GroupBridge(boost::filesystem::path group_socket_path)
group_socket_endpoint(group_socket_path.string()),
group_socket_acceptor(
create_acceptor_if_inactive(plugin_context, group_socket_endpoint)),
events_timer(plugin_context),
shutdown_timer(plugin_context) {
// Write this process's original STDOUT and STDERR streams to the logger
// TODO: This works for output generated by plugins, but not for debug
@@ -114,19 +122,13 @@ GroupBridge::~GroupBridge() {
}
void GroupBridge::handle_plugin_dispatch(const GroupRequest request) {
using namespace std::literals::chrono_literals;
// At this point the `active_plugins` map will already contain the
// intialized plugin's `Vst2Bridge` instance and this thread's handle
auto& [thread, bridge] = active_plugins.at(request);
// Blocks the main thread until the plugin shuts down, handling all events
// on the main IO context
// TODO: Maybe add a function to each vstbridge that returns whether the
// message loop should be postponed, and pass a function here that
// checks if this is the case for any of the plugins?
bridge->handle_dispatch_multi(plugin_context,
[&]() { return should_skip_message_loop(); });
// Blocks this thread until the plugin shuts down, handling all events on
// the main IO context
bridge->handle_dispatch_multi(plugin_context);
logger.log("'" + request.plugin_path + "' has exited");
// After the plugin has exited, we'll remove this thread's plugin from the
@@ -156,6 +158,7 @@ void GroupBridge::handle_plugin_dispatch(const GroupRequest request) {
void GroupBridge::handle_incoming_connections() {
accept_requests();
async_handle_events();
logger.log(
"Group host is up and running, now accepting incoming connections");
@@ -233,6 +236,49 @@ void GroupBridge::accept_requests() {
});
}
void GroupBridge::async_handle_events() {
// Try to keep a steady framerate, but add in delays to let other events get
// handled if the GUI message handling somehow takes very long.
events_timer.expires_at(
std::max(events_timer.expiry() + event_loop_interval,
std::chrono::steady_clock::now() + 5ms));
events_timer.async_wait([&](const boost::system::error_code& error) {
if (error.failed()) {
return;
}
{
// Always handle X11 events
std::lock_guard lock(active_plugins_mutex);
for (auto& [parameters, value] : active_plugins) {
auto& [thread, bridge] = value;
bridge->handle_x11_events();
}
}
// Handle Win32 messages unless plugins are in the middle of opening
// their editor
// TODO: Check if those same weird crashes with Serum are happening
// again with these normal threads
if (!should_skip_message_loop()) {
MSG msg;
// Keep the loop responsive by not handling too many events at once
// TODO: For some reason the Melda plugins run into a seemingly
// infinite timer loop for a little while after opening a
// second editor. Without this limit everything will get
// blocked indefinitely. How could this be fixed?
for (int i = 0;
i < 20 && PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE); i++) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
async_handle_events();
});
}
void GroupBridge::async_log_pipe_lines(
boost::asio::posix::stream_descriptor& pipe,
boost::asio::streambuf& buffer,