From 8c2befc140fc11355032d436f4dcaa9c93b9a142 Mon Sep 17 00:00:00 2001 From: Jonas 'Sortie' Termansen Date: Fri, 21 Feb 2014 17:05:10 +0100 Subject: [PATCH] Clean up scheduler. --- kernel/debugger.cpp | 4 +- kernel/include/sortix/kernel/scheduler.h | 13 +- kernel/include/sortix/kernel/thread.h | 7 +- kernel/scheduler.cpp | 252 ++++++++--------------- kernel/thread.cpp | 8 +- 5 files changed, 97 insertions(+), 187 deletions(-) diff --git a/kernel/debugger.cpp b/kernel/debugger.cpp index 7fac6781..e3e64df0 100644 --- a/kernel/debugger.cpp +++ b/kernel/debugger.cpp @@ -318,8 +318,8 @@ Process* FindProcess(pid_t least_pid, pid_t max_pid) if ( least_pid <= current_process->pid && current_process->pid <= max_pid ) best = current_process; Thread* first_thread = current_thread; - for ( Thread* iter = first_thread->schedulerlistnext; - iter != first_thread; iter = iter->schedulerlistnext ) + for ( Thread* iter = first_thread->scheduler_list_next; + iter != first_thread; iter = iter->scheduler_list_next ) if ( least_pid <= iter->process->pid && iter->process->pid <= max_pid && (!best || iter->process->pid < best->pid) ) best = iter->process; diff --git a/kernel/include/sortix/kernel/scheduler.h b/kernel/include/sortix/kernel/scheduler.h index 7475e688..e43c860a 100644 --- a/kernel/include/sortix/kernel/scheduler.h +++ b/kernel/include/sortix/kernel/scheduler.h @@ -45,21 +45,24 @@ enum ThreadState { NONE, RUNNABLE, BLOCKING, DEAD }; namespace Sortix { namespace Scheduler { -void Init(); -void Switch(CPU::InterruptRegisters* regs); #if defined(__i386__) || defined(__x86_64__) -inline static void Yield() { asm volatile ("int $129"); } +static inline void Yield() +{ + asm volatile ("int $129"); +} __attribute__ ((noreturn)) -inline static void ExitThread() +static inline void ExitThread() { asm volatile ("int $132"); __builtin_unreachable(); } #endif + +void Init(); +void Switch(CPU::InterruptRegisters* regs); void SetThreadState(Thread* thread, ThreadState state); ThreadState GetThreadState(Thread* thread); void SetIdleThread(Thread* thread); -void SetDummyThreadOwner(Process* process); void SetInitProcess(Process* init); Process* GetInitProcess(); Process* GetKernelProcess(); diff --git a/kernel/include/sortix/kernel/thread.h b/kernel/include/sortix/kernel/thread.h index e964da17..1c266d4f 100644 --- a/kernel/include/sortix/kernel/thread.h +++ b/kernel/include/sortix/kernel/thread.h @@ -92,15 +92,12 @@ public: public: size_t id; Process* process; - bool terminated; Thread* prevsibling; Thread* nextsibling; -// These are some things used internally by the scheduler and should not be -// touched by anything but it. Consider it private. public: - Thread* schedulerlistprev; - Thread* schedulerlistnext; + Thread* scheduler_list_prev; + Thread* scheduler_list_next; volatile ThreadState state; uint8_t fpuenv[512UL + 16UL]; uint8_t* fpuenvaligned; diff --git a/kernel/scheduler.cpp b/kernel/scheduler.cpp index 0c6dfb9e..5cd8b2f4 100644 --- a/kernel/scheduler.cpp +++ b/kernel/scheduler.cpp @@ -27,12 +27,12 @@ #include #include #include - #include #include #include +#include #include #include #include @@ -43,116 +43,69 @@ #include #include +#if defined(__i386__) || defined(__x86_64__) #include "x86-family/gdt.h" #include "x86-family/float.h" +#endif namespace Sortix { namespace Scheduler { -const uint32_t SCHED_MAGIC = 0x1234567; - -volatile unsigned long premagic; -static Thread* currentthread; -} // namespace Scheduler -Thread* CurrentThread() { return Scheduler::currentthread; } -Process* CurrentProcess() { return CurrentThread()->process; } -namespace Scheduler { - -uint8_t dummythreaddata[sizeof(Thread)] __attribute__ ((aligned (8))); -Thread* dummythread; -Thread* idlethread; -Thread* firstrunnablethread; -Thread* firstsleepingthread; -Process* initprocess; -volatile unsigned long postmagic; - -static inline void SetCurrentThread(Thread* newcurrentthread) -{ - currentthread = newcurrentthread; -} - -void LogBeginSwitch(Thread* current, const CPU::InterruptRegisters* regs); -void LogSwitch(Thread* current, Thread* next); -void LogEndSwitch(Thread* current, const CPU::InterruptRegisters* regs); +static Thread* current_thread; +static Thread* idle_thread; +static Thread* first_runnable_thread; +static Thread* first_sleeping_thread; +static Process* init_process; static Thread* PopNextThread() { - if ( !firstrunnablethread ) { return idlethread; } - Thread* result = firstrunnablethread; - firstrunnablethread = firstrunnablethread->schedulerlistnext; - return result; -} + if ( first_runnable_thread ) + { + Thread* result = first_runnable_thread; + first_runnable_thread = first_runnable_thread->scheduler_list_next; + return result; + } -static Thread* ValidatedPopNextThread() -{ - assert(premagic == SCHED_MAGIC); - assert(postmagic == SCHED_MAGIC); - Thread* nextthread = PopNextThread(); - if ( !nextthread ) { Panic("Had no thread to switch to."); } - if ( nextthread->terminated ) - { - PanicF("Running a terminated thread 0x%p", nextthread); - } - addr_t newaddrspace = nextthread->process->addrspace; - if ( !Page::IsAligned(newaddrspace) ) - { - PanicF("Thread 0x%p, process %ji (0x%p) (backup: %i), had bad " - "address space variable: 0x%zx: not page-aligned " - "(backup: 0x%zx)\n", nextthread, - (intmax_t) nextthread->process->pid, nextthread->process, - -1/*nextthread->pidbackup*/, newaddrspace, - (addr_t)-1 /*nextthread->addrspacebackup*/); - } - return nextthread; + return idle_thread; } static void DoActualSwitch(CPU::InterruptRegisters* regs) { - Thread* current = CurrentThread(); - LogBeginSwitch(current, regs); + Thread* prev = CurrentThread(); + Thread* next = PopNextThread(); - Thread* next = ValidatedPopNextThread(); - LogSwitch(current, next); + if ( prev == next ) + return; - if ( current == next ) { return; } - - current->SaveRegisters(regs); + prev->SaveRegisters(regs); next->LoadRegisters(regs); + Memory::SwitchAddressSpace(next->addrspace); + current_thread = next; + +#if defined(__i386__) || defined(__x86_64__) Float::NotityTaskSwitch(); - - addr_t newaddrspace = next->addrspace; - Memory::SwitchAddressSpace(newaddrspace); - SetCurrentThread(next); - - addr_t stacklower = next->kernelstackpos; - size_t stacksize = next->kernelstacksize; - addr_t stackhigher = stacklower + stacksize; - assert(stacklower && stacksize && stackhigher); - GDT::SetKernelStack(stacklower, stacksize, stackhigher); - -#if defined(__x86_64__) - current->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); - current->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); - wrmsr(MSRID_FSBASE, (uint64_t) next->fsbase); - wrmsr(MSRID_GSBASE, (uint64_t) next->gsbase); -#elif defined(__i386__) - current->fsbase = (unsigned long) GDT::GetFSBase(); - current->gsbase = (unsigned long) GDT::GetGSBase(); - GDT::SetFSBase((uint32_t) next->fsbase); - GDT::SetGSBase((uint32_t) next->gsbase); + GDT::SetKernelStack(next->kernelstackpos, next->kernelstacksize, + next->kernelstackpos + next->kernelstacksize); #endif - LogEndSwitch(next, regs); +#if defined(__i386__) + prev->fsbase = (unsigned long) GDT::GetFSBase(); + prev->gsbase = (unsigned long) GDT::GetGSBase(); + GDT::SetFSBase((uint32_t) next->fsbase); + GDT::SetGSBase((uint32_t) next->gsbase); +#elif defined(__x86_64__) + prev->fsbase = (unsigned long) rdmsr(MSRID_FSBASE); + prev->gsbase = (unsigned long) rdmsr(MSRID_GSBASE); + wrmsr(MSRID_FSBASE, (uint64_t) next->fsbase); + wrmsr(MSRID_GSBASE, (uint64_t) next->gsbase); +#endif } void Switch(CPU::InterruptRegisters* regs) { - assert(premagic == SCHED_MAGIC); - assert(postmagic == SCHED_MAGIC); DoActualSwitch(regs); - assert(premagic == SCHED_MAGIC); - assert(postmagic == SCHED_MAGIC); + if ( regs->signal_pending && regs->InUserspace() ) { Interrupt::Enable(); @@ -160,49 +113,6 @@ void Switch(CPU::InterruptRegisters* regs) } } -const bool DEBUG_BEGINCTXSWITCH = false; -const bool DEBUG_CTXSWITCH = false; -const bool DEBUG_ENDCTXSWITCH = false; - -void LogBeginSwitch(Thread* current, const CPU::InterruptRegisters* regs) -{ - bool alwaysdebug = false; - bool isidlethread = current == idlethread; - bool dodebug = DEBUG_BEGINCTXSWITCH && !isidlethread; - if ( alwaysdebug || dodebug ) - { - Log::PrintF("Switching from 0x%p", current); - regs->LogRegisters(); - Log::Print("\n"); - } -} - -void LogSwitch(Thread* current, Thread* next) -{ - bool alwaysdebug = false; - bool different = current == idlethread; - bool dodebug = DEBUG_CTXSWITCH && different; - if ( alwaysdebug || dodebug ) - { - Log::PrintF("switching from %ji:%u (0x%p) to %ji:%u (0x%p) \n", - (intmax_t) current->process->pid, 0, current, - (intmax_t) next->process->pid, 0, next); - } -} - -void LogEndSwitch(Thread* current, const CPU::InterruptRegisters* regs) -{ - bool alwaysdebug = false; - bool isidlethread = current == idlethread; - bool dodebug = DEBUG_BEGINCTXSWITCH && !isidlethread; - if ( alwaysdebug || dodebug ) - { - Log::PrintF("Switched to 0x%p", current); - regs->LogRegisters(); - Log::Print("\n"); - } -} - void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/) { Switch(regs); @@ -210,9 +120,11 @@ void InterruptYieldCPU(CPU::InterruptRegisters* regs, void* /*user*/) void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/) { +#if defined(__i386__) || defined(__x86_64__) // Can't use floating point instructions from now. - Float::NofityTaskExit(currentthread); - SetThreadState(currentthread, ThreadState::DEAD); + Float::NofityTaskExit(current_thread); +#endif + SetThreadState(current_thread, ThreadState::DEAD); InterruptYieldCPU(regs, NULL); } @@ -220,30 +132,25 @@ void ThreadExitCPU(CPU::InterruptRegisters* regs, void* /*user*/) // nothing, which is only run when the system has nothing to do. void SetIdleThread(Thread* thread) { - assert(!idlethread); - idlethread = thread; + assert(!idle_thread); + idle_thread = thread; SetThreadState(thread, ThreadState::NONE); - SetCurrentThread(thread); -} - -void SetDummyThreadOwner(Process* process) -{ - dummythread->process = process; + current_thread = thread; } void SetInitProcess(Process* init) { - initprocess = init; + init_process = init; } Process* GetInitProcess() { - return initprocess; + return init_process; } Process* GetKernelProcess() { - return idlethread->process; + return idle_thread->process; } void SetThreadState(Thread* thread, ThreadState state) @@ -254,31 +161,34 @@ void SetThreadState(Thread* thread, ThreadState state) if ( thread->state == ThreadState::RUNNABLE && state != ThreadState::RUNNABLE ) { - if ( thread == firstrunnablethread ) { firstrunnablethread = thread->schedulerlistnext; } - if ( thread == firstrunnablethread ) { firstrunnablethread = NULL; } - assert(thread->schedulerlistprev); - assert(thread->schedulerlistnext); - thread->schedulerlistprev->schedulerlistnext = thread->schedulerlistnext; - thread->schedulerlistnext->schedulerlistprev = thread->schedulerlistprev; - thread->schedulerlistprev = NULL; - thread->schedulerlistnext = NULL; + if ( thread == first_runnable_thread ) + first_runnable_thread = thread->scheduler_list_next; + if ( thread == first_runnable_thread ) + first_runnable_thread = NULL; + assert(thread->scheduler_list_prev); + assert(thread->scheduler_list_next); + thread->scheduler_list_prev->scheduler_list_next = thread->scheduler_list_next; + thread->scheduler_list_next->scheduler_list_prev = thread->scheduler_list_prev; + thread->scheduler_list_prev = NULL; + thread->scheduler_list_next = NULL; } // Insert the thread into the scheduler's carousel linked list. if ( thread->state != ThreadState::RUNNABLE && state == ThreadState::RUNNABLE ) { - if ( firstrunnablethread == NULL ) { firstrunnablethread = thread; } - thread->schedulerlistprev = firstrunnablethread->schedulerlistprev; - thread->schedulerlistnext = firstrunnablethread; - firstrunnablethread->schedulerlistprev = thread; - thread->schedulerlistprev->schedulerlistnext = thread; + if ( first_runnable_thread == NULL ) + first_runnable_thread = thread; + thread->scheduler_list_prev = first_runnable_thread->scheduler_list_prev; + thread->scheduler_list_next = first_runnable_thread; + first_runnable_thread->scheduler_list_prev = thread; + thread->scheduler_list_prev->scheduler_list_next = thread; } thread->state = state; - assert(thread->state != ThreadState::RUNNABLE || thread->schedulerlistprev); - assert(thread->state != ThreadState::RUNNABLE || thread->schedulerlistnext); + assert(thread->state != ThreadState::RUNNABLE || thread->scheduler_list_prev); + assert(thread->state != ThreadState::RUNNABLE || thread->scheduler_list_next); Interrupt::SetEnabled(wasenabled); } @@ -321,19 +231,9 @@ static int sys_sched_yield(void) void Init() { - premagic = postmagic = SCHED_MAGIC; - - // We use a dummy so that the first context switch won't crash when the - // current thread is accessed. This lets us avoid checking whether it is - // NULL (which it only will be once), which gives simpler code. - dummythread = (Thread*) &dummythreaddata; - memset(dummythread, 0, sizeof(*dummythread)); - dummythread->schedulerlistprev = dummythread; - dummythread->schedulerlistnext = dummythread; - currentthread = dummythread; - firstrunnablethread = NULL; - firstsleepingthread = NULL; - idlethread = NULL; + first_runnable_thread = NULL; + first_sleeping_thread = NULL; + idle_thread = NULL; Syscall::Register(SYSCALL_SLEEP, (void*) sys_sleep); Syscall::Register(SYSCALL_USLEEP, (void*) sys_usleep); @@ -342,3 +242,17 @@ void Init() } // namespace Scheduler } // namespace Sortix + +namespace Sortix { + +Thread* CurrentThread() +{ + return Scheduler::current_thread; +} + +Process* CurrentProcess() +{ + return CurrentThread()->process; +} + +} // namespace Sortix diff --git a/kernel/thread.cpp b/kernel/thread.cpp index 59648f24..1d729171 100644 --- a/kernel/thread.cpp +++ b/kernel/thread.cpp @@ -52,8 +52,8 @@ Thread::Thread() process = NULL; prevsibling = NULL; nextsibling = NULL; - schedulerlistprev = NULL; - schedulerlistnext = NULL; + scheduler_list_prev = NULL; + scheduler_list_next = NULL; state = NONE; memset(®isters, 0, sizeof(registers)); fsbase = 0; @@ -62,7 +62,6 @@ Thread::Thread() kernelstacksize = 0; kernelstackmalloced = false; pledged_destruction = false; - terminated = false; fpuinitialized = false; // If malloc isn't 16-byte aligned, then we can't rely on offsets in // our own class, so we'll just fix ourselves nicely up. @@ -81,7 +80,6 @@ Thread::~Thread() assert(CurrentThread() != this); if ( kernelstackmalloced ) delete[] (uint8_t*) kernelstackpos; - terminated = true; } addr_t Thread::SwitchAddressSpace(addr_t newaddrspace) @@ -232,8 +230,6 @@ static int sys_exit_thread(int requested_exit_code, continue; if ( iter->pledged_destruction ) continue; - if ( iter->terminated ) - continue; is_others = true; } if ( !(flags & EXIT_THREAD_ONLY_IF_OTHERS) || is_others )