Make wake up optional

This commit is contained in:
Wildan M
2026-04-26 07:15:10 +07:00
parent 643726852b
commit ea1d915bbc
2 changed files with 58 additions and 46 deletions
+6
View File
@@ -107,6 +107,12 @@ pub fn idle_contexts(token: LockToken<'_, L1>) -> MutexGuard<'_, L2, VecDeque<Co
IDLE_CONTEXTS.lock(token)
}
pub fn idle_contexts_try(
token: LockToken<'_, L1>,
) -> Option<MutexGuard<'_, L2, VecDeque<ContextRef>>> {
IDLE_CONTEXTS.try_lock(token)
}
pub fn run_contexts(token: LockToken<'_, L0>) -> MutexGuard<'_, L1, RunContextData> {
RUN_CONTEXTS.lock(token)
}
+52 -46
View File
@@ -4,8 +4,8 @@
use crate::{
context::{
self, arch, contexts, idle_contexts, run_contexts, ArcContextLockWriteGuard, Context,
ContextLock,
self, arch, contexts, idle_contexts, idle_contexts_try, run_contexts,
ArcContextLockWriteGuard, Context, ContextLock,
},
cpu_set::LogicalCpuId,
cpu_stats::{self, CpuState},
@@ -177,50 +177,7 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult {
}
// Alarm (previously in update_runnable)
// TODO: Optimise this somehow. Perhaps using a separate timer queue?
let mut wakeups = Vec::new();
{
let current_context = context::current();
let idle_contexts = idle_contexts(token.downgrade());
let (mut idle_contexts, mut token) = idle_contexts.into_split();
let len = idle_contexts.len();
for i in 0..len {
let Some(context_ref) = idle_contexts.pop_front() else {
break;
};
let Some(context_ref) = context_ref.upgrade() else {
continue;
};
if Arc::ptr_eq(&context_ref, &current_context) {
idle_contexts.push_back(ContextRef(context_ref));
continue;
}
let Some(guard) = context_ref.try_read(token.token()) else {
idle_contexts.push_back(ContextRef(context_ref));
continue;
};
if guard.status.is_soft_blocked() {
if let Some(wake) = guard.wake {
if switch_time >= wake {
let prio = guard.prio;
drop(guard);
wakeups.push((prio, ContextRef(context_ref)));
continue;
}
}
}
if guard.status.is_runnable() && !guard.running {
let prio = guard.prio;
drop(guard);
wakeups.push((prio, ContextRef(context_ref)));
continue;
}
drop(guard);
idle_contexts.push_back(ContextRef(context_ref));
}
}
let wakeups = wakeup_contexts(token, switch_time);
if wakeups.len() > 0 {
let mut run_contexts = run_contexts(token.token());
@@ -347,6 +304,55 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult {
}
}
fn wakeup_contexts(token: &mut CleanLockToken, switch_time: u128) -> Vec<(usize, ContextRef)> {
// TODO: Optimise this somehow. Perhaps using a separate timer queue?
let mut wakeups = Vec::new();
let current_context = context::current();
let Some(idle_contexts) = idle_contexts_try(token.downgrade()) else {
// other cpus may spawning or killing contexts so let's skip wakeups to avoid contention
return wakeups;
};
let (mut idle_contexts, mut token) = idle_contexts.into_split();
let len = idle_contexts.len();
for i in 0..len {
let Some(context_ref) = idle_contexts.pop_front() else {
break;
};
let Some(context_ref) = context_ref.upgrade() else {
continue;
};
if Arc::ptr_eq(&context_ref, &current_context) {
idle_contexts.push_back(ContextRef(context_ref));
continue;
}
let Some(guard) = context_ref.try_read(token.token()) else {
idle_contexts.push_back(ContextRef(context_ref));
continue;
};
if guard.status.is_soft_blocked() {
if let Some(wake) = guard.wake {
if switch_time >= wake {
let prio = guard.prio;
drop(guard);
wakeups.push((prio, ContextRef(context_ref)));
continue;
}
}
}
if guard.status.is_runnable() && !guard.running {
let prio = guard.prio;
drop(guard);
wakeups.push((prio, ContextRef(context_ref)));
continue;
}
drop(guard);
idle_contexts.push_back(ContextRef(context_ref));
}
wakeups
}
/// This is the scheduler function which currently utilises Deficit Weighted Round Robin Scheduler
fn select_next_context(
token: &mut CleanLockToken,