The possibly last enhancement regarding SCHED_* emulation.
Linux also provides (40) rt_priority and (41) policy. Adding these would require to determine (or fake) fields (26) to (39) first :-)
-- Regards, Christian
From 0beb9cbe93e9984c4f82365a328b81df4829c2f2 Mon Sep 17 00:00:00 2001 From: Christian Franke <christian.fra...@t-online.de> Date: Fri, 13 Dec 2024 16:12:39 +0100 Subject: [PATCH] Cygwin: /proc/<PID>/stat: set field (18) according to scheduling policy If a realtime policy is selected, set the '(18) priority' field to the negated sched_priority minus one. If SCHED_IDLE is selected, set it to (usually) 36. In both cases, the values are mapped from the current Windows priority. Also set '(19) nice' to the originally requested nice value unless it is no longer consistent with the Windows priority. Move the sched_priority from/to Windows priority mapping from sched_get/setparam() to new functions in miscfuncs.cc. Signed-off-by: Christian Franke <christian.fra...@t-online.de> --- winsup/cygwin/fhandler/process.cc | 25 +++++++++-- winsup/cygwin/local_includes/miscfuncs.h | 2 + winsup/cygwin/miscfuncs.cc | 56 ++++++++++++++++++++++-- winsup/cygwin/release/3.6.0 | 6 +++ winsup/cygwin/sched.cc | 40 +++-------------- 5 files changed, 88 insertions(+), 41 deletions(-) diff --git a/winsup/cygwin/fhandler/process.cc b/winsup/cygwin/fhandler/process.cc index 37bdff84e..3fba180a0 100644 --- a/winsup/cygwin/fhandler/process.cc +++ b/winsup/cygwin/fhandler/process.cc @@ -1098,7 +1098,6 @@ format_process_stat (void *data, char *&destbuf) unsigned long fault_count = 0UL, vmsize = 0UL, vmrss = 0UL, vmmaxrss = 0UL; uint64_t utime = 0ULL, stime = 0ULL, start_time = 0ULL; - int nice = 0; /* ctty maj is 31:16, min is 15:0; tty_nr s/b maj 15:8, min 31:20, 7:0; maj is 31:16 >> 16 & fff << 8; min is 15:0 >> 8 & ff << 20 | & ff */ int tty_nr = 0; @@ -1131,6 +1130,8 @@ format_process_stat (void *data, char *&destbuf) else state = get_process_state (p->dwProcessId); + int nice = 0, prio = 0; + NTSTATUS status; HANDLE hProcess; VM_COUNTERS vmc = { 0 }; @@ -1168,7 +1169,25 @@ format_process_stat (void *data, char *&destbuf) if (!NT_SUCCESS (status)) debug_printf ("NtQueryInformationProcess(ProcessQuotaLimits): " "status %y", status); - nice = winprio_to_nice (GetPriorityClass (hProcess)); + + nice = p->nice; + DWORD winprio = GetPriorityClass (hProcess); + if (p->sched_policy == SCHED_FIFO || p->sched_policy == SCHED_RR) + /* Linux proc_pid_stat(5): (18) priority - For processes running a + real-time scheduling policy ..., this is the negated scheduling + priority, minus one. */ + prio = - winprio_to_schedprio (winprio) - 1; /* -33(high)...-2(low) */ + else if (p->sched_policy == SCHED_IDLE) + /* Expected: winprio == IDLE_PRIORITY_CLASS. */ + prio = NZERO + winprio_to_nice (winprio); /* 36 */ + else + { + /* Use originally requested nice value unless no longer consistent. */ + bool batch = (p->sched_policy == SCHED_BATCH); + if (winprio != nice_to_winprio (nice, batch)) + nice = winprio_to_nice (winprio, batch); + prio = NZERO + nice; /* 0(high)...39(low) */ + } CloseHandle (hProcess); } status = NtQuerySystemInformation (SystemTimeOfDayInformation, @@ -1201,7 +1220,7 @@ format_process_stat (void *data, char *&destbuf) p->ppid, p->pgid, p->sid, tty_nr, -1, 0, fault_count, fault_count, 0, 0, utime, stime, utime, stime, - NZERO + nice, nice, 0, 0, + prio, nice, 0, 0, start_time, vmsize, vmrss, vmmaxrss ); diff --git a/winsup/cygwin/local_includes/miscfuncs.h b/winsup/cygwin/local_includes/miscfuncs.h index 6001a1636..fd10e40f1 100644 --- a/winsup/cygwin/local_includes/miscfuncs.h +++ b/winsup/cygwin/local_includes/miscfuncs.h @@ -46,6 +46,8 @@ is_alt_numpad_event (PINPUT_RECORD pirec) int winprio_to_nice (DWORD prio, bool batch = false); DWORD nice_to_winprio (int &nice, bool batch = false); +int winprio_to_schedprio (DWORD prio); +DWORD schedprio_to_winprio (int schedprio); 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 6faf04937..31080d043 100644 --- a/winsup/cygwin/miscfuncs.cc +++ b/winsup/cygwin/miscfuncs.cc @@ -104,7 +104,7 @@ yield () } /* - Mapping of nice value from/to Windows priority + Mapping of nice value or sched_priority from/to Windows priority ('batch' is used for SCHED_BATCH policy). nice_to_winprio() winprio_to_nice() @@ -115,6 +115,14 @@ yield () -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 + + schedprio_to_winprio() winprio_to_schedprio() + 1....6 0 IDLE_PRIORITY_CLASS 3 + 7...12 1 BELOW_NORMAL_PRIORITY_CLASS 9 + 13...18 2 NORMAL_PRIORITY_CLASS 15 + 19...24 3 ABOVE_NORMAL_PRIORITY_CLASS 21 + 25...30 4 HIGH_PRIORITY_CLASS 27 + 31...32 5 REALTIME_PRIORITY_CLASS 32 */ /* *_PRIORITY_CLASS -> 0...5 */ @@ -167,9 +175,25 @@ nice_to_winprio_impl (int nice, bool batch = false) return level_to_winprio (level); } +/* *_PRIORITY_CLASS -> sched_priority */ +constexpr int +winprio_to_schedprio_impl (DWORD prio) +{ + int level = winprio_to_level (prio); + return (level < 5 ? 3 + level * 6 : 32); +} + +/* sched_priority -> *_PRIORITY_CLASS */ +constexpr DWORD +schedprio_to_winprio_impl (int schedprio) +{ + int level = (schedprio <= 1 ? 0 : (schedprio < 32 ? (schedprio - 1) / 6 : 5)); + return level_to_winprio (level); +} + /* Check consistency at compile time. */ constexpr bool -check_nice_winprio_mapping () +check_nice_schedprio_winprio_mapping () { for (int nice = -NZERO; nice < NZERO; nice++) for (int batch = 0; batch <= 1; batch++) { @@ -179,16 +203,28 @@ check_nice_winprio_mapping () if (prio != prio2) return false; } + for (int schedprio = 1; schedprio <= 32; schedprio++) + { + DWORD prio = schedprio_to_winprio_impl (schedprio); + int schedprio2 = winprio_to_schedprio_impl (prio); + DWORD prio2 = schedprio_to_winprio_impl (schedprio2); + if (prio != prio2) + return false; + } return true; } -static_assert (check_nice_winprio_mapping()); +static_assert (check_nice_schedprio_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); +static_assert (schedprio_to_winprio_impl(1) == IDLE_PRIORITY_CLASS); +static_assert (schedprio_to_winprio_impl(15) == NORMAL_PRIORITY_CLASS); +static_assert (winprio_to_schedprio_impl(NORMAL_PRIORITY_CLASS) == 15); +static_assert (schedprio_to_winprio_impl(32) == REALTIME_PRIORITY_CLASS); /* Get a default value for the nice factor. */ int @@ -210,6 +246,20 @@ nice_to_winprio (int &nice, bool batch /* = false */) return nice_to_winprio_impl (nice, batch); } +/* Get a default sched_priority from a Win32 priority. */ +int +winprio_to_schedprio (DWORD prio) +{ + return winprio_to_schedprio_impl (prio); +} + +/* Get a Win32 priority matching the sched_priority. */ +DWORD +schedprio_to_winprio (int schedprio) +{ + return schedprio_to_winprio_impl (schedprio); +} + /* 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. Always revert to original priority if diff --git a/winsup/cygwin/release/3.6.0 b/winsup/cygwin/release/3.6.0 index 4e0726e8f..1739980fd 100644 --- a/winsup/cygwin/release/3.6.0 +++ b/winsup/cygwin/release/3.6.0 @@ -69,3 +69,9 @@ What changed: each child process created with fork(2). Note: Windows does not offer alternative scheduling policies so this could only emulate API behavior. + +- If SCHED_FIFO or SCHED_RR is selected, the /proc/<PID>/stat field + '(18) priority' is now set to the negated sched_policy minus one. + If SCHED_IDLE is selected, this field is set to 36. + The '(19) nice' field is now set to the originally requested nice + value unless it is no longer consistent with the Windows priority. diff --git a/winsup/cygwin/sched.cc b/winsup/cygwin/sched.cc index d75a3404f..43b17357b 100644 --- a/winsup/cygwin/sched.cc +++ b/winsup/cygwin/sched.cc @@ -120,29 +120,7 @@ sched_getparam (pid_t pid, struct sched_param *param) return -1; } /* calculate the unix priority. */ - switch (pclass) - { - case IDLE_PRIORITY_CLASS: - param->sched_priority = 3; - break; - case BELOW_NORMAL_PRIORITY_CLASS: - param->sched_priority = 9; - break; - case NORMAL_PRIORITY_CLASS: - default: - param->sched_priority = 15; - break; - case ABOVE_NORMAL_PRIORITY_CLASS: - param->sched_priority = 21; - break; - case HIGH_PRIORITY_CLASS: - param->sched_priority = 27; - break; - case REALTIME_PRIORITY_CLASS: - param->sched_priority = 32; - break; - } - + param->sched_priority = winprio_to_schedprio (pclass); return 0; } @@ -244,18 +222,10 @@ sched_setparam_pinfo (pinfo & p, const struct sched_param *param) else if (p->sched_policy == SCHED_IDLE && pri == 0) /* Idle policy, ignore the nice value. */ pclass = IDLE_PRIORITY_CLASS; - else if (1 <= pri && pri <= 6) - pclass = IDLE_PRIORITY_CLASS; - else if (pri <= 12) - pclass = BELOW_NORMAL_PRIORITY_CLASS; - else if (pri <= 18) - pclass = NORMAL_PRIORITY_CLASS; - else if (pri <= 24) - pclass = ABOVE_NORMAL_PRIORITY_CLASS; - else if (pri <= 30) - pclass = HIGH_PRIORITY_CLASS; - else if (pri <= 32) - pclass = REALTIME_PRIORITY_CLASS; + else if ((p->sched_policy == SCHED_FIFO || p->sched_policy == SCHED_RR) + && valid_sched_parameters (param)) + /* Realtime policy, apply requested priority. */ + pclass = schedprio_to_winprio (param->sched_priority); else { set_errno (EINVAL); -- 2.45.1