From 59262f6bf233976fa0344aaba1520bb20d157ce9 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Mon, 29 Sep 2014 23:17:36 +0200 Subject: [PATCH] Refactor interrupt handler registration. --- kernel/com.cpp | 10 ++++- kernel/include/sortix/kernel/interrupt.h | 20 +++++++-- kernel/kb/ps2.cpp | 6 ++- kernel/kb/ps2.h | 2 + kernel/x86-family/interrupt.cpp | 56 +++++++++++++++++------- kernel/x86-family/time.cpp | 6 ++- 6 files changed, 76 insertions(+), 24 deletions(-) diff --git a/kernel/com.cpp b/kernel/com.cpp index 6e49e465..8cd8cd57 100644 --- a/kernel/com.cpp +++ b/kernel/com.cpp @@ -415,6 +415,9 @@ static void UARTIRQHandler(struct interrupt_context* /*intctx*/, void* /*user*/) } } +static struct interrupt_handler irq3_handler; +static struct interrupt_handler irq4_handler; + void Init(const char* devpath, Ref slashdev) { ioctx_t ctx; SetupKernelIOCtx(&ctx); @@ -434,8 +437,11 @@ void Init(const char* devpath, Ref slashdev) PanicF("Unable to link %s/%s to COM port driver.", devpath, name); } - Interrupt::RegisterHandler(Interrupt::IRQ3, UARTIRQHandler, NULL); - Interrupt::RegisterHandler(Interrupt::IRQ4, UARTIRQHandler, NULL); + irq3_handler.handler = UARTIRQHandler; + irq4_handler.handler = UARTIRQHandler; + + Interrupt::RegisterHandler(Interrupt::IRQ3, &irq3_handler); + Interrupt::RegisterHandler(Interrupt::IRQ4, &irq4_handler); // Initialize the ports so we can transfer data. for ( size_t i = 1; i <= NUMCOMPORTS; i++ ) diff --git a/kernel/include/sortix/kernel/interrupt.h b/kernel/include/sortix/kernel/interrupt.h index d9923217..fe12afa2 100644 --- a/kernel/include/sortix/kernel/interrupt.h +++ b/kernel/include/sortix/kernel/interrupt.h @@ -31,6 +31,21 @@ #include namespace Sortix { + +struct interrupt_context; + +struct interrupt_handler +{ + void (*handler)(struct interrupt_context*, void*); + void* context; + struct interrupt_handler* next; + struct interrupt_handler* prev; +}; + +} // namespace Sortix + +namespace Sortix { + namespace Interrupt { #if defined(__i386__) || defined(__x86_64__) @@ -100,9 +115,8 @@ inline bool SetEnabled(bool is_enabled) return wasenabled; } - -typedef void (*Handler)(struct interrupt_context* intctx, void* user); -void RegisterHandler(unsigned int index, Handler handler, void* user); +void RegisterHandler(unsigned int index, struct interrupt_handler* handler); +void UnregisterHandler(unsigned int index, struct interrupt_handler* handler); void Init(); void InitWorker(); diff --git a/kernel/kb/ps2.cpp b/kernel/kb/ps2.cpp index b263d34b..a751f70f 100644 --- a/kernel/kb/ps2.cpp +++ b/kernel/kb/ps2.cpp @@ -76,7 +76,9 @@ PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt) this->leds = 0; this->scancodeescaped = false; this->kblock = KTHREAD_MUTEX_INITIALIZER; - Interrupt::RegisterHandler(interrupt, PS2Keyboard__OnInterrupt, this); + interrupt_registration.handler = PS2Keyboard__OnInterrupt; + interrupt_registration.context = this; + Interrupt::RegisterHandler(interrupt, &interrupt_registration); // If any scancodes were already pending, our interrupt handler will // never be called. Let's just discard anything pending. @@ -85,7 +87,7 @@ PS2Keyboard::PS2Keyboard(uint16_t iobase, uint8_t interrupt) PS2Keyboard::~PS2Keyboard() { - Interrupt::RegisterHandler(interrupt, NULL, NULL); + Interrupt::RegisterHandler(interrupt, &interrupt_registration); delete[] queue; } diff --git a/kernel/kb/ps2.h b/kernel/kb/ps2.h index 19941eab..9d426677 100644 --- a/kernel/kb/ps2.h +++ b/kernel/kb/ps2.h @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -56,6 +57,7 @@ private: void NotifyOwner(); private: + struct interrupt_handler interrupt_registration; int* queue; size_t queuelength; size_t queueoffset; diff --git a/kernel/x86-family/interrupt.cpp b/kernel/x86-family/interrupt.cpp index 3ea1b9f6..47f81a95 100644 --- a/kernel/x86-family/interrupt.cpp +++ b/kernel/x86-family/interrupt.cpp @@ -134,16 +134,35 @@ const char* exception_names[] = const unsigned int NUM_INTERRUPTS = 256U; static struct IDT::idt_entry interrupt_table[NUM_INTERRUPTS]; -static Handler interrupt_handlers[NUM_INTERRUPTS]; -static void* interrupt_handler_context[NUM_INTERRUPTS]; +static struct interrupt_handler* interrupt_handlers[NUM_INTERRUPTS]; -void RegisterHandler(unsigned int index, - Interrupt::Handler handler, - void* context) +static struct interrupt_handler Scheduler__InterruptYieldCPU_handler; +static struct interrupt_handler Signal__DispatchHandler_handler; +static struct interrupt_handler Signal__ReturnHandler_handler; +static struct interrupt_handler Scheduler__ThreadExitCPU_handler; + +void RegisterHandler(unsigned int index, struct interrupt_handler* handler) { assert(index < NUM_INTERRUPTS); + bool was_enabled = SetEnabled(false); + handler->prev = NULL; + if ( (handler->next = interrupt_handlers[index]) ) + handler->next->prev = handler; interrupt_handlers[index] = handler; - interrupt_handler_context[index] = context; + SetEnabled(was_enabled); +} + +void UnregisterHandler(unsigned int index, struct interrupt_handler* handler) +{ + assert(index < NUM_INTERRUPTS); + bool was_enabled = SetEnabled(false); + if ( handler->prev ) + handler->prev->next = handler->next; + else + interrupt_handlers[index] = handler->next; + if ( handler->next ) + handler->next->prev = handler->prev; + SetEnabled(was_enabled); } static void RegisterRawHandler(unsigned int index, @@ -168,11 +187,7 @@ void Init() // Initialize the interrupt table entries to the null interrupt handler. memset(&interrupt_table, 0, sizeof(interrupt_table)); for ( unsigned int i = 0; i < NUM_INTERRUPTS; i++ ) - { - interrupt_handlers[i] = NULL; - interrupt_handler_context[i] = NULL; RegisterRawHandler(i, interrupt_handler_null, false, false); - } // Remap the IRQ table on the PICs. PIC::ReprogramPIC(); @@ -231,10 +246,14 @@ void Init() RegisterRawHandler(131, isr131, true, true); RegisterRawHandler(132, thread_exit_handler, true, false); - RegisterHandler(129, Scheduler::InterruptYieldCPU, NULL); - RegisterHandler(130, Signal::DispatchHandler, NULL); - RegisterHandler(131, Signal::ReturnHandler, NULL); - RegisterHandler(132, Scheduler::ThreadExitCPU, NULL); + Scheduler__InterruptYieldCPU_handler.handler = Scheduler::InterruptYieldCPU; + RegisterHandler(129, &Scheduler__InterruptYieldCPU_handler); + Signal__DispatchHandler_handler.handler = Signal::DispatchHandler; + RegisterHandler(130, &Signal__DispatchHandler_handler); + Signal__ReturnHandler_handler.handler = Signal::ReturnHandler; + RegisterHandler(131, &Signal__ReturnHandler_handler); + Scheduler__ThreadExitCPU_handler.handler = Scheduler::ThreadExitCPU; + RegisterHandler(132, &Scheduler__ThreadExitCPU_handler); IDT::Set(interrupt_table, NUM_INTERRUPTS); @@ -333,8 +352,13 @@ extern "C" void interrupt_handler(struct interrupt_context* intctx) KernelCrashHandler(intctx); else if ( is_crash && is_in_user ) UserCrashHandler(intctx); - else if ( interrupt_handlers[int_no] ) - interrupt_handlers[int_no](intctx, interrupt_handler_context[int_no]); + else + { + for ( struct interrupt_handler* iter = interrupt_handlers[int_no]; + iter; + iter = iter->next ) + iter->handler(intctx, iter->context); + } // Send an end of interrupt signal to the PICs if we got an IRQ. if ( IRQ0 <= int_no && int_no <= IRQ15 ) diff --git a/kernel/x86-family/time.cpp b/kernel/x86-family/time.cpp index db022403..f70edb94 100644 --- a/kernel/x86-family/time.cpp +++ b/kernel/x86-family/time.cpp @@ -74,6 +74,8 @@ static void RequestIRQ0(uint16_t divisor) extern Clock* realtime_clock; extern Clock* uptime_clock; +struct interrupt_handler timer_interrupt_registration; + static struct timespec tick_period; static long tick_frequency; static uint16_t tick_divisor; @@ -126,7 +128,9 @@ void InitializeProcessClocks(Process* process) void Start() { // Handle timer interrupts if they arrive. - Interrupt::RegisterHandler(Interrupt::IRQ0, &OnIRQ0, NULL); + timer_interrupt_registration.handler = OnIRQ0; + timer_interrupt_registration.context = 0; + Interrupt::RegisterHandler(Interrupt::IRQ0, &timer_interrupt_registration); // Request a timer interrupt now that we can handle them safely. RequestIRQ0(tick_divisor);