use super::*;
use crate::{
sched::{
algorithm::{
BalanceScan, EnqueueReason, FairEntity, LinkedRqTaskRef, PickTaskResult, PickedThread,
QueuedThreadSnapshot, RtEligibility,
},
system::{
task_system::{SwitchEndpoint, TaskSystem},
thread_sched::{SchedulerPlacement, ThreadSchedCell, ThreadSchedState},
},
},
thread::SchedulingUrgency,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(in crate::sched::system) enum OwnerRqTaskState {
Current,
Queued { outgoing: bool },
DelayedFair { outgoing: bool },
Inactive,
}
impl OwnerRqTaskState {
pub(in crate::sched::system) const fn is_current(self) -> bool {
matches!(self, Self::Current)
}
pub(in crate::sched::system) const fn is_queued(self) -> bool {
matches!(self, Self::Queued { .. })
}
pub(in crate::sched::system) const fn is_runnable(self) -> bool {
matches!(self, Self::Current | Self::Queued { .. })
}
pub(in crate::sched::system) const fn is_delayed_fair(self) -> bool {
matches!(self, Self::DelayedFair { .. })
}
}
#[derive(Clone, Copy)]
pub(crate) enum OwnerRqEntry {
IrqSave,
SchedulerFrame,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum OwnerRqContext {
RuntimeIrqSave,
SchedulerFrame,
OfflineBootstrap,
}
impl OwnerRqEntry {
pub(crate) const fn requires_owner_context_validation(self) -> bool {
matches!(self, Self::IrqSave)
}
pub(in crate::sched::system) unsafe fn lock_thread_sched(
self,
cell: &ThreadSchedCell,
) -> IrqTicketGuard<'_, ThreadSchedState> {
match self {
Self::IrqSave => cell.lock(),
Self::SchedulerFrame => {
unsafe { cell.lock_scheduler_frame() }
}
}
}
#[inline(always)]
pub(crate) unsafe fn begin<'a>(
self,
system: &'a TaskSystem,
remote: &'a CpuRemote,
) -> OwnerRqTxn<'a> {
match self {
Self::IrqSave => OwnerRqTxn::begin(system, remote),
Self::SchedulerFrame => {
unsafe { OwnerRqTxn::begin_scheduler(system, remote) }
}
}
}
}
pub(crate) struct OwnerRqTxn<'a> {
system: &'a TaskSystem,
remote: &'a CpuRemote,
run_queue: Option<IrqTicketGuard<'a, CpuRunQueueState>>,
clock: RunQueueClockSnapshot,
request: Option<SchedulerRequestClaim>,
context: OwnerRqContext,
finished: bool,
}
#[derive(Debug)]
pub(crate) struct RqSwitchBaton {
owner: CpuId,
_raw: RawTicketBaton<CpuRunQueueState>,
}
impl RqSwitchBaton {
pub(crate) fn finish(self, owner: CpuId) -> Result<(), TaskError> {
if self.owner != owner {
return Err(TaskError::InvalidConfiguration);
}
drop(self);
Ok(())
}
}
impl<'a> OwnerRqTxn<'a> {
fn run_queue(&self) -> &CpuRunQueueState {
self.run_queue
.as_ref()
.expect("an unfinished rq transaction must retain its lock")
}
fn run_queue_mut(&mut self) -> &mut CpuRunQueueState {
self.run_queue
.as_mut()
.expect("an unfinished rq transaction must retain its lock")
}
fn scheduler_queue_mut(&mut self) -> &mut RunQueue {
self.run_queue_mut().owner_transaction_queue_mut()
}
pub(crate) fn begin(system: &'a TaskSystem, remote: &'a CpuRemote) -> Self {
let mut run_queue = remote.lock_run_queue(RunQueueGuardSource::Transaction);
let clock = run_queue.update_clock();
#[cfg(feature = "qperf-metrics")]
crate::diagnostics::counters::record_owner_rq_irqsave_transaction();
Self {
system,
remote,
run_queue: Some(run_queue),
clock,
request: None,
context: OwnerRqContext::RuntimeIrqSave,
finished: false,
}
}
pub(crate) fn begin_nested(
system: &'a TaskSystem,
remote: &'a CpuRemote,
irq_owner: &'a IrqOwner<'_>,
) -> Self {
let mut run_queue = remote.lock_run_queue_nested(irq_owner);
let clock = run_queue.update_clock();
#[cfg(feature = "qperf-metrics")]
crate::diagnostics::counters::record_owner_rq_irqsave_transaction();
Self {
system,
remote,
run_queue: Some(run_queue),
clock,
request: None,
context: OwnerRqContext::RuntimeIrqSave,
finished: false,
}
}
pub(crate) unsafe fn begin_scheduler(system: &'a TaskSystem, remote: &'a CpuRemote) -> Self {
#[cfg(feature = "qperf-metrics")]
let rq_lock_started_ns = task_runtime::monotonic_now().as_nanos();
let mut run_queue = unsafe { remote.lock_run_queue_irq_disabled() };
#[cfg(feature = "qperf-metrics")]
let rq_lock_finished_ns = task_runtime::monotonic_now().as_nanos();
let clock = run_queue.update_clock();
#[cfg(feature = "qperf-metrics")]
{
let rq_clock_finished_ns = task_runtime::monotonic_now().as_nanos();
crate::diagnostics::counters::qperf_record_switch_scheduler_detail(
13,
rq_lock_started_ns,
rq_lock_finished_ns,
);
crate::diagnostics::counters::qperf_record_switch_scheduler_detail(
14,
rq_lock_finished_ns,
rq_clock_finished_ns,
);
crate::diagnostics::counters::record_owner_rq_scheduler_transaction();
}
Self {
system,
remote,
run_queue: Some(run_queue),
clock,
request: None,
context: OwnerRqContext::SchedulerFrame,
finished: false,
}
}
pub(crate) unsafe fn begin_bootstrap(system: &'a TaskSystem, remote: &'a CpuRemote) -> Self {
let mut run_queue = unsafe { remote.lock_run_queue_irq_disabled() };
let clock = run_queue.update_clock();
#[cfg(feature = "qperf-metrics")]
crate::diagnostics::counters::record_owner_rq_bootstrap_transaction();
Self {
system,
remote,
run_queue: Some(run_queue),
clock,
request: None,
context: OwnerRqContext::OfflineBootstrap,
finished: false,
}
}
pub(crate) const fn clock(&self) -> RunQueueClockSnapshot {
self.clock
}
pub(crate) const fn owner(&self) -> CpuId {
self.remote.owner()
}
pub(crate) fn current_runtime_deadline(&self) -> SchedulerRuntimeDeadline {
self.run_queue().current_runtime_deadline()
}
pub(crate) fn scheduler_deadline_rq_observation(
&self,
cpu: &CpuLocal,
) -> SchedulerDeadlineRqObservation {
assert_eq!(
cpu.owner(),
self.owner(),
"scheduler deadline observation must use its owner CPU transaction"
);
cpu.scheduler_deadline_rq_observation_in_run_queue(self.run_queue())
}
pub(crate) fn claim_scheduler_request(
&mut self,
scope: SchedulerRequestScope,
) -> SchedulerRequestClaim {
let claim = self.remote.claim_scheduler_request(scope);
self.request = Some(self.request.map_or(claim, |current| current.merge(claim)));
self.request
.expect("scheduler request claim was just installed")
}
pub(crate) fn adopt_scheduler_request(&mut self, claim: SchedulerRequestClaim) {
assert!(
self.request.replace(claim).is_none(),
"one rq transaction may adopt only one initial scheduler claim"
);
}
pub(crate) fn merge_scheduler_request(
&mut self,
scope: SchedulerRequestScope,
) -> SchedulerRequestClaim {
self.claim_scheduler_request(scope)
}
}
impl Deref for OwnerRqTxn<'_> {
type Target = CpuRunQueueState;
fn deref(&self) -> &Self::Target {
self.run_queue
.as_ref()
.expect("an unfinished rq transaction must retain its lock")
}
}
impl Drop for OwnerRqTxn<'_> {
fn drop(&mut self) {
if !self.finished {
task_runtime::fatal_invariant(0x5251_5458, self.remote.owner().as_u32() as usize);
}
}
}
mod observation;
mod membership;
mod selection;
mod accounting;
mod commit;