Unify STDIO redirection in Wine host launching

This may also fix some weird cases where everything appeared to work
fine, but where the file descriptors weren't actually assigned
correctly. Not sure what that happened, but it with carla-single the
Wine host's STDOUT and STDERR would still point to the orignal pty even
though everything still went through the pipes.
This commit is contained in:
Robbert van der Helm
2021-05-18 15:34:35 +02:00
parent f7901266b7
commit 99428ba28e
2 changed files with 47 additions and 43 deletions
+4 -43
View File
@@ -18,8 +18,6 @@
#include <boost/asio/read_until.hpp>
#include <boost/process/env.hpp>
#include <boost/process/extend.hpp>
#include <boost/process/io.hpp>
#include <boost/process/start_dir.hpp>
#include "src/common/utils.h"
@@ -27,40 +25,6 @@
namespace bp = boost::process;
namespace fs = boost::filesystem;
/**
* Simple helper function around `boost::process::child` that launches the host
* application (`*.exe`) wrapped in winedbg if compiling with
* `-Dwith-winedbg=true`. Keep in mind that winedbg does not handle arguments
* containing spaces, so most Windows paths will be split up into multiple
* arugments.
*/
template <typename... Args>
bp::child launch_host(fs::path host_path, Args&&... args) {
return bp::child(
#ifdef WITH_WINEDBG
// Use the terminal output or `$YABRIDGE_DEBUG_LOG` to get yabridge's
// output, and use the printed target command in a GDB session where you
// load the yabridge `.so` file you're trying to debug
"/usr/bin/winedbg", "--gdb", "--no-start", host_path.string() + ".so",
#else
host_path,
#endif
// NOTE: If the Wine process outlives the host, then it may cause issues
// if our process is still keeping the host's file descriptors
// alive that. This can prevent Ardour from restarting after an
// unexpected shutdown. Because of this we won't use `vfork()`,
// but instead we'll just manually close all non-STDIO file
// descriptors.
bp::extend::on_exec_setup =
[](auto& /*executor*/) {
const int max_fds = static_cast<int>(sysconf(_SC_OPEN_MAX));
for (int fd = STDERR_FILENO + 1; fd < max_fds; fd++) {
close(fd);
}
},
std::forward<Args>(args)...);
}
HostProcess::HostProcess(boost::asio::io_context& io_context,
Logger& logger,
Sockets& sockets)
@@ -100,12 +64,10 @@ IndividualHost::IndividualHost(boost::asio::io_context& io_context,
// watchdog on the Wine plugin host process that shuts down the
// sockets after this process shuts down
std::to_string(getpid()),
bp::env = plugin_info.create_host_env(),
bp::std_out = stdout_pipe,
bp::std_err = stderr_pipe
bp::env = plugin_info.create_host_env()
#ifdef WITH_WINEDBG
, // winedbg has no reliable way to escape spaces, so
// we'll start the process in the plugin's directory
, // winedbg has no reliable way to escape spaces, so
// we'll start the process in the plugin's directory
bp::start_dir = plugin_info.windows_plugin_path.parent_path()
#endif
)) {
@@ -189,8 +151,7 @@ GroupHost::GroupHost(boost::asio::io_context& io_context,
// it will likely outlive it.
bp::child group_host =
launch_host(host_path, group_socket_path,
bp::env = plugin_info.create_host_env(),
bp::std_out = stdout_pipe, bp::std_err = stderr_pipe);
bp::env = plugin_info.create_host_env());
group_host.detach();
const pid_t group_host_pid = group_host.id();
+43
View File
@@ -22,6 +22,8 @@
#include <boost/asio/streambuf.hpp>
#include <boost/filesystem.hpp>
#include <boost/process/child.hpp>
#include <boost/process/extend.hpp>
#include <boost/process/io.hpp>
#include "../common/communication/common.h"
#include "../common/logging/common.h"
@@ -57,6 +59,47 @@ class HostProcess {
*/
virtual void terminate() = 0;
/**
* Simple helper function around `boost::process::child` that launches the
* host application (`*.exe`) with some basic setup. This includes setting
* up the asynchronous pipes for STDIO redirection, closing file descriptors
* to prevent leaks, and wrapping everything in winedbg if we're compiling
* with `-Dwith-winedbg=true`. Keep in mind that winedbg does not handle
* arguments containing spaces, so most Windows paths will be split up into
* multiple arugments.
*/
template <typename... Args>
boost::process::child launch_host(boost::filesystem::path host_path,
Args&&... args) {
return boost::process::child(
#ifdef WITH_WINEDBG
// Use the terminal output or `$YABRIDGE_DEBUG_LOG` to get
// yabridge's output, and use the printed target command in a GDB
// session where you load the yabridge `.so` file you're trying to
// debug
"/usr/bin/winedbg", "--gdb", "--no-start",
host_path.string() + ".so",
#else
host_path,
#endif
boost::process::std_out = stdout_pipe,
boost::process::std_err = stderr_pipe,
// NOTE: If the Wine process outlives the host, then it may cause
// issues if our process is still keeping the host's file
// descriptors alive that. This can prevent Ardour from
// restarting after an unexpected shutdown. Because of this we
// won't use `vfork()`, but instead we'll just manually close
// all non-STDIO file descriptors.
boost::process::extend::on_exec_setup =
[this](auto& /*executor*/) {
const int max_fds = static_cast<int>(sysconf(_SC_OPEN_MAX));
for (int fd = STDERR_FILENO + 1; fd < max_fds; fd++) {
close(fd);
}
},
std::forward<Args>(args)...);
}
protected:
/**
* Initialize the host process by setting up the STDIO redirection.