Warn on startup if RLIMIT_MEMLOCK is set too low

This should diagnose issues like #119.
This commit is contained in:
Robbert van der Helm
2021-07-18 23:12:10 +02:00
parent 5bce89d50b
commit 0e57f410a9
4 changed files with 60 additions and 5 deletions
+2
View File
@@ -14,6 +14,8 @@ Versioning](https://semver.org/spec/v2.0.0.html).
shared memory. If you have not yet set up realtime priviliges and memory
locking limits for your user, then yabridge may not be able to map enough
shared memory for processing audio in plugins with a lot of inputs or outputs.
- Also added a warning for thisq in the initialization message if yabridge
detects a low value for `RLIMIT_MEMLOCK`.
### Fixed
+9
View File
@@ -57,6 +57,15 @@ bool set_realtime_priority(bool sched_fifo, int priority) noexcept {
&params) == 0;
}
std::optional<rlim_t> get_memlock_limit() noexcept {
rlimit limits{};
if (getrlimit(RLIMIT_MEMLOCK, &limits) == 0) {
return limits.rlim_cur;
} else {
return std::nullopt;
}
}
std::optional<rlim_t> get_rttime_limit() noexcept {
rlimit limits{};
if (getrlimit(RLIMIT_RTTIME, &limits) == 0) {
+13 -4
View File
@@ -106,10 +106,19 @@ std::optional<int> get_realtime_priority() noexcept;
bool set_realtime_priority(bool sched_fifo, int priority = 5) noexcept;
/**
* Get the (soft) `RTTIME` resource limit, or the amount of time a `SCHED_FIFO`
* process may spend uninterrupted before being killed by the scheduler. A value
* of `-1`/`RLIM_INFINITY` means that there is no limit. If there was some error
* fetching this value, then a nullopt will be returned.
* Get the (soft) `RLIMIT_MEMLOCK` resource limit. If this is set to some low
* value, then we'll print a warning during initialization because mapping
* shared memory may fail. A value of `-1`/`RLIM_INFINITY` means that there is
* no limit. If there was some error fetching this value, then a nullopt will be
* returned.
*/
std::optional<rlim_t> get_memlock_limit() noexcept;
/**
* Get the (soft) `RLIMIT_RTTIME` resource limit, or the amount of time a
* `SCHED_FIFO` process may spend uninterrupted before being killed by the
* scheduler. A value of `-1`/`RLIM_INFINITY` means that there is no limit. If
* there was some error fetching this value, then a nullopt will be returned.
*
* This is useful to diagnose issues caused by PipeWire. They use rtkit at the
* moment, and both rtkit and PipeWire's rtkit module will enable a realtime CPU
+36 -1
View File
@@ -29,6 +29,14 @@
#include "../../common/utils.h"
#include "../host-process.h"
/**
* If the amount of lockable memory is below this, then we'll warn about it
* during startup. Otherwise we may run into issues when mapping shared memory
* for plugins with a lot of inputs or outputs. We would of course prefer this
* to just be set to `RLIM_INFINITY`, but this seems like a reasonable amount.
*/
constexpr int memlock_min_safe_threshold = 256 << 20;
/**
* PipeWire uses rtkit, and both set `RLIMIT_RTTIME` to some low value. Normally
* this is kept at unlimited, and low values can cause the host process to get
@@ -149,7 +157,8 @@ class PluginBridge {
init_msg << " RLIMIT_RTTIME is set to " << *rttime_limit
<< " us. This can happen when" << std::endl;
init_msg << " using PipeWire. yabridge may crash when "
<< "loading plugins" << std::endl;
"loading plugins"
<< std::endl;
init_msg << " until you fix this." << std::endl;
init_msg << std::endl;
} else {
@@ -162,6 +171,32 @@ class PluginBridge {
} else {
init_msg << "'no'" << std::endl;
}
// This doesn't really fit here, but this seems like the place to warn
// about low memlock limits. Because this is meant to just be a helpful
// warning, we won't print anything at all when there's no need to.
if (auto memlock_limit = get_memlock_limit()) {
if (*memlock_limit != RLIM_INFINITY &&
*memlock_limit < memlock_min_safe_threshold) {
init_msg << "memlock limit: 'WARNING: " << *memlock_limit
<< " bytes, see below'" << std::endl;
init_msg << std::endl;
init_msg
<< " With a low memory locking limit, yabridge may not be"
<< std::endl;
init_msg << " be able to map enough shared memory for audio "
"buffers,"
<< std::endl;
init_msg << " yabridge may crash when using plugins with "
"many inputs"
<< std::endl;
init_msg << " or outputs until you fix this." << std::endl;
init_msg << std::endl;
}
} else {
init_msg
<< "memlock limit: 'WARNING: Could not fetch RLIMIT_MEMLOCK'"
<< std::endl;
}
init_msg << "sockets: '" << sockets.base_dir.string() << "'"
<< std::endl;