Refactor interrupt handler registration.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-09-29 23:17:36 +02:00
parent ede6d8f800
commit 59262f6bf2
6 changed files with 76 additions and 24 deletions

View File

@ -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<Descriptor> slashdev)
{
ioctx_t ctx; SetupKernelIOCtx(&ctx);
@ -434,8 +437,11 @@ void Init(const char* devpath, Ref<Descriptor> 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++ )

View File

@ -31,6 +31,21 @@
#include <sortix/kernel/registers.h>
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();

View File

@ -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;
}

View File

@ -28,6 +28,7 @@
#include <stddef.h>
#include <stdint.h>
#include <sortix/kernel/interrupt.h>
#include <sortix/kernel/kthread.h>
#include <sortix/kernel/keyboard.h>
@ -56,6 +57,7 @@ private:
void NotifyOwner();
private:
struct interrupt_handler interrupt_registration;
int* queue;
size_t queuelength;
size_t queueoffset;

View File

@ -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 )

View File

@ -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);