diff --git a/src/context/context.rs b/src/context/context.rs
index c01f5424f0..24619645f5 100644
--- a/src/context/context.rs
+++ b/src/context/context.rs
@@ -140,8 +140,6 @@ pub struct Context {
pub fmap_ret: Option,
/// Priority
pub prio: usize,
- /// Enqueued
- pub enqueued: bool,
// TODO: id can reappear after wraparound?
pub owner_proc_id: Option,
@@ -200,7 +198,6 @@ impl Context {
userspace: false,
fmap_ret: None,
prio: 20,
- enqueued: false,
being_sigkilled: false,
owner_proc_id,
diff --git a/src/context/mod.rs b/src/context/mod.rs
index b1eba00320..ce0be59a28 100644
--- a/src/context/mod.rs
+++ b/src/context/mod.rs
@@ -77,6 +77,9 @@ static CONTEXTS: RwLock> = RwLock::new(BTreeSet::new())
// Actual context store for the scheduler
static RUN_CONTEXTS: Mutex = Mutex::new(RunContextData::new());
+// Context that has been pushed out from RUN_CONTEXTS after being idle
+static IDLE_CONTEXTS: Mutex> = Mutex::new(VecDeque::new());
+
pub struct RunContextData {
set: [VecDeque; 40],
}
@@ -100,6 +103,10 @@ pub fn contexts_mut(token: LockToken<'_, L1>) -> RwLockWriteGuard<'_, L2, BTreeS
CONTEXTS.write(token)
}
+pub fn idle_contexts(token: LockToken<'_, L1>) -> MutexGuard<'_, L2, VecDeque> {
+ IDLE_CONTEXTS.lock(token)
+}
+
pub fn run_contexts(token: LockToken<'_, L0>) -> MutexGuard<'_, L1, RunContextData> {
RUN_CONTEXTS.lock(token)
}
@@ -118,7 +125,6 @@ pub fn init(token: &mut CleanLockToken) {
context.status = Status::Runnable;
context.running = true;
context.cpu_id = Some(crate::cpu_id());
- context.enqueued = false;
let priority = context.prio;
@@ -136,25 +142,6 @@ pub fn init(token: &mut CleanLockToken) {
}
}
-pub fn wakeup_context(context_lock: &Arc>, mut token: LockToken) {
- let priority = {
- let mut context = context_lock.write(token.token());
-
- context.wake = None;
- context.unblock();
-
- if !(context.status.is_runnable() && !context.running && !context.enqueued) {
- return;
- }
-
- context.enqueued = true;
-
- context.prio
- };
-
- run_contexts(token).set[priority].push_back(ContextRef(Arc::clone(context_lock)));
-}
-
pub fn current() -> Arc {
PercpuBlock::current()
.switch_internals
@@ -219,9 +206,8 @@ pub fn spawn(
let context_ref = ContextRef(Arc::clone(&context_lock));
let run_ref = ContextRef(Arc::clone(&context_lock));
- run_contexts(token.token()).set[20].push_back(run_ref);
- contexts_mut(token.token().downgrade()).insert(context_ref);
- context_lock.write(token.token()).enqueued = true;
+ idle_contexts(token.downgrade()).push_back(run_ref);
+ contexts_mut(token.downgrade()).insert(context_ref);
Ok(context_lock)
}
diff --git a/src/context/switch.rs b/src/context/switch.rs
index 6ab88a935b..cc58b9efb1 100644
--- a/src/context/switch.rs
+++ b/src/context/switch.rs
@@ -3,7 +3,10 @@
//! handling process states and synchronization.
use crate::{
- context::{self, arch, contexts, run_contexts, ArcContextLockWriteGuard, Context, ContextLock},
+ context::{
+ self, arch, contexts, idle_contexts, run_contexts, ArcContextLockWriteGuard, Context,
+ ContextLock,
+ },
cpu_set::LogicalCpuId,
cpu_stats::{self, CpuState},
percpu::PercpuBlock,
@@ -22,6 +25,7 @@ use super::ContextRef;
enum UpdateResult {
CanSwitch,
Skip,
+ Blocked,
}
// A simple geometric series where value[i] ~= value[i - 1] * 1.25
@@ -72,7 +76,7 @@ unsafe fn update_runnable(
if context.status.is_runnable() {
UpdateResult::CanSwitch
} else {
- UpdateResult::Skip
+ UpdateResult::Blocked
}
}
@@ -177,34 +181,52 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult {
let mut wakeups = Vec::new();
{
let current_context = context::current();
- let idle_context = percpu.switch_internals.idle_context();
-
- let mut contexts_guard = contexts(token.downgrade());
- let (context, mut token) = contexts_guard.token_split();
- for context_ref in context.iter().filter_map(|r| r.upgrade()) {
+ 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, ¤t_context) {
+ idle_contexts.push_back(ContextRef(context_ref));
continue;
}
- if Arc::ptr_eq(&context_ref, &idle_context) {
+ let Some(guard) = context_ref.try_read(token.token()) else {
+ idle_contexts.push_back(ContextRef(context_ref));
continue;
- }
- let guard = context_ref.read(token.token());
+ };
if guard.status.is_soft_blocked() {
if let Some(wake) = guard.wake {
if switch_time >= wake {
- wakeups.push(Arc::clone(&context_ref));
+ let prio = guard.prio;
+ drop(guard);
+ wakeups.push((prio, ContextRef(context_ref)));
continue;
}
}
}
- if guard.status.is_runnable() && !guard.enqueued && !guard.running {
- wakeups.push(Arc::clone(&context_ref));
+ 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));
}
}
- for context_lock in wakeups {
- context::wakeup_context(&context_lock, token.token());
+
+ if wakeups.len() > 0 {
+ let mut run_contexts = run_contexts(token.token());
+ for (prio, context_lock) in wakeups {
+ run_contexts.set[prio].push_back(context_lock);
+ }
}
let cpu_id = crate::cpu_id();
@@ -334,8 +356,10 @@ fn select_next_context(
was_idle: bool,
prev_context_guard: &mut ArcRwLockWriteGuard,
) -> Result