diff --git a/include/Tier1/CInterruptDispatcher.h b/include/Tier1/CInterruptDispatcher.h index 82d7667..fa798c4 100644 --- a/include/Tier1/CInterruptDispatcher.h +++ b/include/Tier1/CInterruptDispatcher.h @@ -6,6 +6,7 @@ extern "C" { #include "Tier0/interrupts.h" #include "Tier0/panic.h" + #include "Tier0/kstdio.h" }; // I am going to programmer hell for this @@ -16,6 +17,7 @@ extern "C" { //CInterruptDispatcher StaticDispatcher Implementation #define CID_SDIS_IMP(n) void CInterruptDispatcher::d_Interrupt##n( \ T_ISR_REGISTERS_ERR R) { \ + kprintf("oioi\naaaa\nbbbbb\n"); \ if (m_Dispatchers[n] != 0) \ m_Dispatchers[n]->Dispatch(&R); \ } diff --git a/include/Tier1/CRoundRobinScheduler.h b/include/Tier1/CRoundRobinScheduler.h index c4807d4..633a30c 100644 --- a/include/Tier1/CRoundRobinScheduler.h +++ b/include/Tier1/CRoundRobinScheduler.h @@ -11,6 +11,7 @@ namespace cb { void AddTask(CTask *Task); void NextTask(void); CTask *GetCurrentTask(void); + void DispatchAvailableSemaphore(CSemaphore *Semaphore); private: CTask *m_CurrentTask; CLinearList m_TaskQueue; diff --git a/include/Tier1/CScheduler.h b/include/Tier1/CScheduler.h index 1bc9a5a..ad210b9 100644 --- a/include/Tier1/CScheduler.h +++ b/include/Tier1/CScheduler.h @@ -5,6 +5,7 @@ #include "Tier1/CTask.h" #include "Tier1/IScheduler.h" +#include "Tier1/CSemaphore.h" extern "C" { #include "Tier0/interrupts.h" @@ -19,12 +20,15 @@ namespace cb { private: IScheduler *m_CurrentScheduler; - static void TimerTick(T_ISR_REGISTERS R); + static bool TimerTick(u32 Extra); public: CScheduler(void); static void Enable(void); static void AddTask(CTask *Task); static CTask *GetCurrentTask(void); + static void NextTask(void); + + static void DispatchAvailableSemaphore(CSemaphore *Semaphore); }; }; diff --git a/include/Tier1/CTask.h b/include/Tier1/CTask.h index 775f754..b1c8efd 100644 --- a/include/Tier1/CTask.h +++ b/include/Tier1/CTask.h @@ -4,6 +4,8 @@ #include "types.h" #include "Tier1/CKernel.h" #include "Tier1/CPageDirectory.h" +#include "Tier1/CSemaphore.h" +#include "Tier0/semaphore.h" // Task memory map... // _______________________ @@ -82,10 +84,17 @@ namespace cb { ETP_REALTIME }; enum ETaskRing { - ETP_RING0, - ETP_RING1, - ETP_RING2, - ETP_RING3 + ETR_RING0, + ETR_RING1, + ETR_RING2, + ETR_RING3 + }; + enum ETaskStatus { + ETS_RUNNING, + ETS_DISABLED, + ETS_SLEEPING, + ETS_WAITING_FOR_SEMAPHORE, + ETS_WAITING_FOR_MESSAGE }; class CPageDirectory; class CTask { @@ -100,6 +109,8 @@ namespace cb { volatile u32 m_PID; volatile u32 m_ESP, m_EIP, m_EBP; + volatile ETaskStatus m_Status; + volatile u32 m_StatusData; u32 m_HeapStart; u32 m_HeapSize; @@ -150,6 +161,29 @@ namespace cb { void Dump(void); + void CedeTimeSlice(void); + void WaitForSemaphore(T_SEMAPHORE *Semaphore); + void WaitForSemaphore(CSemaphore *Semaphore); + + // Makes the scheduler never give us a time slice + void Disable(void); + void Enable(void); + + // Like sleep(). Usually microseconds. + void Sleep(u32 Ticks); + + // Used for waking up via a CTimer + static bool WakeUp(u32 Extra); + + inline ETaskStatus GetStatus(void) + { + return m_Status; + } + + inline u32 GetStatusData(void) + { + return m_StatusData; + } }; }; diff --git a/include/Tier1/CTimer.h b/include/Tier1/CTimer.h index 8f4bb91..77451c6 100644 --- a/include/Tier1/CTimer.h +++ b/include/Tier1/CTimer.h @@ -1,9 +1,39 @@ #ifndef __CTIMER_H__ #define __CTIMER_H__ +#include "Tier1/CInterruptDispatcher.h" +#include "Tier1/Util/CLinearList.h" +#include "types.h" + namespace cb { + typedef bool(*TTimerCallback)(u32); + typedef struct { + TTimerCallback Callback; + u32 Interval; + s32 Times; + u32 NextCall; + u32 Extra; + } TCallbackInfo; class CTimer { - void Enable(bool Enabled); + public: + static void Create(u32 Interval, s32 Times, TTimerCallback Callback, + u32 Extra = 0); + inline static u32 GetTicks(void) + { + if (!m_Initialized) + Initialize(); + return m_NumTicks; + } + private: + static CLinearList m_Callbacks; + volatile static u32 m_NumTicks; + static void Initialize(void); + static void Dispatch(void *Registers); + static bool m_Initialized; + + // 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 3da2254..8606837 100644 --- a/include/Tier1/IScheduler.h +++ b/include/Tier1/IScheduler.h @@ -2,7 +2,7 @@ #define __ISCHEDULER_H__ #include "Tier1/CTask.h" -#include "Tier0/semaphore.h" +#include "Tier1/CSemaphore.h" namespace cb { class IScheduler { @@ -11,8 +11,7 @@ namespace cb { virtual void AddTask(CTask *Task) = 0; virtual void NextTask(void) = 0; virtual CTask *GetCurrentTask(void) = 0; - virtual void AcquireSemaphore(T_SEMAPHORE *Semaphore) = 0; - virtual void ReleaseSemaphore(T_SEMAPHORE *Semaphore) = 0; + virtual void DispatchAvailableSemaphore(CSemaphore *Semaphore) = 0; }; }; diff --git a/include/Tier1/Util/CLinearList.h b/include/Tier1/Util/CLinearList.h index d05a371..661f516 100644 --- a/include/Tier1/Util/CLinearList.h +++ b/include/Tier1/Util/CLinearList.h @@ -4,6 +4,7 @@ extern "C" { #include "Tier0/heap.h" #include "Tier0/panic.h" + #include "Tier0/kstdlib.h" }; namespace cb { @@ -59,7 +60,7 @@ namespace cb { TLinearListNode *NewNode = (TLinearListNode *)kmalloc(sizeof(TLinearListNode)); - NewNode->Data = Element; + kmemcpy(&NewNode->Data, &Element, sizeof(_T)); NewNode->Next = 0; LastNode->Next = NewNode; @@ -163,17 +164,17 @@ namespace cb { m_SizeCacheValid = false; return; } - ASSERT(m_Data); + ASSERT(m_Data != 0); TLinearListNode *NodeBefore = m_Data; for (u32 i = 0; i < Index - 1; i++) { NodeBefore = NodeBefore->Next; - ASSERT(NodeBefore); + ASSERT(NodeBefore != 0); } TLinearListNode *NodeToBeDeleted = NodeBefore->Next; - ASSERT(NodeToBeDeleted); + ASSERT(NodeToBeDeleted != 0); TLinearListNode *NodeAfter = NodeToBeDeleted->Next; kfree((void*)NodeToBeDeleted); NodeBefore->Next = NodeAfter; diff --git a/src/Tier1/CKernel.cpp b/src/Tier1/CKernel.cpp index bd8836a..585f5ee 100644 --- a/src/Tier1/CKernel.cpp +++ b/src/Tier1/CKernel.cpp @@ -7,6 +7,8 @@ #include "Tier1/CScheduler.h" #include "Tier1/Util/CVector.h" #include "Tier1/Util/CLinearList.h" +#include "Tier1/CTimer.h" + using namespace cb; CKernel g_Kernel; @@ -52,33 +54,29 @@ void CKernel::Start(void) m_DriverManager->AddDriver(Ramdisk); m_DriverManager->LoadNew(); - CTask *KernelTask = CreateKernelTask(); kprintf("[i] Kernel task has TID %i.\n", KernelTask->GetPID()); CScheduler::AddTask(KernelTask); CScheduler::Enable(); - //PANIC("I LIKE THE COCK"); - CTask *ParentTask = CScheduler::GetCurrentTask(); CTask *NewTask = ParentTask->Fork(); + CTimer::GetTicks(); if (NewTask == ParentTask) { + for (;;) { - for (volatile u32 i = 0; i < 3500; i++) + for (volatile u32 i = 0; i < 14000; i++) { for (volatile u32 j = 0; j < 650; j++){} } - kprintf("[i] Hello! I'm the parent process.\n"); + kprintf("[i] Hello! I'm the parent process %i.\n", CTimer::GetTicks()); } } else { for (;;) { - for (volatile u32 i = 0; i < 3500; i++) - { - for (volatile u32 j = 0; j < 650; j++){} - } + CScheduler::GetCurrentTask()->Sleep(1000); kprintf("[i] Hello! I'm the child process.\n"); } } diff --git a/src/Tier1/CRoundRobinScheduler.cpp b/src/Tier1/CRoundRobinScheduler.cpp index 6e6d6df..482cfc2 100644 --- a/src/Tier1/CRoundRobinScheduler.cpp +++ b/src/Tier1/CRoundRobinScheduler.cpp @@ -20,11 +20,16 @@ __attribute__((optimize("O0"))) void CRoundRobinScheduler::NextTask(void) PANIC("No tasks in queue!"); // Fetch next task. - m_TaskQueuePosition++; - if (m_TaskQueuePosition >= m_TaskQueue.GetSize()) - // Something happened - restart the queue - m_TaskQueuePosition = 0; - CTask *NextTask = m_TaskQueue[m_TaskQueuePosition]; + CTask *NextTask; + do { + m_TaskQueuePosition++; + + if (m_TaskQueuePosition >= m_TaskQueue.GetSize()) + // Something happened - restart the queue + m_TaskQueuePosition = 0; + NextTask = m_TaskQueue[m_TaskQueuePosition]; + } + while (NextTask->GetStatus() != ETS_RUNNING); if (m_CurrentTask->GetPID() == NextTask->GetPID()) return; @@ -89,3 +94,18 @@ CTask *CRoundRobinScheduler::GetCurrentTask(void) { return m_CurrentTask; } + +void CRoundRobinScheduler::DispatchAvailableSemaphore(CSemaphore *Semaphore) +{ + u32 Physical = GetCurrentTask()->GetPageDirectory()-> + Translate((u32)Semaphore); + for (u32 i = 0; i < m_TaskQueue.GetSize(); i++) + { + CTask *Task = m_TaskQueue[i]; + if (Task->GetStatus() == ETS_WAITING_FOR_SEMAPHORE && + Task->GetStatusData() == Physical) + { + Task->Enable(); + } + } +} diff --git a/src/Tier1/CScheduler.cpp b/src/Tier1/CScheduler.cpp index 42b4bf8..d0dc4cf 100644 --- a/src/Tier1/CScheduler.cpp +++ b/src/Tier1/CScheduler.cpp @@ -2,6 +2,7 @@ using namespace cb; #include "Tier1/CRoundRobinScheduler.h" +#include "Tier1/CTimer.h" extern "C" { #include "Tier0/heap.h" @@ -32,20 +33,22 @@ CTask *CScheduler::GetCurrentTask(void) void CScheduler::Enable(void) { - u32 Divisor = 0xFFFFFFFF; - koutb(0x43, 0x36); - u8 Low = (u8)(Divisor & 0xFF); - u8 High = (u8)((Divisor >> 8) & 0xFF); - koutb(0x40, Low); - koutb(0x40, High); - - interrupts_setup_irq(0x00, (void*)CScheduler::TimerTick); + // 20ms quntum + CTimer::Create(200, -1, TimerTick); } -__attribute__((optimize("O0"))) void CScheduler::TimerTick(T_ISR_REGISTERS R) +__attribute__((optimize("O0"))) bool CScheduler::TimerTick(u32 Extra) { - __asm__ volatile("cli"); g_Scheduler.m_CurrentScheduler->NextTask(); - interrupts_irq_finish(0); - __asm__ volatile("sti"); + return true; +} + +void CScheduler::NextTask(void) +{ + g_Scheduler.m_CurrentScheduler->NextTask(); +} + +void CScheduler::DispatchAvailableSemaphore(CSemaphore *Semaphore) +{ + g_Scheduler.m_CurrentScheduler->DispatchAvailableSemaphore(Semaphore); } diff --git a/src/Tier1/CSemaphore.cpp b/src/Tier1/CSemaphore.cpp index 7e4a372..c69d450 100644 --- a/src/Tier1/CSemaphore.cpp +++ b/src/Tier1/CSemaphore.cpp @@ -1,4 +1,5 @@ #include "Tier1/CSemaphore.h" +#include "Tier1/CScheduler.h" using namespace cb; CSemaphore::CSemaphore(u32 Available) @@ -8,18 +9,30 @@ CSemaphore::CSemaphore(u32 Available) void CSemaphore::Acquire(void) { - // Just spinlock... - while (1) + __asm__ volatile("cli"); + if (atomic_read(&m_Available) > 0) { - if (atomic_read(&m_Available) > 0) - { - atomic_dec(&m_Available); - break; - } + atomic_dec(&m_Available); + return; } + else + { + // Tell the scheduler we are waiting for the semaphore + CScheduler::GetCurrentTask()->WaitForSemaphore(this); + + // If we are here, try to acquire the semaphore again. + Acquire(); + } + __asm__ volatile("sti"); } void CSemaphore::Release(void) { + __asm__ volatile("cli"); atomic_inc(&m_Available); + + // If the resource is now free, tell the scheduler + if (atomic_read(&m_Available) > 0) + CScheduler::DispatchAvailableSemaphore(this); + __asm__ volatile("sti"); } diff --git a/src/Tier1/CTask.cpp b/src/Tier1/CTask.cpp index 0eb285b..faf883e 100644 --- a/src/Tier1/CTask.cpp +++ b/src/Tier1/CTask.cpp @@ -9,6 +9,7 @@ extern "C" { }; #include "Tier1/CScheduler.h" +#include "Tier1/CTimer.h" extern CPageDirectory *g_KernelPageDirectory; u32 CTaskNextPID = 0; @@ -27,10 +28,11 @@ CTask::CTask(bool User, bool Empty) else m_CreatedStack = false; + m_Status = ETS_RUNNING; m_PID = CTaskNextPID++; m_Priority = ETP_NORMAL; m_Owner = 0; - m_Ring = (User ? ETP_RING3 : ETP_RING0); + m_Ring = (User ? ETR_RING3 : ETR_RING0); } CTask::~CTask(void) @@ -130,3 +132,58 @@ void CTask::Dump(void) m_ESP, m_EBP, m_EIP); } +void CTask::CedeTimeSlice(void) +{ + CScheduler::NextTask(); +} + +void CTask::WaitForSemaphore(T_SEMAPHORE *Semaphore) +{ + __asm__ volatile ("cli"); + m_Status = ETS_WAITING_FOR_SEMAPHORE; + m_StatusData = m_Directory->Translate((u32)Semaphore); + + CedeTimeSlice(); + __asm__ volatile ("sti"); +} + +void CTask::WaitForSemaphore(CSemaphore *Semaphore) +{ + __asm__ volatile ("cli"); + m_Status = ETS_WAITING_FOR_SEMAPHORE; + m_StatusData = m_Directory->Translate((u32)Semaphore); + + CedeTimeSlice(); + __asm__ volatile ("sti"); +} + +void CTask::Disable(void) +{ + __asm__ volatile ("cli"); + m_Status = ETS_DISABLED; + CedeTimeSlice(); + __asm__ volatile ("sti"); +} + +void CTask::Enable(void) +{ + __asm__ volatile ("cli"); + m_Status = ETS_RUNNING; + __asm__ volatile ("sti"); +} + +void CTask::Sleep(u32 Ticks) +{ + __asm__ volatile ("cli"); + m_Status = ETS_DISABLED; + CTimer::Create(Ticks, 1, WakeUp, (u32)this); + CedeTimeSlice(); + __asm__ volatile ("sti"); +} + +bool CTask::WakeUp(u32 Extra) +{ + CTask *Task = (CTask*)Extra; + Task->Enable(); + return true; +} diff --git a/src/Tier1/CTimer.cpp b/src/Tier1/CTimer.cpp new file mode 100644 index 0000000..1fa737b --- /dev/null +++ b/src/Tier1/CTimer.cpp @@ -0,0 +1,95 @@ +#include "Tier1/CTimer.h" +using namespace cb; + +extern "C" { + #include "Tier0/kstdio.h" + #include "Tier0/interrupts.h" +} + +volatile u32 CTimer::m_NumTicks = 0; +bool CTimer::m_Initialized = false; +CLinearList CTimer::m_Callbacks; + +void CTimer::Initialize(void) +{ + u32 Divider = 1193180 / 1000; // microseconds + koutb(0x43, 0x36); + u8 Low = (u8)(Divider & 0xFF); + u8 High = (u8)((Divider >> 8) & 0xFF); + koutb(0x40, Low); + koutb(0x40, High); + + interrupts_setup_irq(0x00, (void*)Dispatch); + m_Initialized = true; +} + +void CTimer::Dispatch(void *Registers) +{ + __asm__ volatile("cli"); + m_NumTicks++; + + if (m_NumTicks > (0xFFFFFFFF - 1000)) // 1000 ticks margin + Reschedule(); + for (u32 i = 0; i < m_Callbacks.GetSize(); i++) + { + TCallbackInfo &Callback = m_Callbacks[i]; + if (Callback.Times == -1 || Callback.Times > 0) + { + if (m_NumTicks > Callback.NextCall) + { + if (Callback.Times != -1) + Callback.Times--; + + Callback.NextCall += Callback.Interval; + + // Call the callback + bool Continue = (Callback.Callback)(Callback.Extra); + if (!Continue) + { + m_Callbacks.Delete(i); + // TODO: fix this hack + i--; + continue; + } + } + } + else + { + m_Callbacks.Delete(i); + // TODO: fix this hack + i--; + continue; + } + } + interrupts_irq_finish(0); + __asm__ volatile("sti"); +} + +void CTimer::Reschedule(void) +{ + u32 Amount = 0xFFFFFFFF - 1000; + + for (u32 i = 0; i < m_Callbacks.GetSize(); i++) + { + TCallbackInfo &Callback = m_Callbacks[i]; + Callback.NextCall -= Amount; + } + + m_NumTicks -= Amount; +} + +void CTimer::Create(u32 Interval, s32 Times, TTimerCallback Callback, u32 Extra) +{ + if (!m_Initialized) + Initialize(); + + TCallbackInfo NewCallback; + + NewCallback.Interval = Interval; + NewCallback.Times = Times; + NewCallback.Callback = Callback; + NewCallback.NextCall = m_NumTicks + Interval; + NewCallback.Extra = Extra; + + m_Callbacks.Push(NewCallback); +}