Răsfoiți Sursa

fix: irq handlers should be unlocked when being handled

greatbridf 3 săptămâni în urmă
părinte
comite
9aae18ed2e
2 a modificat fișierele cu 8 adăugiri și 10 ștergeri
  1. 8 9
      src/kernel/interrupt.rs
  2. 0 1
      src/kernel/timer.rs

+ 8 - 9
src/kernel/interrupt.rs

@@ -1,6 +1,4 @@
-use alloc::boxed::Box;
-use alloc::vec;
-use alloc::vec::Vec;
+use alloc::sync::Arc;
 
 use lazy_static::lazy_static;
 
@@ -35,8 +33,8 @@ extern "C" {
 }
 
 lazy_static! {
-    static ref IRQ_HANDLERS: Spin<[Vec<Box<dyn Fn() + Send>>; 16]> =
-        Spin::new(core::array::from_fn(|_| vec![]));
+    static ref IRQ_HANDLERS: Spin<[Option<Arc<dyn Fn() + Send + Sync>>; 16]> =
+        Spin::new([const { None }; 16]);
     static ref IDT: [IDTEntry; 256] = core::array::from_fn(|idx| {
         match idx {
             0..0x80 => IDTEntry::new(unsafe { ISR_START_ADDR } + 8 * idx, 0x08, 0x8e),
@@ -75,8 +73,8 @@ impl IDTEntry {
 fn irq_handler(irqno: usize) {
     assert!(irqno < 16);
 
-    let handlers = IRQ_HANDLERS.lock();
-    for handler in handlers[irqno as usize].iter() {
+    let handler = IRQ_HANDLERS.lock()[irqno as usize].as_ref().cloned();
+    if let Some(handler) = handler {
         handler();
     }
 
@@ -113,13 +111,14 @@ pub extern "C" fn interrupt_handler(int_stack: *mut interrupt_stack, mmxregs: *m
 
 pub fn register_irq_handler<F>(irqno: i32, handler: F) -> Result<(), u32>
 where
-    F: Fn() + Send + 'static,
+    F: Fn() + Send + Sync + 'static,
 {
     if irqno < 0 || irqno >= 16 {
         return Err(EINVAL);
     }
 
-    IRQ_HANDLERS.lock_irq()[irqno as usize].push(Box::new(handler));
+    let old = IRQ_HANDLERS.lock_irq()[irqno as usize].replace(Arc::new(handler));
+    assert!(old.is_none(), "IRQ handler already registered");
     Ok(())
 }
 

+ 0 - 1
src/kernel/timer.rs

@@ -29,7 +29,6 @@ impl Ticks {
 fn timer_interrupt() {
     TICKS.fetch_add(1, Ordering::Relaxed);
     if preempt::count() == 0 {
-        println_debug!("Timer interrupt reschedule");
         // To make scheduler satisfied.
         preempt::disable();
         Scheduler::schedule();