diff --git a/Cargo.lock b/Cargo.lock index ba5ffbdf87..f5b6528f7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -128,6 +128,7 @@ dependencies = [ "axlog", "axruntime", "axstd", + "axtask", "memory_addr", ] diff --git a/modules/axhal/linker.lds.S b/modules/axhal/linker.lds.S index 73b7a7884d..ea5213735f 100644 --- a/modules/axhal/linker.lds.S +++ b/modules/axhal/linker.lds.S @@ -29,6 +29,11 @@ SECTIONS _sdata = .; *(.data.boot_page_table) . = ALIGN(4K); + + __start_ax_task_ext = .; + *(ax_task_ext) + __stop_ax_task_ext = .; + *(.data .data.*) *(.sdata .sdata.*) *(.got .got.*) @@ -53,13 +58,9 @@ SECTIONS _percpu_load_start = .; *(.percpu .percpu.*) _percpu_load_end = .; - . = ALIGN(64); - _percpu_size_aligned = .; - - . = _percpu_load_start + _percpu_size_aligned * %SMP%; + . = _percpu_load_start + ALIGN(64) * %SMP%; } . = _percpu_start + SIZEOF(.percpu); - _percpu_end = .; . = ALIGN(4K); _edata = .; diff --git a/modules/axhal/src/arch/x86_64/context.rs b/modules/axhal/src/arch/x86_64/context.rs index e4bc073229..b3c31727f1 100644 --- a/modules/axhal/src/arch/x86_64/context.rs +++ b/modules/axhal/src/arch/x86_64/context.rs @@ -1,7 +1,7 @@ use core::{arch::asm, fmt}; use memory_addr::VirtAddr; -#[cfg(feature = "irq")] +#[cfg(all(feature = "irq", feature = "uspace"))] use x86_64::registers::rflags::RFlags; #[cfg(feature = "uspace")] diff --git a/modules/axtask/src/api.rs b/modules/axtask/src/api.rs index 8e75f270ea..9196fabf30 100644 --- a/modules/axtask/src/api.rs +++ b/modules/axtask/src/api.rs @@ -7,6 +7,8 @@ pub(crate) use crate::run_queue::{AxRunQueue, RUN_QUEUE}; #[doc(cfg(feature = "multitask"))] pub use crate::task::{CurrentTask, TaskId, TaskInner}; #[doc(cfg(feature = "multitask"))] +pub use crate::task_ext::{TaskExtMut, TaskExtRef}; +#[doc(cfg(feature = "multitask"))] pub use crate::wait_queue::WaitQueue; /// The reference type of a task. diff --git a/modules/axtask/src/lib.rs b/modules/axtask/src/lib.rs index b02a1ea1f2..475b3232b1 100644 --- a/modules/axtask/src/lib.rs +++ b/modules/axtask/src/lib.rs @@ -28,6 +28,7 @@ #![cfg_attr(not(test), no_std)] #![feature(doc_cfg)] #![feature(doc_auto_cfg)] +#![feature(linkage)] #[cfg(test)] mod tests; @@ -40,6 +41,7 @@ cfg_if::cfg_if! { mod run_queue; mod task; + mod task_ext; mod api; mod wait_queue; diff --git a/modules/axtask/src/run_queue.rs b/modules/axtask/src/run_queue.rs index 9c31f4384c..ee7abb49cb 100644 --- a/modules/axtask/src/run_queue.rs +++ b/modules/axtask/src/run_queue.rs @@ -214,6 +214,7 @@ fn gc_entry() { } pub(crate) fn init() { + // Put the subsequent execution into the `main` task. const IDLE_TASK_STACK_SIZE: usize = 4096; let idle_task = TaskInner::new(|| crate::run_idle(), "idle".into(), IDLE_TASK_STACK_SIZE); IDLE_TASK.with_current(|i| i.init_by(idle_task.clone())); @@ -226,6 +227,7 @@ pub(crate) fn init() { } pub(crate) fn init_secondary() { + // Put the subsequent execution into the `idle` task. let idle_task = TaskInner::new_init("idle".into()); idle_task.set_state(TaskState::Running); IDLE_TASK.with_current(|i| i.init_by(idle_task.clone())); diff --git a/modules/axtask/src/task.rs b/modules/axtask/src/task.rs index 7db9d78b61..6833672054 100644 --- a/modules/axtask/src/task.rs +++ b/modules/axtask/src/task.rs @@ -12,6 +12,7 @@ use axhal::tls::TlsArea; use axhal::arch::TaskContext; use memory_addr::{align_up_4k, VirtAddr}; +use crate::task_ext::AxTaskExt; use crate::{AxRunQueue, AxTask, AxTaskRef, WaitQueue}; /// A unique identifier for a thread. @@ -52,6 +53,7 @@ pub struct TaskInner { kstack: Option, ctx: UnsafeCell, + task_ext: AxTaskExt, #[cfg(feature = "tls")] tls: TlsArea, @@ -109,6 +111,19 @@ impl TaskInner { .wait_until(|| self.state() == TaskState::Exited); Some(self.exit_code.load(Ordering::Acquire)) } + + /// Returns the pointer to the user-defined task extended data. + /// + /// # Safety + /// + /// The caller should not access the pointer directly, use [`TaskExtRef::task_ext`] + /// or [`TaskExtMut::task_ext_mut`] instead. + /// + /// [`TaskExtRef::task_ext`]: crate::task_ext::TaskExtRef::task_ext + /// [`TaskExtMut::task_ext_mut`]: crate::task_ext::TaskExtMut::task_ext_mut + pub unsafe fn task_ext_ptr(&self) -> *mut u8 { + self.task_ext.as_ptr() + } } // private methods @@ -132,6 +147,7 @@ impl TaskInner { wait_for_exit: WaitQueue::new(), kstack: None, ctx: UnsafeCell::new(TaskContext::new()), + task_ext: AxTaskExt::alloc(), #[cfg(feature = "tls")] tls: TlsArea::alloc(), } diff --git a/modules/axtask/src/task_ext.rs b/modules/axtask/src/task_ext.rs new file mode 100644 index 0000000000..47d9ead2e9 --- /dev/null +++ b/modules/axtask/src/task_ext.rs @@ -0,0 +1,108 @@ +//! User-defined task extended data. + +extern "C" { + fn __start_ax_task_ext(); + fn __stop_ax_task_ext(); +} + +#[no_mangle] +#[linkage = "weak"] +#[link_section = "ax_task_ext"] +static __AX_TASK_EXT: () = (); + +pub(crate) struct AxTaskExt { + ptr: *mut u8, +} + +impl AxTaskExt { + fn size() -> usize { + __stop_ax_task_ext as usize - __start_ax_task_ext as usize + } + + pub(crate) fn as_ptr(&self) -> *mut u8 { + self.ptr + } + + pub(crate) fn alloc() -> Self { + let size = Self::size(); + let ptr = if size == 0 { + core::ptr::null_mut() + } else { + let layout = core::alloc::Layout::from_size_align(size, 0x10).unwrap(); + let dst = unsafe { alloc::alloc::alloc(layout) }; + let src = &__AX_TASK_EXT as *const _ as *const u8; + unsafe { core::ptr::copy_nonoverlapping(src, dst, size) }; + dst + }; + Self { ptr } + } +} + +impl Drop for AxTaskExt { + fn drop(&mut self) { + if !self.ptr.is_null() { + let layout = core::alloc::Layout::from_size_align(Self::size(), 0x10).unwrap(); + unsafe { alloc::alloc::dealloc(self.ptr, layout) }; + } + } +} + +/// A trait to convert [`TaskInner::task_ext_ptr`] to the reference of the +/// concrete type. +/// +/// [`TaskInner::task_ext_ptr`]: crate::TaskInner::task_ext_ptr +pub trait TaskExtRef { + /// Get a reference to the task extended data. + fn task_ext(&self) -> &T; +} + +/// A trait to convert [`TaskInner::task_ext_ptr`] to the mutable reference of +/// the concrete type. +/// +/// [`TaskInner::task_ext_ptr`]: crate::TaskInner::task_ext_ptr +pub trait TaskExtMut { + /// Get a mutable reference to the task extended data. + fn task_ext_mut(&mut self) -> &mut T; +} + +/// Define the task extended data. +/// +/// It automatically implements [`TaskExtRef`] and [`TaskExtMut`] for +/// [`TaskInner`]. +/// +/// # Example +/// +/// ```no_run +/// use axtask::{def_task_ext, TaskExtRef}; +/// +/// pub struct TaskExtImpl { +/// proc_id: usize, +/// } +/// +/// def_task_ext!(TaskExtImpl, TaskExtImpl { proc_id: 0 }); +/// +/// let task = axtask::spawn(|| {}); +/// assert_eq!(task.task_ext().proc_id, 0); +/// ``` +/// +/// [`TaskInner`]: crate::TaskInner +#[macro_export] +macro_rules! def_task_ext { + ($task_ext_struct:ty, $default:expr) => { + #[no_mangle] + #[link_section = "ax_task_ext"] + static __AX_TASK_EXT: $task_ext_struct = $default; + + impl $crate::TaskExtRef<$task_ext_struct> for $crate::TaskInner { + fn task_ext(&self) -> &$task_ext_struct { + unsafe { &*(self.task_ext_ptr() as *const $task_ext_struct) } + } + } + + impl $crate::TaskExtMut<$task_ext_struct> for $crate::TaskInner { + fn task_ext_mut(&mut self) -> &mut $task_ext_struct { + unsafe { &mut *(self.task_ext_ptr() as *mut $task_ext_struct) } + } + } + }; +} diff --git a/variants/monolithic/Cargo.toml b/variants/monolithic/Cargo.toml index 7644e1e22a..ae79bbc73d 100644 --- a/variants/monolithic/Cargo.toml +++ b/variants/monolithic/Cargo.toml @@ -8,5 +8,6 @@ axstd = { path = "../../ulib/axstd", features = ["paging"] } axhal = { path = "../../modules/axhal", features = ["uspace"] } axlog = { path = "../../modules/axlog" } axconfig = { path = "../../modules/axconfig" } -axruntime = { path = "../../modules/axruntime" } +axtask = { path = "../../modules/axtask" } +axruntime = { path = "../../modules/axruntime", features = ["multitask"] } memory_addr = { path = "../../crates/memory_addr" } diff --git a/variants/monolithic/src/main.rs b/variants/monolithic/src/main.rs index 8f19dc714e..fd35a66c80 100644 --- a/variants/monolithic/src/main.rs +++ b/variants/monolithic/src/main.rs @@ -6,12 +6,15 @@ extern crate axlog; extern crate alloc; extern crate axstd; +mod task; + use memory_addr::VirtAddr; use axhal::arch::UspaceContext; use axhal::mem::virt_to_phys; use axhal::paging::MappingFlags; use axruntime::KERNEL_PAGE_TABLE; +use axtask::TaskExtRef; const USER_STACK_SIZE: usize = 4096; @@ -73,6 +76,12 @@ fn run_apps() -> ! { .unwrap(); let ctx = UspaceContext::new(entry_vaddr.into(), ustack_top, 2333); + let pid = axtask::current().task_ext().proc_id; + let parent = axtask::current().task_ext().parent; + warn!("pid = {}", pid); + warn!("parent = {}", parent); + assert_eq!(pid, 233); + assert_eq!(parent, 456); info!( "Enter user space: entry={:#x}, ustack={:#x}, kstack={:#x}", diff --git a/variants/monolithic/src/task.rs b/variants/monolithic/src/task.rs new file mode 100644 index 0000000000..f737425f98 --- /dev/null +++ b/variants/monolithic/src/task.rs @@ -0,0 +1,15 @@ +pub struct TaskExt { + pub proc_id: usize, + pub parent: usize, +} + +impl TaskExt { + pub const fn default() -> Self { + Self { + proc_id: 233, + parent: 456, + } + } +} + +axtask::def_task_ext!(TaskExt, TaskExt::default());