Now with a better scheduler!

alentours-dev
Sergiusz Bazanski 2011-05-03 13:59:20 +02:00
parent c3c1001931
commit 1eff2dc879
13 changed files with 304 additions and 47 deletions

View File

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

View File

@ -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<CTask *> m_TaskQueue;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

95
src/Tier1/CTimer.cpp Normal file
View File

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