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
+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;