mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Rename PluginContext to MainContext for clarity
This commit is contained in:
@@ -84,14 +84,14 @@ StdIoCapture::~StdIoCapture() {
|
|||||||
GroupBridge::GroupBridge(boost::filesystem::path group_socket_path)
|
GroupBridge::GroupBridge(boost::filesystem::path group_socket_path)
|
||||||
: logger(Logger::create_from_environment(
|
: logger(Logger::create_from_environment(
|
||||||
create_logger_prefix(group_socket_path))),
|
create_logger_prefix(group_socket_path))),
|
||||||
plugin_context(),
|
main_context(),
|
||||||
stdio_context(),
|
stdio_context(),
|
||||||
stdout_redirect(stdio_context, STDOUT_FILENO),
|
stdout_redirect(stdio_context, STDOUT_FILENO),
|
||||||
stderr_redirect(stdio_context, STDERR_FILENO),
|
stderr_redirect(stdio_context, STDERR_FILENO),
|
||||||
group_socket_endpoint(group_socket_path.string()),
|
group_socket_endpoint(group_socket_path.string()),
|
||||||
group_socket_acceptor(create_acceptor_if_inactive(plugin_context.context,
|
group_socket_acceptor(create_acceptor_if_inactive(main_context.context,
|
||||||
group_socket_endpoint)),
|
group_socket_endpoint)),
|
||||||
shutdown_timer(plugin_context.context) {
|
shutdown_timer(main_context.context) {
|
||||||
// Write this process's original STDOUT and STDERR streams to the logger
|
// Write this process's original STDOUT and STDERR streams to the logger
|
||||||
// TODO: This works for output generated by plugins, but not for debug
|
// TODO: This works for output generated by plugins, but not for debug
|
||||||
// messages generated by wineserver. Is it possible to catch those?
|
// messages generated by wineserver. Is it possible to catch those?
|
||||||
@@ -125,7 +125,7 @@ void GroupBridge::handle_plugin_dispatch(size_t plugin_id) {
|
|||||||
// potentially corrupt our heap. This way we can also properly join the
|
// potentially corrupt our heap. This way we can also properly join the
|
||||||
// thread again. If no active plugins remain, then we'll terminate the
|
// thread again. If no active plugins remain, then we'll terminate the
|
||||||
// process.
|
// process.
|
||||||
boost::asio::post(plugin_context.context, [this, plugin_id]() {
|
boost::asio::post(main_context.context, [this, plugin_id]() {
|
||||||
std::lock_guard lock(active_plugins_mutex);
|
std::lock_guard lock(active_plugins_mutex);
|
||||||
|
|
||||||
// The join is implicit because we're using Win32Thread (which mimics
|
// The join is implicit because we're using Win32Thread (which mimics
|
||||||
@@ -147,7 +147,7 @@ void GroupBridge::handle_plugin_dispatch(size_t plugin_id) {
|
|||||||
if (active_plugins.size() == 0) {
|
if (active_plugins.size() == 0) {
|
||||||
logger.log(
|
logger.log(
|
||||||
"All plugins have exited, shutting down the group process");
|
"All plugins have exited, shutting down the group process");
|
||||||
plugin_context.stop();
|
main_context.stop();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -158,7 +158,7 @@ void GroupBridge::handle_incoming_connections() {
|
|||||||
|
|
||||||
logger.log(
|
logger.log(
|
||||||
"Group host is up and running, now accepting incoming connections");
|
"Group host is up and running, now accepting incoming connections");
|
||||||
plugin_context.run();
|
main_context.run();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GroupBridge::should_skip_message_loop() {
|
bool GroupBridge::should_skip_message_loop() {
|
||||||
@@ -188,7 +188,7 @@ void GroupBridge::accept_requests() {
|
|||||||
logger.log("Error while listening for incoming connections:");
|
logger.log("Error while listening for incoming connections:");
|
||||||
logger.log(error.message());
|
logger.log(error.message());
|
||||||
|
|
||||||
plugin_context.stop();
|
main_context.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the parameters, and then host the plugin in this process
|
// Read the parameters, and then host the plugin in this process
|
||||||
@@ -208,7 +208,7 @@ void GroupBridge::accept_requests() {
|
|||||||
request.endpoint_base_dir + "'");
|
request.endpoint_base_dir + "'");
|
||||||
try {
|
try {
|
||||||
auto bridge = std::make_unique<Vst2Bridge>(
|
auto bridge = std::make_unique<Vst2Bridge>(
|
||||||
plugin_context, request.plugin_path,
|
main_context, request.plugin_path,
|
||||||
request.endpoint_base_dir);
|
request.endpoint_base_dir);
|
||||||
logger.log("Finished initializing '" + request.plugin_path +
|
logger.log("Finished initializing '" + request.plugin_path +
|
||||||
"'");
|
"'");
|
||||||
@@ -235,7 +235,7 @@ void GroupBridge::accept_requests() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GroupBridge::async_handle_events() {
|
void GroupBridge::async_handle_events() {
|
||||||
plugin_context.async_handle_events([&]() {
|
main_context.async_handle_events([&]() {
|
||||||
{
|
{
|
||||||
// Always handle X11 events
|
// Always handle X11 events
|
||||||
std::lock_guard lock(active_plugins_mutex);
|
std::lock_guard lock(active_plugins_mutex);
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ class GroupBridge {
|
|||||||
* event handling and message loop interaction also has to be done from that
|
* event handling and message loop interaction also has to be done from that
|
||||||
* thread, which is why we initialize the plugin here and use the
|
* thread, which is why we initialize the plugin here and use the
|
||||||
* `handle_dispatch()` function to run events within the same
|
* `handle_dispatch()` function to run events within the same
|
||||||
* `plugin_context`.
|
* `main_context`.
|
||||||
*
|
*
|
||||||
* @see handle_plugin_dispatch
|
* @see handle_plugin_dispatch
|
||||||
*/
|
*/
|
||||||
@@ -217,13 +217,13 @@ class GroupBridge {
|
|||||||
* operations that may involve the Win32 mesasge loop (e.g. initialization
|
* operations that may involve the Win32 mesasge loop (e.g. initialization
|
||||||
* and most `AEffect::dispatcher()` calls) should be run on.
|
* and most `AEffect::dispatcher()` calls) should be run on.
|
||||||
*/
|
*/
|
||||||
PluginContext plugin_context;
|
MainContext main_context;
|
||||||
/**
|
/**
|
||||||
* A seperate IO context that handles the STDIO redirect through
|
* A seperate IO context that handles the STDIO redirect through
|
||||||
* `StdIoCapture`. This is seperated the `plugin_context` above so that
|
* `StdIoCapture`. This is separated from the `main_context` above so that
|
||||||
* STDIO capture does not get blocked by blocking GUI operations. Since
|
* STDIO capture does not get blocked by GUI operations. Since every GUI
|
||||||
* every GUI related operation should be run from the same thread, we can't
|
* related operation should be run from the same thread, we can't just add
|
||||||
* just add another thread to the main IO context.
|
* another thread to the main IO context.
|
||||||
*/
|
*/
|
||||||
boost::asio::io_context stdio_context;
|
boost::asio::io_context stdio_context;
|
||||||
|
|
||||||
|
|||||||
@@ -66,13 +66,13 @@ Vst2Bridge& get_bridge_instance(const AEffect* plugin) {
|
|||||||
return *static_cast<Vst2Bridge*>(plugin->ptr1);
|
return *static_cast<Vst2Bridge*>(plugin->ptr1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vst2Bridge::Vst2Bridge(PluginContext& main_context,
|
Vst2Bridge::Vst2Bridge(MainContext& main_context,
|
||||||
std::string plugin_dll_path,
|
std::string plugin_dll_path,
|
||||||
std::string endpoint_base_dir)
|
std::string endpoint_base_dir)
|
||||||
: vst_plugin_path(plugin_dll_path),
|
: vst_plugin_path(plugin_dll_path),
|
||||||
plugin_context(main_context),
|
main_context(main_context),
|
||||||
plugin_handle(LoadLibrary(plugin_dll_path.c_str()), FreeLibrary),
|
plugin_handle(LoadLibrary(plugin_dll_path.c_str()), FreeLibrary),
|
||||||
sockets(plugin_context.context, endpoint_base_dir, false) {
|
sockets(main_context.context, endpoint_base_dir, false) {
|
||||||
// Got to love these C APIs
|
// Got to love these C APIs
|
||||||
if (!plugin_handle) {
|
if (!plugin_handle) {
|
||||||
throw std::runtime_error("Could not load the Windows .dll file at '" +
|
throw std::runtime_error("Could not load the Windows .dll file at '" +
|
||||||
@@ -350,7 +350,7 @@ void Vst2Bridge::handle_dispatch() {
|
|||||||
// and where the Win32 message loop is handled.
|
// and where the Win32 message loop is handled.
|
||||||
if (unsafe_opcodes.contains(opcode)) {
|
if (unsafe_opcodes.contains(opcode)) {
|
||||||
std::promise<intptr_t> dispatch_result;
|
std::promise<intptr_t> dispatch_result;
|
||||||
boost::asio::dispatch(plugin_context.context, [&]() {
|
boost::asio::dispatch(main_context.context, [&]() {
|
||||||
const intptr_t result = dispatch_wrapper(
|
const intptr_t result = dispatch_wrapper(
|
||||||
plugin, opcode, index, value, data, option);
|
plugin, opcode, index, value, data, option);
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class Vst2Bridge {
|
|||||||
* @throw std::runtime_error Thrown when the VST plugin could not be loaded,
|
* @throw std::runtime_error Thrown when the VST plugin could not be loaded,
|
||||||
* or if communication could not be set up.
|
* or if communication could not be set up.
|
||||||
*/
|
*/
|
||||||
Vst2Bridge(PluginContext& main_context,
|
Vst2Bridge(MainContext& main_context,
|
||||||
std::string plugin_dll_path,
|
std::string plugin_dll_path,
|
||||||
std::string endpoint_base_dir);
|
std::string endpoint_base_dir);
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ class Vst2Bridge {
|
|||||||
* message handling can be performed from a single thread, even when hosting
|
* message handling can be performed from a single thread, even when hosting
|
||||||
* multiple plugins.
|
* multiple plugins.
|
||||||
*/
|
*/
|
||||||
PluginContext& plugin_context;
|
MainContext& main_context;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The configuration for this instance of yabridge based on the `.so` file
|
* The configuration for this instance of yabridge based on the `.so` file
|
||||||
|
|||||||
@@ -65,11 +65,11 @@ int __cdecl main(int argc, char* argv[]) {
|
|||||||
// don't need to differentiate between individually hosted plugins and
|
// don't need to differentiate between individually hosted plugins and
|
||||||
// plugin groups when it comes to event handling.
|
// plugin groups when it comes to event handling.
|
||||||
// TODO: Update documentation once we figure out if we can safely replace
|
// TODO: Update documentation once we figure out if we can safely replace
|
||||||
// PluginContext again with a normal `io_context`.
|
// MainContext again with a normal `io_context`.
|
||||||
PluginContext plugin_context{};
|
MainContext main_context{};
|
||||||
std::unique_ptr<Vst2Bridge> bridge;
|
std::unique_ptr<Vst2Bridge> bridge;
|
||||||
try {
|
try {
|
||||||
bridge = std::make_unique<Vst2Bridge>(plugin_context, plugin_dll_path,
|
bridge = std::make_unique<Vst2Bridge>(main_context, plugin_dll_path,
|
||||||
socket_endpoint_path);
|
socket_endpoint_path);
|
||||||
} catch (const std::runtime_error& error) {
|
} catch (const std::runtime_error& error) {
|
||||||
std::cerr << "Error while initializing Wine VST host:" << std::endl;
|
std::cerr << "Error while initializing Wine VST host:" << std::endl;
|
||||||
@@ -87,9 +87,9 @@ int __cdecl main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Handle Win32 messages and X11 events on a timer, just like in
|
// Handle Win32 messages and X11 events on a timer, just like in
|
||||||
// `GroupBridge::async_handle_events()``
|
// `GroupBridge::async_handle_events()``
|
||||||
plugin_context.async_handle_events([&]() {
|
main_context.async_handle_events([&]() {
|
||||||
bridge->handle_x11_events();
|
bridge->handle_x11_events();
|
||||||
bridge->handle_win32_events();
|
bridge->handle_win32_events();
|
||||||
});
|
});
|
||||||
plugin_context.run();
|
main_context.run();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,15 @@
|
|||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
|
||||||
PluginContext::PluginContext() : context(), events_timer(context) {}
|
MainContext::MainContext() : context(), events_timer(context) {}
|
||||||
|
|
||||||
|
void MainContext::run() {
|
||||||
|
context.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainContext::stop() {
|
||||||
|
context.stop();
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t WINAPI
|
uint32_t WINAPI
|
||||||
win32_thread_trampoline(fu2::unique_function<void()>* entry_point) {
|
win32_thread_trampoline(fu2::unique_function<void()>* entry_point) {
|
||||||
@@ -34,14 +42,6 @@ Win32Thread& Win32Thread::operator=(Win32Thread&& o) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginContext::run() {
|
|
||||||
context.run();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PluginContext::stop() {
|
|
||||||
context.stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
Win32Thread::Win32Thread() : handle(nullptr, nullptr) {}
|
Win32Thread::Win32Thread() : handle(nullptr, nullptr) {}
|
||||||
|
|
||||||
Win32Timer::Win32Timer(HWND window_handle,
|
Win32Timer::Win32Timer(HWND window_handle,
|
||||||
|
|||||||
+12
-11
@@ -39,18 +39,16 @@ constexpr std::chrono::duration event_loop_interval =
|
|||||||
std::chrono::milliseconds(1000) / 30;
|
std::chrono::milliseconds(1000) / 30;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A wrapper around `boost::asio::io_context()`. A single instance is shared for
|
* A wrapper around `boost::asio::io_context()` to serve as the application's
|
||||||
* all plugins in a plugin group so that most events can be handled on the main
|
* main IO context. A single instance is shared for all plugins in a plugin
|
||||||
* thread, which can be required because all GUI related operations have to be
|
* group so that several important events can be handled on the main thread,
|
||||||
* handled from the same thread. If during the Win32 message loop the plugin
|
* which can be required because in the Win32 model all GUI related operations
|
||||||
* performs a host callback and the host then calls a function on the plugin in
|
* have to be handled from the same thread. This will be run from the
|
||||||
* response, then this IO context will still be busy with the message loop
|
* application's main thread.
|
||||||
* which. To prevent a deadlock in this situation, we'll allow different threads
|
|
||||||
* to handle `dispatch()` calls while the message loop is running.
|
|
||||||
*/
|
*/
|
||||||
class PluginContext {
|
class MainContext {
|
||||||
public:
|
public:
|
||||||
PluginContext();
|
MainContext();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run the IO context. This rest of this class assumes that this is only
|
* Run the IO context. This rest of this class assumes that this is only
|
||||||
@@ -60,7 +58,7 @@ class PluginContext {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Drop all future work from the IO context. This does not necessarily mean
|
* Drop all future work from the IO context. This does not necessarily mean
|
||||||
* that the thread that called `plugin_context.run()` immediatly returns.
|
* that the thread that called `main_context.run()` immediatly returns.
|
||||||
*/
|
*/
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
@@ -98,6 +96,9 @@ class PluginContext {
|
|||||||
* Is `true` if the context is currently handling the Win32 message loop and
|
* Is `true` if the context is currently handling the Win32 message loop and
|
||||||
* incoming `dispatch()` events should be handled on their own thread (as
|
* incoming `dispatch()` events should be handled on their own thread (as
|
||||||
* posting them to the IO context will thus block).
|
* posting them to the IO context will thus block).
|
||||||
|
*
|
||||||
|
* TODO: No longer used after the thread rework, we can probably just drop
|
||||||
|
* this if everything works out
|
||||||
*/
|
*/
|
||||||
std::atomic_bool event_loop_active;
|
std::atomic_bool event_loop_active;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user