use crate::{
sched::{CpuId, SchedulingClass},
thread::ThreadId,
};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum InboxKind {
OwnerControl,
Reclaim,
TaskWork,
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum InboxOperation {
Migration,
AffinityUpdate,
DeadlineRefresh,
BalanceRequest,
Reclaim,
SchedulerTick,
DeadlineOverrun,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct InboxMessage {
kind: InboxKind,
operation: InboxOperation,
thread_id: ThreadId,
source_cpu: u32,
target_cpu: u32,
generation: u64,
placement_demand: u64,
balance_class: Option<SchedulingClass>,
payload: usize,
}
impl InboxMessage {
const NO_CPU: u32 = u32::MAX;
pub const EMPTY: Self = Self {
kind: InboxKind::Reclaim,
operation: InboxOperation::Reclaim,
thread_id: ThreadId::from_parts(0, 0),
source_cpu: Self::NO_CPU,
target_cpu: Self::NO_CPU,
generation: 0,
placement_demand: 0,
balance_class: None,
payload: 0,
};
pub const fn migration_with_payload(
thread_id: ThreadId,
source_cpu: CpuId,
target_cpu: CpuId,
generation: u64,
placement_demand: u64,
payload: usize,
) -> Self {
Self {
kind: InboxKind::OwnerControl,
operation: InboxOperation::Migration,
thread_id,
source_cpu: source_cpu.as_u32(),
target_cpu: target_cpu.as_u32(),
generation,
placement_demand,
balance_class: None,
payload,
}
}
pub const fn affinity_update_with_payload(
thread_id: ThreadId,
owner: CpuId,
target_cpu: CpuId,
payload: usize,
) -> Self {
Self {
kind: InboxKind::OwnerControl,
operation: InboxOperation::AffinityUpdate,
thread_id,
source_cpu: owner.as_u32(),
target_cpu: target_cpu.as_u32(),
generation: thread_id.generation() as u64,
placement_demand: 0,
balance_class: None,
payload,
}
}
pub const fn deadline_refresh_with_payload(
thread_id: ThreadId,
owner: CpuId,
generation: u64,
payload: usize,
) -> Self {
Self {
kind: InboxKind::OwnerControl,
operation: InboxOperation::DeadlineRefresh,
thread_id,
source_cpu: owner.as_u32(),
target_cpu: owner.as_u32(),
generation,
placement_demand: 0,
balance_class: None,
payload,
}
}
pub const fn balance_request(
source_cpu: CpuId,
target_cpu: CpuId,
reservation: u64,
class: SchedulingClass,
) -> Self {
Self {
kind: InboxKind::OwnerControl,
operation: InboxOperation::BalanceRequest,
thread_id: ThreadId::from_parts(0, 0),
source_cpu: source_cpu.as_u32(),
target_cpu: target_cpu.as_u32(),
generation: reservation,
placement_demand: 0,
balance_class: Some(class),
payload: 0,
}
}
pub const fn is_balance_request(self) -> bool {
self.operation as u8 == InboxOperation::BalanceRequest as u8 && self.payload == 0
}
pub const fn balance_reservation(self) -> Option<u64> {
if self.is_balance_request() {
Some(self.generation)
} else {
None
}
}
pub const fn balance_class(self) -> Option<SchedulingClass> {
if self.is_balance_request() {
self.balance_class
} else {
None
}
}
pub const fn reclaim(thread_id: ThreadId, generation: u64, payload: usize) -> Self {
Self {
kind: InboxKind::Reclaim,
operation: InboxOperation::Reclaim,
thread_id,
source_cpu: Self::NO_CPU,
target_cpu: Self::NO_CPU,
generation,
placement_demand: 0,
balance_class: None,
payload,
}
}
pub const fn scheduler_tick(thread_id: ThreadId, payload: usize) -> Self {
Self {
kind: InboxKind::TaskWork,
operation: InboxOperation::SchedulerTick,
thread_id,
source_cpu: Self::NO_CPU,
target_cpu: Self::NO_CPU,
generation: thread_id.generation() as u64,
placement_demand: 0,
balance_class: None,
payload,
}
}
pub const fn deadline_overrun(thread_id: ThreadId, payload: usize) -> Self {
Self {
kind: InboxKind::TaskWork,
operation: InboxOperation::DeadlineOverrun,
thread_id,
source_cpu: Self::NO_CPU,
target_cpu: Self::NO_CPU,
generation: thread_id.generation() as u64,
placement_demand: 0,
balance_class: None,
payload,
}
}
pub const fn kind(self) -> InboxKind {
self.kind
}
pub const fn operation(self) -> InboxOperation {
self.operation
}
pub const fn thread_id(self) -> ThreadId {
self.thread_id
}
pub const fn source_cpu(self) -> Option<CpuId> {
if self.source_cpu == Self::NO_CPU {
None
} else {
Some(CpuId::new(self.source_cpu))
}
}
pub const fn target_cpu(self) -> Option<CpuId> {
if self.target_cpu == Self::NO_CPU {
None
} else {
Some(CpuId::new(self.target_cpu))
}
}
pub const fn placement_demand(self) -> u64 {
self.placement_demand
}
pub const fn payload(self) -> usize {
self.payload
}
}