feat: lib/utils/linked_list: drop cell

This commit is contained in:
Paul Pan 2024-08-22 16:26:25 +08:00
parent 5a3f220a3e
commit a3b70e1c49
3 changed files with 89 additions and 68 deletions

View File

@ -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)
}
}

View File

@ -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) {

View File

@ -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)
);
}
}
}