Skip to content

Commit

Permalink
Use spinlock instead of rwlock to use aquire functionality which rais…
Browse files Browse the repository at this point in the history
…es and lowers ipl level accordingly
  • Loading branch information
Lockna committed Sep 12, 2024
1 parent eda66cd commit 6e17507
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 49 deletions.
6 changes: 5 additions & 1 deletion crates/libxernel/src/sync/spin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ impl<T: ?Sized> Spinlock<T> {
OnDrop::new(self.lock(), callback)
}

//pub fn aquire_at(&self, ipl: IPL) -> OnDrop<T, F> {}
pub fn aquire_at(&self, ipl: IPL) -> OnDrop<SpinlockGuard<'_, T>, impl FnOnce()> {
let ipl = raise_ipl(ipl);
let callback = move || splx(ipl);
OnDrop::new(self.lock(), callback)
}

/// Unlocking a spinlock
///
Expand Down
46 changes: 31 additions & 15 deletions xernel/kernel/src/cpu.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use crate::arch::amd64::apic::APIC;
use crate::arch::amd64::{rdmsr, wrmsr, KERNEL_GS_BASE};
use crate::dpc::DpcQueue;
use crate::dpc::{DpcCall, DpcQueue};
use crate::sched::process::Process;
use crate::sched::thread::Thread;
use crate::timer::timer_event::TimerEvent;
use crate::timer::timer_queue::TimerQueue;
use alloc::boxed::Box;
use alloc::collections::VecDeque;
Expand All @@ -12,7 +13,8 @@ use core::cell::{Cell, UnsafeCell};
use core::ops::Deref;
use core::pin::Pin;
use core::sync::atomic::{AtomicUsize, Ordering};
use libxernel::sync::{Once, RwLock, Spinlock};
use libxernel::ipl::IPL;
use libxernel::sync::{Once, Spinlock};

static CPU_ID_COUNTER: AtomicUsize = AtomicUsize::new(0);

Expand Down Expand Up @@ -124,14 +126,28 @@ pub struct Cpu {

cpu_id: usize,
pub lapic_id: u32,
pub run_queue: RwLock<VecDeque<Arc<Thread>>>,
pub wait_queue: RwLock<VecDeque<Arc<Thread>>>,
pub current_thread: RwLock<Option<Arc<Thread>>>,
pub run_queue: Spinlock<VecDeque<Arc<Thread>>>,
pub wait_queue: Spinlock<VecDeque<Arc<Thread>>>,
pub current_thread: Spinlock<Option<Arc<Thread>>>,
pub idle_thread: Arc<Thread>,

pub timer_queue: RwLock<TimerQueue>,
pub dpc_queue: RwLock<DpcQueue>,
pub next: RwLock<Option<Arc<Thread>>>,
pub timer_queue: Spinlock<TimerQueue>,
pub dpc_queue: Spinlock<DpcQueue>,
pub next: Spinlock<Option<Arc<Thread>>>,
}

impl Cpu {
pub fn enqueue_timer(&self, event: TimerEvent) {
self.timer_queue.aquire_at(IPL::High).enqueue(event);
}

pub fn enqueue_dpc(&self, dpc: Box<dyn DpcCall>) {
self.dpc_queue.aquire_at(IPL::High).enqueue(dpc);
}

pub fn enqueue_thread(&self, thread: Arc<Thread>) {
self.run_queue.aquire().push_back(thread)
}
}

pub fn register_cpu() {
Expand All @@ -143,13 +159,13 @@ pub fn register_cpu() {
kernel_stack: Cell::new(0),
cpu_id,
lapic_id,
run_queue: RwLock::new(VecDeque::new()),
wait_queue: RwLock::new(VecDeque::new()),
current_thread: RwLock::new(None),
run_queue: Spinlock::new(VecDeque::new()),
wait_queue: Spinlock::new(VecDeque::new()),
current_thread: Spinlock::new(None),
idle_thread: Arc::new(Thread::idle_thread()),
timer_queue: RwLock::new(TimerQueue::new()),
dpc_queue: RwLock::new(DpcQueue::new()),
next: RwLock::new(None),
timer_queue: Spinlock::new(TimerQueue::new()),
dpc_queue: Spinlock::new(DpcQueue::new()),
next: Spinlock::new(None),
}));

// use KERNEL_GS_BASE to store the cpu_data
Expand All @@ -167,7 +183,7 @@ pub fn current_cpu() -> Pin<&'static Cpu> {
pub fn current_thread() -> Arc<Thread> {
current_cpu()
.current_thread
.read()
.aquire()
.clone()
.unwrap_or(current_cpu().idle_thread.clone())
}
Expand Down
10 changes: 5 additions & 5 deletions xernel/kernel/src/dpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ pub fn enqueue_dpc(dpc: Box<dyn DpcCall>) {
return;
}

current_cpu().dpc_queue.write().enqueue(dpc);
current_cpu().enqueue_dpc(dpc);
raise_dpc_interrupt()
}

