Skip to main content

ax_task/thread/
error.rs

1//! Errors returned by the scheduler model.
2
3/// Invariant that rejected a PI waiter graph transition.
4#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
5pub enum PiWaitStateError {
6    /// A thread attempted to wait on a mutex it already owns.
7    #[error("waiter is the physical lock owner")]
8    WaiterOwnsLock,
9    /// The first physical waiter found scheduler ownership left behind.
10    #[error("first waiter observed stale scheduler lock ownership")]
11    StaleSchedulerOwnership,
12    /// Physical ownership disagrees with the existing scheduler waiter graph.
13    #[error("owned lock disagrees with its scheduler waiter graph")]
14    PhysicalOwnerMismatch,
15    /// An ownerless physical handoff has no scheduler-selected waiter.
16    #[error("ownerless handoff has no selected scheduler waiter")]
17    OwnerlessSelectionMissing,
18    /// The waiter or physical owner has already exited.
19    #[error("waiter or physical owner has already exited")]
20    ExitedParticipant,
21    /// The waiter already owns a different PI wait edge.
22    #[error("waiter is already blocked on a PI lock")]
23    WaiterAlreadyBlocked,
24}
25
26/// Errors produced by task-system operations.
27#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
28pub enum TaskError {
29    /// A task-system configuration field is internally inconsistent.
30    #[error("invalid task-system configuration")]
31    InvalidConfiguration,
32    /// The requested CPU count is zero or cannot be represented.
33    #[error("invalid CPU count: {0}")]
34    InvalidCpuCount(usize),
35    /// A CPU identifier is outside the configured topology.
36    #[error("CPU {0} is outside the configured topology")]
37    InvalidCpu(u32),
38    /// A CPU-local object was used by a CPU other than its owner.
39    #[error("CPU-local owner mismatch: expected {expected}, got {actual}")]
40    CpuOwnerMismatch {
41        /// CPU that owns the object.
42        expected: u32,
43        /// CPU attempting the operation.
44        actual: u32,
45    },
46    /// The calling CPU's scheduler object already has an active owner borrow.
47    #[error("CPU-local scheduler owner is already borrowed")]
48    CpuOwnerBorrowed,
49    /// The CPU is already registered or online.
50    #[error("CPU {0} is already online")]
51    CpuAlreadyOnline(u32),
52    /// The CPU is not online.
53    #[error("CPU {0} is not online")]
54    CpuOffline(u32),
55    /// The CPU still owns runnable, timed, or remotely published work.
56    #[error("CPU {0} is not quiescent enough to go offline")]
57    CpuNotQuiescent(u32),
58    /// A scheduler topology must retain at least one online CPU.
59    #[error("CPU {0} is the last online CPU")]
60    LastOnlineCpu(u32),
61    /// A nice value is outside `-20..=19`.
62    #[error("invalid nice value: {0}")]
63    InvalidNice(i8),
64    /// An RT priority is outside `1..=99`.
65    #[error("invalid real-time priority: {0}")]
66    InvalidRtPriority(u8),
67    /// A round-robin quantum is zero.
68    #[error("round-robin quantum must be non-zero")]
69    InvalidRoundRobinQuantum,
70    /// Deadline parameters violate `0 < runtime <= deadline <= period`.
71    #[error(
72        "invalid deadline parameters: runtime={runtime_ns}, deadline={deadline_ns}, \
73         period={period_ns}"
74    )]
75    InvalidDeadline {
76        /// Reserved runtime in nanoseconds.
77        runtime_ns: u64,
78        /// Relative deadline in nanoseconds.
79        deadline_ns: u64,
80        /// Replenishment period in nanoseconds.
81        period_ns: u64,
82    },
83    /// Deadline flags contain unsupported bits.
84    #[error("unsupported deadline flags: {0:#x}")]
85    UnsupportedDeadlineFlags(u32),
86    /// A deadline reservation exceeds root-domain capacity.
87    #[error("deadline admission would exceed the configured root-domain capacity")]
88    DeadlineAdmission,
89    /// Deadline affinity does not cover every online CPU.
90    #[error("deadline affinity must cover the complete online root domain")]
91    DeadlineAffinity,
92    /// The thread identifier is stale or unknown.
93    #[error("unknown or stale thread identifier")]
94    StaleThreadId,
95    /// A local executor wake header does not belong to the calling thread.
96    #[error("executor owner mismatch: expected thread {expected:#x}, got {actual:#x}")]
97    ExecutorOwnerMismatch {
98        /// Thread encoded in the direct wake header.
99        expected: u64,
100        /// Calling scheduler thread.
101        actual: u64,
102    },
103    /// The requested lifecycle transition is invalid.
104    #[error("invalid thread-state transition from {from:?} to {to:?}")]
105    InvalidTransition {
106        /// State before the attempted transition.
107        from: crate::thread::ThreadState,
108        /// Requested state.
109        to: crate::thread::ThreadState,
110    },
111    /// A thread is already present in a run queue.
112    #[error("thread is already queued")]
113    AlreadyQueued,
114    /// A thread is not in a schedulable state.
115    #[error("thread is not ready to be queued")]
116    NotReady,
117    /// A thread cannot be reaped before reaching `Exited`.
118    #[error("thread must be exited before it can be reaped")]
119    NotExited,
120    /// The CPU has no idle thread and no runnable work.
121    #[error("CPU has no runnable or idle thread")]
122    NoRunnableThread,
123    /// A configured fixed-capacity resource is exhausted.
124    #[error("timer capacity is exhausted")]
125    TimerCapacity,
126    /// The cold-path scheduler thread reservation is exhausted.
127    #[error("scheduler thread capacity is exhausted")]
128    ThreadCapacity,
129    /// An affinity update would move a thread away from its owner-CPU sleep timer.
130    #[error("thread affinity excludes the CPU owning an active sleep timer")]
131    ActiveTimerAffinity,
132    /// The runtime-backed facade has not been initialized.
133    #[error("task runtime is not initialized")]
134    NotInitialized,
135    /// A runtime handle is non-null but violates the object handle contract.
136    #[error("runtime returned an invalid task object handle")]
137    InvalidRuntimeHandle,
138    /// Scheduling was requested from hard IRQ or another non-safe-point context.
139    #[error("operation requires a scheduler safe point")]
140    UnsafeContext,
141    /// PI ownership or waiter metadata does not match the requested transition.
142    #[error("invalid priority-inheritance state")]
143    InvalidPiState,
144    /// A PI waiter could not enter the lock graph because one checked invariant failed.
145    #[error("invalid priority-inheritance wait state: {0}")]
146    InvalidPiWaitState(PiWaitStateError),
147    /// A transitive priority donation would form a lock dependency cycle.
148    #[error("priority-inheritance dependency cycle")]
149    PiCycle,
150    /// A PI operation exceeded the bounded owner-chain walk.
151    #[error("priority-inheritance chain exceeds the configured depth {limit}")]
152    PiChainLimit {
153        /// Maximum owner depth admitted by one graph transaction.
154        limit: usize,
155    },
156    /// Thread wake/handle references still retain runtime-owned resources.
157    #[error("thread resources are still referenced")]
158    ThreadBusy,
159    /// A runtime resource teardown operation failed.
160    #[error("runtime resource operation failed with status {0}")]
161    RuntimeFailure(u32),
162}
163
164/// Errors produced by the scheduler-owned membarrier protocol.
165#[derive(Clone, Copy, Debug, Eq, PartialEq, thiserror::Error)]
166pub enum MembarrierError {
167    /// An expedited command was issued before registration became ready.
168    #[error("membarrier facility is not registered for the current address space")]
169    NotRegistered,
170    /// The scheduler/runtime boundary rejected the operation.
171    #[error(transparent)]
172    Task(#[from] TaskError),
173}