diff --git a/kernel/src/objects/cap.rs b/kernel/src/objects/cap.rs index cbe76af..eb143ff 100644 --- a/kernel/src/objects/cap.rs +++ b/kernel/src/objects/cap.rs @@ -42,12 +42,14 @@ impl RawCap { } } +pub const CAP_ENTRY_LINK_ID: usize = 1; + pub struct CapEntry { pub cap: RawCap, - pub link: Link, + pub link: Link, } -LinkHelperImpl!(CapEntry: link); +LinkHelperImpl!(CapEntry { link } => CAP_ENTRY_LINK_ID); impl CapEntry { pub fn new(cap: RawCap) -> Self { diff --git a/kernel/src/objects/tcb.rs b/kernel/src/objects/tcb.rs index 2830026..706f80a 100644 --- a/kernel/src/objects/tcb.rs +++ b/kernel/src/objects/tcb.rs @@ -24,6 +24,8 @@ pub enum ThreadState { Idle, } +pub const SCHED_QUEUE_LINK_ID: usize = 1; + #[repr(C)] pub struct TcbObject { pub trapframe: TrapContext, // must be the first field @@ -38,10 +40,11 @@ pub struct TcbObject { state: ThreadState, time_tick: usize, tid: usize, - pub link: Link, + + pub sched_queue: Link, } -LinkHelperImpl!(TcbObject:link); +LinkHelperImpl!(TcbObject { sched_queue } => SCHED_QUEUE_LINK_ID); const_assert_eq!(ObjectType::TCB.size(0), ObjectType::TCB.size(0x42)); const_assert!(core::mem::size_of::() <= ObjectType::TCB.size(0)); @@ -59,7 +62,7 @@ impl TcbObject { state: ThreadState::Inactive, time_tick: 0, tid: TID_ALLOCATOR.fetch_add(1, Ordering::SeqCst), - link: Link::default(), + sched_queue: Link::default(), } } diff --git a/kernel/src/scheduler.rs b/kernel/src/scheduler.rs index 18a4ecf..314e131 100644 --- a/kernel/src/scheduler.rs +++ b/kernel/src/scheduler.rs @@ -2,6 +2,7 @@ use crate::objects::*; use core::sync::atomic::AtomicPtr; use log::{error, trace}; use spin::lazy::Lazy; +use tcb::SCHED_QUEUE_LINK_ID; use utils::{container_of_mut, linked_list::Link}; #[thread_local] @@ -17,7 +18,7 @@ pub static SCHEDULER: Scheduler = Scheduler::new(); // TODO: add a shared buffer to transfer TCB between cores pub struct Scheduler { - head: Link, + head: Link, } impl Scheduler { @@ -27,7 +28,7 @@ impl Scheduler { pub fn init(&self) { unsafe { - let head = Some(AtomicPtr::new(container_of_mut!(&self.head, TcbObject, link))); + let head = Some(AtomicPtr::new(container_of_mut!(&self.head, TcbObject, sched_queue))); self.head.set_next(&head); self.head.set_prev(&head); } @@ -48,7 +49,7 @@ impl Scheduler { // put to the end of the queue if next.timetick() == 0 || !next.schedulable() { - next.link.detach(); + next.sched_queue.detach(); self.head.prepend(next); } } diff --git a/lib/utils/src/linked_list.rs b/lib/utils/src/linked_list.rs index 0dc4d0d..c637d4c 100644 --- a/lib/utils/src/linked_list.rs +++ b/lib/utils/src/linked_list.rs @@ -13,35 +13,39 @@ macro_rules! as_mut_ptr { #[macro_export] macro_rules! LinkHelperImpl { - ($type:ty : $field:ident) => { - impl LinkHelper for $type { + ($type:ty { $field:ident } => $id:expr) => { + impl LinkHelper<$id> for $type { const LINK_OFFSET: usize = core::mem::offset_of!($type, $field) as usize; } }; } -pub trait LinkHelper: Sized { +pub trait LinkHelper: Sized { const LINK_OFFSET: usize; /// # Safety /// LINK_OFFSET must be a valid field offset of Self - unsafe fn get_link(&self) -> &Link { - &*(to_field_offset!(self, Link, Self::LINK_OFFSET)) + unsafe fn get_link(&self) -> &Link { + &*(to_field_offset!(self, Link, Self::LINK_OFFSET)) } } -pub struct Link { +unsafe fn get_link, const ID: usize>(node: &T) -> &Link { + >::get_link(node) +} + +pub struct Link, const ID: usize> { pub prev: Option>, pub next: Option>, } -impl Default for Link { +impl, const ID: usize> Default for Link { fn default() -> Self { Self::new() } } -impl Clone for Link { +impl, const ID: usize> Clone for Link { fn clone(&self) -> Self { Self { prev: copy_ptr(&self.prev), @@ -50,7 +54,7 @@ impl Clone for Link { } } -impl Link { +impl, const ID: usize> Link { pub const fn new() -> Self { Self { prev: None, next: None } } @@ -104,12 +108,12 @@ impl Link { pub fn prepend(&self, new: &T) { unsafe { // setup new's link - new.get_link().set_prev(self.prev_raw()); - new.get_link().set_next(&Some(AtomicPtr::new(as_mut_ptr!(self.object())))); + get_link(new).set_prev(self.prev_raw()); + get_link(new).set_next(&Some(AtomicPtr::new(as_mut_ptr!(self.object())))); // setup prev's link if let Some(prev) = self.prev_raw() { - load_ptr(prev).get_link().set_next(&Some(AtomicPtr::new(as_mut_ptr!(new)))); + get_link(load_ptr(prev)).set_next(&Some(AtomicPtr::new(as_mut_ptr!(new)))); } // setup self's link @@ -120,12 +124,12 @@ impl Link { pub fn append(&self, new: &T) { unsafe { // setup new's link - new.get_link().set_prev(&Some(AtomicPtr::new(as_mut_ptr!(self.object())))); - new.get_link().set_next(self.next_raw()); + get_link(new).set_prev(&Some(AtomicPtr::new(as_mut_ptr!(self.object())))); + get_link(new).set_next(self.next_raw()); // setup next's link if let Some(next) = self.next_raw() { - load_ptr(next).get_link().set_prev(&Some(AtomicPtr::new(as_mut_ptr!(new)))) + get_link(load_ptr(next)).set_prev(&Some(AtomicPtr::new(as_mut_ptr!(new)))) } // setup self's link @@ -137,12 +141,12 @@ impl Link { unsafe { // setup prev's link if let Some(prev) = self.prev_raw() { - load_ptr(prev).get_link().set_next(self.next_raw()) + get_link(load_ptr(prev)).set_next(self.next_raw()) } // setup next's link if let Some(next) = self.next_raw() { - load_ptr(next).get_link().set_prev(self.prev_raw()) + get_link(load_ptr(next)).set_prev(self.prev_raw()) } // setup self's link @@ -167,94 +171,191 @@ mod tests { use super::*; struct Node { - link: Link, + link1: Link, + link2: Link, value: i32, } - LinkHelperImpl!(Node: link); + LinkHelperImpl!(Node { link1 } => 1); + LinkHelperImpl!(Node { link2 } => 2); #[test] fn test_linked_list() { - let node1 = Node { - link: Link::default(), + let n1 = Node { + link1: Link::default(), + link2: Link::default(), value: 1, }; - let node2 = Node { - link: Link::default(), + let n2 = Node { + link1: Link::default(), + link2: Link::default(), value: 2, }; - let node3 = Node { - link: Link::default(), + let n3 = Node { + link1: Link::default(), + link2: Link::default(), value: 3, }; - node1.link.append(&node2); - node2.link.append(&node3); + // link1: node1 <-> node2 <-> node3 + n1.link1.append(&n2); + n2.link1.append(&n3); + // link2: node1 <-> node3 <-> node2 + n1.link2.append(&n3); + n3.link2.append(&n2); + + // link1: check object unsafe { - // check object - assert_eq!(as_mut_ptr!(node1.link.object() => Node), as_mut_ptr!(&node1 => Node)); - assert_eq!(node1.link.object().value, 1); - assert_eq!(as_mut_ptr!(node2.link.object() => Node), as_mut_ptr!(&node2 => Node)); - assert_eq!(node2.link.object().value, 2); - assert_eq!(as_mut_ptr!(node3.link.object() => Node), as_mut_ptr!(&node3 => Node)); - assert_eq!(node3.link.object().value, 3); + assert_eq!(as_mut_ptr!(n1.link1.object() => Node), as_mut_ptr!(&n1 => Node)); + assert_eq!(n1.link1.object().value, 1); + assert_eq!(as_mut_ptr!(n2.link1.object() => Node), as_mut_ptr!(&n2 => Node)); + assert_eq!(n2.link1.object().value, 2); + assert_eq!(as_mut_ptr!(n3.link1.object() => Node), as_mut_ptr!(&n3 => Node)); + assert_eq!(n3.link1.object().value, 3); } + // link2: check object unsafe { - // check get_link - assert_eq!(as_mut_ptr!(node1.get_link() => Link), as_mut_ptr!(&node1.link)); - assert_eq!(as_mut_ptr!(node2.get_link() => Link), as_mut_ptr!(&node2.link)); - assert_eq!(as_mut_ptr!(node3.get_link() => Link), as_mut_ptr!(&node3.link)); + assert_eq!(as_mut_ptr!(n1.link2.object() => Node), as_mut_ptr!(&n1 => Node)); + assert_eq!(n1.link2.object().value, 1); + assert_eq!(as_mut_ptr!(n2.link2.object() => Node), as_mut_ptr!(&n2 => Node)); + assert_eq!(n2.link2.object().value, 2); + assert_eq!(as_mut_ptr!(n3.link2.object() => Node), as_mut_ptr!(&n3 => Node)); + assert_eq!(n3.link2.object().value, 3); } - { - // check next link - assert!(node1.link.next_raw().is_some()); - assert_eq!( - node1.link.next_raw().as_ref().unwrap().load(Ordering::Acquire), - as_mut_ptr!(&node2) - ); - assert!(node2.link.next_raw().is_some()); - assert_eq!( - node2.link.next_raw().as_ref().unwrap().load(Ordering::Acquire), - as_mut_ptr!(&node3) - ); - assert!(node3.link.next_raw().is_none()); + // link1: check get_link + unsafe { + assert_eq!(as_mut_ptr!(get_link::<_, 1>(&n1) => Link), as_mut_ptr!(&n1.link1)); + assert_eq!(as_mut_ptr!(get_link::<_, 1>(&n2) => Link), as_mut_ptr!(&n2.link1)); + assert_eq!(as_mut_ptr!(get_link::<_, 1>(&n3) => Link), as_mut_ptr!(&n3.link1)); } + // link2: check get_link + unsafe { + assert_eq!(as_mut_ptr!(get_link::<_, 2>(&n1) => Link), as_mut_ptr!(&n1.link2)); + assert_eq!(as_mut_ptr!(get_link::<_, 2>(&n2) => Link), as_mut_ptr!(&n2.link2)); + assert_eq!(as_mut_ptr!(get_link::<_, 2>(&n3) => Link), as_mut_ptr!(&n3.link2)); + } + + // link1: check next link { - // check prev link - assert!(node1.link.prev_raw().is_none()); - assert!(node2.link.prev_raw().is_some()); + // node1 -> node2 + assert!(n1.link1.next_raw().is_some()); assert_eq!( - node2.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire), - as_mut_ptr!(&node1) + n1.link1.next_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n2) ); - assert!(node3.link.prev_raw().is_some()); + + // node2 -> node3 + assert!(n2.link1.next_raw().is_some()); assert_eq!( - node3.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire), - as_mut_ptr!(&node2) + n2.link1.next_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n3) + ); + + // node3 -> None + assert!(n3.link1.next_raw().is_none()); + } + + // link2: check next link + { + // node1 -> node3 + assert!(n1.link2.next_raw().is_some()); + assert_eq!( + n1.link2.next_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n3) + ); + + // node3 -> node2 + assert!(n3.link2.next_raw().is_some()); + assert_eq!( + n3.link2.next_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n2) + ); + + // node2 -> None + assert!(n2.link2.next_raw().is_none()); + } + + // link1: check prev link + { + // none <- node1 + assert!(n1.link1.prev_raw().is_none()); + + // node1 <- node2 + assert!(n2.link1.prev_raw().is_some()); + assert_eq!( + n2.link1.prev_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n1) + ); + + // node2 <- node3 + assert!(n3.link1.prev_raw().is_some()); + assert_eq!( + n3.link1.prev_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n2) ); } + // link2: check prev link { - // check detach - node2.link.detach(); + // none <- node1 + assert!(n1.link2.prev_raw().is_none()); - assert!(node2.link.next_raw().is_none()); - assert!(node2.link.prev_raw().is_none()); - - assert!(node1.link.next_raw().is_some()); + // node1 <- node3 + assert!(n3.link2.prev_raw().is_some()); assert_eq!( - node1.link.next_raw().as_ref().unwrap().load(Ordering::Acquire), - as_mut_ptr!(&node3) + n3.link2.prev_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n1) ); - assert!(node3.link.prev_raw().is_some()); + // node3 <- node2 + assert!(n2.link2.prev_raw().is_some()); assert_eq!( - node3.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire), - as_mut_ptr!(&node1) + n2.link2.prev_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n3) + ); + } + + // link1: check detach + { + n2.link1.detach(); + + assert!(n2.link1.next_raw().is_none()); + assert!(n2.link1.prev_raw().is_none()); + + assert!(n1.link1.next_raw().is_some()); + assert_eq!( + n1.link1.next_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n3) + ); + + assert!(n3.link1.prev_raw().is_some()); + assert_eq!( + n3.link1.prev_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n1) + ); + } + + // link2: check detach + { + n3.link2.detach(); + + assert!(n3.link2.next_raw().is_none()); + assert!(n3.link2.prev_raw().is_none()); + + assert!(n1.link2.next_raw().is_some()); + assert_eq!( + n1.link2.next_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n2) + ); + + assert!(n2.link2.prev_raw().is_some()); + assert_eq!( + n2.link2.prev_raw().as_ref().unwrap().load(Ordering::Acquire), + as_mut_ptr!(&n1) ); } }