diff options
Diffstat (limited to 'src/pulsecore/core-util.c')
-rw-r--r-- | src/pulsecore/core-util.c | 96 |
1 files changed, 78 insertions, 18 deletions
diff --git a/src/pulsecore/core-util.c b/src/pulsecore/core-util.c index a71ba0b0..1fdd1890 100644 --- a/src/pulsecore/core-util.c +++ b/src/pulsecore/core-util.c @@ -50,6 +50,10 @@ #ifdef HAVE_SCHED_H #include <sched.h> + +#if defined(__linux__) && !defined(SCHED_RESET_ON_FORK) +#define SCHED_RESET_ON_FORK 0x40000000 +#endif #endif #ifdef HAVE_SYS_RESOURCE_H @@ -92,6 +96,10 @@ #include <xlocale.h> #endif +#ifdef HAVE_DBUS +#include "rtkit.h" +#endif + #include <pulse/xmalloc.h> #include <pulse/util.h> #include <pulse/utf8.h> @@ -552,16 +560,68 @@ char *pa_strlcpy(char *b, const char *s, size_t l) { return b; } +static int set_scheduler(int rtprio) { + struct sched_param sp; + int r; +#ifdef HAVE_DBUS + DBusError error; + DBusConnection *bus; + + dbus_error_init(&error); +#endif + + pa_zero(sp); + sp.sched_priority = rtprio; + +#ifdef SCHED_RESET_ON_FORK + if ((r = pthread_setschedparam(pthread_self(), SCHED_RR|SCHED_RESET_ON_FORK, &sp)) == 0) { + pa_log_debug("SCHED_RR|SCHED_RESET_ON_FORK worked."); + return 0; + } +#endif + + if ((r = pthread_setschedparam(pthread_self(), SCHED_RR, &sp)) == 0) { + pa_log_debug("SCHED_RR worked."); + return 0; + } + +#ifdef HAVE_DBUS + /* Try to talk to RealtimeKit */ + + if (!(bus = dbus_bus_get(DBUS_BUS_SYSTEM, &error))) { + pa_log("Failed to connect to system bus: %s\n", error.message); + dbus_error_free(&error); + errno = -EIO; + return -1; + } + + r = rtkit_make_realtime(bus, 0, rtprio); + dbus_connection_unref(bus); + + if (r >= 0) { + pa_log_debug("RealtimeKit worked."); + return 0; + } + + errno = -r; +#else + errno = r; +#endif + + return -1; +} + /* Make the current thread a realtime thread, and acquire the highest * rtprio we can get that is less or equal the specified parameter. If * the thread is already realtime, don't do anything. */ int pa_make_realtime(int rtprio) { #ifdef _POSIX_PRIORITY_SCHEDULING - struct sched_param sp; int r, policy; + struct sched_param sp; + int rtprio_try; - memset(&sp, 0, sizeof(sp)); + pa_zero(sp); policy = 0; if ((r = pthread_getschedparam(pthread_self(), &policy, &sp)) != 0) { @@ -569,29 +629,29 @@ int pa_make_realtime(int rtprio) { return -1; } - if (policy == SCHED_FIFO && sp.sched_priority >= rtprio) { - pa_log_info("Thread already being scheduled with SCHED_FIFO with priority %i.", sp.sched_priority); +#ifdef SCHED_RESET_ON_FORK + policy &= ~SCHED_RESET_ON_FORK; +#endif + + if ((policy == SCHED_FIFO || policy == SCHED_RR) && sp.sched_priority >= rtprio) { + pa_log_info("Thread already being scheduled with SCHED_FIFO/SCHED_RR with priority %i.", sp.sched_priority); return 0; } - sp.sched_priority = rtprio; - if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) != 0) { - - while (sp.sched_priority > 1) { - sp.sched_priority --; + if (set_scheduler(rtprio) >= 0) { + pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i.", rtprio); + return 0; + } - if ((r = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp)) == 0) { - pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i, which is lower than the requested %i.", sp.sched_priority, rtprio); - return 0; - } + for (rtprio_try = rtprio-1; rtprio_try >= 1; rtprio_try--) { + if (set_scheduler(rtprio_try)) { + pa_log_info("Successfully enabled SCHED_RR scheduling for thread, with priority %i, which is lower than the requested %i.", rtprio_try, rtprio); + return 0; } - - pa_log_warn("pthread_setschedparam(): %s", pa_cstrerror(r)); - return -1; } - pa_log_info("Successfully enabled SCHED_FIFO scheduling for thread, with priority %i.", sp.sched_priority); - return 0; + pa_log_warn("Failed to acquire real-time scheduling: %s", pa_cstrerror(r)); + return -1; #else errno = ENOTSUP; |