mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-04-17 13:48:38 -04:00
sched: Work: deref into Arc<Task> rather than OwnedTask
Since a Arc<Work> can be obtained from `TASK_LIST`, this would allow the potential mutation of 'owned'-state from other CPUs thereby causing a race condition. Thefore, ensure that the deref of an `Arc<Work>` only permits access to `t_shared`.
This commit is contained in:
@@ -60,7 +60,7 @@ pub async fn sys_capget(hdrp: TUA<CapUserHeader>, datap: TUA<CapUserData>) -> Re
|
||||
.iter()
|
||||
.find(|task| task.0.tgid.value() == header.pid as u32)
|
||||
.and_then(|task| task.1.upgrade())
|
||||
.map(|x| x.t_shared.clone())
|
||||
.map(|x| (*x).clone())
|
||||
.ok_or(KernelError::NoProcess)?
|
||||
};
|
||||
match header.version {
|
||||
@@ -96,7 +96,7 @@ pub async fn sys_capset(hdrp: TUA<CapUserHeader>, datap: TUA<CapUserData>) -> Re
|
||||
.iter()
|
||||
.find(|task| task.0.tgid.value() == header.pid as u32)
|
||||
.and_then(|task| task.1.upgrade())
|
||||
.map(|x| x.t_shared.clone())
|
||||
.map(|x| (*x).clone())
|
||||
.ok_or(KernelError::NoProcess)?
|
||||
};
|
||||
|
||||
|
||||
@@ -218,11 +218,11 @@ impl SchedState {
|
||||
{
|
||||
let current = self.run_q.current_mut();
|
||||
|
||||
current.task.update_accounting(Some(now_inst));
|
||||
current.work.task.update_accounting(Some(now_inst));
|
||||
|
||||
// Reset accounting baseline after updating stats to avoid double-counting
|
||||
// the same time interval on the next scheduler tick.
|
||||
current.task.reset_last_account(now_inst);
|
||||
current.work.reset_last_account(now_inst);
|
||||
}
|
||||
|
||||
self.run_q.schedule(now_inst)
|
||||
@@ -270,7 +270,7 @@ pub fn sys_sched_yield() -> Result<usize> {
|
||||
}
|
||||
|
||||
pub fn current_work() -> Arc<Work> {
|
||||
SCHED_STATE.borrow().run_q.current().task.clone()
|
||||
SCHED_STATE.borrow().run_q.current().work.clone()
|
||||
}
|
||||
|
||||
pub fn current_work_waker() -> Waker {
|
||||
|
||||
@@ -101,8 +101,8 @@ impl RunQueue {
|
||||
let mut deferred_drops: Vec<RunnableTask> = Vec::new();
|
||||
|
||||
if let Some(mut cur_task) = self.running_task.take() {
|
||||
prev_task = Arc::as_ptr(&cur_task.task);
|
||||
let state = cur_task.task.state.load(Ordering::Acquire);
|
||||
prev_task = Arc::as_ptr(&cur_task.work);
|
||||
let state = cur_task.work.state.load(Ordering::Acquire);
|
||||
match state {
|
||||
TaskState::Running | TaskState::Woken => {
|
||||
if cur_task.tick(now) {
|
||||
@@ -116,7 +116,7 @@ impl RunQueue {
|
||||
TaskState::PendingSleep | TaskState::PendingStop => {
|
||||
// Task wants to deactivate. Drop the RunnableTask now to
|
||||
// restore sched_data.
|
||||
let work = cur_task.task.clone();
|
||||
let work = cur_task.work.clone();
|
||||
cur_task.sched_data.last_cpu = ArchImpl::id();
|
||||
self.total_weight = self.total_weight.saturating_sub(cur_task.weight() as u64);
|
||||
drop(cur_task);
|
||||
@@ -138,17 +138,17 @@ impl RunQueue {
|
||||
{
|
||||
next_task.about_to_execute(now);
|
||||
|
||||
if Arc::as_ptr(&next_task.task) != prev_task {
|
||||
if Arc::as_ptr(&next_task.work) != prev_task {
|
||||
// If we scheduled a different task than before, context switch.
|
||||
NUM_CONTEXT_SWITCHES.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
next_task.switch_context();
|
||||
|
||||
next_task.task.reset_last_account(now);
|
||||
next_task.work.reset_last_account(now);
|
||||
|
||||
CUR_TASK_PTR
|
||||
.borrow_mut()
|
||||
.set_current(Box::as_ptr(&next_task.task.task) as *mut _);
|
||||
.set_current(Box::as_ptr(&next_task.work.task) as *mut _);
|
||||
}
|
||||
|
||||
self.running_task = Some(next_task);
|
||||
@@ -158,7 +158,7 @@ impl RunQueue {
|
||||
|
||||
CUR_TASK_PTR
|
||||
.borrow_mut()
|
||||
.set_current(Box::as_ptr(&self.idle.task.task) as *mut _);
|
||||
.set_current(Box::as_ptr(&self.idle.work.task) as *mut _);
|
||||
}
|
||||
|
||||
deferred_drops
|
||||
@@ -192,7 +192,7 @@ impl RunQueue {
|
||||
}
|
||||
|
||||
while let Some(ByDeadline(best)) = self.eligible.pop() {
|
||||
if best.task.state.load(Ordering::Acquire).is_finished() {
|
||||
if best.work.state.load(Ordering::Acquire).is_finished() {
|
||||
self.total_weight = self.total_weight.saturating_sub(best.weight() as u64);
|
||||
deferred_drops.push(best);
|
||||
continue;
|
||||
@@ -211,8 +211,9 @@ impl RunQueue {
|
||||
None
|
||||
}
|
||||
|
||||
fn enqueue(&mut self, task: RunnableTask) {
|
||||
task.task.state.mark_runnable();
|
||||
fn enqueue(&mut self, mut task: RunnableTask) {
|
||||
task.refresh_priority();
|
||||
task.work.state.mark_runnable();
|
||||
|
||||
if self.v_clock.is_task_eligible(&task) {
|
||||
self.eligible.push(ByDeadline(task));
|
||||
|
||||
@@ -7,7 +7,7 @@ use super::{DEFAULT_TIME_SLICE, SCHED_WEIGHT_BASE, VT_FIXED_SHIFT};
|
||||
use crate::{
|
||||
arch::{Arch, ArchImpl},
|
||||
drivers::timer::{Instant, schedule_preempt},
|
||||
process::owned::OwnedTask,
|
||||
process::{Task, owned::OwnedTask},
|
||||
sync::SpinLock,
|
||||
};
|
||||
|
||||
@@ -16,12 +16,6 @@ use state::TaskStateMachine;
|
||||
|
||||
pub mod state;
|
||||
|
||||
pub struct Work {
|
||||
pub task: Box<OwnedTask>,
|
||||
pub state: TaskStateMachine,
|
||||
pub sched_data: SpinLock<Option<SchedulerData>>,
|
||||
}
|
||||
|
||||
pub const NR_CPUS: usize = 256;
|
||||
pub const CPU_MASK_SIZE: usize = NR_CPUS / 64;
|
||||
|
||||
@@ -37,10 +31,11 @@ pub struct SchedulerData {
|
||||
pub last_run: Option<Instant>,
|
||||
pub last_cpu: usize,
|
||||
pub cpu_mask: [u64; CPU_MASK_SIZE],
|
||||
pub priority: i8,
|
||||
}
|
||||
|
||||
impl SchedulerData {
|
||||
fn new() -> Self {
|
||||
fn new(task: &Box<OwnedTask>) -> Self {
|
||||
Self {
|
||||
v_runtime: 0,
|
||||
v_eligible: 0,
|
||||
@@ -50,58 +45,72 @@ impl SchedulerData {
|
||||
last_run: None,
|
||||
last_cpu: usize::MAX,
|
||||
cpu_mask: [u64::MAX; CPU_MASK_SIZE],
|
||||
priority: task.priority(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Work {
|
||||
pub task: Box<OwnedTask>,
|
||||
pub state: TaskStateMachine,
|
||||
pub sched_data: SpinLock<Option<SchedulerData>>,
|
||||
}
|
||||
|
||||
|
||||
impl Deref for Work {
|
||||
type Target = Arc<Task>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.task.t_shared
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Work {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.task.t_shared
|
||||
}
|
||||
}
|
||||
|
||||
impl Work {
|
||||
pub fn new(task: Box<OwnedTask>) -> Arc<Self> {
|
||||
let sched_data = SchedulerData::new(&task);
|
||||
|
||||
Arc::new(Self {
|
||||
task,
|
||||
state: TaskStateMachine::new(),
|
||||
sched_data: SpinLock::new(Some(sched_data)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_runnable(self: Arc<Self>) -> RunnableTask {
|
||||
let mut sd = self
|
||||
.sched_data
|
||||
.lock_save_irq()
|
||||
.take()
|
||||
.expect("Should have sched data");
|
||||
|
||||
// Refresh priority.
|
||||
sd.priority = self.task.priority();
|
||||
|
||||
RunnableTask {
|
||||
work: self,
|
||||
sched_data: sd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RunnableTask {
|
||||
pub(super) task: Arc<Work>,
|
||||
pub(super) work: Arc<Work>,
|
||||
pub(super) sched_data: SchedulerData,
|
||||
}
|
||||
|
||||
impl Drop for RunnableTask {
|
||||
// Replace the hot sched info back into the struct.
|
||||
fn drop(&mut self) {
|
||||
*self.task.sched_data.lock_save_irq() = Some(self.sched_data.clone());
|
||||
*self.work.sched_data.lock_save_irq() = Some(self.sched_data.clone());
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Work {
|
||||
type Target = OwnedTask;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.task
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for Work {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.task
|
||||
}
|
||||
}
|
||||
|
||||
impl Work {
|
||||
pub fn new(task: Box<OwnedTask>) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
task,
|
||||
state: TaskStateMachine::new(),
|
||||
sched_data: SpinLock::new(Some(SchedulerData::new())),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn into_runnable(self: Arc<Self>) -> RunnableTask {
|
||||
let sd = self
|
||||
.sched_data
|
||||
.lock_save_irq()
|
||||
.take()
|
||||
.expect("Should have sched data");
|
||||
|
||||
RunnableTask {
|
||||
task: self,
|
||||
sched_data: sd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RunnableTask {
|
||||
type Target = SchedulerData;
|
||||
@@ -161,7 +170,7 @@ impl RunnableTask {
|
||||
/// weight = priority + SCHED_WEIGHT_BASE
|
||||
/// The sum is clamped to a minimum of 1
|
||||
pub fn weight(&self) -> u32 {
|
||||
let w = self.task.priority() as i32 + SCHED_WEIGHT_BASE;
|
||||
let w = self.sched_data.priority as i32 + SCHED_WEIGHT_BASE;
|
||||
if w <= 0 { 1 } else { w as u32 }
|
||||
}
|
||||
|
||||
@@ -199,7 +208,7 @@ impl RunnableTask {
|
||||
/// Setup task accounting info such that it is about to be executed.
|
||||
pub fn about_to_execute(&mut self, now: Instant) {
|
||||
self.exec_start = Some(now);
|
||||
self.task.state.activate();
|
||||
self.work.state.activate();
|
||||
|
||||
// Deadline logic
|
||||
if self.deadline.is_none_or(|d| d <= now + DEFAULT_TIME_SLICE) {
|
||||
@@ -212,6 +221,10 @@ impl RunnableTask {
|
||||
}
|
||||
|
||||
pub fn switch_context(&self) {
|
||||
ArchImpl::context_switch(self.task.t_shared.clone());
|
||||
ArchImpl::context_switch(self.work.task.t_shared.clone());
|
||||
}
|
||||
|
||||
pub fn refresh_priority(&mut self) {
|
||||
self.sched_data.priority = self.work.task.priority();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user