[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[tyndur-devel] [PATCH] kernel2: IRQ-Sharing (Bug 79)



! Ein IRQ sollte erst dann demaskiert werden, wenn alle RPCs, die ihn
  behandeln, zurückgekehrt sind.

Signed-off-by: Max Reitz <max@xxxxxxxxxx>
---
 src/kernel2/include/im.h        |   12 ++++++++++++
 src/kernel2/src/interrupts/im.c |   25 +++++++++++++++++++++++++
 src/kernel2/src/syscalls/rpc.c  |    4 +++-
 3 files changed, 40 insertions(+), 1 deletions(-)

diff --git a/src/kernel2/include/im.h b/src/kernel2/include/im.h
index 05f7200..23ccf22 100644
--- a/src/kernel2/include/im.h
+++ b/src/kernel2/include/im.h
@@ -54,6 +54,18 @@ void im_disable(void);
 void im_enable_irq(uint8_t irq);
 void im_disable_irq(uint8_t irq);
 
+/**
+ * Zeigt an, dass ein RPC zu einem Task ausgelöst wurde, der den entsprechenden
+ * IRQ verarbeiten soll.
+ */
+void im_irq_handlers_increment(uint8_t irq);
+/**
+ * Zeigt an, dass solch ein RPC beendet wurde. Ist die Zahl der Tasks, die sich
+ * um diesen IRQ kümmern, auf 0 gesunken, kann der IRQ wieder per im_enable_irq
+ * zugelassen werden.
+ */
+void im_irq_handlers_decrement(uint8_t irq);
+
 void im_end_of_interrupt(uint8_t interrupt);
 interrupt_stack_frame_t* im_handler(interrupt_stack_frame_t* isf);
 interrupt_stack_frame_t* im_prepare_current_thread(void);
diff --git a/src/kernel2/src/interrupts/im.c b/src/kernel2/src/interrupts/im.c
index 97862ac..f22498a 100644
--- a/src/kernel2/src/interrupts/im.c
+++ b/src/kernel2/src/interrupts/im.c
@@ -34,6 +34,7 @@
  */
 
 #include <stdbool.h>
+#include <lock.h>
 #include <types.h>
 #include <lost/config.h>
 
@@ -67,6 +68,12 @@ static int intr_num_tasks[IM_NUM_INTERRUPTS];
 // Interrupt 0 sind, sonst true).
 static bool any_intr[IM_NUM_INTERRUPTS];
 
+// Anzahl von Tasks, die sich gerade um einen bestimmten IRQ kümmern (zu denen
+// also ein fastrpc_irq ausgeführt wurde und noch nicht beendet ist)
+static uint32_t intr_active_tasks[IM_NUM_INTERRUPTS];
+// Ein Lock für dieses Array
+static lock_t intr_active_tasks_lock = LOCK_UNLOCKED;
+
 void im_send_interrupts(void);
 bool fastrpc_irq(pm_process_t* callee, size_t metadata_size, void* metadata,
     size_t data_size, void* data, uint8_t irq);
@@ -373,3 +380,21 @@ void im_send_interrupts(void)
         pm_scheduler_try_switch(new_thread);
     }
 }
+
+void im_irq_handlers_increment(uint8_t irq)
+{
+    locked_increment(&intr_active_tasks[irq]);
+}
+
+void im_irq_handlers_decrement(uint8_t irq)
+{
+    lock(&intr_active_tasks_lock);
+
+    if (--intr_active_tasks[irq] <= 0)
+    {
+        intr_active_tasks[irq] = 0;
+        im_enable_irq(irq);
+    }
+
+    unlock(&intr_active_tasks_lock);
+}
diff --git a/src/kernel2/src/syscalls/rpc.c b/src/kernel2/src/syscalls/rpc.c
index 382c882..1b57ae0 100644
--- a/src/kernel2/src/syscalls/rpc.c
+++ b/src/kernel2/src/syscalls/rpc.c
@@ -325,6 +325,8 @@ bool fastrpc_irq(pm_process_t* callee, size_t metadata_size, void* metadata,
         return false;
     }
 
+    im_irq_handlers_increment(irq);
+
     rpc_t* rpc = list_get_element_at(callee->rpcs, 0);
     rpc->reenable_irq = irq;
 
@@ -381,7 +383,7 @@ void syscall_fastrpc_ret(void)
     // Wenn es ein IRQ-verarbeitender RPC war, den Interrupt jetzt
     // wieder aktivieren
     if (rpc->reenable_irq) {
-        im_enable_irq(rpc->reenable_irq);
+        im_irq_handlers_decrement(rpc->reenable_irq);
     }
 
     free(rpc);
-- 
1.7.4.4