use alloc::sync::Arc;
use core::marker::PhantomData;
pub use crate::{
runtime::switch::dispatch::{
ExitPermit, commit_current_exit, exit_current_thread, prepare_current_exit,
yield_current_cpu,
},
sync::wait_queue::{sleep, sleep_until},
thread::current::park::{
CurrentParkDisposition, CurrentParkResume, CurrentParkStart, PreparedCurrentPark,
begin_current_park,
},
};
use crate::{
runtime::{
context::{
RuntimeSchedulerFrameGuard, runtime_current_cpu_mut, runtime_task_system,
validate_schedule_context,
},
switch::{RuntimeScheduleOrigin, RuntimeSchedulerEntry, dispatch::execute_switch_plan},
task_runtime,
},
sched::CpuSet,
thread::{
CurrentThreadToken, TaskError, ThreadCore, ThreadExtensionLease, ThreadHandle, ThreadId,
},
};
pub fn current_thread_handle() -> Result<ThreadHandle, TaskError> {
#[cfg(feature = "qperf-metrics")]
crate::diagnostics::counters::record_current_thread_handle_query();
let publication = current_thread_publication()?;
unsafe { publication.acquire_handle() }
}
#[inline(always)]
pub fn current_thread_id() -> Result<ThreadId, TaskError> {
let identity = current_thread_identity()?;
Ok(ThreadId::from_parts(identity.slot, identity.generation))
}
#[inline(always)]
pub fn current_thread_token() -> Result<CurrentThreadToken, TaskError> {
Ok(CurrentThreadToken::new(current_thread_id()?))
}
#[inline(always)]
pub(crate) fn current_thread_identity()
-> Result<crate::runtime::switch::ThreadIdentityV1, TaskError> {
let identity = task_runtime::current_thread_identity();
if identity.is_bound() {
return Ok(identity);
}
let publication = task_runtime::current_thread_publication();
if publication.identity() != identity || !publication.owner().is_none() {
return Err(TaskError::InvalidRuntimeHandle);
}
let _system = runtime_task_system()?;
Err(TaskError::NoRunnableThread)
}
pub(crate) fn current_thread_publication()
-> Result<crate::runtime::switch::CurrentThreadPublication, TaskError> {
let publication = task_runtime::current_thread_publication();
let identity = publication.identity();
if !identity.is_bound() {
if !publication.owner().is_none() {
return Err(TaskError::InvalidRuntimeHandle);
}
let _system = runtime_task_system()?;
return Err(TaskError::NoRunnableThread);
}
if publication.owner().is_none() {
return Err(TaskError::InvalidRuntimeHandle);
}
Ok(publication)
}
pub(crate) fn current_thread_core_arc() -> Result<Arc<ThreadCore>, TaskError> {
let publication = current_thread_publication()?;
unsafe { publication.acquire_scheduler_core() }
}
pub fn validate_blocking_context() -> Result<(), TaskError> {
acquire_blocking_permit().map(|_| ())
}
pub(crate) struct BlockingPermit {
_not_send: PhantomData<*mut ()>,
}
pub(crate) fn acquire_blocking_permit() -> Result<BlockingPermit, TaskError> {
validate_schedule_context(RuntimeScheduleOrigin::Block)?;
Ok(BlockingPermit {
_not_send: PhantomData,
})
}
pub fn current_thread_extension() -> Result<Option<ThreadExtensionLease>, TaskError> {
let handle = current_thread_handle()?;
Ok(handle
.extension_view()
.map(|view| ThreadExtensionLease::new(view, handle)))
}
pub fn set_current_thread_affinity(affinity: CpuSet) -> Result<(), TaskError> {
let mut scheduler_frame = RuntimeSchedulerFrameGuard::enter(
RuntimeScheduleOrigin::Yield,
RuntimeSchedulerEntry::Task,
)?;
let current = scheduler_frame.current_thread_ref()?;
let system = scheduler_frame.task_system();
let mut outcome = {
let mut cpu = runtime_current_cpu_mut(&mut scheduler_frame)?;
let must_migrate = system.set_current_affinity(cpu.as_mut(), affinity)?;
if !must_migrate {
return Ok(());
}
unsafe { system.yield_current_in_scheduler_frame(cpu.as_mut()) }.unwrap_or_else(|_| {
task_runtime::fatal_invariant(0x4558_0021, current.id().as_u64() as usize);
})
};
let decision = outcome.decision_mut().unwrap_or_else(|| {
task_runtime::fatal_invariant(0x4558_0022, current.id().as_u64() as usize)
});
execute_switch_plan(&mut scheduler_frame, decision);
Ok(())
}
pub(crate) mod park;