Manually close descriptors instead of using vfork

With `vfork()` the child process inherits the parents process image and
prevents copying them, but if it outlives its parent then the file
descriptors will still remain open. Manually closing all file
descriptors is the only solution here.

This was only an issue with Ardour since they don't open all of their
files with `FD_CLOEXEC`. Last update's watchdog timer somewhat mitigated
the issue, but Ardour should now no longer freeze when reopening because
of this. The watchdog timer is still necessary, since hanging Wine
processes will still prevent the Wine server from shutting down.
This commit is contained in:
Robbert van der Helm
2021-05-16 15:24:31 +02:00
parent 448243050a
commit 883b6b7700
3 changed files with 21 additions and 7 deletions
+15 -4
View File
@@ -18,6 +18,7 @@
#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>
@@ -44,10 +45,20 @@ bp::child launch_host(fs::path host_path, Args&&... args) {
#else
host_path,
#endif
// We'll use vfork() instead of fork to avoid potential issues with
// inheriting file descriptors
// https://github.com/robbert-vdh/yabridge/issues/45
bp::posix::use_vfork, std::forward<Args>(args)...);
// 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,