From 164ea30d44ba81eef2a6d856d7655e21c8f0cd33 Mon Sep 17 00:00:00 2001 From: Sergiusz Bazanski Date: Mon, 27 Jun 2011 17:59:54 +0200 Subject: [PATCH] Some scheduler fixes. --- .settings/org.eclipse.cdt.core.prefs | 4 +- Makefile | 2 +- include/Tier1/CRoundRobinScheduler.h | 5 ++- include/Tier1/CScheduler.h | 12 ++++-- include/Tier1/CSemaphore.h | 2 +- include/Tier1/CTimer.h | 16 +++++++- include/Tier1/IScheduler.h | 3 +- include/Tier1/Util/CLinearList.h | 28 +++++++++++-- src/Tier1/CKernel.cpp | 8 +++- src/Tier1/CRoundRobinScheduler.cpp | 59 ++++++++++++++++------------ src/Tier1/CScheduler.cpp | 38 ++++++++++++++---- src/Tier1/CTask.cpp | 4 +- src/Tier1/CTimer.cpp | 29 ++++++++++++-- 13 files changed, 158 insertions(+), 52 deletions(-) diff --git a/.settings/org.eclipse.cdt.core.prefs b/.settings/org.eclipse.cdt.core.prefs index 41bcc48..d2f82a0 100644 --- a/.settings/org.eclipse.cdt.core.prefs +++ b/.settings/org.eclipse.cdt.core.prefs @@ -1,7 +1,7 @@ -#Sun May 08 13:56:50 CEST 2011 +#Sun May 08 17:23:22 CEST 2011 eclipse.preferences.version=1 environment/project/cdt.managedbuild.toolchain.gnu.mingw.base.561123667/PATH/delimiter=; environment/project/cdt.managedbuild.toolchain.gnu.mingw.base.561123667/PATH/operation=replace -environment/project/cdt.managedbuild.toolchain.gnu.mingw.base.561123667/PATH/value=C\:\\cygwin\\bin;C\:\\Windows\\system32;C\:\\Windows; +environment/project/cdt.managedbuild.toolchain.gnu.mingw.base.561123667/PATH/value=C\:\\Development\\qemu;C\:\\cygwin\\bin;C\:\\Windows\\system32;C\:\\Windows; environment/project/cdt.managedbuild.toolchain.gnu.mingw.base.561123667/append=true environment/project/cdt.managedbuild.toolchain.gnu.mingw.base.561123667/appendContributed=true diff --git a/Makefile b/Makefile index 3913e84..40613e2 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ # Seriously. # # Fuck M4. I do this because it's probably the most portable way, and I don't -# wan't to write Yet Another Compile System because fuck that shit. I could +# want to write Yet Another Compile System because fuck that shit. I could # use cmake but I don't know whether it is flexible enough. It probably is # but whatever. I wrote this piece of shit below, let's just keep it that # way. There are better way to do the hthings I do below, but who gives a diff --git a/include/Tier1/CRoundRobinScheduler.h b/include/Tier1/CRoundRobinScheduler.h index dee8c46..28673dd 100644 --- a/include/Tier1/CRoundRobinScheduler.h +++ b/include/Tier1/CRoundRobinScheduler.h @@ -9,13 +9,16 @@ namespace cb { public: void Enable(bool Enabled); void AddTask(CTask *Task); - void NextTask(void); + void NextTask(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip); CTask *GetCurrentTask(void); void SetSemaphoreAvailable(CSemaphore *Semaphore); + void PrioritizeTask(CTask *Task); private: CTask *m_CurrentTask; CLinearList m_TaskQueue; u32 m_iTaskQueuePosition; + + CTask *m_PrioritizedTask; }; }; diff --git a/include/Tier1/CScheduler.h b/include/Tier1/CScheduler.h index ad210b9..6124f3c 100644 --- a/include/Tier1/CScheduler.h +++ b/include/Tier1/CScheduler.h @@ -7,6 +7,8 @@ #include "Tier1/IScheduler.h" #include "Tier1/CSemaphore.h" +#define CSCHEDULER_INTERRUPT_YIELD 0x99 + extern "C" { #include "Tier0/interrupts.h" } @@ -16,17 +18,21 @@ namespace cb { CTask *Task; struct STaskQueueNode *Next; } TTaskQueueNode; - class CScheduler { + class CScheduler{ private: IScheduler *m_CurrentScheduler; - static bool TimerTick(u32 Extra); + static void TimerTick(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip); + static void Yield(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip); + + static u32 m_NumTicks; public: CScheduler(void); static void Enable(void); static void AddTask(CTask *Task); static CTask *GetCurrentTask(void); - static void NextTask(void); + static void NextTask(); + static void PrioritizeTask(CTask *Task); static void DispatchAvailableSemaphore(CSemaphore *Semaphore); }; diff --git a/include/Tier1/CSemaphore.h b/include/Tier1/CSemaphore.h index 5387b56..0a27c77 100644 --- a/include/Tier1/CSemaphore.h +++ b/include/Tier1/CSemaphore.h @@ -9,7 +9,7 @@ extern "C" { namespace cb { class CSemaphore { - private: + protected: T_ATOMIC m_Available; public: CSemaphore(u32 Available = 1); diff --git a/include/Tier1/CTimer.h b/include/Tier1/CTimer.h index 0d4b6ec..1856489 100644 --- a/include/Tier1/CTimer.h +++ b/include/Tier1/CTimer.h @@ -3,34 +3,46 @@ #include "Tier1/CInterruptDispatcher.h" #include "Tier1/Util/CLinearList.h" +#include "Tier1/CTask.h" +#include "Tier1/CSemaphore.h" #include "types.h" namespace cb { typedef bool(*TTimerCallback)(u32); + typedef void(*TTimerFastHook)(u32, u32, u32, u32, u32, u32, u32, u32, u32); typedef struct { TTimerCallback Callback; u32 Interval; s32 Times; u32 NextCall; u32 Extra; + CTask *Task; } TCallbackInfo; class CTimer { public: static void Create(u32 Interval, s32 Times, TTimerCallback Callback, u32 Extra = 0); + // This is like ::Create, but faster, and there can only be one, and it's fixed interval + static void SetFastTimerHook(TTimerFastHook Hook); inline static u32 GetTicks(void) { if (!m_bInitialized) Initialize(); - return m_nTicks; + m_GetTicksSemaphore.Acquire(); + volatile u32 Ticks = m_nTicks; + m_GetTicksSemaphore.Release(); + return Ticks; } private: static CLinearList m_Callbacks; volatile static u32 m_nTicks; static void Initialize(void); - static void Dispatch(void *Registers); + static void Dispatch(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip); static bool m_bInitialized; + static TTimerFastHook m_FastHook; + static CSemaphore m_GetTicksSemaphore; + // Called when the number of ticks is just about to overflow. // Reschedules all the callbacks. static void Reschedule(void); diff --git a/include/Tier1/IScheduler.h b/include/Tier1/IScheduler.h index c7521ef..9075806 100644 --- a/include/Tier1/IScheduler.h +++ b/include/Tier1/IScheduler.h @@ -9,9 +9,10 @@ namespace cb { public: virtual void Enable(bool Enabled) = 0; virtual void AddTask(CTask *Task) = 0; - virtual void NextTask(void) = 0; + virtual void NextTask(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip) = 0; virtual CTask *GetCurrentTask(void) = 0; virtual void SetSemaphoreAvailable(CSemaphore *Semaphore) = 0; + virtual void PrioritizeTask(CTask *Task) = 0; }; }; diff --git a/include/Tier1/Util/CLinearList.h b/include/Tier1/Util/CLinearList.h index 661f516..d0cd77a 100644 --- a/include/Tier1/Util/CLinearList.h +++ b/include/Tier1/Util/CLinearList.h @@ -5,6 +5,7 @@ extern "C" { #include "Tier0/heap.h" #include "Tier0/panic.h" #include "Tier0/kstdlib.h" + #include "Tier0/kstdio.h" }; namespace cb { @@ -96,12 +97,18 @@ namespace cb { template _T &CLinearList<_T>::operator[](u32 Index) { - ASSERT(m_Data != 0); + ASSERT(m_Data != 0); TLinearListNode *Node = m_Data; for (u32 i = 0; i < Index; i++) { Node = Node->Next; - ASSERT(Node != 0); + //ASSERT(Node != 0); + if (Node == 0) + { + kprintf("fail\n"); + __asm__ volatile("cli"); + for(;;){} + } } return Node->Data; @@ -164,10 +171,25 @@ namespace cb { m_SizeCacheValid = false; return; } + ASSERT(m_Data != 0); + if (Index == 0) + { + ASSERT(m_Data != 0); + + TLinearListNode *ToBeDeleted = m_Data; + TLinearListNode *NodeAfter = m_Data->Next; + m_Data = NodeAfter; + + kfree((void*)ToBeDeleted); + + m_SizeCacheValid = false; + return; + } + TLinearListNode *NodeBefore = m_Data; - for (u32 i = 0; i < Index - 1; i++) + for (s32 i = 0; i < (s32)Index - 1; i++) { NodeBefore = NodeBefore->Next; ASSERT(NodeBefore != 0); diff --git a/src/Tier1/CKernel.cpp b/src/Tier1/CKernel.cpp index 6de6025..a1c22e6 100644 --- a/src/Tier1/CKernel.cpp +++ b/src/Tier1/CKernel.cpp @@ -66,8 +66,12 @@ void CKernel::Start(void) else { for (;;) { - CScheduler::GetCurrentTask()->Sleep(1000); - kprintf("[i] Hello! I'm the child process.\n"); + //CScheduler::GetCurrentTask()->Sleep(1000); + for (volatile u32 i = 0; i < 14000; i++) + { + for (volatile u32 j = 0; j < 650; j++){} + } + kprintf("[i] Hello! I'm the child process %i.\n", CTimer::GetTicks()); } } } diff --git a/src/Tier1/CRoundRobinScheduler.cpp b/src/Tier1/CRoundRobinScheduler.cpp index c037354..20cb1fa 100644 --- a/src/Tier1/CRoundRobinScheduler.cpp +++ b/src/Tier1/CRoundRobinScheduler.cpp @@ -10,30 +10,43 @@ extern "C" { void CRoundRobinScheduler::Enable(bool Enabled) { m_iTaskQueuePosition = 0; + m_PrioritizedTask = 0; } -__attribute__((optimize("O0"))) void CRoundRobinScheduler::NextTask(void) +__attribute__((optimize("O0"))) void CRoundRobinScheduler::NextTask(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip) { - volatile u32 NewEBP, NewESP, NewEIP, EBP, ESP, Directory; + // A wild magic value appears! + esp += 12; + + volatile u32 NewEBP, NewESP, NewEIP, Directory; - if (m_TaskQueue.GetSize() == 0) + if (m_TaskQueue.GetSize() < 1) PANIC("No tasks in queue!"); // Fetch next task. CTask *NextTask; - do { - m_iTaskQueuePosition++; - - if (m_iTaskQueuePosition >= m_TaskQueue.GetSize()) - // Something happened - restart the queue - m_iTaskQueuePosition = 0; - NextTask = m_TaskQueue[m_iTaskQueuePosition]; + /*if (m_PrioritizedTask != 0) + { + NextTask = m_PrioritizedTask; + m_PrioritizedTask = 0; } - while (NextTask->GetStatus() != ETS_RUNNING); - + else + {*/ + do { + m_iTaskQueuePosition++; + + if (m_iTaskQueuePosition >= m_TaskQueue.GetSize()) + // Something happened - restart the queue + m_iTaskQueuePosition = 0; + NextTask = m_TaskQueue[m_iTaskQueuePosition]; + } + while (NextTask->GetStatus() != ETS_RUNNING); + //} if (m_CurrentTask->GetPID() == NextTask->GetPID()) return; + //kprintf("switching from %x %x %x (%i to %i)\n", eip, esp, ebp, m_CurrentTask->GetPID(), NextTask->GetPID()); + //kprintf("[i] %i -> %i (%x)\n", m_CurrentTask->GetPID(), NextTask->GetPID(), NextTask); // Read task details @@ -47,26 +60,18 @@ __attribute__((optimize("O0"))) void CRoundRobinScheduler::NextTask(void) } // Save current task details - __asm__ volatile("mov %%esp, %0" : "=r"(ESP)); - __asm__ volatile("mov %%ebp, %0" : "=r"(EBP)); - m_CurrentTask->SetEBP(EBP); - m_CurrentTask->SetESP(ESP); + m_CurrentTask->SetEBP(ebp); + m_CurrentTask->SetESP(esp); // Return point - volatile u32 ReturnPoint = ctask_geteip(); - - if (ReturnPoint == 0xFEEDFACE) - { - //We are in the next task already - return; - } + volatile u32 ReturnPoint = eip; m_CurrentTask->SetEIP(ReturnPoint); // Switch to next task m_CurrentTask = NextTask; Directory = NextTask->GetPageDirectoryPhysicalAddress(); - //kprintf("[i] I was told to jump to %x (%x %x); %x\n", NewEIP, NewESP, + //kprintf("[i] I was told to jump to %x (%x %x); %x\n", NewEIP, NewESP, // NewEBP, Directory); //for(;;){} interrupts_irq_finish(0); @@ -75,7 +80,6 @@ __attribute__((optimize("O0"))) void CRoundRobinScheduler::NextTask(void) "movl %2, %%ebp\n" "movl %3, %%cr3\n" "movl %0, %%ecx\n" - "movl $0xFEEDFACE, %%eax\n" "jmp *%%ecx" :: "r"(NewEIP), "r"(NewESP), @@ -95,6 +99,11 @@ CTask *CRoundRobinScheduler::GetCurrentTask(void) return m_CurrentTask; } +void CRoundRobinScheduler::PrioritizeTask(CTask *Task) +{ + m_PrioritizedTask = Task; +} + void CRoundRobinScheduler::SetSemaphoreAvailable(CSemaphore *Semaphore) { u32 Physical = GetCurrentTask()->GetPageDirectory()-> diff --git a/src/Tier1/CScheduler.cpp b/src/Tier1/CScheduler.cpp index 2745c1e..127fda3 100644 --- a/src/Tier1/CScheduler.cpp +++ b/src/Tier1/CScheduler.cpp @@ -3,14 +3,17 @@ using namespace cb; #include "Tier1/CRoundRobinScheduler.h" #include "Tier1/CTimer.h" +#include "Tier1/CTask.h" extern "C" { #include "Tier0/heap.h" #include "Tier0/panic.h" #include "Tier0/kstdio.h" + #include "Tier0/interrupts.h" } volatile CScheduler g_Scheduler; +u32 CScheduler::m_NumTicks = 0; CScheduler::CScheduler(void) { @@ -31,21 +34,42 @@ CTask *CScheduler::GetCurrentTask(void) return g_Scheduler.m_CurrentScheduler->GetCurrentTask(); } +void CScheduler::PrioritizeTask(CTask *Task) +{ + g_Scheduler.m_CurrentScheduler->PrioritizeTask(Task); +} + void CScheduler::Enable(void) { - // 20ms quntum - CTimer::Create(200, -1, TimerTick); + CTimer::SetFastTimerHook(TimerTick); + + // Add the Yield interrupt + interrupts_setup_isr(CSCHEDULER_INTERRUPT_YIELD, (void*)Yield, E_INTERRUPTS_RING0); } -__attribute__((optimize("O0"))) bool CScheduler::TimerTick(u32 Extra) +__attribute__((optimize("O0"))) void CScheduler::Yield(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip) { - g_Scheduler.m_CurrentScheduler->NextTask(); - return true; + __asm__ volatile("cli"); + m_NumTicks = 0; + g_Scheduler.m_CurrentScheduler->NextTask(edi, esi, ebp, esp, ebx, edx, ecx, eax, eip); + __asm__ volatile("sti"); } -void CScheduler::NextTask(void) +__attribute__((optimize("O0"))) void CScheduler::TimerTick(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip) { - g_Scheduler.m_CurrentScheduler->NextTask(); + if (m_NumTicks > 20) + { + m_NumTicks = 0; + g_Scheduler.m_CurrentScheduler->NextTask(edi, esi, ebp, esp, ebx, edx, ecx, eax, eip); + } + m_NumTicks++; +} + +__attribute__((optimize("O0"))) void CScheduler::NextTask(void) +{ + __asm__ volatile("pusha"); + __asm__ volatile ("int $0x99"); + __asm__ volatile("popa"); } void CScheduler::DispatchAvailableSemaphore(CSemaphore *Semaphore) diff --git a/src/Tier1/CTask.cpp b/src/Tier1/CTask.cpp index 667cfb8..f49af57 100644 --- a/src/Tier1/CTask.cpp +++ b/src/Tier1/CTask.cpp @@ -132,9 +132,11 @@ void CTask::Dump(void) m_ESP, m_EBP, m_EIP); } -void CTask::Yield(void) +__attribute__((optimize("O0"))) void CTask::Yield(void) { + //kprintf("Entering NextTask\n"); CScheduler::NextTask(); + //kprintf("returned from NextTask\n"); } void CTask::WaitForSemaphore(T_SEMAPHORE *Semaphore) diff --git a/src/Tier1/CTimer.cpp b/src/Tier1/CTimer.cpp index 1886059..dbac9c1 100644 --- a/src/Tier1/CTimer.cpp +++ b/src/Tier1/CTimer.cpp @@ -1,4 +1,5 @@ #include "Tier1/CTimer.h" +#include "Tier1/CScheduler.h" using namespace cb; extern "C" { @@ -6,9 +7,11 @@ extern "C" { #include "Tier0/interrupts.h" } +TTimerFastHook CTimer::m_FastHook = 0; volatile u32 CTimer::m_nTicks = 0; bool CTimer::m_bInitialized = false; CLinearList CTimer::m_Callbacks; +CSemaphore CTimer::m_GetTicksSemaphore; void CTimer::Initialize(void) { @@ -23,9 +26,22 @@ void CTimer::Initialize(void) m_bInitialized = true; } -void CTimer::Dispatch(void *Registers) +void CTimer::SetFastTimerHook(TTimerFastHook Hook) +{ + __asm__ volatile("cli"); + + m_FastHook = Hook; + + __asm__ volatile("sti"); +} + +void CTimer::Dispatch(u32 edi, u32 esi, u32 ebp, u32 esp, u32 ebx, u32 edx, u32 ecx, u32 eax, u32 eip) { __asm__ volatile("cli"); + + if (m_FastHook) + (*m_FastHook)(edi, esi, ebp, esp, ebx, edx, ecx, eax, eip); + m_nTicks++; if (m_nTicks > (0xFFFFFFFF - 1000)) // 1000 ticks margin @@ -49,8 +65,10 @@ void CTimer::Dispatch(void *Registers) m_Callbacks.Delete(i); // TODO: fix this hack i--; - continue; } + // We can only take care of one timer callback... + CScheduler::PrioritizeTask(Callback.Task); + break; } } else @@ -63,6 +81,9 @@ void CTimer::Dispatch(void *Registers) } interrupts_irq_finish(0); __asm__ volatile("sti"); + + // Tough love for the current task. + //CScheduler::GetCurrentTask()->Yield(); } void CTimer::Reschedule(void) @@ -88,8 +109,10 @@ void CTimer::Create(u32 Interval, s32 Times, TTimerCallback Callback, u32 Extra) NewCallback.Interval = Interval; NewCallback.Times = Times; NewCallback.Callback = Callback; - NewCallback.NextCall = m_nTicks + Interval; + // Why minus 1? "Lag" compensation. + NewCallback.NextCall = m_nTicks + Interval - 1; NewCallback.Extra = Extra; + NewCallback.Task = CScheduler::GetCurrentTask(); m_Callbacks.Push(NewCallback); }