axtask/
task_ext.rs

1//! User-defined task extended data.
2
3use core::alloc::Layout;
4use core::mem::{align_of, size_of};
5
6#[unsafe(no_mangle)]
7#[linkage = "weak"]
8static __AX_TASK_EXT_SIZE: usize = 0;
9
10#[unsafe(no_mangle)]
11#[linkage = "weak"]
12static __AX_TASK_EXT_ALIGN: usize = 0;
13
14#[unsafe(no_mangle)]
15#[linkage = "weak"]
16fn __ax_task_ext_drop(_data: *mut u8) {}
17
18/// A wrapper of pointer to the task extended data.
19pub(crate) struct AxTaskExt {
20    ptr: *mut u8,
21}
22
23impl AxTaskExt {
24    /// Returns the expected size of the task extended structure.
25    pub fn size() -> usize {
26        unsafe extern "C" {
27            static __AX_TASK_EXT_SIZE: usize;
28        }
29        unsafe { __AX_TASK_EXT_SIZE }
30    }
31
32    /// Returns the expected alignment of the task extended structure.
33    pub fn align() -> usize {
34        unsafe extern "C" {
35            static __AX_TASK_EXT_ALIGN: usize;
36        }
37        unsafe { __AX_TASK_EXT_ALIGN }
38    }
39
40    /// Construct an empty task extended structure that contains no data
41    /// (zero size).
42    pub const fn empty() -> Self {
43        Self {
44            ptr: core::ptr::null_mut(),
45        }
46    }
47
48    /// Returns `true` if the task extended structure is empty.
49    pub const fn is_empty(&self) -> bool {
50        self.ptr.is_null()
51    }
52
53    /// Allocates the space for the task extended data, but does not
54    /// initialize the data.
55    pub unsafe fn uninited() -> Self {
56        let size = Self::size();
57        let align = Self::align();
58        let ptr = if size == 0 {
59            core::ptr::null_mut()
60        } else {
61            let layout = Layout::from_size_align(size, align).unwrap();
62            unsafe { alloc::alloc::alloc(layout) }
63        };
64        Self { ptr }
65    }
66
67    /// Gets the raw pointer to the task extended data.
68    pub const fn as_ptr(&self) -> *mut u8 {
69        self.ptr
70    }
71
72    /// Write the given object to the task extended data.
73    ///
74    /// Returns [`None`] if the data size is zero, otherwise returns a mutable
75    /// reference to the content.
76    ///
77    /// # Panics
78    ///
79    /// Panics If the sizes and alignments of the two object do not match.
80    pub fn write<T: Sized>(&mut self, data: T) -> Option<&mut T> {
81        let data_size = size_of::<T>();
82        let data_align = align_of::<T>();
83        if data_size != Self::size() {
84            panic!("size mismatch: {} != {}", data_size, Self::size());
85        }
86        if data_align != Self::align() {
87            panic!("align mismatch: {} != {}", data_align, Self::align());
88        }
89
90        if self.ptr.is_null() {
91            *self = unsafe { Self::uninited() };
92        }
93        if data_size > 0 {
94            let ptr = self.ptr as *mut T;
95            assert!(!ptr.is_null());
96            unsafe {
97                ptr.write(data);
98                Some(&mut *ptr)
99            }
100        } else {
101            None
102        }
103    }
104}
105
106impl Drop for AxTaskExt {
107    fn drop(&mut self) {
108        if !self.ptr.is_null() {
109            unsafe extern "C" {
110                fn __ax_task_ext_drop(data: *mut u8);
111            }
112            unsafe { __ax_task_ext_drop(self.ptr) };
113
114            let layout = Layout::from_size_align(Self::size(), Self::align()).unwrap();
115            unsafe { alloc::alloc::dealloc(self.ptr, layout) };
116        }
117    }
118}
119
120/// A trait to convert [`TaskInner::task_ext_ptr`] to the reference of the
121/// concrete type.
122///
123/// [`TaskInner::task_ext_ptr`]: crate::TaskInner::task_ext_ptr
124pub trait TaskExtRef<T: Sized> {
125    /// Get a reference to the task extended data.
126    fn task_ext(&self) -> &T;
127}
128
129/// A trait to convert [`TaskInner::task_ext_ptr`] to the mutable reference of
130/// the concrete type.
131///
132/// [`TaskInner::task_ext_ptr`]: crate::TaskInner::task_ext_ptr
133pub trait TaskExtMut<T: Sized> {
134    /// Get a mutable reference to the task extended data.
135    fn task_ext_mut(&mut self) -> &mut T;
136}
137
138/// Define the task extended data.
139///
140/// It automatically implements [`TaskExtRef`] and [`TaskExtMut`] for
141/// [`TaskInner`].
142///
143/// # Example
144///
145/// ```
146/// # #![allow(non_local_definitions)]
147/// use axtask::{def_task_ext, TaskExtRef, TaskInner};
148///
149/// pub struct TaskExtImpl {
150///    proc_id: usize,
151/// }
152///
153/// def_task_ext!(TaskExtImpl);
154///
155/// axtask::init_scheduler();
156///
157/// let mut inner = TaskInner::new(|| {},  "".into(), 0x1000);
158/// assert!(inner.init_task_ext(TaskExtImpl { proc_id: 233 }).is_some());
159/// // cannot initialize twice
160/// assert!(inner.init_task_ext(TaskExtImpl { proc_id: 0xdead }).is_none());
161///
162/// let task = axtask::spawn_task(inner);
163/// assert_eq!(task.task_ext().proc_id, 233);
164/// ```
165///
166/// [`TaskInner`]: crate::TaskInner
167#[macro_export]
168macro_rules! def_task_ext {
169    ($task_ext_struct:ty) => {
170        #[unsafe(no_mangle)]
171        static __AX_TASK_EXT_SIZE: usize = ::core::mem::size_of::<$task_ext_struct>();
172
173        #[unsafe(no_mangle)]
174        static __AX_TASK_EXT_ALIGN: usize = ::core::mem::align_of::<$task_ext_struct>();
175
176        #[unsafe(no_mangle)]
177        fn __ax_task_ext_drop(data: *mut u8) {
178            unsafe { core::ptr::drop_in_place(data as *mut $task_ext_struct) };
179        }
180
181        impl $crate::TaskExtRef<$task_ext_struct> for $crate::TaskInner {
182            fn task_ext(&self) -> &$task_ext_struct {
183                unsafe {
184                    let ptr = self.task_ext_ptr() as *const $task_ext_struct;
185                    assert!(!ptr.is_null());
186                    &*ptr
187                }
188            }
189        }
190
191        impl $crate::TaskExtMut<$task_ext_struct> for $crate::TaskInner {
192            fn task_ext_mut(&mut self) -> &mut $task_ext_struct {
193                unsafe {
194                    let ptr = self.task_ext_ptr() as *mut $task_ext_struct;
195                    assert!(!ptr.is_null());
196                    &mut *ptr
197                }
198            }
199        }
200    };
201}