浏览代码

Get rid of recursed Arcs in the kernel

徐启航 2 年之前
父节点
当前提交
40cb39f6b1

+ 5 - 5
h2o/kernel/src/cpu/intr/imp.rs

@@ -68,7 +68,7 @@ impl Interrupt {
     }
 }
 
-unsafe impl DefaultFeature for Arc<Interrupt> {
+unsafe impl DefaultFeature for Interrupt {
     fn default_features() -> Feature {
         Feature::SEND | Feature::WAIT
     }
@@ -111,7 +111,7 @@ mod syscall {
 
         let intr = SCHED.with_current(|cur| {
             let handles = cur.space().handles();
-            let res = handles.get::<Arc<Resource<u32>>>(res)?;
+            let res = handles.get::<Resource<u32>>(res)?;
             Interrupt::new(&res, gsi, level_triggered)
         })?;
 
@@ -123,7 +123,7 @@ mod syscall {
         MANAGER.mask(gsi, false)?;
 
         let event = Arc::downgrade(&intr) as _;
-        SCHED.with_current(|cur| unsafe { cur.space().handles().insert(intr, Some(event)) })
+        SCHED.with_current(|cur| unsafe { cur.space().handles().insert_raw(intr, Some(event)) })
     }
 
     #[syscall]
@@ -135,7 +135,7 @@ mod syscall {
         let intr = unsafe { (*SCHED.current()).as_ref().ok_or(ESRCH)? }
             .space()
             .handles()
-            .get::<Arc<Interrupt>>(hdl)?;
+            .get::<Interrupt>(hdl)?;
         if !intr.features().contains(Feature::WAIT) {
             return Err(EPERM);
         }
@@ -154,7 +154,7 @@ mod syscall {
     fn intr_drop(hdl: Handle) -> Result {
         hdl.check_null()?;
         SCHED.with_current(|cur| {
-            let intr = cur.space().handles().remove::<Arc<Interrupt>>(hdl)?;
+            let intr = cur.space().handles().remove::<Interrupt>(hdl)?;
             intr.cancel();
             MANAGER.register(intr.gsi, None)?;
             Ok(())

+ 2 - 2
h2o/kernel/src/dev.rs

@@ -48,7 +48,7 @@ mod syscall {
     #[syscall]
     fn pio_acq(res: Handle, base: u16, size: u16) -> Result {
         SCHED.with_current(|cur| {
-            let res = cur.space().handles().get::<Arc<Resource<u16>>>(res)?;
+            let res = cur.space().handles().get::<Resource<u16>>(res)?;
             if !{ res.features() }.contains(Feature::READ | Feature::WRITE) {
                 return Err(EPERM);
             }
@@ -71,7 +71,7 @@ mod syscall {
     #[syscall]
     fn pio_rel(res: Handle, base: u16, size: u16) -> Result {
         SCHED.with_current(|cur| {
-            let res = cur.space().handles().get::<Arc<Resource<u16>>>(res)?;
+            let res = cur.space().handles().get::<Resource<u16>>(res)?;
             if res.magic_eq(pio_resource())
                 && res.range().start <= base
                 && base + size <= res.range().end

+ 3 - 4
h2o/kernel/src/dev/res.rs

@@ -71,14 +71,13 @@ impl<T: Ord + Copy> Drop for Resource<T> {
     }
 }
 
-unsafe impl<T: Ord + Copy + Send + Sync + Any> DefaultFeature for Arc<Resource<T>> {
+unsafe impl<T: Ord + Copy + Send + Sync + Any> DefaultFeature for Resource<T> {
     fn default_features() -> Feature {
         Feature::SEND | Feature::SYNC | Feature::READ | Feature::WRITE
     }
 }
 
 mod syscall {
-    use alloc::sync::Arc;
     use core::{any::Any, ops::Add};
 
     use sv_call::*;
@@ -91,12 +90,12 @@ mod syscall {
         size: T,
     ) -> Result<Handle> {
         SCHED.with_current(|cur| {
-            let res = cur.space().handles().get::<Arc<Resource<T>>>(hdl)?;
+            let res = cur.space().handles().get::<Resource<T>>(hdl)?;
             if !res.features().contains(Feature::SYNC) {
                 return Err(EPERM);
             }
             let sub = res.allocate(base..(base + size)).ok_or(ENOMEM)?;
-            cur.space().handles().insert(sub, None)
+            cur.space().handles().insert_raw(sub, None)
         })
     }
 

+ 2 - 2
h2o/kernel/src/mem/syscall.rs

@@ -140,7 +140,7 @@ fn space_new(root_virt: UserPtr<Out, Handle>) -> Result<Handle> {
     SCHED.with_current(|cur| {
         let space = TaskSpace::new(cur.tid().ty())?;
         let virt = Arc::downgrade(space.mem().root());
-        let ret = cur.space().handles().insert(space, None)?;
+        let ret = cur.space().handles().insert_raw(space, None)?;
         unsafe {
             let virt = cur.space().handles().insert_unchecked(
                 virt,
@@ -259,7 +259,7 @@ fn phys_acq(res: Handle, addr: usize, size: usize) -> Result<Handle> {
     }
 
     SCHED.with_current(|cur| {
-        let res = cur.space().handles().get::<Arc<Resource<usize>>>(res)?;
+        let res = cur.space().handles().get::<Resource<usize>>(res)?;
         if res.magic_eq(super::mem_resource())
             && res.range().start <= addr
             && addr + size <= res.range().end

+ 1 - 1
h2o/kernel/src/sched/imp/waiter.rs

@@ -77,7 +77,7 @@ impl Waiter for Blocker {
     }
 }
 
-unsafe impl DefaultFeature for Arc<Blocker> {
+unsafe impl DefaultFeature for Blocker {
     fn default_features() -> sv_call::Feature {
         Feature::SEND | Feature::WAIT
     }

+ 3 - 3
h2o/kernel/src/sched/ipc.rs

@@ -195,7 +195,7 @@ mod syscall {
             let event = obj.event().upgrade().ok_or(EPIPE)?;
 
             let blocker = Blocker::new(&event, wake_all, signal);
-            cur.space().handles().insert(blocker, None)
+            cur.space().handles().insert_raw(blocker, None)
         })
     }
 
@@ -204,11 +204,11 @@ mod syscall {
         let pree = PREEMPT.lock();
         let cur = unsafe { (*SCHED.current()).as_ref().ok_or(ESRCH) }?;
 
-        let blocker = cur.space().handles().get::<Arc<Blocker>>(waiter)?;
+        let blocker = cur.space().handles().get::<Blocker>(waiter)?;
         blocker.wait(pree, time::from_us(timeout_us))?;
 
         let (detach_ret, signal) = Arc::clone(&blocker).detach();
-        SCHED.with_current(|cur| cur.space().handles().remove::<Arc<Blocker>>(waiter))?;
+        SCHED.with_current(|cur| cur.space().handles().remove::<Blocker>(waiter))?;
 
         if !detach_ret {
             Err(ETIME)

+ 5 - 1
h2o/kernel/src/sched/ipc/channel.rs

@@ -269,7 +269,11 @@ unsafe impl DefaultFeature for Channel {
 impl Drop for Channel {
     fn drop(&mut self) {
         if let Some(peer) = self.peer.upgrade() {
-            peer.event.notify(0, usize::MAX);
+            peer.event.cancel();
+            let _pree = PREEMPT.lock();
+            for (_, caller) in peer.callers.lock().iter() {
+                caller.event.cancel();
+            }
         }
     }
 }

+ 3 - 3
h2o/kernel/src/sched/task.rs

@@ -66,7 +66,7 @@ fn exec_inner(
     name: Option<String>,
     ty: Option<Type>,
     affinity: Option<CpuMask>,
-    space: Arsc<Space>,
+    space: Arc<Space>,
     init_chan: sv_call::Handle,
     s: &Starter,
 ) -> sv_call::Result<Init> {
@@ -98,7 +98,7 @@ fn exec_inner(
 #[inline]
 fn exec(
     name: Option<String>,
-    space: Arsc<Space>,
+    space: Arc<Space>,
     init_chan: sv_call::Handle,
     starter: &Starter,
 ) -> sv_call::Result<(Init, sv_call::Handle)> {
@@ -114,7 +114,7 @@ fn exec(
     })
 }
 
-fn create(name: Option<String>, space: Arsc<Space>) -> sv_call::Result<(Init, sv_call::Handle)> {
+fn create(name: Option<String>, space: Arc<Space>) -> sv_call::Result<(Init, sv_call::Handle)> {
     let cur = super::SCHED.with_current(|cur| Ok(cur.tid.clone()))?;
 
     let ty = cur.ty();

+ 1 - 1
h2o/kernel/src/sched/task/elf.rs

@@ -125,7 +125,7 @@ fn load_elf(space: &Arc<Space>, file: &Elf, image: &[u8]) -> sv_call::Result<(LA
 
 pub fn from_elf(
     image: &[u8],
-    space: Arsc<super::Space>,
+    space: Arc<super::Space>,
     name: String,
     affinity: CpuMask,
     init_chan: hdl::Ref,

+ 25 - 4
h2o/kernel/src/sched/task/hdl.rs

@@ -1,6 +1,6 @@
 mod node;
 
-use alloc::sync::Weak;
+use alloc::sync::{Weak, Arc};
 use core::{any::Any, pin::Pin, ptr::NonNull};
 
 use archop::Azy;
@@ -17,10 +17,22 @@ struct Value {
     index: B18,
 }
 
-pub unsafe trait DefaultFeature: Any + Send {
+pub unsafe trait DefaultFeature: Any + Send + Sync {
     fn default_features() -> Feature;
 }
 
+unsafe impl<T: DefaultFeature + ?Sized> DefaultFeature for crate::sched::Arsc<T> {
+    fn default_features() -> Feature {
+        T::default_features()
+    }
+}
+
+unsafe impl<T: DefaultFeature + ?Sized> DefaultFeature for alloc::sync::Arc<T> {
+    fn default_features() -> Feature {
+        T::default_features()
+    }
+}
+
 #[derive(Debug)]
 pub struct HandleMap {
     list: Mutex<node::List>,
@@ -88,11 +100,20 @@ impl HandleMap {
         self.encode(link)
     }
 
+    #[inline]
+    pub fn insert_raw<T: DefaultFeature>(
+        &self,
+        obj: Arc<T>,
+        event: Option<Weak<dyn Event>>,
+    ) -> Result<sv_call::Handle> {
+        self.insert_ref(Ref::from_raw(obj, event)?)
+    }
+
     /// # Safety
     ///
     /// The caller must ensure that `T` is [`Send`] if `send` and [`Sync`] if
     /// `sync`.
-    pub unsafe fn insert_unchecked<T: 'static>(
+    pub unsafe fn insert_unchecked<T: Send + Sync + 'static>(
         &self,
         data: T,
         feat: Feature,
@@ -118,7 +139,7 @@ impl HandleMap {
         PREEMPT.scope(|| self.list.lock().remove(link))
     }
 
-    pub fn remove<T: Send + Any>(&self, handle: sv_call::Handle) -> Result<Ref<T>> {
+    pub fn remove<T: Send + Sync + Any>(&self, handle: sv_call::Handle) -> Result<Ref<T>> {
         self.decode(handle).and_then(|value| {
             // SAFETY: Dereference within the available range.
             let ptr = unsafe { value.as_ref() };

+ 35 - 10
h2o/kernel/src/sched/task/hdl/node.rs

@@ -1,4 +1,4 @@
-use alloc::sync::Weak;
+use alloc::sync::{Weak, Arc};
 use core::{
     any::Any,
     fmt,
@@ -15,7 +15,7 @@ use sv_call::{Feature, Result};
 use super::DefaultFeature;
 use crate::{
     mem::Arena,
-    sched::{Arsc, Event, PREEMPT},
+    sched::{Event, PREEMPT},
 };
 
 pub const MAX_HANDLE_COUNT: usize = 1 << 16;
@@ -23,13 +23,13 @@ pub const MAX_HANDLE_COUNT: usize = 1 << 16;
 pub(super) static HR_ARENA: Azy<Arena<Ref>> = Azy::new(|| Arena::new(MAX_HANDLE_COUNT));
 
 #[derive(Debug)]
-pub struct Ref<T: ?Sized = dyn Any> {
+pub struct Ref<T: ?Sized = dyn Any + Send + Sync> {
     _marker: PhantomPinned,
     next: Option<Ptr>,
     prev: Option<Ptr>,
     event: Weak<dyn Event>,
     feat: Feature,
-    obj: Arsc<T>,
+    obj: Arc<T>,
 }
 pub type Ptr = NonNull<Ref>;
 
@@ -50,6 +50,18 @@ impl<T: ?Sized> Ref<T> {
     where
         T: Sized,
     {
+        Self::from_raw_unchecked(Arc::try_new(data)?, feat, event)
+    }
+
+    /// # Safety
+    ///
+    /// The caller must ensure that `T` is [`Send`] if `send` and [`Sync`] if
+    /// `sync`.
+    pub unsafe fn from_raw_unchecked(
+        obj: Arc<T>,
+        feat: Feature,
+        event: Option<Weak<dyn Event>>,
+    ) -> sv_call::Result<Self> {
         let event = event.unwrap_or(Weak::<crate::sched::BasicEvent>::new() as _);
         if event.strong_count() == 0 && feat.contains(Feature::WAIT) {
             return Err(sv_call::EPERM);
@@ -60,7 +72,7 @@ impl<T: ?Sized> Ref<T> {
             prev: None,
             event,
             feat,
-            obj: Arsc::try_new(data)?,
+            obj,
         })
     }
 
@@ -72,11 +84,24 @@ impl<T: ?Sized> Ref<T> {
         unsafe { Self::try_new_unchecked(data, T::default_features(), event) }
     }
 
+    #[inline]
+    pub fn from_raw(obj: Arc<T>, event: Option<Weak<dyn Event>>) -> sv_call::Result<Self>
+    where
+        T: DefaultFeature,
+    {
+        unsafe { Self::from_raw_unchecked(obj, T::default_features(), event) }
+    }
+
+    #[inline]
+    pub fn into_raw(this: Self) -> Arc<T> {
+        this.obj
+    }
+
     /// # Safety
     ///
     /// The caller must ensure that `self` is owned by the current task if its
     /// not [`Send`].
-    pub unsafe fn deref_unchecked(&self) -> &T {
+    pub unsafe fn deref_unchecked(&self) -> &Arc<T> {
         &self.obj
     }
 
@@ -100,8 +125,8 @@ impl<T: ?Sized> Ref<T> {
     }
 }
 
-impl<T: ?Sized + Send> Deref for Ref<T> {
-    type Target = T;
+impl<T: ?Sized + Send + Sync> Deref for Ref<T> {
+    type Target = Arc<T>;
 
     #[inline]
     fn deref(&self) -> &Self::Target {
@@ -124,7 +149,7 @@ impl Ref {
         }
     }
 
-    pub fn downcast<T: Any>(self) -> core::result::Result<Ref<T>, Self> {
+    pub fn downcast<T: Any + Send + Sync>(self) -> core::result::Result<Ref<T>, Self> {
         match self.obj.downcast() {
             Ok(obj) => Ok(Ref {
                 _marker: PhantomPinned,
@@ -158,7 +183,7 @@ impl Ref {
             prev: None,
             event: Weak::clone(&self.event),
             feat: self.feat,
-            obj: Arsc::clone(&self.obj),
+            obj: Arc::clone(&self.obj),
         }
     }
 

+ 1 - 1
h2o/kernel/src/sched/task/idle.rs

@@ -28,7 +28,7 @@ pub(super) static IDLE: Lazy<Tid> = Lazy::new(|| {
         .build()
         .unwrap();
 
-    let space = super::Space::new_current().expect("Failed to create space");
+    let space = super::Space::new_current();
     let stack = space::init_stack(space.mem(), DEFAULT_STACK_SIZE)
         .expect("Failed to initialize stack for IDLE");
 

+ 4 - 4
h2o/kernel/src/sched/task/sm.rs

@@ -91,7 +91,7 @@ impl TaskInfo {
 pub struct Context {
     pub(in crate::sched) tid: Tid,
 
-    pub(in crate::sched) space: Arsc<Space>,
+    pub(in crate::sched) space: Arc<Space>,
     pub(in crate::sched) kstack: ctx::Kstack,
     pub(in crate::sched) ext_frame: ctx::ExtFrame,
     pub(in crate::sched) io_bitmap: Option<BitVec>,
@@ -107,7 +107,7 @@ impl Context {
     }
 
     #[inline]
-    pub fn space(&self) -> &Arsc<Space> {
+    pub fn space(&self) -> &Arc<Space> {
         &self.space
     }
 
@@ -212,7 +212,7 @@ impl IntoReady for Init {
 impl Init {
     pub fn new(
         tid: Tid,
-        space: Arsc<Space>,
+        space: Arc<Space>,
         kstack: ctx::Kstack,
         ext_frame: ctx::ExtFrame,
     ) -> Self {
@@ -325,7 +325,7 @@ impl Blocked {
     }
 
     #[inline]
-    pub fn space(&self) -> &Arsc<Space> {
+    pub fn space(&self) -> &Arc<Space> {
         &self.ctx.space
     }
 

+ 7 - 12
h2o/kernel/src/sched/task/space.rs

@@ -8,10 +8,7 @@ use super::{
 };
 use crate::{
     mem,
-    sched::{
-        wait::{Futex, FutexKey, FutexRef, Futexes},
-        Arsc,
-    },
+    sched::wait::{Futex, FutexKey, FutexRef, Futexes},
 };
 
 #[derive(Debug)]
@@ -25,23 +22,21 @@ unsafe impl Send for Space {}
 unsafe impl Sync for Space {}
 
 impl Space {
-    pub fn new(ty: super::Type) -> sv_call::Result<Arsc<Self>> {
+    pub fn new(ty: super::Type) -> sv_call::Result<Arc<Self>> {
         let mem = mem::space::Space::try_new(ty)?;
-        Arsc::try_new(Space {
+        Ok(Arc::new(Space {
             mem,
             handles: HandleMap::new(),
             futexes: Futexes::new(Default::default()),
-        })
-        .map_err(sv_call::Error::from)
+        }))
     }
 
-    pub fn new_current() -> sv_call::Result<Arsc<Self>> {
-        Arsc::try_new(Space {
+    pub fn new_current() -> Arc<Self> {
+        Arc::new(Space {
             mem: mem::space::with_current(Arc::clone),
             handles: HandleMap::new(),
             futexes: Futexes::new(Default::default()),
         })
-        .map_err(sv_call::Error::from)
     }
 
     #[inline]
@@ -81,7 +76,7 @@ impl Space {
     }
 }
 
-unsafe impl DefaultFeature for Arsc<Space> {
+unsafe impl DefaultFeature for Space {
     fn default_features() -> Feature {
         Feature::READ | Feature::WRITE
     }

+ 12 - 9
h2o/kernel/src/sched/task/syscall.rs

@@ -5,7 +5,10 @@ use paging::LAddr;
 use spin::Mutex;
 use sv_call::*;
 
-use super::{hdl::DefaultFeature, Blocked, RunningState, Signal, Space, Tid};
+use super::{
+    hdl::{DefaultFeature, Ref},
+    Blocked, RunningState, Signal, Space, Tid,
+};
 use crate::{
     cpu::time::Instant,
     sched::{imp::MIN_TIME_GRAN, Arsc, PREEMPT, SCHED},
@@ -96,10 +99,10 @@ fn task_exec(ci: UserPtr<In, task::ExecInfo>) -> Result<Handle> {
             Some(handles.remove::<crate::sched::ipc::Channel>(ci.init_chan)?)
         };
         if ci.space == Handle::NULL {
-            Ok((init_chan, Arsc::clone(cur.space())))
+            Ok((init_chan, Arc::clone(cur.space())))
         } else {
-            let space = handles.remove::<Arsc<Space>>(ci.space)?;
-            Ok((init_chan, Arsc::clone(&space)))
+            let space = handles.remove::<Space>(ci.space)?;
+            Ok((init_chan, Ref::into_raw(space)))
         }
     })?;
 
@@ -133,18 +136,18 @@ fn task_new(
     let name = get_name(name, name_len)?;
 
     let new_space = if space == Handle::NULL {
-        SCHED.with_current(|cur| Ok(Arsc::clone(cur.space())))?
+        SCHED.with_current(|cur| Ok(Arc::clone(cur.space())))?
     } else {
         SCHED.with_current(|cur| {
             cur.space()
                 .handles()
-                .remove::<Arsc<Space>>(space)
-                .map(|space| Arsc::clone(&space))
+                .remove::<Space>(space)
+                .map(Ref::into_raw)
         })?
     };
     let mut sus_slot = Arsc::try_new_uninit()?;
 
-    let (task, hdl) = super::create(name, Arsc::clone(&new_space))?;
+    let (task, hdl) = super::create(name, Arc::clone(&new_space))?;
 
     let task = super::Ready::block(
         super::IntoReady::into_ready(task, unsafe { crate::cpu::id() }, MIN_TIME_GRAN),
@@ -185,7 +188,7 @@ fn task_join(hdl: Handle, retval: UserPtr<Out, usize>) -> Result {
 fn task_ctl(hdl: Handle, op: u32, data: UserPtr<InOut, Handle>) -> Result {
     hdl.check_null()?;
 
-    let cur = SCHED.with_current(|cur| Ok(Arsc::clone(cur.space())))?;
+    let cur = SCHED.with_current(|cur| Ok(Arc::clone(cur.space())))?;
 
     match op {
         task::TASK_CTL_KILL => {

+ 22 - 5
h2o/kernel/src/syscall.rs

@@ -2,15 +2,32 @@
 //!
 //! ## Adding a syscall (`fn cast_init(k: *mut K) -> *const L`)
 //!
-//! Just create a private submodule `syscall` in a file and write the processing
-//! code:
+//! 1. Add a new JSON file in the target directory of the kernel source root
+//! with the following content as the prototype, or append it to an existing
+//! file:
+//!
+//! ```json
+//! {
+//!     "name": "sv_cast_init",
+//!     "returns": "*const L",
+//!     "args": [
+//!         {
+//!             "name": "k",
+//!             "ty": "*mut K"
+//!         }
+//!     ]
+//! }
+//! ```
+//!
+//! 2. Create a private submodule `syscall` in a source file and write the
+//! processing code:
 //!
 //! ```rust,no_run
 //! mod syscall {
 //!       use sv_call::*;
 //!       #[syscall]
-//!       fn cast_init(k: *mut K) -> *const L {
-//!             init(k);
+//!       fn cast_init(k: *mut K) -> Result<*const L> {
+//!             // init(k);
 //!             Ok(k.cast())
 //!       }
 //! }
@@ -55,6 +72,6 @@ mod syscall {
 
     #[syscall]
     fn int_get(hdl: Handle) -> Result<u64> {
-        SCHED.with_current(|cur| cur.space().handles().get::<u64>(hdl).map(|obj| **obj))
+        SCHED.with_current(|cur| cur.space().handles().get::<u64>(hdl).map(|obj| ***obj))
     }
 }