mirror of
https://github.com/panpaul/tiny_os
synced 2024-09-20 09:45:19 +08:00
feat: lib/utils/linked_list: drop cell
This commit is contained in:
parent
5a3f220a3e
commit
a3b70e1c49
@ -14,7 +14,7 @@
|
||||
|
||||
*/
|
||||
|
||||
use core::{marker::PhantomData, ptr::NonNull};
|
||||
use core::marker::PhantomData;
|
||||
use uapi::{
|
||||
cap::ObjectType,
|
||||
error::{SysError, SysResult},
|
||||
@ -61,22 +61,7 @@ impl<'a, T: KernelObject + ?Sized> TryFrom<&'a CapEntry> for Cap<'a, T> {
|
||||
|
||||
impl<'a, T: KernelObject + ?Sized> Cap<'a, T> {
|
||||
pub fn append(&mut self, new: &mut CapEntry) {
|
||||
let next = self.cte.link.next_raw();
|
||||
|
||||
// update new cap's link
|
||||
new.link.set_prev(Some(NonNull::from(self.cte)));
|
||||
new.link.set_next(next);
|
||||
|
||||
// record new cap's addr
|
||||
let new_addr = Some(NonNull::from(new));
|
||||
|
||||
// update next cap's link.prev
|
||||
if let Some(mut next) = next {
|
||||
unsafe { next.as_mut().link.set_prev(new_addr) };
|
||||
}
|
||||
|
||||
// update self's link.next
|
||||
self.cte.link.next.set(new_addr);
|
||||
self.cte.link.append(new)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
use crate::objects::*;
|
||||
use core::ptr::NonNull;
|
||||
use core::sync::atomic::AtomicPtr;
|
||||
use log::{error, trace};
|
||||
use spin::lazy::Lazy;
|
||||
use utils::{container_of, linked_list::Link};
|
||||
use utils::{container_of_mut, linked_list::Link};
|
||||
|
||||
#[thread_local]
|
||||
pub static IDLE_THREAD: Lazy<TcbObject> = Lazy::new(|| {
|
||||
@ -26,9 +26,11 @@ impl Scheduler {
|
||||
}
|
||||
|
||||
pub fn init(&self) {
|
||||
let head = unsafe { Some(NonNull::from(&*container_of!(&self.head, TcbObject, link))) };
|
||||
self.head.set_next(head);
|
||||
self.head.set_prev(head);
|
||||
unsafe {
|
||||
let head = Some(AtomicPtr::new(container_of_mut!(&self.head, TcbObject, link)));
|
||||
self.head.set_next(&head);
|
||||
self.head.set_prev(&head);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add(&self, tcb: &TcbObject) {
|
||||
|
@ -1,5 +1,15 @@
|
||||
use crate::{container_of_offset, to_field_offset};
|
||||
use core::{cell::Cell, ptr::NonNull};
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! as_mut_ptr {
|
||||
($ref:expr => $type:ty) => {
|
||||
$ref as *const _ as *mut $type
|
||||
};
|
||||
($ref:expr) => {
|
||||
$ref as *const _ as *mut _
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! LinkHelperImpl {
|
||||
@ -21,8 +31,8 @@ pub trait LinkHelper: Sized {
|
||||
}
|
||||
|
||||
pub struct Link<T: LinkHelper> {
|
||||
pub prev: Cell<Option<NonNull<T>>>,
|
||||
pub next: Cell<Option<NonNull<T>>>,
|
||||
pub prev: Option<AtomicPtr<T>>,
|
||||
pub next: Option<AtomicPtr<T>>,
|
||||
}
|
||||
|
||||
impl<T: LinkHelper> Default for Link<T> {
|
||||
@ -34,18 +44,15 @@ impl<T: LinkHelper> Default for Link<T> {
|
||||
impl<T: LinkHelper> Clone for Link<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
prev: Cell::new(self.prev.get()),
|
||||
next: Cell::new(self.next.get()),
|
||||
prev: copy_ptr(&self.prev),
|
||||
next: copy_ptr(&self.next),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: LinkHelper> Link<T> {
|
||||
pub const fn new() -> Self {
|
||||
Self {
|
||||
prev: Cell::new(None),
|
||||
next: Cell::new(None),
|
||||
}
|
||||
Self { prev: None, next: None }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
@ -54,67 +61,75 @@ impl<T: LinkHelper> Link<T> {
|
||||
&*(container_of_offset!(self, T, T::LINK_OFFSET))
|
||||
}
|
||||
|
||||
pub fn prev_raw(&self) -> Option<NonNull<T>> {
|
||||
self.prev.get()
|
||||
pub fn prev_raw(&self) -> &Option<AtomicPtr<T>> {
|
||||
&self.prev
|
||||
}
|
||||
|
||||
pub fn next_raw(&self) -> Option<NonNull<T>> {
|
||||
self.next.get()
|
||||
pub fn next_raw(&self) -> &Option<AtomicPtr<T>> {
|
||||
&self.next
|
||||
}
|
||||
|
||||
pub fn prev(&self) -> Option<&T> {
|
||||
self.prev_raw().map(|p| unsafe { &*p.as_ptr() })
|
||||
self.prev_raw().as_ref().map(|p| unsafe { &*p.load(Ordering::Acquire) })
|
||||
}
|
||||
|
||||
pub fn prev_mut(&self) -> Option<&mut T> {
|
||||
self.prev_raw().map(|p| unsafe { &mut *p.as_ptr() })
|
||||
self.prev_raw().as_ref().map(|p| unsafe { &mut *p.load(Ordering::Acquire) })
|
||||
}
|
||||
|
||||
pub fn next(&self) -> Option<&T> {
|
||||
self.next_raw().map(|n| unsafe { &*n.as_ptr() })
|
||||
self.next_raw().as_ref().map(|n| unsafe { &*n.load(Ordering::Acquire) })
|
||||
}
|
||||
|
||||
pub fn next_mut(&self) -> Option<&mut T> {
|
||||
self.next_raw().map(|n| unsafe { &mut *n.as_ptr() })
|
||||
self.next_raw().as_ref().map(|n| unsafe { &mut *n.load(Ordering::Acquire) })
|
||||
}
|
||||
|
||||
pub fn set_prev(&self, prev: Option<NonNull<T>>) {
|
||||
self.prev.set(prev);
|
||||
/// # Safety
|
||||
/// Take care of race condition
|
||||
pub unsafe fn set_prev(&self, prev: &Option<AtomicPtr<T>>) {
|
||||
#[allow(invalid_reference_casting)]
|
||||
let link = &mut *(self as *const _ as *mut Self);
|
||||
link.prev = copy_ptr(prev);
|
||||
}
|
||||
|
||||
pub fn set_next(&self, next: Option<NonNull<T>>) {
|
||||
self.next.set(next);
|
||||
/// # Safety
|
||||
/// Take care of race condition
|
||||
pub unsafe fn set_next(&self, next: &Option<AtomicPtr<T>>) {
|
||||
#[allow(invalid_reference_casting)]
|
||||
let link = &mut *(self as *const _ as *mut Self);
|
||||
link.next = copy_ptr(next);
|
||||
}
|
||||
|
||||
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(NonNull::from(self.object())));
|
||||
new.get_link().set_next(&Some(AtomicPtr::new(as_mut_ptr!(self.object()))));
|
||||
|
||||
// setup prev's link
|
||||
if let Some(prev) = self.prev_raw() {
|
||||
prev.as_ref().get_link().set_next(Some(NonNull::from(new)))
|
||||
load_ptr(prev).get_link().set_next(&Some(AtomicPtr::new(as_mut_ptr!(new))));
|
||||
}
|
||||
|
||||
// setup self's link
|
||||
self.set_prev(Some(NonNull::from(new)));
|
||||
self.set_prev(&Some(AtomicPtr::new(as_mut_ptr!(new))));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append(&self, new: &T) {
|
||||
unsafe {
|
||||
// setup new's link
|
||||
new.get_link().set_prev(Some(NonNull::from(self.object())));
|
||||
new.get_link().set_prev(&Some(AtomicPtr::new(as_mut_ptr!(self.object()))));
|
||||
new.get_link().set_next(self.next_raw());
|
||||
|
||||
// setup next's link
|
||||
if let Some(next) = self.next_raw() {
|
||||
next.as_ref().get_link().set_prev(Some(NonNull::from(new)))
|
||||
load_ptr(next).get_link().set_prev(&Some(AtomicPtr::new(as_mut_ptr!(new))))
|
||||
}
|
||||
|
||||
// setup self's link
|
||||
self.set_next(Some(NonNull::from(new)));
|
||||
self.set_next(&Some(AtomicPtr::new(as_mut_ptr!(new))));
|
||||
}
|
||||
}
|
||||
|
||||
@ -122,21 +137,31 @@ impl<T: LinkHelper> Link<T> {
|
||||
unsafe {
|
||||
// setup prev's link
|
||||
if let Some(prev) = self.prev_raw() {
|
||||
prev.as_ref().get_link().set_next(self.next_raw())
|
||||
load_ptr(prev).get_link().set_next(self.next_raw())
|
||||
}
|
||||
|
||||
// setup next's link
|
||||
if let Some(next) = self.next_raw() {
|
||||
next.as_ref().get_link().set_prev(self.prev_raw())
|
||||
load_ptr(next).get_link().set_prev(self.prev_raw())
|
||||
}
|
||||
|
||||
// setup self's link
|
||||
self.set_prev(None);
|
||||
self.set_next(None);
|
||||
self.set_prev(&None);
|
||||
self.set_next(&None);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn copy_ptr<T>(ptr: &Option<AtomicPtr<T>>) -> Option<AtomicPtr<T>> {
|
||||
ptr.as_ref().map(|p| AtomicPtr::new(p.load(Ordering::Acquire)))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn load_ptr<'a, T>(ptr: &AtomicPtr<T>) -> &'a mut T {
|
||||
&mut *ptr.load(Ordering::Acquire)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -148,15 +173,6 @@ mod tests {
|
||||
|
||||
LinkHelperImpl!(Node: link);
|
||||
|
||||
macro_rules! as_mut_ptr {
|
||||
($ref:expr => $type:ty) => {
|
||||
$ref as *const _ as *mut $type
|
||||
};
|
||||
($ref:expr) => {
|
||||
$ref as *const _ as *mut _
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_linked_list() {
|
||||
let node1 = Node {
|
||||
@ -195,9 +211,15 @@ mod tests {
|
||||
{
|
||||
// check next link
|
||||
assert!(node1.link.next_raw().is_some());
|
||||
assert_eq!(node1.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||
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().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||
assert_eq!(
|
||||
node2.link.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node3)
|
||||
);
|
||||
assert!(node3.link.next_raw().is_none());
|
||||
}
|
||||
|
||||
@ -205,9 +227,15 @@ mod tests {
|
||||
// check prev link
|
||||
assert!(node1.link.prev_raw().is_none());
|
||||
assert!(node2.link.prev_raw().is_some());
|
||||
assert_eq!(node2.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||
assert_eq!(
|
||||
node2.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node1)
|
||||
);
|
||||
assert!(node3.link.prev_raw().is_some());
|
||||
assert_eq!(node3.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node2));
|
||||
assert_eq!(
|
||||
node3.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node2)
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
@ -218,10 +246,16 @@ mod tests {
|
||||
assert!(node2.link.prev_raw().is_none());
|
||||
|
||||
assert!(node1.link.next_raw().is_some());
|
||||
assert_eq!(node1.link.next_raw().unwrap().as_ptr(), as_mut_ptr!(&node3));
|
||||
assert_eq!(
|
||||
node1.link.next_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node3)
|
||||
);
|
||||
|
||||
assert!(node3.link.prev_raw().is_some());
|
||||
assert_eq!(node3.link.prev_raw().unwrap().as_ptr(), as_mut_ptr!(&node1));
|
||||
assert_eq!(
|
||||
node3.link.prev_raw().as_ref().unwrap().load(Ordering::Acquire),
|
||||
as_mut_ptr!(&node1)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user