scheduler

This commit is contained in:
Garen Tyler 2023-11-03 20:45:16 -06:00
parent a168c989cf
commit 0a1e889d54
Signed by: garentyler
GPG Key ID: D7A048C454CB7054
3 changed files with 40 additions and 67 deletions

View File

@ -79,18 +79,13 @@ void printstr(char *s);
void printint(int n); void printint(int n);
// proc.c // proc.c
void exit(int);
void proc_mapstacks(pagetable_t); void proc_mapstacks(pagetable_t);
pagetable_t proc_pagetable(struct proc *); pagetable_t proc_pagetable(struct proc *);
void proc_freepagetable(pagetable_t, uint64); void proc_freepagetable(pagetable_t, uint64);
int kill(int);
int killed(struct proc *); int killed(struct proc *);
void setkilled(struct proc *);
struct cpu *mycpu(void); struct cpu *mycpu(void);
struct proc *myproc(); struct proc *myproc();
void procinit(void); void procinit(void);
void scheduler(void) __attribute__((noreturn));
void sched(void);
void sleep_lock(void *, struct spinlock *); void sleep_lock(void *, struct spinlock *);
void userinit(void); void userinit(void);
int wait(uint64); int wait(uint64);

View File

@ -109,11 +109,6 @@ userinit(void)
// Caller must hold wait_lock. // Caller must hold wait_lock.
void reparent(struct proc *p); 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. // Wait for a child process to exit and return its pid.
// Return -1 if this process has no children. // Return -1 if this process has no children.
int 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() // A fork child's very first scheduling by scheduler()
// will swtch to forkret. // will swtch to forkret.
void 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); int killed(struct proc *p);
// Copy to either a user address, or kernel address, // Copy to either a user address, or kernel address,

View File

@ -1,20 +1,20 @@
use super::{ use super::{
context::Context, context::Context,
cpu::Cpu, cpu::Cpu,
process::{Process, ProcessState}, process::{proc, Process, ProcessState},
}; };
use crate::{ use crate::{
arch::riscv::intr_get, arch::riscv::{intr_get, intr_on},
sync::spinlock::{Spinlock, SpinlockGuard}, sync::spinlock::{Spinlock, SpinlockGuard},
}; };
use core::{ use core::{
ffi::c_void, ffi::c_void,
ptr::{addr_of_mut, null_mut}, ptr::{addr_of, addr_of_mut, null_mut},
}; };
extern "C" { extern "C" {
pub fn wakeup(chan: *const c_void); pub fn wakeup(chan: *const c_void);
pub fn scheduler() -> !; // pub fn scheduler() -> !;
pub fn swtch(a: *mut Context, b: *mut Context); pub fn swtch(a: *mut Context, b: *mut Context);
} }
@ -26,6 +26,41 @@ pub unsafe fn r#yield() {
sched(); 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 /// Switch to scheduler. Must hold only p->lock
/// and have changed proc->state. Saves and restores /// and have changed proc->state. Saves and restores
/// previous_interrupts_enabled because previous_interrupts_enabled is a property of this /// 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 /// be proc->previous_interrupts_enabled and proc->interrupt_disable_layers, but that would
/// break in the few places where a lock is held but /// break in the few places where a lock is held but
/// there's no process. /// there's no process.
#[no_mangle] pub unsafe fn sched() {
pub unsafe extern "C" fn sched() {
let p = Process::current().unwrap(); let p = Process::current().unwrap();
let cpu = Cpu::current(); let cpu = Cpu::current();