Files
ViperOS/VKernel/Kernel/sched/sched.vp
T
TermiNexus dcb7c5c2c0 chore(ViperOS): 落库内核侧进行中的改动(26 文件,+1573/-1805)
内容由用户产出,本次仅代为提交、未做任何语义修改;含 static 修饰符前置迁移等(新增 static 前缀 16 行)。提交消息为中性描述——如需更精确的说明请 amend。
2026-09-28 15:24:52 +08:00

290 lines
9.0 KiB
Plaintext

import drivers.serial.uart.serial as serial
import sched.process as proc
import mm.mm as mm
import viperlib
import asm
define THREAD_READY = 0
define THREAD_RUNNING = 1
define THREAD_BLOCKED = 2
define THREAD_DONE = 3
define MAX_THREADS = 16
define THREAD_STACK_SIZE = 65536
define SCHED_QUANTUM = 10
_yield_cnt: uint32 = 0
_yield_lock: int = 0
class Thread:
rsp: uint64
stack: rawptr
stack_size: uint64
func: rawptr
arg: rawptr
state: int
tid: int
pid: int
def block(self):
self.state = THREAD_BLOCKED
Scheduler._yield()
def unblock(self):
if self.state == THREAD_BLOCKED:
self.state = THREAD_READY
@property
def is_running(self) -> bool: return self.state == THREAD_RUNNING
@property
def is_blocked(self) -> bool: return self.state == THREAD_BLOCKED
@property
def is_done(self) -> bool: return self.state == THREAD_DONE
class Scheduler:
threads: [MAX_THREADS]Thread
current_tid: int
thread_count: int
enabled: int
needs_reschedule: int
tick_count: int
def __init__(self):
global _sched_ptr
_sched_ptr = &_sched_storage
s: Scheduler* = _sched_ptr
s.current_tid = 0
s.thread_count = 1
s.enabled = 0
s.needs_reschedule = 0
s.tick_count = 0
for i in range(MAX_THREADS):
s.threads[i].rsp = 0
s.threads[i].stack = None
s.threads[i].stack_size = 0
s.threads[i].func = None
s.threads[i].arg = None
s.threads[i].state = THREAD_DONE
s.threads[i].tid = i
s.threads[i].pid = 0
s.enabled = 1
s.threads[0].state = THREAD_RUNNING
s.threads[0].tid = 0
main_rsp_ptr: rawptr = &s.threads[0].rsp
__asm__(f"""mov qword ptr [{asminp(main_rsp_ptr, ASM_DESCR.REG_ANY)}], rsp""",
op=[ASM_DESCR.CLOBBER_MEMORY])
@staticmethod
def _yield():
global _switch_old_rsp, _switch_new_rsp, _yield_cnt, _yield_lock
_if_saved: int = 0
__asm__(f"""pushfq
pop rax
shr rax, 9
and eax, 1
mov {asmout(_if_saved, ASM_DESCR.OUTPUT_REG)}, eax""",
op=[ASM_DESCR.CLOBBER_RAX])
asm.cli()
if _yield_lock:
if _if_saved:
asm.sti()
return
_yield_lock = 1
s: Scheduler* = _sched_ptr
s.needs_reschedule = 0
s.tick_count = 0
old_tid: int = s.current_tid
next_tid: int = old_tid + 1
if next_tid >= s.thread_count:
next_tid = 0
found: int = 0
count: int = 0
while count < s.thread_count:
st: int = s.threads[next_tid].state
if st == THREAD_READY or st == THREAD_RUNNING:
found = 1
break
next_tid += 1
if next_tid >= s.thread_count:
next_tid = 0
count += 1
if found == 0:
_yield_lock = 0
if _if_saved:
asm.sti()
return
if next_tid == old_tid:
_yield_lock = 0
if _if_saved:
asm.sti()
return
if s.threads[old_tid].state == THREAD_RUNNING:
s.threads[old_tid].state = THREAD_READY
s.threads[next_tid].state = THREAD_RUNNING
_switch_old_rsp = &s.threads[old_tid].rsp
_switch_new_rsp = &s.threads[next_tid].rsp
s.current_tid = next_tid
next_pid: int = s.threads[next_tid].pid
_yield_cnt += 1
proc.switch_pid(next_pid)
_yield_lock = 0
_do_switch()
if _if_saved:
asm.sti()
@staticmethod
def sched_tick():
s: Scheduler* = _sched_ptr
if not s.enabled: return
if s.thread_count <= 1: return
s.tick_count += 1
if s.tick_count >= SCHED_QUANTUM:
s.tick_count = 0
s.needs_reschedule = 1
@staticmethod
def try_reschedule():
s: Scheduler* = _sched_ptr
if s.needs_reschedule:
s.needs_reschedule = 0
Scheduler._yield()
@staticmethod
def disable():
s: Scheduler* = _sched_ptr
s.enabled = 0
@staticmethod
def enable():
s: Scheduler* = _sched_ptr
s.enabled = 1
@staticmethod
def current() -> Thread*:
s: Scheduler* = _sched_ptr
return &s.threads[s.current_tid]
@staticmethod
def get_thread(tid: int) -> Thread*:
s: Scheduler* = _sched_ptr
if tid < 0 or tid >= s.thread_count: return None
return &s.threads[tid]
@staticmethod
def create_thread(func: rawptr, arg: rawptr, thread_pid: int = 0) -> Thread*:
s: Scheduler* = _sched_ptr
if s.thread_count >= MAX_THREADS: return None
tid: int = s.thread_count
s.thread_count += 1
th: Thread* = &s.threads[tid]
th.state = THREAD_READY
th.tid = tid
th.pid = thread_pid
th.func = func
th.arg = arg
stack_size: uint64 = THREAD_STACK_SIZE
stack_ptr: rawptr = mm.malloc(stack_size)
if not stack_ptr:
s.thread_count -= 1
return None
th.stack = stack_ptr
th.stack_size = stack_size
stack_top: uint64 = uint64(stack_ptr) + stack_size - 16
stack_top = stack_top & ~uint64(0xF)
entry_addr: uint64 = uint64(&_thread_entry)
sp: rawptr = rawptr(stack_top)
__asm__(f"""mov rax, {asminp(sp, ASM_DESCR.REG_ANY)}
mov qword ptr [rax - 64], 0x202
mov qword ptr [rax - 56], 0
mov qword ptr [rax - 48], 0
mov qword ptr [rax - 40], 0
mov qword ptr [rax - 32], 0
mov qword ptr [rax - 24], 0
mov qword ptr [rax - 16], 0
mov qword ptr [rax - 8], 0
mov qword ptr [rax], {asminp(entry_addr, ASM_DESCR.REG_ANY)}""",
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX])
stack_top = stack_top - 64
th.rsp = stack_top
return th
_sched_storage: Scheduler = Scheduler()
export _sched_ptr: Scheduler* = &_sched_storage
export _switch_old_rsp: rawptr
export _switch_new_rsp: rawptr
@__attribute__(naked)
def _do_switch():
__asm__(f"""push rax
push rbx
push rbp
push r12
push r13
push r14
push r15
pushfq
mov rax, qword ptr [rip + _switch_old_rsp]
mov qword ptr [rax], rsp
mov rax, qword ptr [rip + _switch_new_rsp]
mov rsp, qword ptr [rax]
popfq
pop r15
pop r14
pop r13
pop r12
pop rbp
pop rbx
pop rax
ret""",
op=[ASM_DESCR.CLOBBER_MEMORY])
@__attribute__(naked)
def _thread_entry():
__asm__(f"""sub rsp, 8
mov rax, qword ptr [rip + _sched_ptr]
mov ecx, dword ptr [rax + 896]
movsxd rcx, ecx
imul rcx, rcx, 56
mov rdi, qword ptr [rax + rcx + 32]
mov rax, qword ptr [rax + rcx + 24]
call rax
mov rax, qword ptr [rip + _sched_ptr]
mov ecx, dword ptr [rax + 896]
movsxd rcx, ecx
imul rcx, rcx, 56
mov dword ptr [rax + rcx + 40], 3
add rsp, 8""",
# `call rax` 破坏全部 caller-saved 寄存器(x64 SysV):除 RAX/RCX/RDX/
# R8-R11 外,RSI 与 RDI 也必须声明,否则编译器可能假设其值存活(N9)。
# RSP 由 `sub rsp,8` / `add rsp,8` 配对抵消,净变化为 0,无需声明。
op=[ASM_DESCR.CLOBBER_MEMORY, ASM_DESCR.CLOBBER_RAX,
ASM_DESCR.CLOBBER_RCX, ASM_DESCR.CLOBBER_RDX,
ASM_DESCR.CLOBBER_RSI, ASM_DESCR.CLOBBER_RDI,
ASM_DESCR.CLOBBER_R8, ASM_DESCR.CLOBBER_R9,
ASM_DESCR.CLOBBER_R10, ASM_DESCR.CLOBBER_R11])
Scheduler._yield()
while True:
asm.sti()
asm.hlt()
Scheduler._yield()
def thread_current() -> int:
s: Scheduler* = _sched_ptr
return s.current_tid
def needs_reschedule() -> int:
s: Scheduler* = _sched_ptr
return s.needs_reschedule
def sched_dump():
s: Scheduler* = _sched_ptr
dl: [80]char
viperlib.snprintf(&dl, 80, "[sched] dump: cur=%d cnt=%d yields=%u\n", s.current_tid, s.thread_count, _yield_cnt)
serial.puts(dl)
for i in range(s.thread_count):
sl: [80]char
viperlib.snprintf(&sl, 80, " t%d: st=%d pid=%d rsp=0x%lx\n", i, s.threads[i].state, s.threads[i].pid, s.threads[i].rsp)
serial.puts(sl)