1use alloc::sync::{Arc, Weak};
4#[cfg(feature = "lockdep")]
5use core::cell::UnsafeCell;
6use core::{
7 marker::PhantomData,
8 mem::ManuallyDrop,
9 sync::atomic::{AtomicBool, AtomicPtr, AtomicU8, AtomicU32, AtomicU64, AtomicUsize, Ordering},
10};
11
12mod wake_batch;
13pub use wake_batch::ThreadWakeBatch;
14
15use crate::{
16 runtime::{
17 cpu::PreemptGuardToken,
18 delivery::{
19 inbox::{InboxKind, InboxNode},
20 work::TaskWorkDoorbell,
21 },
22 resource::AddressSpaceMembarrierId,
23 service::SchedulerTickCpuTime,
24 task_runtime,
25 },
26 sched::{
27 CpuId, DeadlineFlags, DeadlinePolicy, FairMode, Nice, RtPriority, SchedulePolicy,
28 algorithm::RunQueueNodeStorage, system::ThreadSchedCell,
29 },
30 thread::{
31 ParkPublication, PiWaitNodeStorage, PiWaitState, SchedulerTickWork, SchedulerTickWorkClaim,
32 SchedulingKey, SchedulingUrgency, TaskError, ThreadAffinityCompletion, ThreadExtensionView,
33 ThreadId, ThreadLifecycle, ThreadState, WakePublication,
34 },
35 time::queue::TaskDeadlineNode,
36};
37
38const REAP_CLAIMED: usize = 1 << (usize::BITS - 1);
39const REAP_MAX_UPGRADE_READERS: usize = REAP_CLAIMED - 1;
40const SCHEDULER_ACTIVITY_CLOSED: usize = 1 << (usize::BITS - 1);
41const SCHEDULER_ACTIVITY_MAX_READERS: usize = SCHEDULER_ACTIVITY_CLOSED - 1;
42
43#[cfg(feature = "lockdep")]
44struct ThreadHeldLocks {
45 stack: UnsafeCell<crate::sync::lockdep::HeldLockStack>,
46}
47
48#[cfg(feature = "lockdep")]
49impl ThreadHeldLocks {
50 const fn new() -> Self {
51 Self {
52 stack: UnsafeCell::new(crate::sync::lockdep::HeldLockStack::new()),
53 }
54 }
55
56 unsafe fn with_mut<R>(
57 &self,
58 operation: impl FnOnce(&mut crate::sync::lockdep::HeldLockStack) -> R,
59 ) -> R {
60 unsafe { operation(&mut *self.stack.get()) }
63 }
64}
65
66#[cfg(feature = "lockdep")]
67impl core::fmt::Debug for ThreadHeldLocks {
68 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
69 formatter.write_str("ThreadHeldLocks(..)")
70 }
71}
72
73#[cfg(feature = "lockdep")]
77unsafe impl Sync for ThreadHeldLocks {}
78
79#[derive(Debug)]
81pub struct ThreadHandle {
82 pub(crate) core: ManuallyDrop<Arc<ThreadCore>>,
83 reap_signal: Arc<ThreadReapSignal>,
84}
85
86impl Drop for ThreadHandle {
87 fn drop(&mut self) {
88 unsafe {
89 ManuallyDrop::drop(&mut self.core);
93 }
94 self.reap_signal.release_external_lease();
95 }
96}
97
98impl Clone for ThreadHandle {
99 fn clone(&self) -> Self {
100 let core = Arc::clone(&self.core);
101 let reap_signal = Arc::clone(&self.reap_signal);
102 reap_signal.acquire_external_lease();
103 Self {
104 core: ManuallyDrop::new(core),
105 reap_signal,
106 }
107 }
108}
109
110impl ThreadHandle {
111 pub(crate) fn from_core(core: Arc<ThreadCore>) -> Self {
112 let reap_signal = Arc::clone(&core.reap_signal);
113 reap_signal.acquire_external_lease();
114 Self {
115 core: ManuallyDrop::new(core),
116 reap_signal,
117 }
118 }
119
120 #[doc(hidden)]
123 pub fn runtime_publication(&self) -> crate::runtime::switch::CurrentThreadPublication {
124 crate::runtime::switch::CurrentThreadPublication::from_core(self.id(), &self.core)
125 }
126
127 pub(crate) fn runtime_core_arc(&self) -> &Arc<ThreadCore> {
128 &self.core
129 }
130
131 pub fn id(&self) -> ThreadId {
133 self.core.id
134 }
135
136 pub fn base_policy(&self) -> SchedulePolicy {
138 self.core.base_policy.load()
139 }
140
141 pub fn effective_policy(&self) -> SchedulePolicy {
143 self.core.effective_policy.load()
144 }
145
146 pub fn execution_reclaimed(&self) -> bool {
148 self.core.execution_reclaimed.load(Ordering::Acquire)
149 }
150
151 pub fn state(&self) -> ThreadState {
153 self.core.state()
154 }
155
156 pub fn downgrade(&self) -> WeakThreadHandle {
158 WeakThreadHandle {
159 core: Arc::downgrade(&self.core),
160 }
161 }
162
163 pub fn wake_handle(&self) -> ThreadWakeHandle {
165 ThreadWakeHandle::from_core(Arc::clone(&self.core))
166 }
167
168 pub fn scheduler_fence_cpu(&self) -> Option<CpuId> {
176 self.core.sched().scheduler_fence_cpu()
177 }
178
179 pub fn assigned_cpu(&self) -> Option<CpuId> {
186 self.core.assigned_cpu()
187 }
188
189 pub(crate) fn extension_view(&self) -> Option<crate::thread::ThreadExtensionView> {
190 self.core.extension_view()
191 }
192}
193
194impl Eq for ThreadHandle {}
195
196impl PartialEq for ThreadHandle {
197 fn eq(&self, other: &Self) -> bool {
198 self.id() == other.id()
199 }
200}
201
202#[derive(Clone, Debug)]
204pub struct WeakThreadHandle {
205 core: Weak<ThreadCore>,
206}
207
208impl WeakThreadHandle {
209 pub fn upgrade(&self) -> Option<ThreadHandle> {
211 let core = self.core.upgrade()?;
212 if !core.try_enter_weak_upgrade() {
213 return None;
214 }
215 let handle = ThreadHandle::from_core(core);
216 handle.core.exit_weak_upgrade();
217 Some(handle)
218 }
219}
220
221#[derive(Debug)]
228pub struct ThreadWakeHandle {
229 pub(crate) core: ManuallyDrop<Arc<ThreadCore>>,
230 reap_signal: Arc<ThreadReapSignal>,
231}
232
233impl Drop for ThreadWakeHandle {
234 fn drop(&mut self) {
235 unsafe {
236 ManuallyDrop::drop(&mut self.core);
238 }
239 self.reap_signal.release_external_lease();
240 }
241}
242
243impl Clone for ThreadWakeHandle {
244 fn clone(&self) -> Self {
245 let core = Arc::clone(&self.core);
246 let reap_signal = Arc::clone(&self.reap_signal);
247 reap_signal.acquire_external_lease();
248 Self {
249 core: ManuallyDrop::new(core),
250 reap_signal,
251 }
252 }
253}
254
255impl ThreadWakeHandle {
256 pub(crate) fn from_core(core: Arc<ThreadCore>) -> Self {
257 let reap_signal = Arc::clone(&core.reap_signal);
258 reap_signal.acquire_external_lease();
259 Self {
260 core: ManuallyDrop::new(core),
261 reap_signal,
262 }
263 }
264
265 pub fn wake(&self) -> WakeResult {
270 self.core.wake(WakeIntent::Normal)
271 }
272
273 pub fn wake_sync(&self) -> WakeResult {
278 debug_assert!(!crate::runtime::task_runtime::in_hard_irq());
279 self.core.wake(WakeIntent::Sync)
280 }
281
282 pub(crate) fn deliver_wait_claim_from_task(
283 &self,
284 claim: &crate::thread::WaitWakeClaim,
285 intent: WakeIntent,
286 ) -> crate::thread::WaitWakeDelivery {
287 crate::runtime::context::wake_wait_claim_from_task(&self.core, claim, intent)
288 }
289
290 pub fn thread_id(&self) -> ThreadId {
292 self.core.id
293 }
294}
295
296impl ThreadCore {
297 fn wake(self: &Arc<Self>, intent: WakeIntent) -> WakeResult {
298 crate::runtime::context::wake_thread_from_current_cpu(self, intent)
299 }
300}
301
302#[derive(Clone, Copy, Debug, Eq, PartialEq)]
303pub(crate) enum WakeIntent {
304 Normal,
305 Sync,
306}
307
308impl WakeIntent {
309 pub(crate) const fn is_sync(self) -> bool {
310 matches!(self, Self::Sync)
311 }
312}
313
314#[derive(Clone, Copy, Debug, Eq, PartialEq)]
316pub enum WakeResult {
317 Notified,
320 AlreadyPending,
322 Exited,
324 Unavailable,
326}
327
328#[derive(Clone, Copy, Debug, Eq, PartialEq)]
330pub struct ThreadRuntimeSnapshot {
331 charged_runtime_ns: u64,
332 running: bool,
333}
334
335impl ThreadRuntimeSnapshot {
336 pub const fn charged_runtime_ns(self) -> u64 {
338 self.charged_runtime_ns
339 }
340
341 pub const fn is_running(self) -> bool {
343 self.running
344 }
345}
346
347#[derive(Debug)]
348struct ThreadReapSignal {
349 exited: AtomicBool,
350 external_leases: AtomicUsize,
351 task_work: Option<Arc<TaskWorkDoorbell>>,
352}
353
354#[must_use = "the scheduler activity guard serializes owner delivery against exit"]
355pub(crate) struct ThreadSchedulerActivity<'thread> {
356 core: &'thread ThreadCore,
357 preempt: PreemptGuardToken,
358 _not_send: PhantomData<*mut ()>,
359}
360
361impl Drop for ThreadSchedulerActivity<'_> {
362 fn drop(&mut self) {
363 self.core.finish_scheduler_activity();
364 release_scheduler_preempt(self.preempt);
365 }
366}
367
368#[must_use = "the owned scheduler exit guard closes new activity until exit commits"]
369pub(crate) struct OwnedThreadSchedulerExit {
370 core: Arc<ThreadCore>,
371 preempt: PreemptGuardToken,
372 sealed: bool,
373 _not_send: PhantomData<*mut ()>,
374}
375
376impl OwnedThreadSchedulerExit {
377 pub(crate) fn seal(&mut self) {
378 self.sealed = true;
379 }
380}
381
382impl Drop for OwnedThreadSchedulerExit {
383 fn drop(&mut self) {
384 if !self.sealed {
385 self.core.reopen_scheduler_activity();
386 }
387 release_scheduler_preempt(self.preempt);
388 }
389}
390
391fn release_scheduler_preempt(token: PreemptGuardToken) {
392 if token.is_none() {
393 return;
394 }
395 unsafe { task_runtime::preempt_guard_exit(token) };
399}
400
401#[must_use = "dropping the delivery lease makes an exited thread reapable"]
402pub(crate) struct ThreadSchedulerInboxDelivery<'thread> {
403 core: &'thread ThreadCore,
404}
405
406impl Drop for ThreadSchedulerInboxDelivery<'_> {
407 fn drop(&mut self) {
408 self.core.finish_scheduler_inbox_delivery();
409 }
410}
411
412impl ThreadReapSignal {
413 fn new(task_work: Option<Arc<TaskWorkDoorbell>>) -> Self {
414 Self {
415 exited: AtomicBool::new(false),
416 external_leases: AtomicUsize::new(0),
417 task_work,
418 }
419 }
420
421 fn mark_exited(&self) {
422 self.exited.store(true, Ordering::Release);
423 }
424
425 fn publish(&self) {
426 if let Some(task_work) = &self.task_work {
427 task_work.publish();
428 }
429 }
430
431 fn acquire_external_lease(&self) {
432 self.external_leases
433 .try_update(Ordering::AcqRel, Ordering::Acquire, |leases| {
434 leases.checked_add(1)
435 })
436 .expect("thread external-lifetime lease count overflow");
437 }
438
439 fn release_external_lease(&self) {
440 let previous = self.external_leases.fetch_sub(1, Ordering::AcqRel);
441 assert!(previous != 0, "unbalanced thread external-lifetime lease");
442 if previous == 1 && self.exited.load(Ordering::Acquire) {
443 self.publish();
444 }
445 }
446
447 fn external_lease_count(&self) -> usize {
448 self.external_leases.load(Ordering::Acquire)
449 }
450}
451
452#[derive(Debug)]
453pub(crate) struct ThreadCore {
454 id: ThreadId,
455 sched: Arc<ThreadSchedCell>,
456 membarrier_identity: AtomicUsize,
459 runqueue_nodes: RunQueueNodeStorage,
460 pi_wait_nodes: PiWaitNodeStorage,
461 extension: Option<ThreadExtensionView>,
464 pub(crate) execution: Option<Arc<crate::thread::execution::ThreadExecution>>,
465 pub(crate) execution_reclaimed: AtomicBool,
466 scheduler_tick_cpu_time: Option<Arc<SchedulerTickCpuTime>>,
467 scheduler_tick_work: Option<SchedulerTickWork>,
468 scheduler_tick_work_generation: AtomicU64,
469 scheduler_tick_observed_ns: AtomicU64,
470 scheduler_tick_work_node: InboxNode,
471 deadline_callback_node: InboxNode,
472 base_policy: AtomicPolicy,
473 effective_policy: AtomicPolicy,
474 effective_key_sequence: AtomicUsize,
475 effective_deadline_active: AtomicBool,
476 effective_deadline_ns: AtomicU64,
477 state: Arc<ThreadLifecycle>,
478 reap_signal: Arc<ThreadReapSignal>,
479 reap_gate: AtomicUsize,
480 scheduler_activity_gate: AtomicUsize,
481 scheduler_inbox_deliveries: AtomicUsize,
482 pub(super) affinity_completion: ThreadAffinityCompletion,
483 park_generation: AtomicU64,
484 park_sequence: AtomicU64,
485 rt_lock_depth: AtomicUsize,
486 ordinary_park_generation: AtomicU64,
487 wake_cpu_hint: AtomicU32,
488 wake_affinity: WakeAffinityState,
489 affinity_update_node: InboxNode,
490 deadline_refresh_node: InboxNode,
491 wake_batch_next: AtomicPtr<ThreadCore>,
492 wake_batch_linked: AtomicBool,
493 sleep_timer: TaskDeadlineNode,
494 deadline_cbs_timer: TaskDeadlineNode,
495 deadline_zero_lag_timer: TaskDeadlineNode,
496 sleep_timer_cpu: AtomicU32,
497 sleep_timer_generation: AtomicU64,
498 migration_node: InboxNode,
499 committed_runtime_ns: AtomicU64,
500 #[cfg(feature = "lockdep")]
501 held_locks: ThreadHeldLocks,
502 pi_wait_state: PiWaitState,
503}
504
505pub(crate) struct ThreadCoreInit {
506 pub(crate) id: ThreadId,
507 pub(crate) policy: SchedulePolicy,
508 pub(crate) sched: Arc<ThreadSchedCell>,
509 pub(crate) extension: Option<ThreadExtensionView>,
510 pub(crate) execution: Option<Arc<crate::thread::execution::ThreadExecution>>,
511 pub(crate) scheduler_tick_cpu_time: Option<Arc<SchedulerTickCpuTime>>,
512 pub(crate) scheduler_tick_work: Option<SchedulerTickWork>,
513 pub(crate) membarrier_identity: AddressSpaceMembarrierId,
514 pub(crate) task_work: Option<Arc<TaskWorkDoorbell>>,
515}
516
517impl ThreadCore {
518 pub(crate) fn new(init: ThreadCoreInit) -> Result<Self, TaskError> {
519 let ThreadCoreInit {
520 id,
521 policy,
522 sched,
523 extension,
524 execution,
525 scheduler_tick_cpu_time,
526 scheduler_tick_work,
527 membarrier_identity,
528 task_work,
529 } = init;
530 debug_assert_eq!(id, sched.id());
531 let lifecycle = Arc::clone(sched.lifecycle());
532 let reap_signal = crate::thread::allocation::try_arc(ThreadReapSignal::new(task_work))?;
533 Ok(Self {
534 id,
535 sched,
536 membarrier_identity: AtomicUsize::new(membarrier_identity.into_raw()),
537 runqueue_nodes: RunQueueNodeStorage::new()?,
538 pi_wait_nodes: PiWaitNodeStorage::new()?,
539 extension,
540 execution,
541 execution_reclaimed: AtomicBool::new(false),
542 scheduler_tick_cpu_time,
543 scheduler_tick_work,
544 scheduler_tick_work_generation: AtomicU64::new(0),
545 scheduler_tick_observed_ns: AtomicU64::new(0),
546 scheduler_tick_work_node: InboxNode::new(InboxKind::TaskWork),
547 deadline_callback_node: InboxNode::new(InboxKind::TaskWork),
548 base_policy: AtomicPolicy::new(policy),
549 effective_policy: AtomicPolicy::new(policy),
550 effective_key_sequence: AtomicUsize::new(0),
551 effective_deadline_active: AtomicBool::new(false),
552 effective_deadline_ns: AtomicU64::new(0),
553 state: lifecycle,
554 reap_signal,
555 reap_gate: AtomicUsize::new(0),
556 scheduler_activity_gate: AtomicUsize::new(0),
557 scheduler_inbox_deliveries: AtomicUsize::new(0),
558 affinity_completion: ThreadAffinityCompletion::new(1),
559 park_generation: AtomicU64::new(0),
560 park_sequence: AtomicU64::new(0),
561 rt_lock_depth: AtomicUsize::new(0),
562 ordinary_park_generation: AtomicU64::new(0),
563 wake_cpu_hint: AtomicU32::new(u32::MAX),
564 wake_affinity: WakeAffinityState::new(),
565 affinity_update_node: InboxNode::new(InboxKind::OwnerControl),
566 deadline_refresh_node: InboxNode::new(InboxKind::OwnerControl),
567 wake_batch_next: AtomicPtr::new(core::ptr::null_mut()),
568 wake_batch_linked: AtomicBool::new(false),
569 sleep_timer: TaskDeadlineNode::for_thread(id),
570 deadline_cbs_timer: TaskDeadlineNode::deadline_cbs_for_thread(id),
571 deadline_zero_lag_timer: TaskDeadlineNode::deadline_zero_lag_for_thread(id),
572 sleep_timer_cpu: AtomicU32::new(u32::MAX),
573 sleep_timer_generation: AtomicU64::new(0),
574 migration_node: InboxNode::new(InboxKind::OwnerControl),
575 committed_runtime_ns: AtomicU64::new(0),
576 #[cfg(feature = "lockdep")]
577 held_locks: ThreadHeldLocks::new(),
578 pi_wait_state: PiWaitState::new(),
579 })
580 }
581
582 pub(crate) const fn runqueue_nodes(&self) -> &RunQueueNodeStorage {
583 &self.runqueue_nodes
584 }
585
586 pub(crate) const fn pi_wait_nodes(&self) -> &PiWaitNodeStorage {
587 &self.pi_wait_nodes
588 }
589
590 pub(crate) fn membarrier_identity(&self) -> AddressSpaceMembarrierId {
591 let raw = self.membarrier_identity.load(Ordering::Acquire);
592 unsafe { AddressSpaceMembarrierId::from_raw(raw) }
596 }
597
598 pub(crate) fn publish_membarrier_identity(&self, identity: AddressSpaceMembarrierId) {
599 self.membarrier_identity
600 .store(identity.into_raw(), Ordering::Release);
601 }
602
603 #[cfg(feature = "lockdep")]
610 pub(crate) unsafe fn with_held_locks<R>(
611 &self,
612 operation: impl FnOnce(&mut crate::sync::lockdep::HeldLockStack) -> R,
613 ) -> R {
614 unsafe { self.held_locks.with_mut(operation) }
615 }
616}
617
618mod lifecycle;
619mod policy;
620mod runtime_accounting;
621mod wake_affinity;
622mod wake_state;
623
624use policy::AtomicPolicy;
625use wake_affinity::WakeAffinityState;
626
627mod control;