mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: linked_list: allow to have multiple links in a same struct
This commit is contained in:
parent
a867e77e3c
commit
c352a0b8c6
@ -42,12 +42,14 @@ impl RawCap {
|
||||
}
|
||||
}
|
||||
|
||||
pub const CAP_ENTRY_LINK_ID: usize = 1;
|
||||
|
||||
pub struct CapEntry {
|
||||
pub cap: RawCap,
|
||||
pub link: Link<Self>,
|
||||
pub link: Link<Self, CAP_ENTRY_LINK_ID>,
|
||||
}
|
||||
|
||||
LinkHelperImpl!(CapEntry: link);
|
||||
LinkHelperImpl!(CapEntry { link } => CAP_ENTRY_LINK_ID);
|
||||
|
||||
impl CapEntry {
|
||||
pub fn new(cap: RawCap) -> Self {
|
||||
|
@ -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<Self>,
|
||||
|
||||
pub sched_queue: Link<Self, SCHED_QUEUE_LINK_ID>,
|
||||
}
|
||||
|
||||
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::<TcbObject>() <= 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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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<TcbObject>,
|
||||
head: Link<TcbObject, SCHED_QUEUE_LINK_ID>,
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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<const ID: usize>: Sized {
|
||||
const LINK_OFFSET: usize;
|
||||
|
||||
/// # Safety
|
||||
/// LINK_OFFSET must be a valid field offset of Self
|
||||
unsafe fn get_link(&self) -> &Link<Self> {
|
||||
&*(to_field_offset!(self, Link<Self>, Self::LINK_OFFSET))
|
||||
unsafe fn get_link(&self) -> &Link<Self, ID> {
|
||||
&*(to_field_offset!(self, Link<Self, ID>, Self::LINK_OFFSET))
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Link<T: LinkHelper> {
|
||||
unsafe fn get_link<T: LinkHelper<ID>, const ID: usize>(node: &T) -> &Link<T, ID> {
|
||||
<T as LinkHelper<ID>>::get_link(node)
|
||||
}
|
||||
|
||||
pub struct Link<T: LinkHelper<ID>, const ID: usize> {
|
||||
pub prev: Option<AtomicPtr<T>>,
|
||||
pub next: Option<AtomicPtr<T>>,
|
||||
}
|
||||
|
||||
impl<T: LinkHelper> Default for Link<T> {
|
||||
impl<T: LinkHelper<ID>, const ID: usize> Default for Link<T, ID> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LinkHelper> Clone for Link<T> {
|
||||
impl<T: LinkHelper<ID>, const ID: usize> Clone for Link<T, ID> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
prev: copy_ptr(&self.prev),
|
||||
@ -50,7 +54,7 @@ impl<T: LinkHelper> Clone for Link<T> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LinkHelper> Link<T> {
|
||||
impl<T: LinkHelper<ID>, const ID: usize> Link<T, ID> {
|
||||
pub const fn new() -> Self {
|
||||
Self { prev: None, next: None }
|
||||
}
|
||||
@ -104,12 +108,12 @@ impl<T: LinkHelper> Link<T> {
|
||||
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<T: LinkHelper> Link<T> {
|
||||
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<T: LinkHelper> Link<T> {
|
||||
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<Node>,
|
||||
link1: Link<Node, 1>,
|
||||
link2: Link<Node, 2>,
|
||||
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<Node>), as_mut_ptr!(&node1.link));
|
||||
assert_eq!(as_mut_ptr!(node2.get_link() => Link<Node>), as_mut_ptr!(&node2.link));
|
||||
assert_eq!(as_mut_ptr!(node3.get_link() => Link<Node>), 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);
|
||||
}
|
||||
|
||||
// link1: check get_link
|
||||
unsafe {
|
||||
assert_eq!(as_mut_ptr!(get_link::<_, 1>(&n1) => Link<Node, 1>), as_mut_ptr!(&n1.link1));
|
||||
assert_eq!(as_mut_ptr!(get_link::<_, 1>(&n2) => Link<Node, 1>), as_mut_ptr!(&n2.link1));
|
||||
assert_eq!(as_mut_ptr!(get_link::<_, 1>(&n3) => Link<Node, 1>), as_mut_ptr!(&n3.link1));
|
||||
}
|
||||
|
||||
// link2: check get_link
|
||||
unsafe {
|
||||
assert_eq!(as_mut_ptr!(get_link::<_, 2>(&n1) => Link<Node, 2>), as_mut_ptr!(&n1.link2));
|
||||
assert_eq!(as_mut_ptr!(get_link::<_, 2>(&n2) => Link<Node, 2>), as_mut_ptr!(&n2.link2));
|
||||
assert_eq!(as_mut_ptr!(get_link::<_, 2>(&n3) => Link<Node, 2>), as_mut_ptr!(&n3.link2));
|
||||
}
|
||||
|
||||
// link1: check next link
|
||||
{
|
||||
// check next link
|
||||
assert!(node1.link.next_raw().is_some());
|
||||
// node1 -> node2
|
||||
assert!(n1.link1.next_raw().is_some());
|
||||
assert_eq!(
|
||||
node1.link.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node2)
|
||||
n1.link1.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&n2)
|
||||
);
|
||||
assert!(node2.link.next_raw().is_some());
|
||||
|
||||
// node2 -> node3
|
||||
assert!(n2.link1.next_raw().is_some());
|
||||
assert_eq!(
|
||||
node2.link.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node3)
|
||||
n2.link1.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&n3)
|
||||
);
|
||||
assert!(node3.link.next_raw().is_none());
|
||||
|
||||
// node3 -> None
|
||||
assert!(n3.link1.next_raw().is_none());
|
||||
}
|
||||
|
||||
// link2: check next link
|
||||
{
|
||||
// check prev link
|
||||
assert!(node1.link.prev_raw().is_none());
|
||||
assert!(node2.link.prev_raw().is_some());
|
||||
// node1 -> node3
|
||||
assert!(n1.link2.next_raw().is_some());
|
||||
assert_eq!(
|
||||
node2.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node1)
|
||||
n1.link2.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&n3)
|
||||
);
|
||||
assert!(node3.link.prev_raw().is_some());
|
||||
|
||||
// node3 -> node2
|
||||
assert!(n3.link2.next_raw().is_some());
|
||||
assert_eq!(
|
||||
node3.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node2)
|
||||
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
|
||||
{
|
||||
// check detach
|
||||
node2.link.detach();
|
||||
// none <- node1
|
||||
assert!(n1.link1.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 <- node2
|
||||
assert!(n2.link1.prev_raw().is_some());
|
||||
assert_eq!(
|
||||
node1.link.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node3)
|
||||
n2.link1.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&n1)
|
||||
);
|
||||
|
||||
assert!(node3.link.prev_raw().is_some());
|
||||
// node2 <- node3
|
||||
assert!(n3.link1.prev_raw().is_some());
|
||||
assert_eq!(
|
||||
node3.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node1)
|
||||
n3.link1.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&n2)
|
||||
);
|
||||
}
|
||||
|
||||
// link2: check prev link
|
||||
{
|
||||
// none <- node1
|
||||
assert!(n1.link2.prev_raw().is_none());
|
||||
|
||||
// node1 <- node3
|
||||
assert!(n3.link2.prev_raw().is_some());
|
||||
assert_eq!(
|
||||
n3.link2.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&n1)
|
||||
);
|
||||
|
||||
// node3 <- node2
|
||||
assert!(n2.link2.prev_raw().is_some());
|
||||
assert_eq!(
|
||||
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)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user