diff options
author | Christian Göttsche <cgzones@googlemail.com> | 2023-01-10 19:40:04 +0100 |
---|---|---|
committer | BenBE <BenBE@geshi.org> | 2023-02-05 00:17:33 +0100 |
commit | da494896914a327476ab7e0298619d742a6205d4 (patch) | |
tree | 700db7b14d148c492b1fb0295462fee2214239ed /Scheduling.c | |
parent | f1da8cfa28cce46cc7a4ab1661be35e2173155ab (diff) |
Add support for scheduling policies
Add a process column for scheduling policy to show the current
scheduling policy of the process.
Add a the ability to change the scheduling policy of a process via the
key 'Y'.
Currently implemented on Linux and FreeBSD only but should be portable,
since sched_getscheduler(2) is part of POSIX.1-2001.
Closes: #1161
Diffstat (limited to 'Scheduling.c')
-rw-r--r-- | Scheduling.c | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/Scheduling.c b/Scheduling.c new file mode 100644 index 00000000..5ca49ae2 --- /dev/null +++ b/Scheduling.c @@ -0,0 +1,154 @@ +/* +htop - Scheduling.c +(C) 2023 htop dev team +Released under the GNU GPLv2+, see the COPYING file +in the source distribution for its full text. +*/ + +#include "Scheduling.h" +#include "EnvScreen.h" + +#ifdef SCHEDULER_SUPPORT + +#include <errno.h> + +#include "FunctionBar.h" +#include "ListItem.h" +#include "Macros.h" +#include "Object.h" +#include "Panel.h" +#include "XUtils.h" + + +static const SchedulingPolicy policies[] = { + [SCHED_OTHER] = { "Other", SCHED_OTHER, false }, +#ifdef SCHED_BATCH + [SCHED_BATCH] = { "Batch", SCHED_BATCH, false }, +#endif +#ifdef SCHED_IDLE + [SCHED_IDLE] = { "Idle", SCHED_IDLE, false }, +#endif + [SCHED_FIFO] = { "FiFo", SCHED_FIFO, true }, + [SCHED_RR] = { "RoundRobin", SCHED_RR, true }, +}; + +#ifdef SCHED_RESET_ON_FORK +static bool reset_on_fork = false; +#endif + + +Panel* Scheduling_newPolicyPanel(int preSelectedPolicy) { + Panel* this = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Select ", "Cancel ")); + Panel_setHeader(this, "New policy:"); + +#ifdef SCHED_RESET_ON_FORK + Panel_add(this, (Object*) ListItem_new(reset_on_fork ? "Reset on fork: on" : "Reset on fork: off", -1)); +#endif + + for (unsigned i = 0; i < ARRAYSIZE(policies); i++) { + if (!policies[i].name) + continue; + + Panel_add(this, (Object*) ListItem_new(policies[i].name, policies[i].id)); + if (policies[i].id == preSelectedPolicy) + Panel_setSelected(this, i); + } + + return this; +} + +void Scheduling_togglePolicyPanelResetOnFork(Panel* schedPanel) { +#ifdef SCHED_RESET_ON_FORK + reset_on_fork = !reset_on_fork; + + ListItem* item = (ListItem*) Panel_get(schedPanel, 0); + + free_and_xStrdup(&item->value, reset_on_fork ? "Reset on fork: on" : "Reset on fork: off"); +#else + (void)schedPanel; +#endif +} + +Panel* Scheduling_newPriorityPanel(int policy, int preSelectedPriority) { + if (policy < 0 || (unsigned)policy >= ARRAYSIZE(policies) || policies[policy].name == NULL) + return NULL; + + if (!policies[policy].prioritySupport) + return NULL; + + int min = sched_get_priority_min(policy); + if (min < 0) + return NULL; + int max = sched_get_priority_max(policy); + if (max < 0 ) + return NULL; + + Panel* this = Panel_new(0, 0, 0, 0, Class(ListItem), true, FunctionBar_newEnterEsc("Select ", "Cancel ")); + Panel_setHeader(this, "Priority:"); + + for (int i = min; i <= max; i++) { + char buf[16]; + xSnprintf(buf, sizeof(buf), "%d", i); + Panel_add(this, (Object*) ListItem_new(buf, i)); + if (i == preSelectedPriority) + Panel_setSelected(this, i); + } + + return this; +} + +bool Scheduling_setPolicy(Process* proc, Arg arg) { + const SchedulingArg* sarg = arg.v; + int policy = sarg->policy; + + assert(policy >= 0); + assert((unsigned)policy < ARRAYSIZE(policies)); + assert(policies[policy].name); + + const struct sched_param param = { .sched_priority = policies[policy].prioritySupport ? sarg->priority : 0 }; + + #ifdef SCHED_RESET_ON_FORK + if (reset_on_fork) + policy &= SCHED_RESET_ON_FORK; + #endif + + int r = sched_setscheduler(proc->pid, policy, ¶m); + + /* POSIX says on success the previous scheduling policy should be returned, + * but Linux always returns 0. */ + return r != -1; +} + +const char* Scheduling_formatPolicy(int policy) { +#ifdef SCHED_RESET_ON_FORK + policy = policy & ~SCHED_RESET_ON_FORK; +#endif + + switch (policy) { + case SCHED_OTHER: + return "OTHER"; + case SCHED_FIFO: + return "FIFO"; + case SCHED_RR: + return "RR"; +#ifdef SCHED_BATCH + case SCHED_BATCH: + return "BATCH"; +#endif +#ifdef SCHED_IDLE + case SCHED_IDLE: + return "IDLE"; +#endif +#ifdef SCHED_DEADLINE + case SCHED_DEADLINE: + return "EDF"; +#endif + default: + return "???"; + } +} + +void Scheduling_readProcessPolicy(Process* proc) { + proc->scheduling_policy = sched_getscheduler(proc->pid); +} +#endif /* SCHEDULER_SUPPORT */ |