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 into_wake_handle(self) -> ThreadWakeHandle {
173 let handle = ManuallyDrop::new(self);
174 unsafe {
179 ThreadWakeHandle {
180 core: core::ptr::read(&handle.core),
181 reap_signal: core::ptr::read(&handle.reap_signal),
182 }
183 }
184 }
185
186 pub fn scheduler_fence_cpu(&self) -> Option<CpuId> {
194 self.core.sched().scheduler_fence_cpu()
195 }
196
197 pub fn assigned_cpu(&self) -> Option<CpuId> {
204 self.core.assigned_cpu()
205 }
206
207 pub(crate) fn extension_view(&self) -> Option<crate::thread::ThreadExtensionView> {
208 self.core.extension_view()
209 }
210}
211
212impl Eq for ThreadHandle {}
213
214impl PartialEq for ThreadHandle {
215 fn eq(&self, other: &Self) -> bool {
216 self.id() == other.id()
217 }
218}
219
220#[derive(Clone, Debug)]
222pub struct WeakThreadHandle {
223 core: Weak<ThreadCore>,
224}
225
226impl WeakThreadHandle {
227 pub fn upgrade(&self) -> Option<ThreadHandle> {
229 let core = self.core.upgrade()?;
230 if !core.try_enter_weak_upgrade() {
231 return None;
232 }
233 let handle = ThreadHandle::from_core(core);
234 handle.core.exit_weak_upgrade();
235 Some(handle)
236 }
237}
238
239#[derive(Debug)]
246pub struct ThreadWakeHandle {
247 pub(crate) core: ManuallyDrop<Arc<ThreadCore>>,
248 reap_signal: Arc<ThreadReapSignal>,
249}
250
251impl Drop for ThreadWakeHandle {
252 fn drop(&mut self) {
253 unsafe {
254 ManuallyDrop::drop(&mut self.core);
256 }
257 self.reap_signal.release_external_lease();
258 }
259}
260
261impl Clone for ThreadWakeHandle {
262 fn clone(&self) -> Self {
263 let core = Arc::clone(&self.core);
264 let reap_signal = Arc::clone(&self.reap_signal);
265 reap_signal.acquire_external_lease();
266 Self {
267 core: ManuallyDrop::new(core),
268 reap_signal,
269 }
270 }
271}
272
273impl ThreadWakeHandle {
274 pub(crate) fn from_core(core: Arc<ThreadCore>) -> Self {
275 let reap_signal = Arc::clone(&core.reap_signal);
276 reap_signal.acquire_external_lease();
277 Self {
278 core: ManuallyDrop::new(core),
279 reap_signal,
280 }
281 }
282
283 pub fn wake(&self) -> WakeResult {
288 self.core.wake(WakeIntent::Normal)
289 }
290
291 pub fn wake_sync(&self) -> WakeResult {
296 debug_assert!(!crate::runtime::task_runtime::in_hard_irq());
297 self.core.wake(WakeIntent::Sync)
298 }
299
300 pub(crate) fn deliver_wait_claim_from_task(
301 &self,
302 claim: &crate::thread::WaitWakeClaim,
303 intent: WakeIntent,
304 ) -> crate::thread::WaitWakeDelivery {
305 crate::runtime::context::wake_wait_claim_from_task(&self.core, claim, intent)
306 }
307
308 pub fn thread_id(&self) -> ThreadId {
310 self.core.id
311 }
312}
313
314impl ThreadCore {
315 fn wake(self: &Arc<Self>, intent: WakeIntent) -> WakeResult {
316 crate::runtime::context::wake_thread_from_current_cpu(self, intent)
317 }
318}
319
320#[derive(Clone, Copy, Debug, Eq, PartialEq)]
321pub(crate) enum WakeIntent {
322 Normal,
323 Sync,
324}
325
326impl WakeIntent {
327 pub(crate) const fn is_sync(self) -> bool {
328 matches!(self, Self::Sync)
329 }
330}
331
332#[derive(Clone, Copy, Debug, Eq, PartialEq)]
334pub enum WakeResult {
335 Notified,
338 AlreadyPending,
340 Exited,
342 Unavailable,
344}
345
346#[derive(Clone, Copy, Debug, Eq, PartialEq)]
348pub struct ThreadRuntimeSnapshot {
349 charged_runtime_ns: u64,
350 running: bool,
351}
352
353impl ThreadRuntimeSnapshot {
354 pub const fn charged_runtime_ns(self) -> u64 {
356 self.charged_runtime_ns
357 }
358
359 pub const fn is_running(self) -> bool {
361 self.running
362 }
363}
364
365#[derive(Debug)]
366struct ThreadReapSignal {
367 exited: AtomicBool,
368 external_leases: AtomicUsize,
369 task_work: Option<Arc<TaskWorkDoorbell>>,
370}
371
372#[must_use = "the scheduler activity guard serializes owner delivery against exit"]
373pub(crate) struct ThreadSchedulerActivity<'thread> {
374 core: &'thread ThreadCore,
375 preempt: PreemptGuardToken,
376 _not_send: PhantomData<*mut ()>,
377}
378
379impl Drop for ThreadSchedulerActivity<'_> {
380 fn drop(&mut self) {
381 self.core.finish_scheduler_activity();
382 release_scheduler_preempt(self.preempt);
383 }
384}
385
386#[must_use = "the owned scheduler exit guard closes new activity until exit commits"]
387pub(crate) struct OwnedThreadSchedulerExit {
388 core: Arc<ThreadCore>,
389 preempt: PreemptGuardToken,
390 sealed: bool,
391 _not_send: PhantomData<*mut ()>,
392}
393
394impl OwnedThreadSchedulerExit {
395 pub(crate) fn seal(&mut self) {
396 self.sealed = true;
397 }
398}
399
400impl Drop for OwnedThreadSchedulerExit {
401 fn drop(&mut self) {
402 if !self.sealed {
403 self.core.reopen_scheduler_activity();
404 }
405 release_scheduler_preempt(self.preempt);
406 }
407}
408
409fn release_scheduler_preempt(token: PreemptGuardToken) {
410 if token.is_none() {
411 return;
412 }
413 unsafe { task_runtime::preempt_guard_exit(token) };
417}
418
419#[must_use = "dropping the delivery lease makes an exited thread reapable"]
420pub(crate) struct ThreadSchedulerInboxDelivery<'thread> {
421 core: &'thread ThreadCore,
422}
423
424impl Drop for ThreadSchedulerInboxDelivery<'_> {
425 fn drop(&mut self) {
426 self.core.finish_scheduler_inbox_delivery();
427 }
428}
429
430impl ThreadReapSignal {
431 fn new(task_work: Option<Arc<TaskWorkDoorbell>>) -> Self {
432 Self {
433 exited: AtomicBool::new(false),
434 external_leases: AtomicUsize::new(0),
435 task_work,
436 }
437 }
438
439 fn mark_exited(&self) {
440 self.exited.store(true, Ordering::Release);
441 }
442
443 fn publish(&self) {
444 if let Some(task_work) = &self.task_work {
445 task_work.publish();
446 }
447 }
448
449 fn acquire_external_lease(&self) {
450 self.external_leases
451 .try_update(Ordering::AcqRel, Ordering::Acquire, |leases| {
452 leases.checked_add(1)
453 })
454 .expect("thread external-lifetime lease count overflow");
455 }
456
457 fn release_external_lease(&self) {
458 let previous = self.external_leases.fetch_sub(1, Ordering::AcqRel);
459 assert!(previous != 0, "unbalanced thread external-lifetime lease");
460 if previous == 1 && self.exited.load(Ordering::Acquire) {
461 self.publish();
462 }
463 }
464
465 fn external_lease_count(&self) -> usize {
466 self.external_leases.load(Ordering::Acquire)
467 }
468}
469
470#[derive(Debug)]
471pub(crate) struct ThreadCore {
472 id: ThreadId,
473 sched: Arc<ThreadSchedCell>,
474 membarrier_identity: AtomicUsize,
477 runqueue_nodes: RunQueueNodeStorage,
478 pi_wait_nodes: PiWaitNodeStorage,
479 extension: Option<ThreadExtensionView>,
482 pub(crate) execution: Option<Arc<crate::thread::execution::ThreadExecution>>,
483 pub(crate) execution_reclaimed: AtomicBool,
484 scheduler_tick_cpu_time: Option<Arc<SchedulerTickCpuTime>>,
485 scheduler_tick_work: Option<SchedulerTickWork>,
486 scheduler_tick_work_generation: AtomicU64,
487 scheduler_tick_observed_ns: AtomicU64,
488 scheduler_tick_work_node: InboxNode,
489 deadline_callback_node: InboxNode,
490 base_policy: AtomicPolicy,
491 effective_policy: AtomicPolicy,
492 effective_key_sequence: AtomicUsize,
493 effective_deadline_active: AtomicBool,
494 effective_deadline_ns: AtomicU64,
495 state: Arc<ThreadLifecycle>,
496 reap_signal: Arc<ThreadReapSignal>,
497 reap_gate: AtomicUsize,
498 scheduler_activity_gate: AtomicUsize,
499 scheduler_inbox_deliveries: AtomicUsize,
500 pub(super) affinity_completion: ThreadAffinityCompletion,
501 park_generation: AtomicU64,
502 park_sequence: AtomicU64,
503 rt_lock_depth: AtomicUsize,
504 ordinary_park_generation: AtomicU64,
505 wake_cpu_hint: AtomicU32,
506 wake_affinity: WakeAffinityState,
507 affinity_update_node: InboxNode,
508 deadline_refresh_node: InboxNode,
509 wake_batch_next: AtomicPtr<ThreadCore>,
510 wake_batch_linked: AtomicBool,
511 sleep_timer: TaskDeadlineNode,
512 deadline_cbs_timer: TaskDeadlineNode,
513 deadline_zero_lag_timer: TaskDeadlineNode,
514 sleep_timer_cpu: AtomicU32,
515 sleep_timer_generation: AtomicU64,
516 migration_node: InboxNode,
517 committed_runtime_ns: AtomicU64,
518 #[cfg(feature = "lockdep")]
519 held_locks: ThreadHeldLocks,
520 pi_wait_state: PiWaitState,
521}
522
523pub(crate) struct ThreadCoreInit {
524 pub(crate) id: ThreadId,
525 pub(crate) policy: SchedulePolicy,
526 pub(crate) sched: Arc<ThreadSchedCell>,
527 pub(crate) extension: Option<ThreadExtensionView>,
528 pub(crate) execution: Option<Arc<crate::thread::execution::ThreadExecution>>,
529 pub(crate) scheduler_tick_cpu_time: Option<Arc<SchedulerTickCpuTime>>,
530 pub(crate) scheduler_tick_work: Option<SchedulerTickWork>,
531 pub(crate) membarrier_identity: AddressSpaceMembarrierId,
532 pub(crate) task_work: Option<Arc<TaskWorkDoorbell>>,
533}
534
535impl ThreadCore {
536 pub(crate) fn new(init: ThreadCoreInit) -> Result<Self, TaskError> {
537 let ThreadCoreInit {
538 id,
539 policy,
540 sched,
541 extension,
542 execution,
543 scheduler_tick_cpu_time,
544 scheduler_tick_work,
545 membarrier_identity,
546 task_work,
547 } = init;
548 debug_assert_eq!(id, sched.id());
549 let lifecycle = Arc::clone(sched.lifecycle());
550 let reap_signal = crate::thread::allocation::try_arc(ThreadReapSignal::new(task_work))?;
551 Ok(Self {
552 id,
553 sched,
554 membarrier_identity: AtomicUsize::new(membarrier_identity.into_raw()),
555 runqueue_nodes: RunQueueNodeStorage::new()?,
556 pi_wait_nodes: PiWaitNodeStorage::new()?,
557 extension,
558 execution,
559 execution_reclaimed: AtomicBool::new(false),
560 scheduler_tick_cpu_time,
561 scheduler_tick_work,
562 scheduler_tick_work_generation: AtomicU64::new(0),
563 scheduler_tick_observed_ns: AtomicU64::new(0),
564 scheduler_tick_work_node: InboxNode::new(InboxKind::TaskWork),
565 deadline_callback_node: InboxNode::new(InboxKind::TaskWork),
566 base_policy: AtomicPolicy::new(policy),
567 effective_policy: AtomicPolicy::new(policy),
568 effective_key_sequence: AtomicUsize::new(0),
569 effective_deadline_active: AtomicBool::new(false),
570 effective_deadline_ns: AtomicU64::new(0),
571 state: lifecycle,
572 reap_signal,
573 reap_gate: AtomicUsize::new(0),
574 scheduler_activity_gate: AtomicUsize::new(0),
575 scheduler_inbox_deliveries: AtomicUsize::new(0),
576 affinity_completion: ThreadAffinityCompletion::new(1),
577 park_generation: AtomicU64::new(0),
578 park_sequence: AtomicU64::new(0),
579 rt_lock_depth: AtomicUsize::new(0),
580 ordinary_park_generation: AtomicU64::new(0),
581 wake_cpu_hint: AtomicU32::new(u32::MAX),
582 wake_affinity: WakeAffinityState::new(),
583 affinity_update_node: InboxNode::new(InboxKind::OwnerControl),
584 deadline_refresh_node: InboxNode::new(InboxKind::OwnerControl),
585 wake_batch_next: AtomicPtr::new(core::ptr::null_mut()),
586 wake_batch_linked: AtomicBool::new(false),
587 sleep_timer: TaskDeadlineNode::for_thread(id),
588 deadline_cbs_timer: TaskDeadlineNode::deadline_cbs_for_thread(id),
589 deadline_zero_lag_timer: TaskDeadlineNode::deadline_zero_lag_for_thread(id),
590 sleep_timer_cpu: AtomicU32::new(u32::MAX),
591 sleep_timer_generation: AtomicU64::new(0),
592 migration_node: InboxNode::new(InboxKind::OwnerControl),
593 committed_runtime_ns: AtomicU64::new(0),
594 #[cfg(feature = "lockdep")]
595 held_locks: ThreadHeldLocks::new(),
596 pi_wait_state: PiWaitState::new(),
597 })
598 }
599
600 pub(crate) const fn runqueue_nodes(&self) -> &RunQueueNodeStorage {
601 &self.runqueue_nodes
602 }
603
604 pub(crate) const fn pi_wait_nodes(&self) -> &PiWaitNodeStorage {
605 &self.pi_wait_nodes
606 }
607
608 pub(crate) fn membarrier_identity(&self) -> AddressSpaceMembarrierId {
609 let raw = self.membarrier_identity.load(Ordering::Acquire);
610 unsafe { AddressSpaceMembarrierId::from_raw(raw) }
614 }
615
616 pub(crate) fn publish_membarrier_identity(&self, identity: AddressSpaceMembarrierId) {
617 self.membarrier_identity
618 .store(identity.into_raw(), Ordering::Release);
619 }
620
621 #[cfg(feature = "lockdep")]
628 pub(crate) unsafe fn with_held_locks<R>(
629 &self,
630 operation: impl FnOnce(&mut crate::sync::lockdep::HeldLockStack) -> R,
631 ) -> R {
632 unsafe { self.held_locks.with_mut(operation) }
633 }
634}
635
636mod lifecycle;
637mod policy;
638mod runtime_accounting;
639mod wake_affinity;
640mod wake_state;
641
642use policy::AtomicPolicy;
643use wake_affinity::WakeAffinityState;
644
645mod control;