Christian Franke wrote:
Corinna Vinschen wrote:
Hi Christian,
On Dec 6 17:52, Christian Franke wrote:
A first attempt to add SCHED_BATCH.
Still TODO:
- Add SCHED_IDLE/BATCH to winsup/doc/posix.xml
- Provide correct values in (18) and (19) of /proc/PID/stat for
SCHED_BATCH.
- Provide correct value in (18) of /proc/PID/stat for SCHED_FIFO/RR.
--
Regards,
Christian
From 0822917252fdade3edc240b4fbfd3c0f47ef1deb Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.fra...@t-online.de>
Date: Fri, 6 Dec 2024 17:32:29 +0100
Subject: [PATCH] Cygwin: sched_setscheduler: accept SCHED_BATCH
Add SCHED_BATCH to <sys/sched.h>. SCHED_BATCH is similar to
SCHED_OTHER,
except that the nice value is mapped to a one step lower Windows
priority.
Rework the mapping functions to ease the addition of this
functionality.
Signed-off-by: Christian Franke <christian.fra...@t-online.de>
---
newlib/libc/include/sys/sched.h | 8 ++
winsup/cygwin/local_includes/miscfuncs.h | 4 +-
winsup/cygwin/miscfuncs.cc | 155
+++++++++++++----------
winsup/cygwin/release/3.6.0 | 11 +-
winsup/cygwin/sched.cc | 15 ++-
winsup/cygwin/syscalls.cc | 20 +--
6 files changed, 129 insertions(+), 84 deletions(-)
diff --git a/newlib/libc/include/sys/sched.h
b/newlib/libc/include/sys/sched.h
index c96355c24..265215211 100644
--- a/newlib/libc/include/sys/sched.h
+++ b/newlib/libc/include/sys/sched.h
@@ -38,6 +38,14 @@ extern "C" {
#define SCHED_FIFO 1
#define SCHED_RR 2
+#if __GNU_VISIBLE
+#if defined(__CYGWIN__)
+#define SCHED_BATCH 0
+#else
+#define SCHED_BATCH 3
+#endif
+#endif
I would prefer that SCHED_BATCH gets its own, single value.
There's no good reason to add another ifdef for that. Why
not just #define SCHED_BATCH 6?
The idea was to keep the non-Cygwin value in sync with Linux.
https://github.com/torvalds/linux/blob/fac04ef/include/uapi/linux/sched.h#L111
Of course we could drop this idea and use 6.
Attached, no other changes.
From 3db9d3c9729f14910035ee969f7e9cff43437317 Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.fra...@t-online.de>
Date: Mon, 9 Dec 2024 12:14:07 +0100
Subject: [PATCH] Cygwin: sched_setscheduler: accept SCHED_BATCH
Add SCHED_BATCH to <sys/sched.h>. SCHED_BATCH is similar to SCHED_OTHER,
except that the nice value is mapped to a one step lower Windows priority.
Rework the mapping functions to ease the addition of this functionality.
Signed-off-by: Christian Franke <christian.fra...@t-online.de>
---
newlib/libc/include/sys/sched.h | 1 +
winsup/cygwin/local_includes/miscfuncs.h | 4 +-
winsup/cygwin/miscfuncs.cc | 155 +++++++++++++----------
winsup/cygwin/release/3.6.0 | 11 +-
winsup/cygwin/sched.cc | 15 ++-
winsup/cygwin/syscalls.cc | 20 +--
6 files changed, 122 insertions(+), 84 deletions(-)
diff --git a/newlib/libc/include/sys/sched.h b/newlib/libc/include/sys/sched.h
index c96355c24..6977d3d4a 100644
--- a/newlib/libc/include/sys/sched.h
+++ b/newlib/libc/include/sys/sched.h
@@ -44,6 +44,7 @@ extern "C" {
#if __GNU_VISIBLE
#define SCHED_IDLE 5
+#define SCHED_BATCH 6
#endif
/* Scheduling Parameters */
diff --git a/winsup/cygwin/local_includes/miscfuncs.h
b/winsup/cygwin/local_includes/miscfuncs.h
index 57dcbfeab..6001a1636 100644
--- a/winsup/cygwin/local_includes/miscfuncs.h
+++ b/winsup/cygwin/local_includes/miscfuncs.h
@@ -44,8 +44,8 @@ is_alt_numpad_event (PINPUT_RECORD pirec)
&& pirec->Event.KeyEvent.wVirtualScanCode == 0x38;
}
-int winprio_to_nice (DWORD);
-DWORD nice_to_winprio (int &);
+int winprio_to_nice (DWORD prio, bool batch = false);
+DWORD nice_to_winprio (int &nice, bool batch = false);
bool set_and_check_winprio (HANDLE proc, DWORD prio, bool set = true);
bool create_pipe (PHANDLE, PHANDLE, LPSECURITY_ATTRIBUTES, DWORD);
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index 0146704ea..6faf04937 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -103,84 +103,111 @@ yield ()
Sleep (0L);
}
-/* Get a default value for the nice factor. When changing these values,
- have a look into the below function nice_to_winprio. The values must
- match the layout of the static "priority" array. */
-int
-winprio_to_nice (DWORD prio)
+/*
+ Mapping of nice value from/to Windows priority
+ ('batch' is used for SCHED_BATCH policy).
+
+ nice_to_winprio() winprio_to_nice()
+ !batch batch Level Windows priority class !batch batch
+ 12...19 4...19 0 IDLE_PRIORITY_CLASS 16 8
+ 4...11 -4....3 1 BELOW_NORMAL_PRIORITY_CLASS 8 0
+ -4....3 -12...-5 2 NORMAL_PRIORITY_CLASS 0 -8
+ -12...-5 -13..-19 3 ABOVE_NORMAL_PRIORITY_CLASS -8 -16
+ -13..-19 -20 4 HIGH_PRIORITY_CLASS -16 -20
+ -20 - 5 REALTIME_PRIORITY_CLASS -20 -20
+*/
+
+/* *_PRIORITY_CLASS -> 0...5 */
+constexpr int
+winprio_to_level (DWORD prio)
{
switch (prio)
{
- case REALTIME_PRIORITY_CLASS:
- return -20;
- case HIGH_PRIORITY_CLASS:
- return -16;
- case ABOVE_NORMAL_PRIORITY_CLASS:
- return -8;
- case NORMAL_PRIORITY_CLASS:
- return 0;
- case BELOW_NORMAL_PRIORITY_CLASS:
- return 8;
- case IDLE_PRIORITY_CLASS:
- return 16;
+ case IDLE_PRIORITY_CLASS: return 0;
+ case BELOW_NORMAL_PRIORITY_CLASS: return 1;
+ default: return 2;
+ case ABOVE_NORMAL_PRIORITY_CLASS: return 3;
+ case HIGH_PRIORITY_CLASS: return 4;
+ case REALTIME_PRIORITY_CLASS: return 5;
}
- return 0;
+}
+
+/* 0...5 -> *_PRIORITY_CLASS */
+constexpr DWORD
+level_to_winprio (int level)
+{
+ switch (level)
+ {
+ case 0: return IDLE_PRIORITY_CLASS;
+ case 1: return BELOW_NORMAL_PRIORITY_CLASS;
+ default: return NORMAL_PRIORITY_CLASS;
+ case 3: return ABOVE_NORMAL_PRIORITY_CLASS;
+ case 4: return HIGH_PRIORITY_CLASS;
+ case 5: return REALTIME_PRIORITY_CLASS;
+ }
+}
+
+/* *_PRIORITY_CLASS -> nice value */
+constexpr int
+winprio_to_nice_impl (DWORD prio, bool batch = false)
+{
+ int level = winprio_to_level (prio);
+ if (batch && level < 5)
+ level++;
+ return (level < 5 ? NZERO - 1 - 3 - level * 8 : -NZERO);
+}
+
+/* nice value -> *_PRIORITY_CLASS */
+constexpr DWORD
+nice_to_winprio_impl (int nice, bool batch = false)
+{
+ int level = (nice > -NZERO ? (NZERO - 1 - nice) / 8 : 5);
+ if (batch && level > 0)
+ level--;
+ return level_to_winprio (level);
+}
+
+/* Check consistency at compile time. */
+constexpr bool
+check_nice_winprio_mapping ()
+{
+ for (int nice = -NZERO; nice < NZERO; nice++)
+ for (int batch = 0; batch <= 1; batch++) {
+ DWORD prio = nice_to_winprio_impl (nice, !!batch);
+ int nice2 = winprio_to_nice_impl (prio, !!batch);
+ DWORD prio2 = nice_to_winprio_impl (nice2, !!batch);
+ if (prio != prio2)
+ return false;
+ }
+ return true;
+}
+
+static_assert (check_nice_winprio_mapping());
+static_assert (nice_to_winprio_impl(NZERO-1, false) == IDLE_PRIORITY_CLASS);
+static_assert (nice_to_winprio_impl(0, true) == BELOW_NORMAL_PRIORITY_CLASS);
+static_assert (winprio_to_nice_impl(BELOW_NORMAL_PRIORITY_CLASS, true) == 0);
+static_assert (nice_to_winprio_impl(0, false) == NORMAL_PRIORITY_CLASS);
+static_assert (winprio_to_nice_impl(NORMAL_PRIORITY_CLASS, false) == 0);
+static_assert (nice_to_winprio_impl(-NZERO, false) == REALTIME_PRIORITY_CLASS);
+
+/* Get a default value for the nice factor. */
+int
+winprio_to_nice (DWORD prio, bool batch /* = false */)
+{
+ return winprio_to_nice_impl (prio, batch);
}
/* Get a Win32 priority matching the incoming nice factor. The incoming
nice is limited to the interval [-NZERO,NZERO-1]. */
DWORD
-nice_to_winprio (int &nice)
+nice_to_winprio (int &nice, bool batch /* = false */)
{
- static const DWORD priority[] =
- {
- REALTIME_PRIORITY_CLASS, /* 0 */
- HIGH_PRIORITY_CLASS, /* 1 */
- HIGH_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS,
- HIGH_PRIORITY_CLASS, /* 7 */
- ABOVE_NORMAL_PRIORITY_CLASS, /* 8 */
- ABOVE_NORMAL_PRIORITY_CLASS,
- ABOVE_NORMAL_PRIORITY_CLASS,
- ABOVE_NORMAL_PRIORITY_CLASS,
- ABOVE_NORMAL_PRIORITY_CLASS,
- ABOVE_NORMAL_PRIORITY_CLASS,
- ABOVE_NORMAL_PRIORITY_CLASS,
- ABOVE_NORMAL_PRIORITY_CLASS, /* 15 */
- NORMAL_PRIORITY_CLASS, /* 16 */
- NORMAL_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS,
- NORMAL_PRIORITY_CLASS, /* 23 */
- BELOW_NORMAL_PRIORITY_CLASS, /* 24 */
- BELOW_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS,
- BELOW_NORMAL_PRIORITY_CLASS, /* 31 */
- IDLE_PRIORITY_CLASS, /* 32 */
- IDLE_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS,
- IDLE_PRIORITY_CLASS /* 39 */
- };
if (nice < -NZERO)
nice = -NZERO;
else if (nice > NZERO - 1)
nice = NZERO - 1;
- DWORD prio = priority[nice + NZERO];
- return prio;
+
+ return nice_to_winprio_impl (nice, batch);
}
/* Set Win32 priority or return false on failure. Also return
diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0
index 8ca91f0c9..11f745b23 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -54,11 +54,12 @@ What changed:
to POSIX and Linux (glibc >= 2.2.4) behavior.
- sched_setscheduler(2) now emulates changes between SCHED_OTHER,
- SCHED_IDLE, SCHED_FIFO and SCHED_RR. If SCHED_OTHER is selected, the
- Windows priority is set according to the nice value. If SCHED_IDLE is
+ SCHED_BATCH, SCHED_IDLE, SCHED_FIFO and SCHED_RR. If SCHED_OTHER or
+ SCHED_BATCH is selected, the Windows priority is set according to the
+ nice value where SCHED_BATCH sets a one step lower priority. If
+ SCHED_IDLE is selected, the nice value is preserved and the Windows
+ priority is set to IDLE_PRIORITY_CLASS. If SCHED_FIFO or SCHED_RR is
selected, the nice value is preserved and the Windows priority is set
- to IDLE_PRIORITY_CLASS. If SCHED_FIFO or SCHED_RR is selected, the
- nice value is preserved and the Windows priority is set according to
- the realtime priority.
+ according to the realtime priority.
Note: Windows does not offer alternative scheduling policies so
this could only emulate API behavior.
diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc
index 8b4e7efc4..ec62ea83c 100644
--- a/winsup/cygwin/sched.cc
+++ b/winsup/cygwin/sched.cc
@@ -34,6 +34,7 @@ sched_get_priority_max (int policy)
switch (policy)
{
case SCHED_OTHER:
+ case SCHED_BATCH:
case SCHED_IDLE:
return 0;
case SCHED_FIFO:
@@ -51,6 +52,7 @@ sched_get_priority_min (int policy)
switch (policy)
{
case SCHED_OTHER:
+ case SCHED_BATCH:
case SCHED_IDLE:
return 0;
case SCHED_FIFO:
@@ -95,7 +97,8 @@ sched_getparam (pid_t pid, struct sched_param *param)
return -1;
}
- if (p->sched_policy == SCHED_OTHER || p->sched_policy == SCHED_IDLE)
+ if (p->sched_policy == SCHED_OTHER || p->sched_policy == SCHED_BATCH
+ || p->sched_policy == SCHED_IDLE)
{
/* No realtime policy. */
param->sched_priority = 0;
@@ -234,9 +237,10 @@ sched_setparam_pinfo (pinfo & p, const struct sched_param
*param)
/* calculate our desired priority class. We only reserve a small area
(31/32) for realtime priority. */
DWORD pclass;
- if (p->sched_policy == SCHED_OTHER && pri == 0)
+ bool batch = (p->sched_policy == SCHED_BATCH);
+ if ((p->sched_policy == SCHED_OTHER || batch) && pri == 0)
/* No realtime policy, reapply the nice value. */
- pclass = nice_to_winprio (p->nice);
+ pclass = nice_to_winprio (p->nice, batch);
else if (p->sched_policy == SCHED_IDLE && pri == 0)
/* Idle policy, ignore the nice value. */
pclass = IDLE_PRIORITY_CLASS;
@@ -422,8 +426,9 @@ sched_setscheduler (pid_t pid, int policy,
const struct sched_param *param)
{
if (!(pid >= 0 && param &&
- (((policy == SCHED_OTHER || policy == SCHED_IDLE) &&
param->sched_priority == 0) ||
- ((policy == SCHED_FIFO || policy == SCHED_RR) &&
valid_sched_parameters(param)))))
+ (((policy == SCHED_OTHER || policy == SCHED_BATCH || policy ==
SCHED_IDLE)
+ && param->sched_priority == 0) || ((policy == SCHED_FIFO || policy ==
SCHED_RR)
+ && valid_sched_parameters(param)))))
{
set_errno (EINVAL);
return -1;
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 0deefeff6..5ff0f02b9 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -3816,9 +3816,6 @@ vhangup ()
extern "C" int
setpriority (int which, id_t who, int value)
{
- DWORD prio = nice_to_winprio (value);
- int error = 0;
-
switch (which)
{
case PRIO_PROCESS:
@@ -3827,8 +3824,10 @@ setpriority (int which, id_t who, int value)
if ((pid_t) who == myself->pid)
{
/* If realtime policy is set, keep prio but check its validity. */
+ bool batch = (myself->sched_policy == SCHED_BATCH);
+ DWORD prio = nice_to_winprio (value, batch);
if (!set_and_check_winprio (GetCurrentProcess (), prio,
- (myself->sched_policy == SCHED_OTHER)))
+ (myself->sched_policy == SCHED_OTHER || batch)))
{
set_errno (EACCES);
return -1;
@@ -3850,6 +3849,8 @@ setpriority (int which, id_t who, int value)
set_errno (EINVAL);
return -1;
}
+
+ int error = 0;
winpids pids ((DWORD) PID_MAP_RW);
for (DWORD i = 0; i < pids.npids; ++i)
{
@@ -3878,9 +3879,11 @@ setpriority (int which, id_t who, int value)
error = EPERM;
else
{
+ bool batch = (p->sched_policy == SCHED_BATCH);
+ DWORD prio = nice_to_winprio (value, batch);
/* If realtime policy is set, keep prio but check its validity. */
if (!set_and_check_winprio (proc_h, prio,
- (p->sched_policy == SCHED_OTHER)))
+ (p->sched_policy == SCHED_OTHER || batch)))
error = EACCES;
else
p->nice = value;
@@ -3909,11 +3912,12 @@ getpriority (int which, id_t who)
who = myself->pid;
if ((pid_t) who == myself->pid)
{
- if (myself->sched_policy == SCHED_OTHER)
+ bool batch = (myself->sched_policy == SCHED_BATCH);
+ if (myself->sched_policy == SCHED_OTHER || batch)
{
DWORD winprio = GetPriorityClass (GetCurrentProcess());
- if (winprio != nice_to_winprio (myself->nice))
- myself->nice = winprio_to_nice (winprio);
+ if (winprio != nice_to_winprio (myself->nice, batch))
+ myself->nice = winprio_to_nice (winprio, batch);
}
return myself->nice;
}
--
2.45.1