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

Reply via email to