feat: add process wait channels

This commit is contained in:
2021-10-31 22:37:29 +02:00
parent b98b53f9f7
commit 1feec06ad0
8 changed files with 175 additions and 2 deletions
+1
View File
@@ -35,6 +35,7 @@ impl IntSource for GenericTimer {
CNTP_TVAL_EL0.set(TIMER_TICK);
CNTP_CTL_EL0.write(CNTP_CTL_EL0::ENABLE::SET);
use crate::proc;
proc::wait::tick();
proc::switch();
Ok(())
}
+7
View File
@@ -1,6 +1,7 @@
//! Timer interface
use crate::dev::Device;
use crate::proc::Pid;
use core::time::Duration;
use error::Errno;
@@ -9,3 +10,9 @@ pub trait TimestampSource: Device {
/// Reads current timestamp as a [Duration] from system start time
fn timestamp(&self) -> Result<Duration, Errno>;
}
///
pub struct Sleep {
deadline: Duration,
pid: Pid
}
+1
View File
@@ -10,6 +10,7 @@
const_panic,
panic_info_message,
alloc_error_handler,
linked_list_cursors,
const_btree_new
)]
#![no_std]
+8
View File
@@ -8,6 +8,9 @@ pub mod elf;
pub mod process;
pub use process::{Pid, Process, ProcessRef, State as ProcessState};
#[allow(missing_docs)]
pub mod wait;
pub mod sched;
pub use sched::Scheduler;
pub(self) use sched::SCHED;
@@ -38,6 +41,11 @@ pub fn switch() {
SCHED.switch(false);
}
///
pub fn process(id: Pid) -> ProcessRef {
PROCESSES.lock().get(&id).unwrap().clone()
}
/// Global list of all processes in the system
pub(self) static PROCESSES: IrqSafeSpinLock<BTreeMap<Pid, ProcessRef>> =
IrqSafeSpinLock::new(BTreeMap::new());
+27 -1
View File
@@ -44,6 +44,7 @@ struct ProcessInner {
space: Option<&'static mut Space>,
state: State,
id: Pid,
wait_flag: bool,
exit: Option<ExitCode>,
}
@@ -161,7 +162,7 @@ impl Process {
assert_eq!(src_lock.state, State::Running);
src_lock.state = State::Ready;
}
assert_eq!(dst_lock.state, State::Ready);
assert!(dst_lock.state == State::Ready || dst_lock.state == State::Waiting);
dst_lock.state = State::Running;
}
@@ -171,6 +172,30 @@ impl Process {
(&mut *src_ctx).switch(&mut *dst_ctx);
}
///
pub fn enter_wait(&self) {
let drop = {
let mut lock = self.inner.lock();
let drop = lock.state == State::Running;
lock.state = State::Waiting;
SCHED.dequeue(lock.id);
drop
};
if drop {
SCHED.switch(true);
}
}
///
pub fn set_wait_flag(&self, v: bool) {
self.inner.lock().wait_flag = v;
}
///
pub fn wait_flag(&self) -> bool {
self.inner.lock().wait_flag
}
/// Returns the process ID
pub fn id(&self) -> Pid {
self.inner.lock().id
@@ -185,6 +210,7 @@ impl Process {
id,
exit: None,
space: None,
wait_flag: false,
state: State::Ready,
}),
});
+115
View File
@@ -0,0 +1,115 @@
use crate::arch::machine;
use crate::proc::{self, sched::SCHED, Pid, Process, ProcessState};
use crate::dev::timer::TimestampSource;
use crate::sync::IrqSafeSpinLock;
use alloc::{vec::Vec, collections::{VecDeque, LinkedList}};
use core::time::Duration;
use error::Errno;
pub struct Wait {
queue: IrqSafeSpinLock<LinkedList<Pid>>,
}
pub struct Timeout {
pid: Pid,
deadline: Duration
}
static TICK_LIST: IrqSafeSpinLock<LinkedList<Timeout>> = IrqSafeSpinLock::new(LinkedList::new());
pub fn tick() {
let time = machine::local_timer().timestamp().unwrap();
let mut list = TICK_LIST.lock();
let mut cursor = list.cursor_front_mut();
while let Some(item) = cursor.current() {
if time > item.deadline {
let pid = item.pid;
cursor.remove_current();
SCHED.enqueue(pid);
} else {
cursor.move_next();
}
}
}
pub fn sleep(timeout: Duration) {
// Dummy wait descriptor which will never receive notifications
static SLEEP_NOTIFY: Wait = Wait::new();
SLEEP_NOTIFY.sleep_on(Some(timeout));
}
impl Wait {
pub const fn new() -> Self {
Self {
queue: IrqSafeSpinLock::new(LinkedList::new())
}
}
pub fn wakeup_all(&self) {
todo!()
}
pub fn wakeup_one(&self) {
// No IRQs will arrive now == safe to manipulate tick list
let mut tick_lock = TICK_LIST.lock();
let pid = self.queue.lock().pop_front();
if let Some(pid) = pid {
let mut cursor = tick_lock.cursor_front_mut();
while let Some(item) = cursor.current() {
if pid == item.pid {
cursor.remove_current();
break;
} else {
cursor.move_next();
}
}
drop(tick_lock);
proc::process(pid).set_wait_flag(false);
SCHED.enqueue(pid);
}
}
pub fn sleep_on(&self, timeout: Option<Duration>) -> Result<(), Errno> {
let proc = Process::current();
let deadline = timeout.map(|t| machine::local_timer().timestamp().unwrap() + t);
let mut queue_lock = Some(self.queue.lock());
queue_lock.as_mut().unwrap().push_back(proc.id());
proc.set_wait_flag(true);
if let Some(deadline) = deadline {
TICK_LIST.lock().push_back(Timeout {
pid: proc.id(),
deadline
});
}
loop {
if !proc.wait_flag() {
return Ok(());
}
queue_lock = None;
proc.enter_wait();
queue_lock = Some(self.queue.lock());
if let Some(deadline) = deadline {
if machine::local_timer().timestamp()? > deadline {
let mut cursor = queue_lock.as_mut().unwrap().cursor_front_mut();
while let Some(&mut item) = cursor.current() {
if proc.id() == item {
cursor.remove_current();
break;
} else {
cursor.move_next();
}
}
return Err(Errno::TimedOut);
}
}
}
}
}
+9
View File
@@ -59,6 +59,15 @@ pub unsafe fn syscall(num: usize, args: &[usize]) -> Result<usize, Errno> {
println!(Level::Debug, "");
Ok(args[1])
}
// sys_ex_sleep
121 => {
use crate::proc::wait;
use core::time::Duration;
wait::sleep(Duration::from_nanos(args[0] as u64));
Ok(0)
}
_ => panic!("Undefined system call: {}", num),
}
}