Skip to content

Commit

Permalink
Introduce idle process to fully avoid busy waiting
Browse files Browse the repository at this point in the history
  • Loading branch information
sysheap committed Dec 1, 2024
1 parent 17d859e commit 29e7609
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 28 deletions.
7 changes: 6 additions & 1 deletion kernel/src/debugging/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ pub fn dump_current_state() {
let current_process = get_current_process();
if let Some(process) = current_process {
let process = process.lock();
info!("Current process:\n{:?}", *process);
info!(
"Current Process: PID={} NAME={} STATE={:?}",
process.get_pid(),
process.get_name(),
process.get_state()
);
}
}
15 changes: 11 additions & 4 deletions kernel/src/interrupts/trap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
page_tables::{KERNEL_PAGE_TABLES, activate_page_table},
},
processes::{
scheduler::{self, get_current_process},
scheduler::{self, get_current_process, is_idle_process_running},
timer,
},
syscalls::handle_syscall,
Expand All @@ -32,10 +32,9 @@ extern "C" fn supervisor_mode_trap(
debug!("Activate KERNEL_PAGE_TABLES");
activate_page_table(&KERNEL_PAGE_TABLES);
debug!(
"Supervisor mode trap occurred! (sepc: {:x?}) (cause: {:?})\nTrap Frame: {:?}",
"Supervisor mode trap occurred! (sepc: {:x?}) (cause: {:?})",
sepc,
cause.get_reason(),
trap_frame
);
if cause.is_interrupt() {
handle_interrupt(cause, stval, sepc, trap_frame);
Expand Down Expand Up @@ -115,7 +114,15 @@ fn handle_interrupt(cause: InterruptCause, _stval: usize, _sepc: usize, _trap_fr
}

fn handle_supervisor_timer_interrupt() {
timer::set_timer(10);
if is_idle_process_running() {
debug!("Deactivate timer interrupt for idle process");
// We only want to wake up if the idle is not running
// If the idle process is schedule it means that no other
// process is able to make progress.
timer::disable_timer();
} else {
timer::set_timer(10);
}
scheduler::schedule();
}

Expand Down
3 changes: 2 additions & 1 deletion kernel/src/logging/configuration.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// This variable contains the list of modules that should be logged. If "kernel" is specified, every module is logged.
const LOG_FOLLOWING_MODULES: &[&str] = &[];
const DONT_LOG_FOLLOWING_MODULES: &[&str] = &["kernel::interrupts::trap"];
const DONT_LOG_FOLLOWING_MODULES: &[&str] =
&["kernel::interrupts::trap", "kernel::debugging::unwinder"];

// TODO: This should be made compile-time, such that this thing doesn't need to be queried at runtime.
pub fn should_log_module(module_name: &str) -> bool {
Expand Down
1 change: 1 addition & 0 deletions kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ extern "C" fn kernel_init(hart_id: usize, device_tree_pointer: *const ()) {
memory::init_page_allocator(&[device_tree_range]);

backtrace::init();
processes::timer::init();

#[cfg(test)]
test_main();
Expand Down
10 changes: 10 additions & 0 deletions kernel/src/processes/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub struct Process {
free_mmap_address: usize,
next_free_descriptor: u64,
open_udp_sockets: BTreeMap<UDPDescriptor, SharedAssignedSocket>,
idle_process: bool,
}

impl Debug for Process {
Expand Down Expand Up @@ -86,6 +87,14 @@ impl Process {
ptr
}

pub fn set_as_idle_process(&mut self) {
self.idle_process = true;
}

pub fn is_idle_process(&self) -> bool {
self.idle_process
}

pub fn register_state_ptr(&self) -> *const TrapFrame {
self.register_state.as_ref() as *const TrapFrame
}
Expand Down Expand Up @@ -145,6 +154,7 @@ impl Process {
free_mmap_address: FREE_MMAP_START_ADDRESS,
next_free_descriptor: 0,
open_udp_sockets: BTreeMap::new(),
idle_process: false,
}
}

Expand Down
26 changes: 20 additions & 6 deletions kernel/src/processes/process_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ use common::mutex::Mutex;

use crate::info;

use super::process::{Pid, Process, ProcessState};
use super::{
process::{Pid, Process, ProcessState},
timer,
};

static PROCESSES: Mutex<VecDeque<Arc<Mutex<Process>>>> = Mutex::new(VecDeque::new());

Expand Down Expand Up @@ -31,19 +34,24 @@ pub fn dump() {
pub fn next_runnable() -> Option<Arc<Mutex<Process>>> {
let mut processes = PROCESSES.lock();
let mut index_to_remove = None;
let mut index_to_remove_idle = None;

for (index, process) in processes.iter().enumerate() {
if process.lock().get_state() == ProcessState::Runnable {
// Replace this condition with your property
index_to_remove = Some(index);
break;
let process = process.lock();
if process.get_state() == ProcessState::Runnable {
if process.is_idle_process() {
index_to_remove_idle = Some(index);
} else {
index_to_remove = Some(index);
break;
}
}
}

if let Some(index) = index_to_remove {
processes.remove(index)
} else {
None
processes.remove(index_to_remove_idle.expect("There must always be an idle process."))
}
}

Expand All @@ -69,10 +77,16 @@ pub fn notify_died(pid: Pid) {

pub fn notify_input() {
let processes = PROCESSES.lock();
let mut notified = false;
for process in processes.iter() {
let mut process = process.lock();
if process.get_state() == ProcessState::WaitingForInput {
process.set_state(ProcessState::Runnable);
notified = true;
}
}
if notified {
// Let's schedule a new process which can process the input
timer::set_timer(0);
}
}
29 changes: 24 additions & 5 deletions kernel/src/processes/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pub fn initialize() {
add_process(process);

let elf = ElfFile::parse(IDLE).expect("Cannot parse ELF file");
let process = Process::from_elf(&elf, "idle");
let mut process = Process::from_elf(&elf, "idle");
process.set_as_idle_process();
add_process(process);

info!("Scheduler initialized and INIT and IDLE process added to queue");
Expand All @@ -33,6 +34,14 @@ unsafe extern "C" {
fn restore_user_context() -> !;
}

pub fn is_idle_process_running() -> bool {
if let Some(process) = get_current_process() {
process.lock().is_idle_process()
} else {
false
}
}

pub fn get_current_process_expect() -> Arc<Mutex<Process>> {
get_current_process()
.expect("There must be a running current process")
Expand Down Expand Up @@ -110,9 +119,15 @@ fn prepare_next_process() {
let current_process = CURRENT_PROCESS.lock().take();

if let Some(current_process) = current_process {
current_process.lock().set_program_counter(cpu::read_sepc());
debug!("Saved context to current process");
debug!("Current process: {:?}", current_process);
{
let mut current_process = current_process.lock();
current_process.set_program_counter(cpu::read_sepc());
debug!(
"Unscheduling PID={} NAME={}",
current_process.get_pid(),
current_process.get_name()
);
}
process_list::enqueue(current_process);
}

Expand All @@ -137,7 +152,11 @@ fn prepare_next_process() {

page_tables::activate_page_table(page_table);

debug!("Next process: {:?}", next_process);
debug!(
"Scheduling PID={} NAME={}",
next_process.get_pid(),
next_process.get_name()
);
}

*CURRENT_PROCESS.lock() = Some(next_process_ref);
Expand Down
26 changes: 23 additions & 3 deletions kernel/src/processes/timer.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,38 @@
use core::arch::asm;

use crate::sbi;
use common::big_endian::BigEndian;

use crate::{device_tree, klibc::runtime_initialized::RuntimeInitializedData, sbi};

pub const CLINT_BASE: usize = 0x2000000;
pub const CLINT_SIZE: usize = 0x10000;

const CLOCKS_PER_MSEC: u64 = 10_000;
static CLOCKS_PER_SEC: RuntimeInitializedData<u64> = RuntimeInitializedData::new();

pub fn init() {
let clocks_per_sec = device_tree::THE
.root_node()
.find_node("cpus")
.expect("There must be a cpus node")
.get_property("timebase-frequency")
.expect("There must be a timebase-frequency")
.consume_sized_type::<BigEndian<u32>>()
.expect("The value must be u32")
.get() as u64;
CLOCKS_PER_SEC.initialize(clocks_per_sec);
}

pub fn set_timer(milliseconds: u64) {
let current = get_current_clocks();
let next = current + (CLOCKS_PER_MSEC * milliseconds);
assert_eq!(*CLOCKS_PER_SEC / 1000, 10_000);
let next = current + ((*CLOCKS_PER_SEC / 1000) * milliseconds);
sbi::extensions::timer_extension::sbi_set_timer(next).assert_success();
}

pub fn disable_timer() {
sbi::extensions::timer_extension::sbi_set_timer(u64::MAX).assert_success();
}

fn get_current_clocks() -> u64 {
let current: u64;
unsafe {
Expand Down
11 changes: 3 additions & 8 deletions userspace/src/bin/yash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
#![no_main]

use alloc::string::{String, ToString};
use common::syscalls::{sys_execute, sys_exit, sys_read_input, sys_wait};
use userspace::{print, println, util::wait};
use common::syscalls::{sys_execute, sys_exit, sys_read_input_wait, sys_wait};
use userspace::{print, println};

extern crate alloc;
extern crate userspace;
Expand All @@ -19,12 +19,7 @@ fn main() {
print!("$ ");
let mut input = String::new();
loop {
let result = loop {
if let Some(c) = sys_read_input() {
break c;
}
wait(10000);
};
let result = sys_read_input_wait();
match result {
b'\r' => {
// Carriage return
Expand Down

0 comments on commit 29e7609

Please sign in to comment.