diff --git a/kernel/defs.h b/kernel/defs.h index 87f84e4..5eda245 100644 --- a/kernel/defs.h +++ b/kernel/defs.h @@ -79,18 +79,13 @@ void printstr(char *s); void printint(int n); // proc.c -void exit(int); void proc_mapstacks(pagetable_t); pagetable_t proc_pagetable(struct proc *); void proc_freepagetable(pagetable_t, uint64); -int kill(int); int killed(struct proc *); -void setkilled(struct proc *); struct cpu *mycpu(void); struct proc *myproc(); void procinit(void); -void scheduler(void) __attribute__((noreturn)); -void sched(void); void sleep_lock(void *, struct spinlock *); void userinit(void); int wait(uint64); diff --git a/kernel/proc.c b/kernel/proc.c index 44f47f0..2ba8fe3 100644 --- a/kernel/proc.c +++ b/kernel/proc.c @@ -109,11 +109,6 @@ userinit(void) // Caller must hold wait_lock. void reparent(struct proc *p); -// Exit the current process. Does not return. -// An exited process remains in the zombie state -// until its parent calls wait(). -void exit(int status); - // Wait for a child process to exit and return its pid. // Return -1 if this process has no children. int @@ -163,52 +158,6 @@ wait(uint64 addr) } } -// Per-CPU process scheduler. -// Each CPU calls scheduler() after setting itself up. -// Scheduler never returns. It loops, doing: -// - choose a process to run. -// - swtch to start running that process. -// - eventually that process transfers control -// via swtch back to the scheduler. -void -scheduler(void) -{ - struct proc *p; - struct cpu *c = mycpu(); - - c->proc = 0; - for(;;){ - // Avoid deadlock by ensuring that devices can interrupt. - intr_on(); - - for(p = proc; p < &proc[NPROC]; p++) { - acquire(&p->lock); - if(p->state == RUNNABLE) { - // Switch to chosen process. It is the process's job - // to release its lock and then reacquire it - // before jumping back to us. - p->state = RUNNING; - c->proc = p; - swtch(&c->context, &p->context); - - // Process is done running for now. - // It should have changed its p->state before coming back. - c->proc = 0; - } - release(&p->lock); - } - } -} - -// Switch to scheduler. Must hold only p->lock -// and have changed proc->state. Saves and restores -// intena because intena is a property of this -// kernel thread, not this CPU. It should -// be proc->intena and proc->noff, but that would -// break in the few places where a lock is held but -// there's no process. -void sched(void); - // A fork child's very first scheduling by scheduler() // will swtch to forkret. void @@ -251,11 +200,6 @@ void wakeup(void *chan) } } -// Kill the process with the given pid. -// The victim won't exit until it tries to return -// to user space (see usertrap() in trap.c). -int kill(int pid); -void setkilled(struct proc *p); int killed(struct proc *p); // Copy to either a user address, or kernel address, diff --git a/kernel/rustkernel/src/proc/scheduler.rs b/kernel/rustkernel/src/proc/scheduler.rs index ef9b883..1deb8cb 100644 --- a/kernel/rustkernel/src/proc/scheduler.rs +++ b/kernel/rustkernel/src/proc/scheduler.rs @@ -1,20 +1,20 @@ use super::{ context::Context, cpu::Cpu, - process::{Process, ProcessState}, + process::{proc, Process, ProcessState}, }; use crate::{ - arch::riscv::intr_get, + arch::riscv::{intr_get, intr_on}, sync::spinlock::{Spinlock, SpinlockGuard}, }; use core::{ ffi::c_void, - ptr::{addr_of_mut, null_mut}, + ptr::{addr_of, addr_of_mut, null_mut}, }; extern "C" { pub fn wakeup(chan: *const c_void); - pub fn scheduler() -> !; + // pub fn scheduler() -> !; pub fn swtch(a: *mut Context, b: *mut Context); } @@ -26,6 +26,41 @@ pub unsafe fn r#yield() { sched(); } +// Per-CPU process scheduler. +// Each CPU calls scheduler() after setting itself up. +// Scheduler never returns. It loops, doing: +// - choose a process to run. +// - swtch to start running that process. +// - eventually that process transfers control +// via swtch back to the scheduler. +pub unsafe fn scheduler() -> ! { + let cpu = Cpu::current(); + cpu.proc = null_mut(); + + loop { + // Avoid deadlock by ensuring that devices can interrupt. + intr_on(); + + for p in &mut proc { + let _guard = p.lock.lock(); + if p.state == ProcessState::Runnable { + // Switch to the chosen process. It's the process's job + // to release its lock and then reacquire it before + // jumping back to us. + p.state = ProcessState::Running; + cpu.proc = addr_of!(*p).cast_mut(); + + // Run the process. + swtch(addr_of_mut!(cpu.context), addr_of_mut!(p.context)); + + // Process is done running for now. + // It should have changed its state before coming back. + cpu.proc = null_mut(); + } + } + } +} + /// Switch to scheduler. Must hold only p->lock /// and have changed proc->state. Saves and restores /// previous_interrupts_enabled because previous_interrupts_enabled is a property of this @@ -33,8 +68,7 @@ pub unsafe fn r#yield() { /// be proc->previous_interrupts_enabled and proc->interrupt_disable_layers, but that would /// break in the few places where a lock is held but /// there's no process. -#[no_mangle] -pub unsafe extern "C" fn sched() { +pub unsafe fn sched() { let p = Process::current().unwrap(); let cpu = Cpu::current();