A very first attempt to let sched_setscheduler() do something possibly
useful.
This patch is on top of
Cygwin: setpriority, sched_setparam: add missing process access right
--
Regards,
Christian
From 54a9b7be2ab4284203daaf154478118cc52409cf Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.fra...@t-online.de>
Date: Fri, 29 Nov 2024 18:41:12 +0100
Subject: [PATCH] Cygwin: sched_setscheduler: accept SCHED_OTHER, SCHED_FIFO
and SCHED_RR
If SCHED_OTHER is selected, set the Windows priority according to the
nice value. If SCHED_FIFO or SCHED_RR is selected, preserve the nice
value and set the Windows priority according to the sched_priority
parameter.
Signed-off-by: Christian Franke <christian.fra...@t-online.de>
---
winsup/cygwin/fork.cc | 1 +
winsup/cygwin/local_includes/miscfuncs.h | 2 +-
winsup/cygwin/local_includes/pinfo.h | 4 +-
winsup/cygwin/miscfuncs.cc | 23 +++--
winsup/cygwin/pinfo.cc | 1 +
winsup/cygwin/release/3.6.0 | 8 ++
winsup/cygwin/sched.cc | 122 ++++++++++++++---------
winsup/cygwin/spawn.cc | 1 +
winsup/cygwin/syscalls.cc | 19 ++--
9 files changed, 118 insertions(+), 63 deletions(-)
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 0742ab363..7d976e882 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -402,6 +402,7 @@ frok::parent (volatile char * volatile stack_here)
}
child->nice = myself->nice;
+ child->sched_policy = myself->sched_policy;
/* Initialize things that are done later in dll_crt0_1 that aren't done
for the forkee. */
diff --git a/winsup/cygwin/local_includes/miscfuncs.h
b/winsup/cygwin/local_includes/miscfuncs.h
index efd7e516b..57dcbfeab 100644
--- a/winsup/cygwin/local_includes/miscfuncs.h
+++ b/winsup/cygwin/local_includes/miscfuncs.h
@@ -46,7 +46,7 @@ is_alt_numpad_event (PINPUT_RECORD pirec)
int winprio_to_nice (DWORD);
DWORD nice_to_winprio (int &);
-bool set_and_check_winprio (HANDLE proc, DWORD prio);
+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/local_includes/pinfo.h
b/winsup/cygwin/local_includes/pinfo.h
index 463f0e851..03e0c4d60 100644
--- a/winsup/cygwin/local_includes/pinfo.h
+++ b/winsup/cygwin/local_includes/pinfo.h
@@ -92,7 +92,9 @@ public:
long start_time;
struct rusage rusage_self;
struct rusage rusage_children;
- int nice;
+
+ int nice; /* nice value for SCHED_OTHER. */
+ int sched_policy; /* SCHED_OTHER, SCHED_FIFO or SCHED_RR. */
/* Non-zero if process was stopped by a signal. */
char stopsig;
diff --git a/winsup/cygwin/miscfuncs.cc b/winsup/cygwin/miscfuncs.cc
index ebe401b93..0146704ea 100644
--- a/winsup/cygwin/miscfuncs.cc
+++ b/winsup/cygwin/miscfuncs.cc
@@ -185,9 +185,10 @@ nice_to_winprio (int &nice)
/* Set Win32 priority or return false on failure. Also return
false and revert to the original priority if a different (lower)
- priority is set instead. */
+ priority is set instead. Always revert to original priority if
+ set==false. */
bool
-set_and_check_winprio (HANDLE proc, DWORD prio)
+set_and_check_winprio (HANDLE proc, DWORD prio, bool set /* = true */)
{
DWORD prev_prio = GetPriorityClass (proc);
if (!prev_prio)
@@ -202,16 +203,20 @@ set_and_check_winprio (HANDLE proc, DWORD prio)
the new priority (REALTIME_PRIORITY_CLASS) requires administrator
privileges. */
DWORD curr_prio = GetPriorityClass (proc);
- if (curr_prio != prio)
+ bool ret = (curr_prio == prio);
+
+ if (set)
{
- debug_printf ("Failed to set priority 0x%x, revert from 0x%x to 0x%x",
- prio, curr_prio, prev_prio);
- SetPriorityClass (proc, prev_prio);
- return false;
+ if (ret)
+ debug_printf ("Changed priority from 0x%x to 0x%x", prev_prio,
curr_prio);
+ else
+ debug_printf ("Failed to set priority 0x%x, revert from 0x%x to 0x%x",
+ prio, curr_prio, prev_prio);
}
+ if (!(set && ret))
+ SetPriorityClass (proc, prev_prio);
- debug_printf ("Changed priority from 0x%x to 0x%x", prev_prio, curr_prio);
- return true;
+ return ret;
}
/* Minimal overlapped pipe I/O implementation for signal and commune stuff. */
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index e31a67d8f..06c966f1e 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -102,6 +102,7 @@ pinfo_init (char **envp, int envc)
myself->gid = ILLEGAL_GID;
environ_init (NULL, 0); /* call after myself has been set up */
myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
+ myself->sched_policy = SCHED_OTHER;
myself->ppid = 1; /* always set last */
debug_printf ("Set nice to %d", myself->nice);
}
diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0
index 1b2f00ad8..9e924dabb 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -52,3 +52,11 @@ What changed:
- nice(2) now returns the new nice value instead of 0 on success
and sets errno to EPERM instead of EACCES on failure. This confirms
to POSIX and Linux (glibc >= 2.2.4) behavior.
+
+- sched_setscheduler(2) now emulates changes between SCHED_OTHER,
+ SCHED_FIFO and SCHED_RR. If SCHED_OTHER is selected, the Windows
+ priority is set according to the nice value. If SCHED_FIFO or
+ SCHED_RR is selected, the nice value is preserved and the Windows
+ priority is set 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 61d5e7be4..c48c433d7 100644
--- a/winsup/cygwin/sched.cc
+++ b/winsup/cygwin/sched.cc
@@ -33,9 +33,10 @@ sched_get_priority_max (int policy)
{
switch (policy)
{
+ case SCHED_OTHER:
+ return 0;
case SCHED_FIFO:
case SCHED_RR:
- case SCHED_OTHER:
return 32;
}
set_errno (EINVAL);
@@ -48,9 +49,10 @@ sched_get_priority_min (int policy)
{
switch (policy)
{
+ case SCHED_OTHER:
+ return 0;
case SCHED_FIFO:
case SCHED_RR:
- case SCHED_OTHER:
return 1;
}
set_errno (EINVAL);
@@ -90,6 +92,14 @@ sched_getparam (pid_t pid, struct sched_param *param)
set_errno (ESRCH);
return -1;
}
+
+ if (p->sched_policy == SCHED_OTHER)
+ {
+ /* No realtime policy. */
+ param->sched_priority = 0;
+ return 0;
+ }
+
process = OpenProcess (PROCESS_QUERY_LIMITED_INFORMATION, FALSE,
p->dwProcessId);
if (!process)
@@ -132,9 +142,6 @@ sched_getparam (pid_t pid, struct sched_param *param)
}
/* get the scheduler for pid
-
- All process's on WIN32 run with SCHED_FIFO. So we just give an answer.
- (WIN32 uses a multi queue FIFO).
*/
int
sched_getscheduler (pid_t pid)
@@ -144,8 +151,13 @@ sched_getscheduler (pid_t pid)
set_errno (EINVAL);
return -1;
}
- else
- return SCHED_FIFO;
+ pinfo p (pid ? pid : getpid ());
+ if (!p)
+ {
+ set_errno (ESRCH);
+ return -1;
+ }
+ return p->sched_policy;
}
/* get the time quantum for pid */
@@ -212,31 +224,18 @@ sched_rr_get_interval (pid_t pid, struct timespec
*interval)
}
/* set the scheduling parameters */
-int
-sched_setparam (pid_t pid, const struct sched_param *param)
+static int
+sched_setparam_pinfo (pinfo & p, const struct sched_param *param)
{
- pid_t localpid;
- int pri;
- DWORD pclass;
- HANDLE process;
-
- if (!param || pid < 0)
- {
- set_errno (EINVAL);
- return -1;
- }
-
- if (!valid_sched_parameters (param))
- {
- set_errno (EINVAL);
- return -1;
- }
-
- pri = param->sched_priority;
+ int pri = param->sched_priority;
/* calculate our desired priority class. We only reserve a small area
(31/32) for realtime priority. */
- if (pri <= 6)
+ DWORD pclass;
+ if (p->sched_policy == SCHED_OTHER && pri == 0)
+ /* No realtime policy, reapply the nice value. */
+ pclass = nice_to_winprio (p->nice);
+ else if (1 <= pri && pri <= 6)
pclass = IDLE_PRIORITY_CLASS;
else if (pri <= 12)
pclass = BELOW_NORMAL_PRIORITY_CLASS;
@@ -246,23 +245,16 @@ sched_setparam (pid_t pid, const struct sched_param
*param)
pclass = ABOVE_NORMAL_PRIORITY_CLASS;
else if (pri <= 30)
pclass = HIGH_PRIORITY_CLASS;
- else
+ else if (pri <= 32)
pclass = REALTIME_PRIORITY_CLASS;
-
- localpid = pid ? pid : getpid ();
-
- pinfo p (localpid);
-
- /* set the class */
-
- if (!p)
+ else
{
- set_errno (ESRCH);
+ set_errno (EINVAL);
return -1;
}
- process = OpenProcess (PROCESS_SET_INFORMATION |
- PROCESS_QUERY_LIMITED_INFORMATION,
- FALSE, p->dwProcessId);
+ HANDLE process = OpenProcess (PROCESS_SET_INFORMATION |
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ FALSE, p->dwProcessId);
if (!process)
{
set_errno (ESRCH);
@@ -279,6 +271,26 @@ sched_setparam (pid_t pid, const struct sched_param *param)
return 0;
}
+int
+sched_setparam (pid_t pid, const struct sched_param *param)
+{
+ if (!(pid >= 0 && param && (param->sched_priority == 0 ||
+ valid_sched_parameters(param))))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ pinfo p (pid ? pid : getpid ());
+ if (!p)
+ {
+ set_errno (ESRCH);
+ return -1;
+ }
+
+ return sched_setparam_pinfo (p, param);
+}
+
/* POSIX thread priorities loosely compare to Windows thread base priorities.
Base priority is a function of process priority class and thread priority.
@@ -404,12 +416,30 @@ int
sched_setscheduler (pid_t pid, int policy,
const struct sched_param *param)
{
- if (policy == SCHED_FIFO) /* returned by sched_getscheduler. */
- return sched_setparam (pid, param);
+ if (!(pid >= 0 && param &&
+ ((policy == SCHED_OTHER && param->sched_priority == 0) ||
+ ((policy == SCHED_FIFO || policy == SCHED_RR) &&
valid_sched_parameters(param)))))
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
- /* on win32, you can't change the scheduler. Doh! */
- set_errno (EINVAL);
- return -1;
+ pinfo p (pid ? pid : getpid ());
+ if (!p)
+ {
+ set_errno (ESRCH);
+ return -1;
+ }
+
+ int prev_policy = p->sched_policy;
+ p->sched_policy = policy;
+ if (sched_setparam_pinfo (p, param))
+ {
+ p->sched_policy = prev_policy;
+ return -1;
+ }
+
+ return 0;
}
/* yield the cpu */
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 60a82991a..7f9f2df64 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -799,6 +799,7 @@ child_info_spawn::worker (const char *prog_arg, const char
*const *argv,
}
child->start_time = time (NULL); /* Register child's starting time. */
child->nice = myself->nice;
+ child->sched_policy = myself->sched_policy;
postfork (child);
if (mode != _P_DETACH
&& (!child.remember () || !child.attach ()))
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index d4fba632c..2243da090 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -3826,7 +3826,9 @@ setpriority (int which, id_t who, int value)
who = myself->pid;
if ((pid_t) who == myself->pid)
{
- if (!set_and_check_winprio (GetCurrentProcess (), prio))
+ /* If realtime policy is set, keep prio but check its validity. */
+ if (!set_and_check_winprio (GetCurrentProcess (), prio,
+ (myself->sched_policy == SCHED_OTHER)))
{
set_errno (EACCES);
return -1;
@@ -3876,7 +3878,9 @@ setpriority (int which, id_t who, int value)
error = EPERM;
else
{
- if (!set_and_check_winprio (proc_h, prio))
+ /* If realtime policy is set, keep prio but check its validity. */
+ if (!set_and_check_winprio (proc_h, prio,
+ (p->sched_policy == SCHED_OTHER)))
error = EACCES;
else
p->nice = value;
@@ -3905,10 +3909,13 @@ getpriority (int which, id_t who)
who = myself->pid;
if ((pid_t) who == myself->pid)
{
- DWORD winprio = GetPriorityClass(GetCurrentProcess());
- if (winprio != nice_to_winprio(myself->nice))
- myself->nice = winprio_to_nice(winprio);
- return myself->nice;
+ if (myself->sched_policy == SCHED_OTHER)
+ {
+ DWORD winprio = GetPriorityClass (GetCurrentProcess());
+ if (winprio != nice_to_winprio (myself->nice))
+ myself->nice = winprio_to_nice (winprio);
+ }
+ return myself->nice;
}
break;
case PRIO_PGRP:
--
2.45.1