Now with a better scheduler!
parent
c3c1001931
commit
1eff2dc879
|
@ -6,6 +6,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "Tier0/interrupts.h"
|
#include "Tier0/interrupts.h"
|
||||||
#include "Tier0/panic.h"
|
#include "Tier0/panic.h"
|
||||||
|
#include "Tier0/kstdio.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
// I am going to programmer hell for this
|
// I am going to programmer hell for this
|
||||||
|
@ -16,6 +17,7 @@ extern "C" {
|
||||||
//CInterruptDispatcher StaticDispatcher Implementation
|
//CInterruptDispatcher StaticDispatcher Implementation
|
||||||
#define CID_SDIS_IMP(n) void CInterruptDispatcher::d_Interrupt##n( \
|
#define CID_SDIS_IMP(n) void CInterruptDispatcher::d_Interrupt##n( \
|
||||||
T_ISR_REGISTERS_ERR R) { \
|
T_ISR_REGISTERS_ERR R) { \
|
||||||
|
kprintf("oioi\naaaa\nbbbbb\n"); \
|
||||||
if (m_Dispatchers[n] != 0) \
|
if (m_Dispatchers[n] != 0) \
|
||||||
m_Dispatchers[n]->Dispatch(&R); \
|
m_Dispatchers[n]->Dispatch(&R); \
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ namespace cb {
|
||||||
void AddTask(CTask *Task);
|
void AddTask(CTask *Task);
|
||||||
void NextTask(void);
|
void NextTask(void);
|
||||||
CTask *GetCurrentTask(void);
|
CTask *GetCurrentTask(void);
|
||||||
|
void DispatchAvailableSemaphore(CSemaphore *Semaphore);
|
||||||
private:
|
private:
|
||||||
CTask *m_CurrentTask;
|
CTask *m_CurrentTask;
|
||||||
CLinearList<CTask *> m_TaskQueue;
|
CLinearList<CTask *> m_TaskQueue;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "Tier1/CTask.h"
|
#include "Tier1/CTask.h"
|
||||||
#include "Tier1/IScheduler.h"
|
#include "Tier1/IScheduler.h"
|
||||||
|
#include "Tier1/CSemaphore.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "Tier0/interrupts.h"
|
#include "Tier0/interrupts.h"
|
||||||
|
@ -19,12 +20,15 @@ namespace cb {
|
||||||
private:
|
private:
|
||||||
IScheduler *m_CurrentScheduler;
|
IScheduler *m_CurrentScheduler;
|
||||||
|
|
||||||
static void TimerTick(T_ISR_REGISTERS R);
|
static bool TimerTick(u32 Extra);
|
||||||
public:
|
public:
|
||||||
CScheduler(void);
|
CScheduler(void);
|
||||||
static void Enable(void);
|
static void Enable(void);
|
||||||
static void AddTask(CTask *Task);
|
static void AddTask(CTask *Task);
|
||||||
static CTask *GetCurrentTask(void);
|
static CTask *GetCurrentTask(void);
|
||||||
|
static void NextTask(void);
|
||||||
|
|
||||||
|
static void DispatchAvailableSemaphore(CSemaphore *Semaphore);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Tier1/CKernel.h"
|
#include "Tier1/CKernel.h"
|
||||||
#include "Tier1/CPageDirectory.h"
|
#include "Tier1/CPageDirectory.h"
|
||||||
|
#include "Tier1/CSemaphore.h"
|
||||||
|
#include "Tier0/semaphore.h"
|
||||||
|
|
||||||
// Task memory map...
|
// Task memory map...
|
||||||
// _______________________
|
// _______________________
|
||||||
|
@ -82,10 +84,17 @@ namespace cb {
|
||||||
ETP_REALTIME
|
ETP_REALTIME
|
||||||
};
|
};
|
||||||
enum ETaskRing {
|
enum ETaskRing {
|
||||||
ETP_RING0,
|
ETR_RING0,
|
||||||
ETP_RING1,
|
ETR_RING1,
|
||||||
ETP_RING2,
|
ETR_RING2,
|
||||||
ETP_RING3
|
ETR_RING3
|
||||||
|
};
|
||||||
|
enum ETaskStatus {
|
||||||
|
ETS_RUNNING,
|
||||||
|
ETS_DISABLED,
|
||||||
|
ETS_SLEEPING,
|
||||||
|
ETS_WAITING_FOR_SEMAPHORE,
|
||||||
|
ETS_WAITING_FOR_MESSAGE
|
||||||
};
|
};
|
||||||
class CPageDirectory;
|
class CPageDirectory;
|
||||||
class CTask {
|
class CTask {
|
||||||
|
@ -100,6 +109,8 @@ namespace cb {
|
||||||
volatile u32 m_PID;
|
volatile u32 m_PID;
|
||||||
|
|
||||||
volatile u32 m_ESP, m_EIP, m_EBP;
|
volatile u32 m_ESP, m_EIP, m_EBP;
|
||||||
|
volatile ETaskStatus m_Status;
|
||||||
|
volatile u32 m_StatusData;
|
||||||
|
|
||||||
u32 m_HeapStart;
|
u32 m_HeapStart;
|
||||||
u32 m_HeapSize;
|
u32 m_HeapSize;
|
||||||
|
@ -150,6 +161,29 @@ namespace cb {
|
||||||
|
|
||||||
void Dump(void);
|
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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,39 @@
|
||||||
#ifndef __CTIMER_H__
|
#ifndef __CTIMER_H__
|
||||||
#define __CTIMER_H__
|
#define __CTIMER_H__
|
||||||
|
|
||||||
|
#include "Tier1/CInterruptDispatcher.h"
|
||||||
|
#include "Tier1/Util/CLinearList.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
namespace cb {
|
namespace cb {
|
||||||
|
typedef bool(*TTimerCallback)(u32);
|
||||||
|
typedef struct {
|
||||||
|
TTimerCallback Callback;
|
||||||
|
u32 Interval;
|
||||||
|
s32 Times;
|
||||||
|
u32 NextCall;
|
||||||
|
u32 Extra;
|
||||||
|
} TCallbackInfo;
|
||||||
class CTimer {
|
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);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
#define __ISCHEDULER_H__
|
#define __ISCHEDULER_H__
|
||||||
|
|
||||||
#include "Tier1/CTask.h"
|
#include "Tier1/CTask.h"
|
||||||
#include "Tier0/semaphore.h"
|
#include "Tier1/CSemaphore.h"
|
||||||
|
|
||||||
namespace cb {
|
namespace cb {
|
||||||
class IScheduler {
|
class IScheduler {
|
||||||
|
@ -11,8 +11,7 @@ namespace cb {
|
||||||
virtual void AddTask(CTask *Task) = 0;
|
virtual void AddTask(CTask *Task) = 0;
|
||||||
virtual void NextTask(void) = 0;
|
virtual void NextTask(void) = 0;
|
||||||
virtual CTask *GetCurrentTask(void) = 0;
|
virtual CTask *GetCurrentTask(void) = 0;
|
||||||
virtual void AcquireSemaphore(T_SEMAPHORE *Semaphore) = 0;
|
virtual void DispatchAvailableSemaphore(CSemaphore *Semaphore) = 0;
|
||||||
virtual void ReleaseSemaphore(T_SEMAPHORE *Semaphore) = 0;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "Tier0/heap.h"
|
#include "Tier0/heap.h"
|
||||||
#include "Tier0/panic.h"
|
#include "Tier0/panic.h"
|
||||||
|
#include "Tier0/kstdlib.h"
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace cb {
|
namespace cb {
|
||||||
|
@ -59,7 +60,7 @@ namespace cb {
|
||||||
|
|
||||||
TLinearListNode *NewNode =
|
TLinearListNode *NewNode =
|
||||||
(TLinearListNode *)kmalloc(sizeof(TLinearListNode));
|
(TLinearListNode *)kmalloc(sizeof(TLinearListNode));
|
||||||
NewNode->Data = Element;
|
kmemcpy(&NewNode->Data, &Element, sizeof(_T));
|
||||||
NewNode->Next = 0;
|
NewNode->Next = 0;
|
||||||
LastNode->Next = NewNode;
|
LastNode->Next = NewNode;
|
||||||
|
|
||||||
|
@ -163,17 +164,17 @@ namespace cb {
|
||||||
m_SizeCacheValid = false;
|
m_SizeCacheValid = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ASSERT(m_Data);
|
ASSERT(m_Data != 0);
|
||||||
|
|
||||||
TLinearListNode *NodeBefore = m_Data;
|
TLinearListNode *NodeBefore = m_Data;
|
||||||
for (u32 i = 0; i < Index - 1; i++)
|
for (u32 i = 0; i < Index - 1; i++)
|
||||||
{
|
{
|
||||||
NodeBefore = NodeBefore->Next;
|
NodeBefore = NodeBefore->Next;
|
||||||
ASSERT(NodeBefore);
|
ASSERT(NodeBefore != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TLinearListNode *NodeToBeDeleted = NodeBefore->Next;
|
TLinearListNode *NodeToBeDeleted = NodeBefore->Next;
|
||||||
ASSERT(NodeToBeDeleted);
|
ASSERT(NodeToBeDeleted != 0);
|
||||||
TLinearListNode *NodeAfter = NodeToBeDeleted->Next;
|
TLinearListNode *NodeAfter = NodeToBeDeleted->Next;
|
||||||
kfree((void*)NodeToBeDeleted);
|
kfree((void*)NodeToBeDeleted);
|
||||||
NodeBefore->Next = NodeAfter;
|
NodeBefore->Next = NodeAfter;
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
#include "Tier1/CScheduler.h"
|
#include "Tier1/CScheduler.h"
|
||||||
#include "Tier1/Util/CVector.h"
|
#include "Tier1/Util/CVector.h"
|
||||||
#include "Tier1/Util/CLinearList.h"
|
#include "Tier1/Util/CLinearList.h"
|
||||||
|
#include "Tier1/CTimer.h"
|
||||||
|
|
||||||
using namespace cb;
|
using namespace cb;
|
||||||
|
|
||||||
CKernel g_Kernel;
|
CKernel g_Kernel;
|
||||||
|
@ -52,33 +54,29 @@ void CKernel::Start(void)
|
||||||
m_DriverManager->AddDriver(Ramdisk);
|
m_DriverManager->AddDriver(Ramdisk);
|
||||||
|
|
||||||
m_DriverManager->LoadNew();
|
m_DriverManager->LoadNew();
|
||||||
|
|
||||||
CTask *KernelTask = CreateKernelTask();
|
CTask *KernelTask = CreateKernelTask();
|
||||||
kprintf("[i] Kernel task has TID %i.\n", KernelTask->GetPID());
|
kprintf("[i] Kernel task has TID %i.\n", KernelTask->GetPID());
|
||||||
CScheduler::AddTask(KernelTask);
|
CScheduler::AddTask(KernelTask);
|
||||||
CScheduler::Enable();
|
CScheduler::Enable();
|
||||||
|
|
||||||
//PANIC("I LIKE THE COCK");
|
|
||||||
|
|
||||||
CTask *ParentTask = CScheduler::GetCurrentTask();
|
CTask *ParentTask = CScheduler::GetCurrentTask();
|
||||||
CTask *NewTask = ParentTask->Fork();
|
CTask *NewTask = ParentTask->Fork();
|
||||||
|
CTimer::GetTicks();
|
||||||
if (NewTask == ParentTask)
|
if (NewTask == ParentTask)
|
||||||
{
|
{
|
||||||
|
|
||||||
for (;;) {
|
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++){}
|
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
|
else
|
||||||
{
|
{
|
||||||
for (;;) {
|
for (;;) {
|
||||||
for (volatile u32 i = 0; i < 3500; i++)
|
CScheduler::GetCurrentTask()->Sleep(1000);
|
||||||
{
|
|
||||||
for (volatile u32 j = 0; j < 650; j++){}
|
|
||||||
}
|
|
||||||
kprintf("[i] Hello! I'm the child process.\n");
|
kprintf("[i] Hello! I'm the child process.\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,11 +20,16 @@ __attribute__((optimize("O0"))) void CRoundRobinScheduler::NextTask(void)
|
||||||
PANIC("No tasks in queue!");
|
PANIC("No tasks in queue!");
|
||||||
|
|
||||||
// Fetch next task.
|
// Fetch next task.
|
||||||
m_TaskQueuePosition++;
|
CTask *NextTask;
|
||||||
if (m_TaskQueuePosition >= m_TaskQueue.GetSize())
|
do {
|
||||||
// Something happened - restart the queue
|
m_TaskQueuePosition++;
|
||||||
m_TaskQueuePosition = 0;
|
|
||||||
CTask *NextTask = m_TaskQueue[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())
|
if (m_CurrentTask->GetPID() == NextTask->GetPID())
|
||||||
return;
|
return;
|
||||||
|
@ -89,3 +94,18 @@ CTask *CRoundRobinScheduler::GetCurrentTask(void)
|
||||||
{
|
{
|
||||||
return m_CurrentTask;
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using namespace cb;
|
using namespace cb;
|
||||||
|
|
||||||
#include "Tier1/CRoundRobinScheduler.h"
|
#include "Tier1/CRoundRobinScheduler.h"
|
||||||
|
#include "Tier1/CTimer.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "Tier0/heap.h"
|
#include "Tier0/heap.h"
|
||||||
|
@ -32,20 +33,22 @@ CTask *CScheduler::GetCurrentTask(void)
|
||||||
|
|
||||||
void CScheduler::Enable(void)
|
void CScheduler::Enable(void)
|
||||||
{
|
{
|
||||||
u32 Divisor = 0xFFFFFFFF;
|
// 20ms quntum
|
||||||
koutb(0x43, 0x36);
|
CTimer::Create(200, -1, TimerTick);
|
||||||
u8 Low = (u8)(Divisor & 0xFF);
|
|
||||||
u8 High = (u8)((Divisor >> 8) & 0xFF);
|
|
||||||
koutb(0x40, Low);
|
|
||||||
koutb(0x40, High);
|
|
||||||
|
|
||||||
interrupts_setup_irq(0x00, (void*)CScheduler::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();
|
g_Scheduler.m_CurrentScheduler->NextTask();
|
||||||
interrupts_irq_finish(0);
|
return true;
|
||||||
__asm__ volatile("sti");
|
}
|
||||||
|
|
||||||
|
void CScheduler::NextTask(void)
|
||||||
|
{
|
||||||
|
g_Scheduler.m_CurrentScheduler->NextTask();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CScheduler::DispatchAvailableSemaphore(CSemaphore *Semaphore)
|
||||||
|
{
|
||||||
|
g_Scheduler.m_CurrentScheduler->DispatchAvailableSemaphore(Semaphore);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "Tier1/CSemaphore.h"
|
#include "Tier1/CSemaphore.h"
|
||||||
|
#include "Tier1/CScheduler.h"
|
||||||
using namespace cb;
|
using namespace cb;
|
||||||
|
|
||||||
CSemaphore::CSemaphore(u32 Available)
|
CSemaphore::CSemaphore(u32 Available)
|
||||||
|
@ -8,18 +9,30 @@ CSemaphore::CSemaphore(u32 Available)
|
||||||
|
|
||||||
void CSemaphore::Acquire(void)
|
void CSemaphore::Acquire(void)
|
||||||
{
|
{
|
||||||
// Just spinlock...
|
__asm__ volatile("cli");
|
||||||
while (1)
|
if (atomic_read(&m_Available) > 0)
|
||||||
{
|
{
|
||||||
if (atomic_read(&m_Available) > 0)
|
atomic_dec(&m_Available);
|
||||||
{
|
return;
|
||||||
atomic_dec(&m_Available);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
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)
|
void CSemaphore::Release(void)
|
||||||
{
|
{
|
||||||
|
__asm__ volatile("cli");
|
||||||
atomic_inc(&m_Available);
|
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");
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ extern "C" {
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "Tier1/CScheduler.h"
|
#include "Tier1/CScheduler.h"
|
||||||
|
#include "Tier1/CTimer.h"
|
||||||
|
|
||||||
extern CPageDirectory *g_KernelPageDirectory;
|
extern CPageDirectory *g_KernelPageDirectory;
|
||||||
u32 CTaskNextPID = 0;
|
u32 CTaskNextPID = 0;
|
||||||
|
@ -27,10 +28,11 @@ CTask::CTask(bool User, bool Empty)
|
||||||
else
|
else
|
||||||
m_CreatedStack = false;
|
m_CreatedStack = false;
|
||||||
|
|
||||||
|
m_Status = ETS_RUNNING;
|
||||||
m_PID = CTaskNextPID++;
|
m_PID = CTaskNextPID++;
|
||||||
m_Priority = ETP_NORMAL;
|
m_Priority = ETP_NORMAL;
|
||||||
m_Owner = 0;
|
m_Owner = 0;
|
||||||
m_Ring = (User ? ETP_RING3 : ETP_RING0);
|
m_Ring = (User ? ETR_RING3 : ETR_RING0);
|
||||||
}
|
}
|
||||||
|
|
||||||
CTask::~CTask(void)
|
CTask::~CTask(void)
|
||||||
|
@ -130,3 +132,58 @@ void CTask::Dump(void)
|
||||||
m_ESP, m_EBP, m_EIP);
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue