diff --git a/src/process/clone.rs b/src/process/clone.rs index a878c18..cec9589 100644 --- a/src/process/clone.rs +++ b/src/process/clone.rs @@ -125,6 +125,7 @@ pub async fn sys_clone( sig_mask: SpinLock::new(new_sigmask), pending_signals: SpinLock::new(SigSet::empty()), state: Arc::new(SpinLock::new(TaskState::Runnable)), + last_run: SpinLock::new(None), } }; diff --git a/src/process/mod.rs b/src/process/mod.rs index fefdc18..0471126 100644 --- a/src/process/mod.rs +++ b/src/process/mod.rs @@ -1,3 +1,4 @@ +use crate::drivers::timer::Instant; use crate::{ arch::{Arch, ArchImpl}, fs::DummyInode, @@ -125,6 +126,7 @@ pub struct Task { pub sig_mask: SpinLock, pub pending_signals: SpinLock, pub priority: i8, + pub last_run: SpinLock>, pub state: Arc>, } @@ -152,6 +154,7 @@ impl Task { sig_mask: SpinLock::new(SigSet::empty()), pending_signals: SpinLock::new(SigSet::empty()), fd_table: Arc::new(SpinLock::new(FileDescriptorTable::new())), + last_run: SpinLock::new(None), } } @@ -172,6 +175,7 @@ impl Task { ctx: SpinLock::new(Context::from_user_ctx( ::new_user_context(VA::null(), VA::null()), )), + last_run: SpinLock::new(None), } } diff --git a/src/sched/mod.rs b/src/sched/mod.rs index 9d0649a..4beaaf9 100644 --- a/src/sched/mod.rs +++ b/src/sched/mod.rs @@ -1,3 +1,4 @@ +use crate::drivers::timer::now; use crate::{ arch::{Arch, ArchImpl}, per_cpu, @@ -5,6 +6,7 @@ use crate::{ sync::OnceLock, }; use alloc::{boxed::Box, collections::btree_map::BTreeMap, sync::Arc}; +use core::cmp::Ordering; use libkernel::{UserAddressSpace, error::Result}; pub mod uspc_ret; @@ -42,6 +44,7 @@ fn schedule() { } let previous_task = current_task(); + *previous_task.last_run.lock_save_irq() = now(); let mut sched_state = SCHED_STATE.borrow_mut(); let next_task = sched_state.find_next_runnable_task(); @@ -125,7 +128,21 @@ impl SchedState { // A process is a candidate if it's runnable and NOT the idle task state == TaskState::Runnable && !candidate_proc.is_idle_task() }) - .max_by_key(|proc| proc.priority()) + .max_by(|proc1, proc2| { + proc1.priority().cmp(&proc2.priority()).then_with(|| { + // If priorities are the same, use last run time to + // decide. + let last_run1 = proc1.last_run.lock_save_irq(); + let last_run2 = proc2.last_run.lock_save_irq(); + + match (*last_run1, *last_run2) { + (Some(t1), Some(t2)) => t1.cmp(&t2), + (Some(_), None) => Ordering::Greater, + (None, Some(_)) => Ordering::Less, + (None, None) => Ordering::Equal, + } + }) + }) .unwrap_or(idle_task) .clone() }