slackbuilds/audio/yabridge/load_posix_spawn_addclosefr...

124 lines
5.2 KiB
Diff

diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4af4cb1a..987a23fe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic
Versioning](https://semver.org/spec/v2.0.0.html).
-## [5.1.1] - 2024-11-04
+## [Unreleased]
+
+### Fixed
+
+- Worked around an interaction between **Ubuntu 24.10** and certain hosts like
+ **Ardour** that would cause yabridge to hang and eventually crash the host by
+ consuming too much memory. This only affected the prebuilt binaries from the
+ releases page.
+
+## [5.1.1] - 2024-12-23
### Fixed
diff --git a/src/common/process.cpp b/src/common/process.cpp
index d9f407d1..5408abed 100644
--- a/src/common/process.cpp
+++ b/src/common/process.cpp
@@ -19,6 +19,7 @@
#include <cassert>
#include <iostream>
+#include <dlfcn.h>
#include <spawn.h>
#include <sys/wait.h>
@@ -323,6 +324,48 @@ Process::StatusResult Process::spawn_get_status() const {
}
}
+/**
+ * Add file handle close actions to a `posix_spawn_file_actions_t` that close
+ * all non-stdio file descriptors.
+ *
+ * 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.
+ */
+static void close_non_stdio_file_descriptions(
+ posix_spawn_file_actions_t& actions) {
+#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 34)
+ posix_spawn_file_actions_addclosefrom_np(&actions, STDERR_FILENO + 1);
+#else
+ // NOTE: As of writing, yabridge is compiled on Ubuntu 20.04, where
+ // `posix_spawn_file_actions_addclosefrom_np()` is not yet available.
+ // For whatever reason that may be, on Ubuntu 24.10 closing all file
+ // handles manually becomes very slow and starts to leak memory when
+ // running yabridge under Ardour. We could bump the minimum Ubuntu
+ // version supported by the binaries and always use this function, but
+ // loading the function at runtime should be fine and gives us better
+ // compatibility even if yabridge is compiled on an older distro.
+ //
+ // https://github.com/robbert-vdh/yabridge/issues/377
+ int (*posix_spawn_file_actions_addclosefrom_np)(posix_spawn_file_actions_t*,
+ int);
+ posix_spawn_file_actions_addclosefrom_np =
+ reinterpret_cast<decltype(posix_spawn_file_actions_addclosefrom_np)>(
+ dlsym(nullptr, "posix_spawn_file_actions_addclosefrom_np"));
+
+ if (posix_spawn_file_actions_addclosefrom_np) {
+ posix_spawn_file_actions_addclosefrom_np(&actions, STDERR_FILENO + 1);
+ } else {
+ const int max_fds = static_cast<int>(sysconf(_SC_OPEN_MAX));
+ for (int fd = STDERR_FILENO + 1; fd < max_fds; fd++) {
+ posix_spawn_file_actions_addclose(&actions, fd);
+ }
+ }
+#endif
+}
+
#ifndef WITHOUT_ASIO
Process::HandleResult Process::spawn_child_piped(
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
@@ -348,20 +391,7 @@ Process::HandleResult Process::spawn_child_piped(
posix_spawn_file_actions_adddup2(&actions, stderr_pipe_fds[1],
STDERR_FILENO);
// We'll close the four pipe fds along with the rest of the file descriptors
-
-// 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.
-#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 34)
- posix_spawn_file_actions_addclosefrom_np(&actions, STDERR_FILENO + 1);
-#else
- const int max_fds = static_cast<int>(sysconf(_SC_OPEN_MAX));
- for (int fd = STDERR_FILENO + 1; fd < max_fds; fd++) {
- posix_spawn_file_actions_addclose(&actions, fd);
- }
-#endif
+ close_non_stdio_file_descriptions(actions);
pid_t child_pid = 0;
const auto result = posix_spawnp(&child_pid, command_.c_str(), &actions,
@@ -407,16 +437,7 @@ Process::HandleResult Process::spawn_child_redirected(
O_WRONLY | O_CREAT | O_APPEND, 0640);
posix_spawn_file_actions_addopen(&actions, STDERR_FILENO, filename.c_str(),
O_WRONLY | O_CREAT | O_APPEND, 0640);
-
- // See the note in the other function
-#if (__GLIBC__ > 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 34)
- posix_spawn_file_actions_addclosefrom_np(&actions, STDERR_FILENO + 1);
-#else
- const int max_fds = static_cast<int>(sysconf(_SC_OPEN_MAX));
- for (int fd = STDERR_FILENO + 1; fd < max_fds; fd++) {
- posix_spawn_file_actions_addclose(&actions, fd);
- }
-#endif
+ close_non_stdio_file_descriptions(actions);
pid_t child_pid = 0;
const auto result = posix_spawnp(&child_pid, command_.c_str(), &actions,