diff --git a/src/context/mod.rs b/src/context/mod.rs index 40bac5190b..88d238773a 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -132,6 +132,7 @@ pub fn init(token: &mut CleanLockToken) { percpu .switch_internals .set_current_context(Arc::clone(&context_lock)); + percpu.switch_internals.set_idle_context(context_lock); } run_contexts(token.downgrade()).set[priority].push_back(context_ref); diff --git a/src/context/switch.rs b/src/context/switch.rs index 601991f6e5..904f506bf5 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -177,6 +177,7 @@ 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(); @@ -184,6 +185,9 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult { if Arc::ptr_eq(&context_ref, ¤t_context) { continue; } + if Arc::ptr_eq(&context_ref, &idle_context) { + continue; + } let guard = context_ref.read(token.token()); if guard.status.is_soft_blocked() { if let Some(wake) = guard.wake { @@ -447,8 +451,14 @@ fn select_next_context( return Ok(Some(next_context_guard)); } else { - // We found no other process to run. - Ok(None) + let idle_context = percpu.switch_internals.idle_context(); + if !Arc::ptr_eq(&prev_context_lock, &idle_context) { + // We switch into the idle context + Ok(Some(unsafe { idle_context.write_arc() })) + } else { + // We found no other process to run. + Ok(None) + } } } @@ -463,6 +473,8 @@ pub struct ContextSwitchPercpu { current_ctxt: RefCell>>, + /// The idle process. + idle_ctxt: RefCell>>, pub(crate) being_sigkilled: Cell, } @@ -473,6 +485,7 @@ impl ContextSwitchPercpu { switch_time: Cell::new(0), pit_ticks: Cell::new(0), current_ctxt: RefCell::new(None), + idle_ctxt: RefCell::new(None), being_sigkilled: Cell::new(false), } } @@ -513,4 +526,28 @@ impl ContextSwitchPercpu { pub unsafe fn set_current_context(&self, new: Arc) { *self.current_ctxt.borrow_mut() = Some(new); } + + /// Sets the idle context to a new value. + /// + /// # Safety + /// This function is unsafe as it modifies the idle context state directly. + /// + /// # Parameters + /// - `new`: The new context to be set as the idle context. + pub unsafe fn set_idle_context(&self, new: Arc) { + *self.idle_ctxt.borrow_mut() = Some(new); + } + + /// Retrieves the current idle context. + /// + /// # Returns + /// A reference to the idle context. + pub fn idle_context(&self) -> Arc { + Arc::clone( + self.idle_ctxt + .borrow() + .as_ref() + .expect("no idle context present"), + ) + } }