aboutsummaryrefslogtreecommitdiff
path: root/audio/yabridge/load_posix_spawn_addclosefrom_np.diff
blob: 9c10fafbb241bcb447dbc76e063e6b484efbfcac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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,