diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bb59c9e..60702ff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,9 @@ Versioning](https://semver.org/spec/v2.0.0.html). allows **ujam** plugins and other plugins made with the Gorilla Engine such as the **LoopCloud** plugins to function correctly as those plugins will throw a seemingly unrelated error when they output to a pipe. +- Added a small warning on initialization when `RLIMIT_RTTIME` is set to some + small value. This happens when using PipeWire, and it can cause crashes when + using loading plugins. ### Changed diff --git a/src/plugin/bridges/common.h b/src/plugin/bridges/common.h index 818f229a..6dd55b3b 100644 --- a/src/plugin/bridges/common.h +++ b/src/plugin/bridges/common.h @@ -22,11 +22,21 @@ // Generated inside of the build directory #include #include +#include #include "../../common/configuration.h" #include "../../common/utils.h" #include "../host-process.h" +/** + * 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 + * terminated during initialization because some plugins may take longer than + * the default 200ms to load. We'll show a warning when the realtime CPU time + * limit is not unlimited (`-1`/`RLIM_INFINITY`) and below this value. + */ +constexpr int rttime_min_safe_threshold = 30'000'000; + /** * Handles all common operations for hosting plugins such as initializing up the * plugin host process, setting up the logger, and logging debug information on @@ -122,9 +132,31 @@ class PluginBridge { << "'" << std::endl; init_msg << "plugin type: '" << plugin_type_to_string(info.plugin_type) << "'" << std::endl; - init_msg << "realtime: '" - << (has_realtime_priority.get() ? "yes" : "no") << "'" - << std::endl; + init_msg << "realtime: "; + if (has_realtime_priority.get()) { + // Warn if `RLIMIT_RTTIME` is set to some low value. This can happen + // when using PipeWire. + if (auto rttime_limit = get_rttime_limit()) { + if (*rttime_limit != RLIM_INFINITY && + *rttime_limit < rttime_min_safe_threshold) { + init_msg << "'yes-ish, see below'" << std::endl; + init_msg << std::endl; + 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; + init_msg << " until you fix this." << std::endl; + init_msg << std::endl; + } else { + init_msg << "'yes'" << std::endl; + } + } else { + init_msg << "'WARNING: Could not fetch RLIMIT_RTTIME'" + << std::endl; + } + } else { + init_msg << "'no'" << std::endl; + } init_msg << "sockets: '" << sockets.base_dir.string() << "'" << std::endl; @@ -339,7 +371,9 @@ class PluginBridge { /** * Whether this process runs with realtime priority. This is set on the * thread that's relaying STDOUT and STDERR output from Wine, hence the need - * for a future. + * for a future. We won't change the scheduler properties on the thread + * that's initializing the plugin because some DAWs may do that from the UI + * thread. */ std::future has_realtime_priority;