You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.2 KiB
165 lines
4.2 KiB
/* |
|
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 */
|
|
|