Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .config-default
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ CONFIG_SCHED_WAKEUP_GRANULARITY=0
CONFIG_SCHED_LOAD_BALANCE_INTERVAL=8
CONFIG_SCHED_BALANCE_BATCH=4
CONFIG_SCHED_MIGRATION_COOLDOWN=4
CONFIG_SCHED_STEAL_HOT_BUDGET=8
CONFIG_SCHED_STEAL_SCAN_LIMIT=32
CONFIG_TASK_DEFAULT_SLICE=5
CONFIG_SCHED_DOMAIN_MAX_LEVELS=3

Expand Down
20 changes: 20 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,26 @@ menu "Scheduler"
Hysteresis against repeatedly bouncing a hot task between CPUs. Idle-CPU
stealing may override this when leaving a CPU idle would be worse.

config SCHED_STEAL_HOT_BUDGET
int "Recently migrated candidates skipped per steal attempt"
default 8
range 0 64
help
When a steal scan is not running for a newly idle CPU and the source
runqueue has at most two runnable tasks, candidates migrated within
SCHED_MIGRATION_COOLDOWN are skipped to avoid bouncing hot tasks. This
bounds how many such candidates one attempt passes over before
abandoning the source runqueue. Zero stops at the first hot candidate.

config SCHED_STEAL_SCAN_LIMIT
int "Maximum runqueue nodes visited per steal attempt"
default 32
range 1 256
help
Hard bound on rb-tree nodes examined by one steal attempt, including
CPU-pinned entities. Keeps load-balancing cost bounded on large
runqueues. Must be at least SCHED_STEAL_HOT_BUDGET.

config TASK_DEFAULT_SLICE
int "Default initial task time slice (ticks)"
default 5
Expand Down
3 changes: 2 additions & 1 deletion drivers/firmware/apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

#include <arch/cpu/cpuid.h>
#include <arch/cpu/eflags.h>
#include <arch/misc/common.h>
#include <arch/tables/idt.h>
#include <boot/limine.h>
Expand Down Expand Up @@ -313,7 +314,7 @@ void send_ipi(uint32_t apic_id, uint32_t command)
break;
}
}
if (rflags & (1ULL << 9)) enable_intr();
if (rflags & X86_EFLAGS_IF) enable_intr();
}

/* Initialize APIC */
Expand Down
34 changes: 34 additions & 0 deletions include/arch/cpu/eflags.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
*
* eflags.h
* x86-64 RFLAGS bits
*
* 2026/10/23 By MicroFish
* Copyright (C) 2020 ViudiraTech, based on the Apache 2.0 license.
*
*/

#ifndef INCLUDE_EFLAGS_H_
#define INCLUDE_EFLAGS_H_

/* RFLAGS bits */
#define X86_EFLAGS_CF (1ULL << 0)
#define X86_EFLAGS_FIXED (1ULL << 1)
#define X86_EFLAGS_PF (1ULL << 2)
#define X86_EFLAGS_AF (1ULL << 4)
#define X86_EFLAGS_ZF (1ULL << 6)
#define X86_EFLAGS_SF (1ULL << 7)
#define X86_EFLAGS_TF (1ULL << 8)
#define X86_EFLAGS_IF (1ULL << 9)
#define X86_EFLAGS_DF (1ULL << 10)
#define X86_EFLAGS_OF (1ULL << 11)
#define X86_EFLAGS_IOPL (3ULL << 12)
#define X86_EFLAGS_NT (1ULL << 14)
#define X86_EFLAGS_RF (1ULL << 16)
#define X86_EFLAGS_VM (1ULL << 17)
#define X86_EFLAGS_AC (1ULL << 18)
#define X86_EFLAGS_VIF (1ULL << 19)
#define X86_EFLAGS_VIP (1ULL << 20)
#define X86_EFLAGS_ID (1ULL << 21)

#endif // INCLUDE_EFLAGS_H_
8 changes: 8 additions & 0 deletions include/kernel/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,14 @@
# define CONFIG_SCHED_MIGRATION_COOLDOWN 4
#endif

