Skip to main content

ax_runtime/thread/
spawn.rs

1//! ArceOS stack defaults and architecture-specific user context assembly.
2
3use ax_task::thread::{PreparedThread, ThreadBuilder};
4
5use super::*;
6
7/// Applies ArceOS stack and guard-page defaults to the common thread builder.
8pub fn builder(name: String) -> ThreadBuilder {
9    ThreadBuilder::new(name)
10        .stack_size(default_task_stack_size())
11        .guard_size(if cfg!(feature = "stack-guard-page") {
12            PAGE_SIZE
13        } else {
14            0
15        })
16}
17
18/// Initial user address space and architecture-specific floating-point state.
19pub struct UserContextOptions {
20    pub(super) address_space: TaskAddressSpace,
21    #[cfg(all(target_arch = "riscv64", feature = "fp-simd"))]
22    pub(super) fp_state: Option<ax_hal::cpu::registers::FpState>,
23    #[cfg(all(not(target_arch = "riscv64"), feature = "fp-simd", feature = "uspace"))]
24    pub(super) inherit_current_fp: bool,
25}
26impl UserContextOptions {
27    /// Creates a user context with the architecture's initial FP state.
28    pub fn new(address_space: TaskAddressSpace) -> Self {
29        Self {
30            address_space,
31            #[cfg(all(target_arch = "riscv64", feature = "fp-simd"))]
32            fp_state: None,
33            #[cfg(all(not(target_arch = "riscv64"), feature = "fp-simd", feature = "uspace"))]
34            inherit_current_fp: false,
35        }
36    }
37    /// Supplies the child's RISC-V floating-point register image.
38    #[cfg(all(target_arch = "riscv64", feature = "fp-simd"))]
39    pub fn with_fp_state(mut self, state: ax_hal::cpu::registers::FpState) -> Self {
40        self.fp_state = Some(state);
41        self
42    }
43    /// Captures the calling thread's user FP state during context preparation.
44    #[cfg(all(not(target_arch = "riscv64"), feature = "fp-simd", feature = "uspace"))]
45    pub fn inherit_current_fp(mut self) -> Self {
46        self.inherit_current_fp = true;
47        self
48    }
49}
50
51/// Prepares user architecture resources without publishing or activating the task.
52///
53/// # Safety
54/// `entry` must enter user mode only with the supplied address-space ownership and
55/// initialized architecture state. Inherited FP state must belong to the caller.
56pub unsafe fn prepare_user_thread(
57    builder: ThreadBuilder,
58    entry: impl FnOnce() + Send + 'static,
59    options: UserContextOptions,
60) -> Result<PreparedThread, TaskError> {
61    #[cfg(all(not(target_arch = "riscv64"), feature = "fp-simd", feature = "uspace"))]
62    if options.inherit_current_fp {
63        context::validate_current_user_fp_clone_context()?;
64    }
65    // SAFETY: the resource factory installs the provided trampoline, and its
66    // rollback owns every partial allocation until returning a complete bundle.
67    unsafe {
68        builder.prepare_with(entry, |request, trampoline| {
69            create_user_resources(request, trampoline, options)
70        })
71    }
72}
73
74/// Exits an ArceOS task, preserving the primary bootstrap termination policy.
75pub fn exit_current(code: i32) -> ! {
76    if primary_bootstrap_thread() == current_thread_id().ok() {
77        crate::terminate();
78    }
79    ax_task::thread::current::exit_current(code)
80}