mirror of https://github.com/htop-dev/htop.git
166 lines
4.2 KiB
C
166 lines
4.2 KiB
C
/*
|
|
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 */
|