diff --git a/src/context/switch.rs b/src/context/switch.rs index d45485848c..8988478a0f 100644 --- a/src/context/switch.rs +++ b/src/context/switch.rs @@ -208,11 +208,23 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult { let cpu_id = crate::cpu_id(); - let mut switch_context_opt = - match select_next_context(token, percpu, cpu_id, switch_time, &mut prev_context_guard) { - Ok(opt) => opt, - Err(early_ret) => return early_ret, - }; + // Update per-cpu times + let percpu_nanos = switch_time.saturating_sub(percpu.switch_internals.switch_time.get()) as u64; + let percpu_ms = percpu_nanos / 1_000_000; + let was_idle = percpu.stats.add_time(percpu_ms) == CpuState::Idle as u8; + percpu.switch_internals.switch_time.set(switch_time); + + let mut switch_context_opt = match select_next_context( + token, + percpu, + cpu_id, + switch_time, + was_idle, + &mut prev_context_guard, + ) { + Ok(opt) => opt, + Err(early_ret) => return early_ret, + }; if switch_context_opt.is_none() { let mut this_contexts = contexts_mut(token.token()); @@ -233,12 +245,6 @@ pub fn switch(token: &mut CleanLockToken) -> SwitchResult { } } - // Update per-cpu times - let percpu_nanos = switch_time.saturating_sub(percpu.switch_internals.switch_time.get()) as u64; - let percpu_ms = percpu_nanos / 1_000_000; - let was_idle = percpu.stats.add_time(percpu_ms) == CpuState::Idle as u8; - percpu.switch_internals.switch_time.set(switch_time); - // Switch process states, TSS stack pointer, and store new context ID match switch_context_opt { Some(mut next_context_guard) => { @@ -343,6 +349,7 @@ fn select_next_context( percpu: &PercpuBlock, cpu_id: LogicalCpuId, switch_time: u128, + was_idle: bool, prev_context_guard: &mut ArcRwLockWriteGuard, ) -> Result, SwitchResult> { let mut contexts_data = run_contexts(token.token()); @@ -424,6 +431,12 @@ fn select_next_context( continue; // Lazy removal of blocked contexts } + // Do not spawn the kernel (the idle context) again after idling, + // otherwise the next switch will idling again + if was_idle && !next_context_guard.userspace { + continue; + } + // Is this context runnable on this CPU? if let UpdateResult::CanSwitch = unsafe { update_runnable(&mut next_context_guard, cpu_id, switch_time) }