diff options
Diffstat (limited to 'Scheduling.c')
-rw-r--r-- | Scheduling.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/Scheduling.c b/Scheduling.c new file mode 100644 index 00000000..406caf7d --- /dev/null +++ b/Scheduling.c @@ -0,0 +1,165 @@ +/* +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 "config.h" // IWYU pragma: keep + +#include "Scheduling.h" + +#ifdef SCHEDULER_SUPPORT + +#include <assert.h> +#include <stddef.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; +} + +static bool Scheduling_setPolicy(Process* p, 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(Process_getPid(p), policy, ¶m); + + /* POSIX says on success the previous scheduling policy should be returned, + * but Linux always returns 0. */ + return r != -1; +} + +bool Scheduling_rowSetPolicy(Row* row, Arg arg) { + Process* p = (Process*) row; + assert(Object_isA((const Object*) p, (const ObjectClass*) &Process_class)); + return Scheduling_setPolicy(p, arg); +} + +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 "???"; + } +} + +/* + * Gather scheduling policy (thread-specific data) + */ +void Scheduling_readProcessPolicy(Process* proc) { + proc->scheduling_policy = sched_getscheduler(Process_getPid(proc)); +} +#endif /* SCHEDULER_SUPPORT */ |