1
0
mirror of https://github.com/sgmarz/osblog.git synced 2024-11-27 20:03:32 +04:00

Added locking to the scheduler. Since this is invoked so often, it causes a race with the test_elf process.

This commit is contained in:
Stephen Marz 2020-04-26 21:08:29 -04:00
parent ef0997be74
commit 532b246f7b
3 changed files with 52 additions and 59 deletions

View File

@ -8,8 +8,8 @@ use crate::syscall::syscall_sleep;
pub const DEFAULT_LOCK_SLEEP: usize = 10000; pub const DEFAULT_LOCK_SLEEP: usize = 10000;
#[repr(u32)] #[repr(u32)]
pub enum MutexState { pub enum MutexState {
Locked = 0, Unlocked = 0,
Unlocked = 1, Locked = 1,
} }
#[repr(C)] #[repr(C)]
@ -44,14 +44,14 @@ impl<'a> Mutex {
/// Never use a sleep lock for the process list. Sleeping requires /// Never use a sleep lock for the process list. Sleeping requires
/// the process list to function, so you'll deadlock if you do. /// the process list to function, so you'll deadlock if you do.
pub fn sleep_lock(&mut self) { pub fn sleep_lock(&mut self) {
while self.lock() == false { while !self.lock() {
syscall_sleep(DEFAULT_LOCK_SLEEP); syscall_sleep(DEFAULT_LOCK_SLEEP);
} }
} }
/// Can safely be used inside of an interrupt context. /// Can safely be used inside of an interrupt context.
pub fn spin_lock(&mut self) { pub fn spin_lock(&mut self) {
while self.lock() == false {} while !self.lock() {}
} }
pub fn unlock(&mut self) { pub fn unlock(&mut self) {

View File

@ -59,7 +59,6 @@ pub fn set_running(pid: u16) -> bool {
// of process pointers. // of process pointers.
let mut retval = false; let mut retval = false;
unsafe { unsafe {
PROCESS_LIST_MUTEX.spin_lock();
if let Some(mut pl) = PROCESS_LIST.take() { if let Some(mut pl) = PROCESS_LIST.take() {
for proc in pl.iter_mut() { for proc in pl.iter_mut() {
if proc.pid == pid { if proc.pid == pid {
@ -73,7 +72,6 @@ pub fn set_running(pid: u16) -> bool {
// Some(pl). // Some(pl).
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
} }
PROCESS_LIST_MUTEX.unlock();
} }
retval retval
} }
@ -86,7 +84,6 @@ pub fn set_waiting(pid: u16) -> bool {
// of process pointers. // of process pointers.
let mut retval = false; let mut retval = false;
unsafe { unsafe {
PROCESS_LIST_MUTEX.spin_lock();
if let Some(mut pl) = PROCESS_LIST.take() { if let Some(mut pl) = PROCESS_LIST.take() {
for proc in pl.iter_mut() { for proc in pl.iter_mut() {
if proc.pid == pid { if proc.pid == pid {
@ -100,7 +97,6 @@ pub fn set_waiting(pid: u16) -> bool {
// Some(pl). // Some(pl).
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
} }
PROCESS_LIST_MUTEX.unlock();
} }
retval retval
} }
@ -111,7 +107,6 @@ pub fn set_sleeping(pid: u16, duration: usize) -> bool {
// of process pointers. // of process pointers.
let mut retval = false; let mut retval = false;
unsafe { unsafe {
PROCESS_LIST_MUTEX.spin_lock();
if let Some(mut pl) = PROCESS_LIST.take() { if let Some(mut pl) = PROCESS_LIST.take() {
for proc in pl.iter_mut() { for proc in pl.iter_mut() {
if proc.pid == pid { if proc.pid == pid {
@ -129,7 +124,6 @@ pub fn set_sleeping(pid: u16, duration: usize) -> bool {
// Some(pl). // Some(pl).
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
} }
PROCESS_LIST_MUTEX.unlock();
} }
retval retval
} }
@ -138,7 +132,6 @@ pub fn set_sleeping(pid: u16, duration: usize) -> bool {
/// this function does nothing. /// this function does nothing.
pub fn delete_process(pid: u16) { pub fn delete_process(pid: u16) {
unsafe { unsafe {
PROCESS_LIST_MUTEX.spin_lock();
if let Some(mut pl) = PROCESS_LIST.take() { if let Some(mut pl) = PROCESS_LIST.take() {
for i in 0..pl.len() { for i in 0..pl.len() {
let p = pl.get_mut(i).unwrap(); let p = pl.get_mut(i).unwrap();
@ -154,7 +147,6 @@ pub fn delete_process(pid: u16) {
// Some(pl). // Some(pl).
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
} }
PROCESS_LIST_MUTEX.unlock();
} }
} }
@ -162,7 +154,6 @@ pub fn delete_process(pid: u16) {
/// unsafe since the process can be deleted and we'll still have a pointer. /// unsafe since the process can be deleted and we'll still have a pointer.
pub unsafe fn get_by_pid(pid: u16) -> *mut Process { pub unsafe fn get_by_pid(pid: u16) -> *mut Process {
let mut ret = null_mut(); let mut ret = null_mut();
PROCESS_LIST_MUTEX.spin_lock();
if let Some(mut pl) = PROCESS_LIST.take() { if let Some(mut pl) = PROCESS_LIST.take() {
for i in pl.iter_mut() { for i in pl.iter_mut() {
if i.get_pid() == pid { if i.get_pid() == pid {
@ -172,7 +163,6 @@ pub unsafe fn get_by_pid(pid: u16) -> *mut Process {
} }
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
} }
PROCESS_LIST_MUTEX.unlock();
ret ret
} }
@ -243,58 +233,57 @@ pub fn add_kernel_process(func: fn()) -> u16 {
// then move ownership back to the PROCESS_LIST. // then move ownership back to the PROCESS_LIST.
// This allows mutual exclusion as anyone else trying to grab // This allows mutual exclusion as anyone else trying to grab
// the process list will get None rather than the Deque. // the process list will get None rather than the Deque.
unsafe { PROCESS_LIST_MUTEX.spin_lock(); } // .take() will replace PROCESS_LIST with None and give
// us the only copy of the Deque.
let func_addr = func as usize;
let func_vaddr = func_addr; //- 0x6000_0000;
// println!("func_addr = {:x} -> {:x}", func_addr, func_vaddr);
// We will convert NEXT_PID below into an atomic increment when
// we start getting into multi-hart processing. For now, we want
// a process. Get it to work, then improve it!
let my_pid = unsafe { NEXT_PID };
let mut ret_proc =
Process { frame: zalloc(1) as *mut TrapFrame,
stack: zalloc(STACK_PAGES),
pid: my_pid,
root: zalloc(1) as *mut Table,
state: ProcessState::Running,
data: ProcessData::zero(),
sleep_until: 0,
program: null_mut()
};
unsafe {
NEXT_PID += 1;
}
// Now we move the stack pointer to the bottom of the
// allocation. The spec shows that register x2 (2) is the stack
// pointer.
// We could use ret_proc.stack.add, but that's an unsafe
// function which would require an unsafe block. So, convert it
// to usize first and then add PAGE_SIZE is better.
// We also need to set the stack adjustment so that it is at the
// bottom of the memory and far away from heap allocations.
unsafe {
(*ret_proc.frame).pc = func_vaddr;
// 1 is the return address register. This makes it so we
// don't have to do syscall_exit() when a kernel process
// finishes.
(*ret_proc.frame).regs[1] = ra_delete_proc as usize;
(*ret_proc.frame).regs[2] =
ret_proc.stack as usize + STACK_PAGES * 4096;
(*ret_proc.frame).mode = CpuMode::Machine as usize;
(*ret_proc.frame).pid = ret_proc.pid as usize;
}
if let Some(mut pl) = unsafe { PROCESS_LIST.take() } { if let Some(mut pl) = unsafe { PROCESS_LIST.take() } {
// .take() will replace PROCESS_LIST with None and give
// us the only copy of the Deque.
let func_addr = func as usize;
let func_vaddr = func_addr; //- 0x6000_0000;
// println!("func_addr = {:x} -> {:x}", func_addr, func_vaddr);
// We will convert NEXT_PID below into an atomic increment when
// we start getting into multi-hart processing. For now, we want
// a process. Get it to work, then improve it!
let my_pid = unsafe { NEXT_PID };
let mut ret_proc =
Process { frame: zalloc(1) as *mut TrapFrame,
stack: zalloc(STACK_PAGES),
pid: my_pid,
root: zalloc(1) as *mut Table,
state: ProcessState::Running,
data: ProcessData::zero(),
sleep_until: 0,
program: null_mut()
};
unsafe {
NEXT_PID += 1;
}
// Now we move the stack pointer to the bottom of the
// allocation. The spec shows that register x2 (2) is the stack
// pointer.
// We could use ret_proc.stack.add, but that's an unsafe
// function which would require an unsafe block. So, convert it
// to usize first and then add PAGE_SIZE is better.
// We also need to set the stack adjustment so that it is at the
// bottom of the memory and far away from heap allocations.
unsafe {
(*ret_proc.frame).pc = func_vaddr;
// 1 is the return address register. This makes it so we
// don't have to do syscall_exit() when a kernel process
// finishes.
(*ret_proc.frame).regs[1] = ra_delete_proc as usize;
(*ret_proc.frame).regs[2] =
ret_proc.stack as usize + STACK_PAGES * 4096;
(*ret_proc.frame).mode = CpuMode::Machine as usize;
(*ret_proc.frame).pid = ret_proc.pid as usize;
}
pl.push_back(ret_proc); pl.push_back(ret_proc);
// Now, we no longer need the owned Deque, so we hand it // Now, we no longer need the owned Deque, so we hand it
// back by replacing the PROCESS_LIST's None with the // back by replacing the PROCESS_LIST's None with the
// Some(pl). // Some(pl).
unsafe { unsafe {
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
PROCESS_LIST_MUTEX.unlock();
} }
return my_pid; my_pid
} }
else { else {
unsafe { PROCESS_LIST_MUTEX.unlock(); } unsafe { PROCESS_LIST_MUTEX.unlock(); }
@ -398,6 +387,7 @@ pub fn add_kernel_process_args(func: fn(args_ptr: usize), args: usize) -> u16 {
/// but later, it should call the shell. /// but later, it should call the shell.
pub fn init() -> usize { pub fn init() -> usize {
unsafe { unsafe {
PROCESS_LIST_MUTEX.spin_lock();
PROCESS_LIST = Some(VecDeque::with_capacity(15)); PROCESS_LIST = Some(VecDeque::with_capacity(15));
// add_process_default(init_process); // add_process_default(init_process);
add_kernel_process(init_process); add_kernel_process(init_process);
@ -412,6 +402,7 @@ pub fn init() -> usize {
// println!("Init's frame is at 0x{:08x}", frame); // println!("Init's frame is at 0x{:08x}", frame);
// Put the process list back in the global. // Put the process list back in the global.
PROCESS_LIST.replace(pl); PROCESS_LIST.replace(pl);
PROCESS_LIST_MUTEX.unlock();
// Return the first instruction's address to execute. // Return the first instruction's address to execute.
// Since we use the MMU, all start here. // Since we use the MMU, all start here.
(*p).pc (*p).pc

View File

@ -3,12 +3,13 @@
// Stephen Marz // Stephen Marz
// 27 Dec 2019 // 27 Dec 2019
use crate::process::{ProcessState, PROCESS_LIST}; use crate::process::{ProcessState, PROCESS_LIST, PROCESS_LIST_MUTEX};
use crate::cpu::get_mtime; use crate::cpu::get_mtime;
pub fn schedule() -> usize { pub fn schedule() -> usize {
let mut frame_addr: usize = 0x1111; let mut frame_addr: usize = 0x1111;
unsafe { unsafe {
PROCESS_LIST_MUTEX.spin_lock();
if let Some(mut pl) = PROCESS_LIST.take() { if let Some(mut pl) = PROCESS_LIST.take() {
// Rust allows us to label loops so that break statements can be // Rust allows us to label loops so that break statements can be
// targeted. // targeted.
@ -39,6 +40,7 @@ pub fn schedule() -> usize {
else { else {
println!("could not take process list"); println!("could not take process list");
} }
PROCESS_LIST_MUTEX.unlock();
} }
frame_addr frame_addr
} }