#ifndef CONFIG_SCHED_STEAL_HOT_BUDGET
# define CONFIG_SCHED_STEAL_HOT_BUDGET 8
#endif

#ifndef CONFIG_SCHED_STEAL_SCAN_LIMIT
# define CONFIG_SCHED_STEAL_SCAN_LIMIT 32
#endif

#ifndef CONFIG_SCHED_LOAD_BALANCE_INTERVAL
# define CONFIG_SCHED_LOAD_BALANCE_INTERVAL 8
#endif
Expand Down
2 changes: 2 additions & 0 deletions include/process/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
#include <libs/util/rbtree.h>
#include <process/kthread.h>

_Static_assert(CONFIG_SCHED_STEAL_HOT_BUDGET <= CONFIG_SCHED_STEAL_SCAN_LIMIT, "steal hot budget exceeds scan limit");

#define SCHED_NICE_0_LOAD 1024ULL // Weight of a nice-0 task (EEVDF)

typedef enum {
Expand Down
7 changes: 4 additions & 3 deletions kernel/process/elf_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
*/

#include <arch/cpu/cpuid.h>
#include <arch/cpu/eflags.h>
#include <fs/core/vfs.h>
#include <kernel/errno.h>
#include <kernel/module/elf.h>
Expand Down Expand Up @@ -720,7 +721,7 @@ int elf_loader_load_process_internal(process_t *proc, const uint8_t *elf_data, s
proc->task->context.r13 = 0;
proc->task->context.r14 = 0;
proc->task->context.r15 = 0;
proc->task->context.rflags = 0x202;
proc->task->context.rflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
proc->task->context.rdi = 0;

if (!entry_out && !rsp_out) {
Expand All @@ -729,7 +730,7 @@ int elf_loader_load_process_internal(process_t *proc, const uint8_t *elf_data, s

*(--kstack) = 0x23;
*(--kstack) = user_rsp;
*(--kstack) = 0x202;
*(--kstack) = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
*(--kstack) = 0x1B;
*(--kstack) = actual_entry;
*(--kstack) = (uint64_t)user_process_enter;
Expand Down Expand Up @@ -875,7 +876,7 @@ int elf_loader_load_user_node(process_t *proc, vfs_node_t node, char *const argv
proc->task->context.r13 = 0;
proc->task->context.r14 = 0;
proc->task->context.r15 = 0;
proc->task->context.rflags = 0x202;
proc->task->context.rflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
proc->task->context.rdi = 0;
if (entry_out) *entry_out = actual_entry;
if (rsp_out) *rsp_out = user_rsp;
Expand Down
5 changes: 3 additions & 2 deletions kernel/process/kthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
*/

#include <arch/cpu/eflags.h>
#include <kernel/debug/debug.h>
#include <kernel/errno.h>
#include <kernel/printk.h>
Expand Down Expand Up @@ -64,7 +65,7 @@ static int setup_kthread_stack(task_t *task, kthread_bootstrap_t *bootstrap)
task->context.r13 = 0;
task->context.r14 = 0;
task->context.r15 = 0;
task->context.rflags = 0x202;
task->context.rflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
task->context.rdi = (uint64_t)bootstrap;
return 0;
}
Expand Down Expand Up @@ -139,7 +140,7 @@ void kthreadd_init(void)
*(--stack) = 0;
*(--stack) = (uint64_t)kthreadd_main;
task->context.rsp = (uint64_t)stack;
task->context.rflags = 0x202;
task->context.rflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
task->context.rdi = 0;

process_t *proc = process_create_kthread(task, "kthreadd");
Expand Down
29 changes: 19 additions & 10 deletions kernel/sched/sched.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
*/

#include <arch/cpu/eflags.h>
#include <arch/cpu/fpu.h>
#include <arch/cpu/smp.h>
#include <arch/misc/common.h>
Expand Down Expand Up @@ -449,7 +450,7 @@ static task_t *local_current(void)
/* Restore the interrupt flag saved by get_rflags(). */
static void restore_intr(uint64_t rflags)
{
if (rflags & (1ULL << 9))
if (rflags & X86_EFLAGS_IF)
enable_intr();
else
disable_intr();
Expand All @@ -465,7 +466,7 @@ static void local_rq_set_curr(eevdf_rq_t *rq, task_t *task)
/* Unlock keeping interrupts off; the caller restores them later. */
static void rq_unlock_irqs_off(eevdf_rq_t *rq, uint64_t rflags)
{
spin_unlock_irqrestore(&rq->lock, rflags & ~(1ULL << 9));
spin_unlock_irqrestore(&rq->lock, rflags & ~X86_EFLAGS_IF);
}

/* Point the TSS stack at the given task's kernel stack */
Expand Down Expand Up @@ -864,7 +865,9 @@ static uint64_t placement_score_locked(task_t *task, uint32_t cpu, uint32_t prev
/* WF_SYNC-like hint: the waker may block/yield soon, so stacking is a bit cheaper. */
uint32_t this_cpu = get_current_cpu_id();
if (sync && cpu == this_cpu && score >= SCHED_SYNC_WAKE_BONUS) score -= SCHED_SYNC_WAKE_BONUS;
if (task && cpu != prev_cpu && scheduler.ticks - task->last_migrate_tick < CONFIG_SCHED_MIGRATION_COOLDOWN) score += SCHED_NICE_0_LOAD / 2ULL;

uint64_t cooldown = CONFIG_SCHED_MIGRATION_COOLDOWN;
if (task && cpu != prev_cpu && cooldown && scheduler.ticks - task->last_migrate_tick < cooldown) score += SCHED_NICE_0_LOAD / 2ULL;

return score;
}
Expand Down Expand Up @@ -1010,18 +1013,24 @@ static task_t *pick_steal_candidate_locked(eevdf_rq_t *src, bool newly_idle)
if (!node) return NULL;
while (node->right) node = node->right;

/* Pinned entities are skipped without spending the movable-candidate budget. */
unsigned int movable = 0;
unsigned int visited = 0;
while (node && movable < 8 && visited++ < 32) {
/* Pinned entities are skipped without spending the hot-candidate budget. */
unsigned int hot_skipped = 0;
unsigned int hot_budget = CONFIG_SCHED_STEAL_HOT_BUDGET;
unsigned int visited = 0;
uint64_t cooldown = CONFIG_SCHED_MIGRATION_COOLDOWN;
while (node && visited++ < CONFIG_SCHED_STEAL_SCAN_LIMIT) {
task_t *task = rb_entry(node, task_t, run_node);

if (task->cpu_pinned) {
node = rb_prev_local(node);
continue;
}
bool hot = scheduler.ticks - task->last_migrate_tick < CONFIG_SCHED_MIGRATION_COOLDOWN;
bool hot = cooldown && scheduler.ticks - task->last_migrate_tick < cooldown;

if (!hot || newly_idle || __atomic_load_n(&src->nr_running, __ATOMIC_RELAXED) > 2) return task;
movable++;
hot_skipped++;

if (hot_skipped >= hot_budget) break;
node = rb_prev_local(node);
}
return NULL;
Expand Down Expand Up @@ -1226,7 +1235,7 @@ static task_t *idle_task_alloc(uint32_t cpu_id)
*(--stack) = (uint64_t)idle_thread;
idle->context.rsp = (uint64_t)stack;
idle->context.rdi = 0;
idle->context.rflags = 0x202;
idle->context.rflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
return idle;
}

Expand Down
5 changes: 3 additions & 2 deletions kernel/signal/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
*/

#include <arch/cpu/eflags.h>
#include <arch/cpu/fpu.h>
#include <kernel/errno.h>
#include <kernel/printk.h>
Expand Down Expand Up @@ -1891,8 +1892,8 @@ int64_t do_rt_sigreturn(syscall_frame_t *frame)
* Clear IOPL, NT and VM so IRETQ cannot enter an invalid privilege state.
*/
const uint64_t user_rflags
= (1ULL << 0) | (1ULL << 2) | (1ULL << 4) | (1ULL << 6) | (1ULL << 7) | (1ULL << 8) | (1ULL << 9) | (1ULL << 10) | (1ULL << 11) | (1ULL << 16) | (1ULL << 18) | (1ULL << 21);
frame->rflags = (gregs[17] & user_rflags) | (1ULL << 1) | (1ULL << 9);
= X86_EFLAGS_CF | X86_EFLAGS_PF | X86_EFLAGS_AF | X86_EFLAGS_ZF | X86_EFLAGS_SF | X86_EFLAGS_TF | X86_EFLAGS_IF | X86_EFLAGS_DF | X86_EFLAGS_OF | X86_EFLAGS_RF | X86_EFLAGS_AC | X86_EFLAGS_ID;
frame->rflags = (gregs[17] & user_rflags) | X86_EFLAGS_FIXED | X86_EFLAGS_IF;
frame->rsp = gregs[15];
frame->cs = 0x33;
frame->ss = 0x2b;
Expand Down
6 changes: 3 additions & 3 deletions kernel/syscall/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*
*/

#include <arch/cpu/eflags.h>
#include <arch/cpu/fpu.h>
#include <arch/cpu/smp.h>
#include <arch/misc/common.h>
Expand Down Expand Up @@ -74,7 +75,6 @@ _Static_assert(sizeof(syscall_frame_t) == 20 * sizeof(uint64_t), "syscall frame
* flag must be clear (SMAP correctness requires IRET).
*/
#define X86_64_CANONICAL_BOUNDARY 0x0000800000000000ULL
#define X86_EFLAGS_AC 0x00040000ULL

#define WNOHANG 0x00000001
#define WUNTRACED 0x00000002
Expand Down Expand Up @@ -4504,7 +4504,7 @@ static int64_t do_execve_resolved(const char *path, vfs_node_t initial_node, cha
memset(frame, 0, sizeof(*frame));
frame->rip = entry;
frame->cs = 0x1B;
frame->rflags = 0x202;
frame->rflags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;
frame->rsp = rsp;
frame->ss = 0x23;
}
Expand Down Expand Up @@ -5938,7 +5938,7 @@ void syscall_init_cpu(void)
star |= ((uint64_t)0x08 << 32) | ((uint64_t)0x23 << 48);
wrmsr(0xC0000081, star);
wrmsr(0xC0000082, (uint64_t)syscall_entry_syscall);
wrmsr(0xC0000084, 0x200);
wrmsr(0xC0000084, X86_EFLAGS_IF);
wrmsr(0xC0000080, rdmsr(0xC0000080) | 1);
}

Expand Down
8 changes: 8 additions & 0 deletions scripts/kconfig.mk
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,14 @@ ifneq ($(CONFIG_SCHED_MIGRATION_COOLDOWN),)
C_CONFIG += -DCONFIG_SCHED_MIGRATION_COOLDOWN=$(CONFIG_SCHED_MIGRATION_COOLDOWN)
endif

ifneq ($(CONFIG_SCHED_STEAL_HOT_BUDGET),)
C_CONFIG += -DCONFIG_SCHED_STEAL_HOT_BUDGET=$(CONFIG_SCHED_STEAL_HOT_BUDGET)
endif

ifneq ($(CONFIG_SCHED_STEAL_SCAN_LIMIT),)
C_CONFIG += -DCONFIG_SCHED_STEAL_SCAN_LIMIT=$(CONFIG_SCHED_STEAL_SCAN_LIMIT)
endif

ifneq ($(CONFIG_PROCESS_MAX_FD),)
C_CONFIG += -DCONFIG_PROCESS_MAX_FD=$(CONFIG_PROCESS_MAX_FD)
endif
Expand Down
Loading