https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=48b189245a135a16ea7dd16e24724820e8003221
commit 48b189245a135a16ea7dd16e24724820e8003221 Author: Christian Franke <[email protected]> AuthorDate: Fri Nov 29 18:41:12 2024 +0100 Commit: Corinna Vinschen <[email protected]> CommitDate: Wed Dec 4 19:06:48 2024 +0100 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 <[email protected]> Diff: --- 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 0742ab36331c..7d976e882250 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 efd7e516b7dc..57dcbfeab31c 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 463f0e8518e3..03e0c4d60005 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 ebe401b93f63..0146704ea6f8 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 e31a67d8f412..06c966f1e1ab 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 1b2f00ad8fd6..9e924dabbf2a 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 61d5e7be49a3..c48c433d7348 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 60a82991a8eb..7f9f2df64912 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 d4fba632c698..2243da090e56 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:
