https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=06952f41ff4897c615fa838c5daf571aacb55d0f

commit 06952f41ff4897c615fa838c5daf571aacb55d0f
Author:     Christian Franke <[email protected]>
AuthorDate: Wed Dec 11 12:48:58 2024 +0100
Commit:     Corinna Vinschen <[email protected]>
CommitDate: Thu Dec 12 10:32:00 2024 +0100

    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 <[email protected]>

Diff:
---
 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 6977d3d4aa80..95509dbf0603 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 7d976e882250..41a533705407 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 03e0c4d60005..be5d53021523 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 06c966f1e1ab..fecf76eb6f36 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 07957425ded1..4e0726e8f204 100644
--- a/winsup/cygwin/release/3.6.0
+++ b/winsup/cygwin/release/3.6.0
@@ -64,5 +64,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 ec62ea83cf68..d75a3404f5d9 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 7f9f2df64912..8016f08640a2 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 ()))

Reply via email to