diff --git a/kernel/include/sortix/kernel/interrupt.h b/kernel/include/sortix/kernel/interrupt.h index 978038b0..118380b4 100644 --- a/kernel/include/sortix/kernel/interrupt.h +++ b/kernel/include/sortix/kernel/interrupt.h @@ -29,6 +29,8 @@ namespace Sortix { struct interrupt_context; +class Thread; + struct interrupt_handler { void (*handler)(struct interrupt_context*, void*); @@ -122,6 +124,9 @@ void Init(); void WorkerThread(void* user); void ScheduleWork(struct interrupt_work* work); +extern Thread* interrupt_worker_thread; +extern bool interrupt_worker_thread_boost; + } // namespace Interrupt } // namespace Sortix diff --git a/kernel/include/sortix/kernel/scheduler.h b/kernel/include/sortix/kernel/scheduler.h index acf37152..1618c64f 100644 --- a/kernel/include/sortix/kernel/scheduler.h +++ b/kernel/include/sortix/kernel/scheduler.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2017 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -49,6 +49,7 @@ static inline void ExitThread() #endif void Switch(struct interrupt_context* intctx); +void SwitchTo(struct interrupt_context* intctx, Thread* new_thread); void SetThreadState(Thread* thread, ThreadState state); ThreadState GetThreadState(Thread* thread); void SetIdleThread(Thread* thread); diff --git a/kernel/interrupt.cpp b/kernel/interrupt.cpp index cbc84b88..23f7ee66 100644 --- a/kernel/interrupt.cpp +++ b/kernel/interrupt.cpp @@ -28,6 +28,9 @@ namespace Sortix { namespace Interrupt { +Thread* interrupt_worker_thread = NULL; +bool interrupt_worker_thread_boost = false; + static struct interrupt_work* first; static struct interrupt_work* last; @@ -63,6 +66,7 @@ void ScheduleWork(struct interrupt_work* work) (last ? last->next : first) = work; work->next = NULL; last = work; + interrupt_worker_thread_boost = true; } } // namespace Interrupt diff --git a/kernel/kernel.cpp b/kernel/kernel.cpp index d0d5f41f..8cefd171 100644 --- a/kernel/kernel.cpp +++ b/kernel/kernel.cpp @@ -423,16 +423,17 @@ static void BootThread(void* /*user*/) // Let's create the interrupt worker thread that executes additional work // requested by interrupt handlers, where such work isn't safe. - Thread* interruptworker = RunKernelThread(Interrupt::WorkerThread, NULL); - if ( !interruptworker ) + Interrupt::interrupt_worker_thread = + RunKernelThread(Interrupt::WorkerThread, NULL); + if ( !Interrupt::interrupt_worker_thread ) Panic("Could not create interrupt worker"); // Initialize the worker thread data structures. Worker::Init(); // Create a general purpose worker thread. - Thread* workerthread = RunKernelThread(Worker::Thread, NULL); - if ( !workerthread ) + Thread* worker_thread = RunKernelThread(Worker::Thread, NULL); + if ( !worker_thread ) Panic("Unable to create general purpose worker thread"); // diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index ae6a6bfe..7be032d1 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -248,8 +248,9 @@ static void FakeInterruptedContext(struct interrupt_context* intctx, int int_no) #endif } -static -void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next) +static void SwitchRegisters(struct interrupt_context* intctx, + Thread* prev, + Thread* next) { if ( prev == next ) return; @@ -264,6 +265,31 @@ void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next) current_thread = next; } +static void SwitchThread(struct interrupt_context* intctx, + Thread* old_thread, + Thread* new_thread) +{ + SwitchRegisters(intctx, old_thread, new_thread); + if ( intctx->signal_pending && InUserspace(intctx) ) + { + // Become the thread for real and run the signal handler. + if ( old_thread == new_thread ) + { + // We're already this thread, so run the signal handler. + Interrupt::Enable(); + assert(Interrupt::IsEnabled()); + Signal::DispatchHandler(intctx, NULL); + } + else + { + // We need to transfer execution to the correct stack. We know the + // the thread is in user-space and isn't using its kernel stack, and + // we know we're not using the stack right now. + FakeInterruptedContext(intctx, 130); + } + } +} + static Thread* idle_thread; static Thread* first_runnable_thread; static Thread* true_current_thread; @@ -308,29 +334,21 @@ static Thread* PopNextThread(bool yielded) return result; } +void SwitchTo(struct interrupt_context* intctx, Thread* new_thread) +{ + Thread* old_thread = CurrentThread(); + if ( new_thread == old_thread ) + return; + first_runnable_thread = old_thread; + true_current_thread = new_thread; + SwitchThread(intctx, old_thread, new_thread); +} + static void RealSwitch(struct interrupt_context* intctx, bool yielded) { Thread* old_thread = CurrentThread(); Thread* new_thread = PopNextThread(yielded); SwitchThread(intctx, old_thread, new_thread); - if ( intctx->signal_pending && InUserspace(intctx) ) - { - // Become the thread for real and run the signal handler. - if ( old_thread == new_thread ) - { - // We're already this thread, so run the signal handler. - Interrupt::Enable(); - assert(Interrupt::IsEnabled()); - Signal::DispatchHandler(intctx, NULL); - } - else - { - // We need to transfer execution to the correct stack. We know the - // the thread is in user-space and isn't using its kernel stack, and - // we know we're not using the stack right now. - FakeInterruptedContext(intctx, 130); - } - } } void Switch(struct interrupt_context* intctx) diff --git a/kernel/x86-family/interrupt.cpp b/kernel/x86-family/interrupt.cpp index 4481ae76..b103e882 100644 --- a/kernel/x86-family/interrupt.cpp +++ b/kernel/x86-family/interrupt.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2012, 2013, 2014 Jonas 'Sortie' Termansen. + * Copyright (c) 2011, 2012, 2013, 2014, 2017 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -357,6 +357,12 @@ extern "C" void interrupt_handler(struct interrupt_context* intctx) // Send an end of interrupt signal to the PICs if we got an IRQ. if ( IRQ0 <= int_no && int_no <= IRQ15 ) PIC::SendEOI(int_no - IRQ0); + + if ( interrupt_worker_thread_boost ) + { + interrupt_worker_thread_boost = false; + Scheduler::SwitchTo(intctx, interrupt_worker_thread); + } } } // namespace Interrupt