use alloc::{boxed::Box, string::String};
use core::{pin::Pin, ptr};
use ax_hal::percpu::CpuPin;
use ax_lazyinit::LazyInit;
use ax_task::{
runtime::{
RuntimeHandleResult, RuntimeStatus, TaskSystem, TaskSystemHandle,
config::TaskSystemConfig,
cpu::{
CpuLocal, CpuRemote, CpuRemoteHandle, CurrentCpuLocalHandle, CurrentCpuOwnerHandles,
IrqGuardToken, RuntimeCpuId,
},
resource::{
AddressSpaceDestroyOutcome, AddressSpaceHandle, AddressSpaceMembarrierState,
AddressSpaceReclaimArmOutcome, ExecutionContextHandle, KernelContextRequest,
MembarrierRegistration, MembarrierRegistrationPhase, RuntimeMembarrierAction,
StackHandle, StackRequest, ThreadResources, TlsHandle, UserContextRequest,
},
switch::{
ContextThreadBinding, CurrentThreadPublication, RuntimeSchedulerFrameEnterResult,
RuntimeSwitchPlan, SchedSwitchRecord, ThreadIdentityV1,
},
task_runtime::impl_trait as impl_task_runtime,
},
sched::{CpuId, CpuSet, FairMode, Nice, SchedulePolicy},
thread::{TaskError, ThreadId, ThreadSpec, current::current_thread_id},
};
mod address_space;
mod mm_activation;
pub use mm_activation::{
AddressSpaceSwitchProof, SchedulerAddressSpaceActivation, SchedulerAddressSpaceOwner,
UserAddressSpaceOwner,
};
mod bootstrap;
pub(crate) mod context;
#[cfg(feature = "fault-injection")]
pub mod creation_probe;
mod resources;
pub(crate) mod runtime_impl;
pub(crate) mod scheduler_events;
mod spawn;
mod thread_resources;
#[cfg(feature = "uspace")]
mod user_entry;
pub use address_space::{
AddressSpaceCpuState, TaskAddressSpace, detach_current_address_space,
switch_current_address_space,
};
use address_space::{
arm_runtime_address_space_reclaim, destroy_runtime_address_space,
release_current_active_address_space, runtime_address_space_membarrier_state,
update_runtime_address_space_membarrier_state,
};
#[cfg(feature = "uspace")]
use bootstrap::current_cpu_remote;
#[cfg(kernel_tls)]
pub(crate) use bootstrap::initialize_early_bootstrap_tls;
#[cfg(test)]
use bootstrap::{IdleEntryAction, idle_entry_action};
pub(crate) use bootstrap::{
PublishedCpuOnline, initialize_primary, publish_current_cpu_online,
start_current_ktimer_service, start_deferred_task_work_service,
};
use bootstrap::{
cpu_remote, current_cpu_owner_handles, idle_context_entry, primary_bootstrap_thread,
scheduler_current_cpu_remote_handle, task_system, with_current_cpu_pin,
};
#[cfg(feature = "smp")]
pub(crate) use bootstrap::{initialize_secondary, run_idle};
use context::{
bind_bootstrap_runtime_context, bind_runtime_context_thread, create_bootstrap_context,
create_runtime_context, create_user_runtime_context, destroy_runtime_context,
finish_runtime_context_switch_tail, scheduler_current_thread_identity,
scheduler_current_thread_publication, switch_runtime_context,
};
pub(crate) fn runtime_task_system_handle() -> TaskSystemHandle {
task_system().map_or(TaskSystemHandle::NONE, |system| {
unsafe { TaskSystemHandle::from_raw((system as *const TaskSystem).expose_provenance()) }
})
}
pub(crate) fn scheduler_frame_capabilities(cpu_pin: &CpuPin) -> RuntimeSchedulerFrameEnterResult {
unsafe {
RuntimeSchedulerFrameEnterResult::success(
runtime_task_system_handle(),
current_cpu_owner_handles(cpu_pin),
)
}
}
#[cfg(feature = "uspace")]
pub(crate) fn current_cpu_needs_reschedule_pinned(cpu_pin: &CpuPin) -> Result<bool, TaskError> {
Ok(current_cpu_remote(cpu_pin)
.ok_or(TaskError::NotInitialized)?
.needs_reschedule())
}
#[cfg(kernel_tls)]
use resources::runtime_tls_pointer;
use resources::{
allocate_runtime_stack, allocate_runtime_tls, deallocate_runtime_stack, deallocate_runtime_tls,
};
pub(crate) use scheduler_events::{on_clock_event, publish_scheduler_tick};
#[cfg(feature = "qperf-metrics")]
pub(crate) use scheduler_events::{
record_irq_return_scheduler_continuation, record_irq_return_scheduler_window,
};
#[cfg(axtest)]
pub fn kernel_thread_retains_active_mm_membarrier_state_for_test() -> bool {
static IDENTITY_ANCHOR: u8 = 0;
let identity_raw = (&IDENTITY_ANCHOR as *const u8).expose_provenance();
let identity =
unsafe { ax_task::runtime::resource::AddressSpaceMembarrierId::from_raw(identity_raw) };
let active_mm_state =
unsafe { ax_task::runtime::resource::AddressSpaceMembarrierState::new(identity, 0) };
ax_task::runtime::resource::scheduled_membarrier_state_for_test(
active_mm_state,
ax_task::runtime::resource::AddressSpaceMembarrierState::NONE,
) == active_mm_state
}
pub fn reset_current_user_fp_state() -> Result<(), TaskError> {
context::reset_current_user_fp_state()
}
#[cfg(all(target_arch = "x86_64", feature = "fp-simd", feature = "uspace"))]
pub fn capture_current_user_fp_state() -> Result<ax_hal::cpu::registers::UserXstate, TaskError> {
context::capture_current_user_fp_state()
}
#[cfg(all(target_arch = "x86_64", feature = "fp-simd", feature = "uspace"))]
pub fn replace_current_user_fp_state(
state: ax_hal::cpu::registers::UserXstate,
) -> Result<(), TaskError> {
context::replace_current_user_fp_state(state)
}
#[cfg(all(feature = "qperf-metrics", any(feature = "ipi", feature = "wake-ipi")))]
pub(crate) use scheduler_events::{record_scheduler_ipi_consume, record_scheduler_ipi_send};
pub use spawn::{UserContextOptions, builder, exit_current, prepare_user_thread};
fn finish_initial_scheduler_switch() {
unsafe { ax_task::runtime::switch::finish_initial_context_switch() }
.expect("initial context switch must finish");
}
#[cfg(all(test, kernel_tls))]
use thread_resources::assemble_bootstrap_resources;
use thread_resources::{create_bootstrap_resources, create_idle_resources, create_user_resources};
#[cfg(feature = "uspace")]
pub use user_entry::UserExecutionContext;
const PAGE_SIZE: usize = 4096;
#[cfg(not(feature = "fs"))]
const DEFAULT_TASK_STACK_SIZE: usize = 256 * 1024;
const fn runtime_status_error(status: RuntimeStatus) -> TaskError {
TaskError::RuntimeFailure(status as u32)
}
const fn runtime_task_stack_size() -> usize {
#[cfg(feature = "fs")]
{
crate::build_info::TASK_STACK_SIZE
}
#[cfg(not(feature = "fs"))]
{
DEFAULT_TASK_STACK_SIZE
}
}
pub const fn default_task_stack_size() -> usize {
runtime_task_stack_size()
}
#[cfg(test)]
mod tests;
mod allocation;