diff --git a/src/kxos-frame/src/sync/rcu/mod.rs b/src/kxos-frame/src/sync/rcu/mod.rs
index 1141c536..09f3d97c 100644
--- a/src/kxos-frame/src/sync/rcu/mod.rs
+++ b/src/kxos-frame/src/sync/rcu/mod.rs
@@ -89,7 +89,7 @@ impl
Drop for RcuReclaimer
{
wq.wake_one();
}
});
- wq.wait_until(|| true);
+ wq.wait_until(None::, || Some(0));
}
}
diff --git a/src/kxos-frame/src/sync/wait.rs b/src/kxos-frame/src/sync/wait.rs
index 1cb07418..11d4dc3f 100644
--- a/src/kxos-frame/src/sync/wait.rs
+++ b/src/kxos-frame/src/sync/wait.rs
@@ -1,69 +1,123 @@
+use alloc::collections::VecDeque;
+use spin::mutex::Mutex;
+
+use crate::{debug, task::Task};
+
/// A wait queue.
///
/// One may wait on a wait queue to put its executing thread to sleep.
/// Multiple threads may be the waiters of a wait queue.
/// Other threads may invoke the `wake`-family methods of a wait queue to
/// wake up one or many waiter threads.
-pub struct WaitQueue {}
+pub struct WaitQueue {
+ waiters: Mutex>>,
+}
-impl WaitQueue {
+impl WaitQueue {
/// Creates a new instance.
pub fn new() -> Self {
- todo!()
+ WaitQueue {
+ waiters: Mutex::new(VecDeque::new()),
+ }
}
/// Wait until some condition becomes true.
///
/// This method takes a closure that tests a user-given condition.
- /// The method only returns if the condition becomes true.
+ /// The method only returns if the condition returns Some(_).
/// A waker thread should first make the condition true, then invoke the
/// `wake`-family method. This ordering is important to ensure that waiter
/// threads do not lose any wakeup notifiations.
///
/// By taking a condition closure, this wait-wakeup mechanism becomes
/// more efficient and robust.
- pub fn wait_until(&self, mut cond: F)
+ pub fn wait_until(&self, data: D, mut cond: F) -> R
where
- F: FnMut() -> bool,
+ F: FnMut() -> Option,
{
- let waiter = Waiter::new();
+ let waiter = Waiter::new(data);
self.enqueue(&waiter);
loop {
- if (cond)() {
+ if let Some(r) = cond() {
self.dequeue(&waiter);
- break;
+ return r;
}
waiter.wait();
}
- self.dequeue(&waiter);
}
/// Wake one waiter thread, if there is one.
pub fn wake_one(&self) {
- todo!()
+ if let Some(waiter) = self.waiters.lock().front_mut() {
+ waiter.wake_up();
+ }
}
/// Wake all waiter threads.
pub fn wake_all(&self) {
- todo!()
+ self.waiters.lock().iter_mut().for_each(|waiter| {
+ waiter.wake_up();
+ });
}
- fn enqueue(&self, waiter: &Waiter) {
- todo!()
+ /// Wake all waiters if given condition returns true.
+ /// The condition will check the data carried by waiter if it satisfy some relation with cond_data
+ pub fn wake_all_on_condition(&self, cond_data: &C, cond: F)
+ where
+ F: Fn(&D, &C) -> bool,
+ {
+ self.waiters.lock().iter_mut().for_each(|waiter| {
+ if cond(waiter.data(), cond_data) {
+ waiter.wake_up()
+ }
+ })
}
- fn dequeue(&self, waiter: &Waiter) {
- todo!()
+
+ fn enqueue(&self, waiter: &Waiter) {
+ self.waiters.lock().push_back(waiter.clone());
+ }
+ fn dequeue(&self, waiter: &Waiter) {
+ let mut waiters_lock = self.waiters.lock();
+ let len = waiters_lock.len();
+ let mut index = 0;
+ for i in 0..len {
+ if waiters_lock[i] == *waiter {
+ index = i;
+ break;
+ }
+ }
+ waiters_lock.remove(index);
+ drop(waiters_lock);
}
}
-struct Waiter {}
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct Waiter {
+ is_woken_up: bool,
+ data: D,
+}
-impl Waiter {
- pub fn new() -> Self {
- todo!()
+impl Waiter {
+ pub fn new(data: D) -> Self {
+ Waiter {
+ is_woken_up: false,
+ data,
+ }
}
pub fn wait(&self) {
- todo!()
+ while !self.is_woken_up {
+ // yield the execution, to allow other task to contine
+ debug!("Waiter: wait");
+ Task::yield_now();
+ }
+ }
+
+ pub fn wake_up(&mut self) {
+ self.is_woken_up = true;
+ }
+
+ pub fn data(&self) -> &D {
+ &self.data
}
}
diff --git a/src/kxos-frame/src/vm/pod.rs b/src/kxos-frame/src/vm/pod.rs
index b4fcb2df..63396ec8 100644
--- a/src/kxos-frame/src/vm/pod.rs
+++ b/src/kxos-frame/src/vm/pod.rs
@@ -55,9 +55,9 @@ pub unsafe trait Pod: Copy + Sized + Debug {
/// FIXME: use derive instead
#[macro_export]
macro_rules! impl_pod_for {
- ($($token:tt),*/* define the input */) => {
+ ($($pod_ty:ty),*/* define the input */) => {
/* define the expansion */
- $(unsafe impl Pod for $token {})*
+ $(unsafe impl Pod for $pod_ty {})*
};
}
diff --git a/src/kxos-std/src/lib.rs b/src/kxos-std/src/lib.rs
index 97c2e811..ed14a631 100644
--- a/src/kxos-std/src/lib.rs
+++ b/src/kxos-std/src/lib.rs
@@ -5,6 +5,9 @@
#![allow(unused_variables)]
#![feature(const_btree_new)]
#![feature(cstr_from_bytes_until_nul)]
+#![feature(half_open_range_patterns)]
+#![feature(exclusive_range_pattern)]
+#![feature(btree_drain_filter)]
use alloc::ffi::CString;
use kxos_frame::{debug, info, println};
diff --git a/src/kxos-std/src/memory/mod.rs b/src/kxos-std/src/memory/mod.rs
index 5444ac23..38b1219c 100644
--- a/src/kxos-std/src/memory/mod.rs
+++ b/src/kxos-std/src/memory/mod.rs
@@ -58,3 +58,12 @@ pub fn write_bytes_to_user(dest: Vaddr, src: &[u8]) {
.expect("[Internal error]Current should have vm space to write bytes to user");
vm_space.write_bytes(dest, src).expect("write bytes failed")
}
+
+/// write val (Plain of Data type) to user space of current process.
+pub fn write_val_to_user(dest: Vaddr, val: T) {
+ let current = Process::current();
+ let vm_space = current
+ .vm_space()
+ .expect("[Internal error]Current should have vm space to write val to user");
+ vm_space.write_val(dest, &val).expect("write val failed");
+}
diff --git a/src/kxos-std/src/process/mod.rs b/src/kxos-std/src/process/mod.rs
index 53955c35..4d300ce7 100644
--- a/src/kxos-std/src/process/mod.rs
+++ b/src/kxos-std/src/process/mod.rs
@@ -1,38 +1,43 @@
use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
+use alloc::collections::BTreeMap;
use alloc::ffi::CString;
-use alloc::{
- sync::{Arc, Weak},
- vec::Vec,
-};
+use alloc::sync::{Arc, Weak};
+use kxos_frame::sync::WaitQueue;
use kxos_frame::{debug, task::Task, user::UserSpace, vm::VmSpace};
use spin::Mutex;
use crate::memory::mmap_area::MmapArea;
use crate::memory::user_heap::UserHeap;
+use self::process_filter::ProcessFilter;
use self::status::ProcessStatus;
use self::task::create_user_task_from_elf;
use self::user_vm_data::UserVm;
pub mod fifo_scheduler;
+pub mod process_filter;
pub mod status;
pub mod task;
pub mod user_vm_data;
+pub mod wait;
static PID_ALLOCATOR: AtomicUsize = AtomicUsize::new(0);
-const CHILDREN_CAPACITY: usize = 16;
+pub type Pid = usize;
+pub type Pgid = usize;
+pub type ExitCode = i32;
/// Process stands for a set of tasks that shares the same userspace.
/// Currently, we only support one task inside a process.
pub struct Process {
// Immutable Part
- pid: usize,
+ pid: Pid,
task: Arc,
filename: Option,
user_space: Option>,
user_vm: Option,
+ waiting_children: WaitQueue,
// Mutable Part
/// The exit code
@@ -42,7 +47,7 @@ pub struct Process {
/// Parent process
parent: Mutex