Expand All @@ -94,19 +94,19 @@ pub fn dispatch_dpcs(_: &mut TrapFrame) {

while let Some(dpc) = {
let old = raise_ipl(IPL::High);
let mut lock = cpu.dpc_queue.write();
let mut lock = cpu.dpc_queue.lock();
let dpc = lock.dequeue();
write_cr8(old);
dpc
} {
dpc.call();
}

let old = cpu.current_thread.read().clone();
let new = cpu.next.read().clone();
let old = cpu.current_thread.aquire().clone();
let new = cpu.next.aquire().clone();

if old.is_some() && new.is_some() {
*cpu.next.write() = None;
**cpu.next.aquire() = None;
let ipl = get_ipl();

switch_threads(old.unwrap(), new.unwrap());
Expand Down
12 changes: 5 additions & 7 deletions xernel/kernel/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ use crate::sched::process::Process;
use crate::sched::process::KERNEL_PROCESS;
use crate::sched::scheduler::reschedule;
use crate::sched::thread::Thread;
use crate::timer::enqueue_timer;
use crate::timer::hardclock;
use crate::timer::timer_event::TimerEvent;
use crate::utils::backtrace;
Expand Down Expand Up @@ -193,18 +192,17 @@ extern "C" fn kernel_main() -> ! {

let kernel_task2 = Thread::kernel_thread_from_fn(task2);

// TODO: use convenience functions
current_cpu().run_queue.write().push_back(Arc::new(main_task));
current_cpu().run_queue.write().push_back(Arc::new(kernel_task));
current_cpu().run_queue.write().push_back(Arc::new(kernel_task2));
current_cpu().enqueue_thread(Arc::new(main_task));
current_cpu().enqueue_thread(Arc::new(kernel_task));
current_cpu().enqueue_thread(Arc::new(kernel_task2));

let timekeeper = TimerEvent::new(hardclock, (), Duration::from_secs(1), false);

enqueue_timer(timekeeper);
current_cpu().enqueue_timer(timekeeper);

let resched = TimerEvent::new(reschedule, (), Duration::from_millis(5), false);

enqueue_timer(resched);
current_cpu().enqueue_timer(resched);

amd64::interrupts::enable();

Expand Down
22 changes: 10 additions & 12 deletions xernel/kernel/src/sched/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,19 @@ use super::thread::{Thread, ThreadStatus};
pub fn reschedule(_: ()) {
let cpu = current_cpu();

let next_ref = cpu.run_queue.write().pop_front();
let next_ref = cpu.run_queue.aquire().pop_front();

let current_ref = cpu.current_thread.read().clone();
let current_ref = cpu.current_thread.aquire().clone();

let old = if let Some(current_thread) = current_ref {
current_thread.clone()
} else {
*cpu.current_thread.write() = Some(cpu.idle_thread.clone());
**cpu.current_thread.aquire() = Some(cpu.idle_thread.clone());
cpu.idle_thread.clone()
};

let new = if let Some(next_thread) = next_ref {
cpu.run_queue.write().push_back(next_thread.clone());
cpu.run_queue.aquire().push_back(next_thread.clone());

next_thread.clone()
} else {
Expand All @@ -37,26 +37,26 @@ pub fn reschedule(_: ()) {
return;
}

*cpu.next.write() = Some(new);
**cpu.next.aquire() = Some(new);
}

pub fn enqueue_thread(thread: Thread) {
current_cpu().run_queue.write().push_back(Arc::new(thread));
current_cpu().run_queue.aquire().push_back(Arc::new(thread));
}

pub fn dequeue_thread(thread: Arc<Thread>) -> Option<Arc<Thread>> {
let cpu = current_cpu();

let mut index_to_remove = 0;

for (i, thrd) in cpu.run_queue.write().iter().enumerate() {
for (i, thrd) in cpu.run_queue.aquire().iter().enumerate() {
if Arc::ptr_eq(&thread, thrd) {
index_to_remove = i;
break;
}
}

let thread = cpu.run_queue.write().remove(index_to_remove);
let thread = cpu.run_queue.aquire().remove(index_to_remove);
thread
}

Expand Down Expand Up @@ -89,7 +89,7 @@ pub fn switch_threads(old: Arc<Thread>, new: Arc<Thread>) {
}
}

*current_cpu().current_thread.write() = Some(new.clone());
**current_cpu().current_thread.aquire() = Some(new.clone());

unsafe {
switch_context(old.context.get(), *new.context.get());
Expand All @@ -101,7 +101,5 @@ fn register_reschedule_event(millis: u64) {

let cpu = current_cpu();

let mut timer_queue = cpu.timer_queue.write();

timer_queue.enqueue(event);
cpu.enqueue_timer(event);
}
11 changes: 2 additions & 9 deletions xernel/kernel/src/timer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn timer_interrupt_handler(_frame: &mut TrapFrame) {

let cpu = current_cpu();

let mut timer_queue = cpu.timer_queue.write();
let mut timer_queue = cpu.timer_queue.aquire_at(IPL::High);

//timer_queue.deadlines();

Expand All @@ -55,19 +55,12 @@ pub fn timer_interrupt_handler(_frame: &mut TrapFrame) {
} else {
// No event in event queue?
}

timer_queue.unlock();
}

pub fn enqueue_timer(event: TimerEvent) {
current_cpu().timer_queue.write().enqueue(event);
}

pub fn hardclock(_: ()) {
println!("hardclock event with uptime {:?}", UPTIME);
UPTIME.fetch_add(1, Ordering::SeqCst);
let event = TimerEvent::new(hardclock, (), Duration::from_secs(1), false);

// TODO: use convenience functions
current_cpu().timer_queue.write().enqueue(event);
current_cpu().enqueue_timer(event);
}

0 comments on commit 6e17507

Please sign in to comment.