feat: SMP stage 2, lock-free fast paths (GetTime, GetProcessId, DebugPutchar, no-op Yield), storm checks yield equivalence
This commit is contained in:
@@ -241,7 +241,7 @@ fn next_runnable() -> types::id::ThreadId {
|
||||
return tid;
|
||||
}
|
||||
crate::mmu::activate(crate::mmu::page_table::table_at(crate::smp::kernel_root()));
|
||||
crate::smp::unlock();
|
||||
release();
|
||||
unsafe { core::arch::asm!("wfi") };
|
||||
crate::smp::service_ipi();
|
||||
crate::smp::lock();
|
||||
@@ -271,6 +271,54 @@ fn dispatch_external() {
|
||||
}
|
||||
}
|
||||
|
||||
/// Releases the kernel lock, first publishing what the lock-free fast
|
||||
/// paths may rely on.
|
||||
fn release() {
|
||||
let kern = kern();
|
||||
for core in 0..crate::smp::num_harts() {
|
||||
let id = types::id::CoreId::from_raw(core as u8);
|
||||
crate::smp::publish_waiting(core, kern.highest_waiting(id).map(|p| p.value()));
|
||||
}
|
||||
let running = kern.current_thread();
|
||||
crate::smp::publish_running(
|
||||
running
|
||||
.and_then(|t| kern.thread_process(t))
|
||||
.map(|p| p.raw()),
|
||||
running
|
||||
.and_then(|t| kern.thread_priority(t))
|
||||
.map(|p| p.value()),
|
||||
);
|
||||
crate::smp::unlock();
|
||||
}
|
||||
|
||||
/// Syscalls answered without the kernel lock, as the kernel would answer
|
||||
/// them: they read nothing the lock guards (the time, the UART, the
|
||||
/// running thread's fixed process id) or, for a Yield that has nobody to
|
||||
/// yield to, change nothing. Any pending IPI or reschedule request sends
|
||||
/// the call down the slow path, so no request is ever skipped.
|
||||
fn fast_syscall(frame: &mut TrapFrame) -> bool {
|
||||
use types::syscall_abi::{SYS_DEBUG_PUTCHAR, SYS_GET_PROCESS_ID, SYS_GET_TIME, SYS_YIELD};
|
||||
if crate::smp::has_pending_request() {
|
||||
return false;
|
||||
}
|
||||
let result = match frame.regs[17] {
|
||||
SYS_GET_TIME => kernel::SyscallResult::Value(crate::hw::timer::read_time() as usize),
|
||||
SYS_GET_PROCESS_ID => match crate::smp::running_pid() {
|
||||
Some(pid) => kernel::SyscallResult::Value(pid),
|
||||
None => return false,
|
||||
},
|
||||
SYS_DEBUG_PUTCHAR => {
|
||||
crate::hw::uart::Uart::new().put_char(frame.regs[10] as u8);
|
||||
kernel::SyscallResult::Ok
|
||||
}
|
||||
SYS_YIELD if crate::smp::yield_is_noop() => kernel::SyscallResult::Ok,
|
||||
_ => return false,
|
||||
};
|
||||
frame.sepc += 4;
|
||||
write_result(frame, &result);
|
||||
true
|
||||
}
|
||||
|
||||
/// Last step before leaving the kernel to userspace: act on a reschedule
|
||||
/// request, make sure this hart has a thread (its own may have been taken
|
||||
/// away by another hart), and translate through that thread's address
|
||||
@@ -311,7 +359,7 @@ pub fn enter_first() -> ! {
|
||||
None => switch_to_next(&mut frame, None),
|
||||
}
|
||||
finish(&mut frame);
|
||||
crate::smp::unlock();
|
||||
release();
|
||||
// SAFETY: `frame` holds a user context; sscratch is set from it on
|
||||
// the way out, so later traps land at the top of this frame.
|
||||
unsafe { trap_return(&mut frame) }
|
||||
@@ -326,6 +374,9 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||
// Checked before taking the lock: this hart may already hold it.
|
||||
kernel_fault(frame, scause);
|
||||
}
|
||||
if scause == CAUSE_ECALL_U && fast_syscall(frame) {
|
||||
return;
|
||||
}
|
||||
crate::smp::service_ipi();
|
||||
crate::smp::lock();
|
||||
if scause & CAUSE_INTERRUPT_BIT != 0 {
|
||||
@@ -334,7 +385,7 @@ extern "C" fn trap_handler_rust(frame: &mut TrapFrame) {
|
||||
handle_exception(frame, scause);
|
||||
}
|
||||
finish(frame);
|
||||
crate::smp::unlock();
|
||||
release();
|
||||
}
|
||||
|
||||
fn handle_interrupt(frame: &mut TrapFrame, cause: usize) {
|
||||
|
||||
Reference in New Issue
Block a user