Corinna Vinschen wrote:
Hi Christian,
On Dec 10 15:16, Christian Franke wrote:
+ /* Handle SCHED_RESET_ON_FORK flag. */
+ if (myself->sched_reset_on_fork)
+ {
+ bool batch = (myself->sched_policy == SCHED_BATCH);
+ bool idle = (myself->sched_policy == SCHED_IDLE);
+ bool set_prio = false;
+ /* Reset negative nice values to zero. */
+ if (myself->nice < 0)
+ {
+ child->nice = 0;
+ set_prio = !idle;
+ }
+ /* Reset realtime policies to SCHED_OTHER. */
+ if (!(myself->sched_policy == SCHED_OTHER || batch || idle))
+ {
+ child->sched_policy = SCHED_OTHER;
+ set_prio = true;
+ }
+ /* Adjust Windows priority if required. */
+ if (set_prio)
+ {
+ HANDLE proc = OpenProcess(PROCESS_SET_INFORMATION |
+ PROCESS_QUERY_LIMITED_INFORMATION,
+ FALSE, child->dwProcessId);
+ if (proc)
+ {
+ set_and_check_winprio(proc, nice_to_winprio(child->nice, batch));
+ CloseHandle(proc);
+ }
+ }
+ }
+ child->sched_reset_on_fork = false;
+
Is it really necessary to go to such length here? For one thing, we
have hchild aka pi.hProcess, which should have all access rights on the
child. Otherwise, the priority of the child process can be set in the
dwCreationFlags parameter, called `c_flags' in frok::parent(). See line
215 in fork.cc.
A new patch setting c_flags directly is attached.
In terms of the SCHED_BATCH value, I'm not going to wait much longer.
If there's no reply on the newlib list tomorrow, I'll push your patch
with SCHED_BATCH set to 6.
Thanks,
Corinna
From 89dfe62ddaa162b3eb911a42b635ad2769470cf2 Mon Sep 17 00:00:00 2001
From: Christian Franke <christian.fra...@t-online.de>
Date: Wed, 11 Dec 2024 12:48:58 +0100
Subject: [PATCH] Cygwin: sched_setscheduler: accept SCHED_RESET_ON_FORK flag
Add SCHED_RESET_ON_FORK to <sys/sched.h>. If this flag is set, SCHED_FIFO
and SCHED_RR are reset to SCHED_OTHER and negative nice values are reset to
zero in each child process created with fork(2).
Signed-off-by: Christian Franke <christian.fra...@t-online.de>
---
newlib/libc/include/sys/sched.h | 3 +++
winsup/cygwin/fork.cc | 37 +++++++++++++++++++++++++---
winsup/cygwin/local_includes/pinfo.h | 5 ++--
winsup/cygwin/pinfo.cc | 1 +
winsup/cygwin/release/3.6.0 | 3 +++
winsup/cygwin/sched.cc | 11 ++++++---
winsup/cygwin/spawn.cc | 1 +
7 files changed, 52 insertions(+), 9 deletions(-)
diff --git a/newlib/libc/include/sys/sched.h b/newlib/libc/include/sys/sched.h
index 6977d3d4a..95509dbf0 100644
--- a/newlib/libc/include/sys/sched.h
+++ b/newlib/libc/include/sys/sched.h
@@ -45,6 +45,9 @@ extern "C" {
#if __GNU_VISIBLE
#define SCHED_IDLE 5
#define SCHED_BATCH 6
+
+/* Flag to drop realtime policies and negative nice values on fork(). */
+#define SCHED_RESET_ON_FORK 0x40000000
#endif
/* Scheduling Parameters */
diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc
index 7d976e882..41a533705 100644
--- a/winsup/cygwin/fork.cc
+++ b/winsup/cygwin/fork.cc
@@ -212,7 +212,37 @@ frok::parent (volatile char * volatile stack_here)
bool fix_impersonation = false;
pinfo child;
- int c_flags = GetPriorityClass (GetCurrentProcess ());
+ /* Inherit scheduling parameters by default. */
+ int child_nice = myself->nice;
+ int child_sched_policy = myself->sched_policy;
+ int c_flags = 0;
+
+ /* Handle SCHED_RESET_ON_FORK flag. */
+ if (myself->sched_reset_on_fork)
+ {
+ bool batch = (myself->sched_policy == SCHED_BATCH);
+ bool idle = (myself->sched_policy == SCHED_IDLE);
+ bool set_prio = false;
+ /* Reset negative nice values to zero. */
+ if (myself->nice < 0)
+ {
+ child_nice = 0;
+ set_prio = !idle;
+ }
+ /* Reset realtime policies to SCHED_OTHER. */
+ if (!(myself->sched_policy == SCHED_OTHER || batch || idle))
+ {
+ child_sched_policy = SCHED_OTHER;
+ set_prio = true;
+ }
+ if (set_prio)
+ c_flags = nice_to_winprio (child_nice, batch);
+ }
+
+ /* Always request a priority because otherwise anything above
+ NORMAL_PRIORITY_CLASS would not be inherited. */
+ if (!c_flags)
+ c_flags = GetPriorityClass (GetCurrentProcess ());
debug_printf ("priority class %d", c_flags);
/* Per MSDN, this must be specified even if lpEnvironment is set to NULL,
otherwise UNICODE characters in the parent environment are not copied
@@ -401,8 +431,9 @@ frok::parent (volatile char * volatile stack_here)
goto cleanup;
}
- child->nice = myself->nice;
- child->sched_policy = myself->sched_policy;
+ child->nice = child_nice;
+ child->sched_policy = child_sched_policy;
+ child->sched_reset_on_fork = false;
/* Initialize things that are done later in dll_crt0_1 that aren't done
for the forkee. */
diff --git a/winsup/cygwin/local_includes/pinfo.h
b/winsup/cygwin/local_includes/pinfo.h
index 03e0c4d60..be5d53021 100644
--- a/winsup/cygwin/local_includes/pinfo.h
+++ b/winsup/cygwin/local_includes/pinfo.h
@@ -93,8 +93,9 @@ public:
struct rusage rusage_self;
struct rusage rusage_children;
- int nice; /* nice value for SCHED_OTHER. */
- int sched_policy; /* SCHED_OTHER, SCHED_FIFO or SCHED_RR. */
+ int nice; /* nice value for SCHED_OTHER and SCHED_BATCH. */
+ int sched_policy; /* SCHED_OTHER/BATCH/IDLE/FIFO/RR */
+ bool sched_reset_on_fork; /* true if SCHED_RESET_ON_FORK flag was set. */
/* Non-zero if process was stopped by a signal. */
char stopsig;
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 06c966f1e..fecf76eb6 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -103,6 +103,7 @@ pinfo_init (char **envp, int envc)
environ_init (NULL, 0); /* call after myself has been set up */
myself->nice = winprio_to_nice (GetPriorityClass (GetCurrentProcess ()));
myself->sched_policy = SCHED_OTHER;
+ myself->sched_reset_on_fork = false;
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 11f745b23..d35aa3036 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -61,5 +61,8 @@ What changed:
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.
+ If the SCHED_RESET_ON_FORK flag is set, SCHED_FIFO and SCHED_RR are
+ reset to SCHED_OTHER and negative nice values are reset to zero in
+ each child process created with fork(2).
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 ec62ea83c..d75a3404f 100644
--- a/winsup/cygwin/sched.cc
+++ b/winsup/cygwin/sched.cc
@@ -162,7 +162,7 @@ sched_getscheduler (pid_t pid)
set_errno (ESRCH);
return -1;
}
- return p->sched_policy;
+ return p->sched_policy | (p->sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0);
}
/* get the time quantum for pid */
@@ -425,9 +425,11 @@ int
sched_setscheduler (pid_t pid, int policy,
const struct sched_param *param)
{
+ int new_policy = policy & ~SCHED_RESET_ON_FORK;
if (!(pid >= 0 && param &&
- (((policy == SCHED_OTHER || policy == SCHED_BATCH || policy ==
SCHED_IDLE)
- && param->sched_priority == 0) || ((policy == SCHED_FIFO || policy ==
SCHED_RR)
+ (((new_policy == SCHED_OTHER || new_policy == SCHED_BATCH
+ || new_policy == SCHED_IDLE) && param->sched_priority == 0)
+ || ((new_policy == SCHED_FIFO || new_policy == SCHED_RR)
&& valid_sched_parameters(param)))))
{
set_errno (EINVAL);
@@ -442,13 +444,14 @@ sched_setscheduler (pid_t pid, int policy,
}
int prev_policy = p->sched_policy;
- p->sched_policy = policy;
+ p->sched_policy = new_policy;
if (sched_setparam_pinfo (p, param))
{
p->sched_policy = prev_policy;
return -1;
}
+ p->sched_reset_on_fork = !!(policy & SCHED_RESET_ON_FORK);
return 0;
}
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index 7f9f2df64..8016f0864 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -800,6 +800,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;
+ child->sched_reset_on_fork = false;
postfork (child);
if (mode != _P_DETACH
&& (!child.remember () || !child.attach ()))
--
2.45.1