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