4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-22 00:38:06 +08:00

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.franke@t-online.de>
This commit is contained in:
Christian Franke 2024-12-09 12:14:07 +01:00 committed by Corinna Vinschen
parent a0527e3786
commit a31a6fe5dd
6 changed files with 122 additions and 84 deletions

View File

@ -44,6 +44,7 @@ extern "C" {
#if __GNU_VISIBLE
#define SCHED_IDLE 5
#define SCHED_BATCH 6
#endif
/* Scheduling Parameters */

View File

@ -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);

View File

@ -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

View File

@ -57,11 +57,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.

View File

@ -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;

View File

@ -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;
}