From 817656504dea224dbf849e5e988e277d798ae08e Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Fri, 9 Feb 2018 18:30:24 +0100
Subject: [PATCH] thread/Util: implement system call wrapper for
 sched_setscheduler()

There is a POSIX definition for sched_setscheduler(), but Linux does
not implement that; instead of changing the process's scheduler, it
only affects one thread.  This has caused some confusion among
application developers and C library developers.

While glibc implements Linux semantics, Musl has made their
sched_setscheduler() function an always-failing no-op, causing the
error message "sched_setscheduler failed: Function not implemented".

 http://git.musl-libc.org/cgit/musl/commit/src/sched/sched_setscheduler.c?id=1e21e78bf7a5c24c217446d8760be7b7188711c2

Instead of relying on the C library which may be unreliable here, we
now roll our own system call wrapper.

Closes #218
---
 NEWS                |  1 +
 src/thread/Util.cxx | 21 ++++++++++++++++++---
 2 files changed, 19 insertions(+), 3 deletions(-)

diff --git a/NEWS b/NEWS
index b82f7b6f0..b11108401 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,5 @@
 ver 0.20.17 (not yet released)
+* fix real-time and idle scheduling with Musl
 
 ver 0.20.16 (2018/02/03)
 * output
diff --git a/src/thread/Util.cxx b/src/thread/Util.cxx
index f30d57368..0dbf8181a 100644
--- a/src/thread/Util.cxx
+++ b/src/thread/Util.cxx
@@ -38,7 +38,9 @@
 #include <windows.h>
 #endif
 
-#if defined(__linux__) && !defined(ANDROID)
+#ifdef __linux__
+
+#ifndef ANDROID
 
 static int
 linux_ioprio_set(int which, int who, int ioprio)
@@ -58,6 +60,19 @@ ioprio_set_idle()
 	linux_ioprio_set(_IOPRIO_WHO_PROCESS, 0, _IOPRIO_IDLE);
 }
 
+#endif /* !ANDROID */
+
+/**
+ * Wrapper for the "sched_setscheduler" system call.  We don't use the
+ * one from the C library because Musl has an intentionally broken
+ * implementation.
+ */
+static int
+linux_sched_setscheduler(pid_t pid, int sched, const struct sched_param *param)
+{
+	return syscall(__NR_sched_setscheduler, pid, sched, param);
+}
+
 #endif
 
 void
@@ -66,7 +81,7 @@ SetThreadIdlePriority()
 #ifdef __linux__
 #ifdef SCHED_IDLE
 	static struct sched_param sched_param;
-	sched_setscheduler(0, SCHED_IDLE, &sched_param);
+	linux_sched_setscheduler(0, SCHED_IDLE, &sched_param);
 #endif
 
 #ifndef ANDROID
@@ -92,7 +107,7 @@ SetThreadRealtime()
 	policy |= SCHED_RESET_ON_FORK;
 #endif
 
-	if (sched_setscheduler(0, policy, &sched_param) < 0)
+	if (linux_sched_setscheduler(0, policy, &sched_param) < 0)
 		throw MakeErrno("sched_setscheduler failed");
 #endif	// __linux__
 };