scheduler
This commit is contained in:
parent
a168c989cf
commit
0a1e889d54
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user