mirror of
https://github.com/Gericom/libtwl.git
synced 2025-06-19 03:25:34 -04:00
242 lines
5.7 KiB
C
242 lines
5.7 KiB
C
#include <nds.h>
|
|
#include "libtwl/rtos/rtosMutex.h"
|
|
#include "libtwl/rtos/rtosIrq.h"
|
|
#include "libtwl/rtos/rtosThread.h"
|
|
|
|
#ifdef LIBTWL_ARM9
|
|
static DTCM_BSS rtos_thread_t sMainThread;
|
|
#endif
|
|
#ifdef LIBTWL_ARM7
|
|
static rtos_thread_t sMainThread;
|
|
#endif
|
|
static rtos_thread_t sIdleThread;
|
|
static u32 sIdleStack[64];
|
|
|
|
static void insertReadyList(rtos_thread_t* thread)
|
|
{
|
|
thread->state = RTOS_THREAD_STATE_READY;
|
|
|
|
int prio = thread->priority;
|
|
|
|
rtos_thread_t* t = gRtosState.threadReadyList;
|
|
if (t->priority <= prio)
|
|
{
|
|
gRtosState.threadReadyList = thread;
|
|
thread->prev = NULL;
|
|
thread->next = t;
|
|
t->prev = thread;
|
|
}
|
|
else
|
|
{
|
|
while (t->priority > prio)
|
|
t = t->next;
|
|
|
|
thread->next = t;
|
|
rtos_thread_t* newPrev = t->prev;
|
|
thread->prev = newPrev;
|
|
t->prev = thread;
|
|
newPrev->next = thread;
|
|
}
|
|
}
|
|
|
|
static void idleMain(void* arg)
|
|
{
|
|
while (true)
|
|
{
|
|
rtos_halt();
|
|
}
|
|
}
|
|
|
|
void rtos_startMainThread(void)
|
|
{
|
|
rtos_createThread(&sIdleThread, 0, idleMain, NULL, sIdleStack, sizeof(sIdleStack));
|
|
sMainThread.inQueue = NULL;
|
|
sMainThread.priority = 16;
|
|
gRtosState.curThread = &sMainThread;
|
|
gRtosState.threadReadyList = &sMainThread;
|
|
gRtosState.threadReadyList->prev = NULL;
|
|
gRtosState.threadReadyList->next = &sIdleThread;
|
|
sIdleThread.prev = &sMainThread;
|
|
sIdleThread.next = NULL;
|
|
sIdleThread.state = RTOS_THREAD_STATE_READY;
|
|
sMainThread.state = RTOS_THREAD_STATE_RUNNING;
|
|
}
|
|
|
|
extern void rtos_switchThreads(rtos_thread_t* cur, rtos_thread_t* new);
|
|
|
|
static void reschedule(void)
|
|
{
|
|
if (gRtosState.curThread == gRtosState.threadReadyList || gRtosState.irqDepth)
|
|
return;
|
|
rtos_thread_t* cur = gRtosState.curThread;
|
|
gRtosState.curThread = gRtosState.threadReadyList;
|
|
gRtosState.curThread->state = RTOS_THREAD_STATE_RUNNING;
|
|
rtos_switchThreads(cur, gRtosState.threadReadyList);
|
|
}
|
|
|
|
static void wakeupQueueWithoutReschedule(rtos_thread_queue_t* queue)
|
|
{
|
|
rtos_thread_t* t = queue->head;
|
|
while (t)
|
|
{
|
|
rtos_thread_t* next = t->next;
|
|
t->inQueue = NULL;
|
|
insertReadyList(t);
|
|
t = next;
|
|
}
|
|
queue->head = NULL;
|
|
}
|
|
|
|
static void threadEnd(void)
|
|
{
|
|
u32 irq = rtos_disableIrqs();
|
|
|
|
rtos_thread_t* cur = gRtosState.curThread;
|
|
|
|
cur->state = RTOS_THREAD_STATE_DEAD;
|
|
gRtosState.threadReadyList = cur->next;
|
|
cur->next->prev = NULL;
|
|
cur->next = NULL;
|
|
cur->prev = NULL;
|
|
|
|
rtos_object_t* obj = cur->objListHead;
|
|
while (obj)
|
|
{
|
|
rtos_object_t* next = obj->next;
|
|
if (obj->type == RTOS_OBJECT_TYPE_MUTEX)
|
|
{
|
|
rtos_mutex_t* mutex = (rtos_mutex_t*)obj;
|
|
mutex->owner = NULL;
|
|
mutex->lockCount = 0;
|
|
wakeupQueueWithoutReschedule(&mutex->queue);
|
|
}
|
|
obj->prev = NULL;
|
|
obj->next = NULL;
|
|
obj = next;
|
|
}
|
|
|
|
wakeupQueueWithoutReschedule(&cur->joinQueue);
|
|
|
|
reschedule();
|
|
|
|
//we'll never return here
|
|
|
|
rtos_restoreIrqs(irq);
|
|
}
|
|
|
|
void rtos_createThread(rtos_thread_t* thread, u8 priority, void (*mainFunc)(void*), void* arg, u32* stack, u32 stackSize)
|
|
{
|
|
u32* stackTop = (u32*)((u8*)stack + stackSize);
|
|
thread->r[0] = (u32)arg;
|
|
thread->r[13] = (u32)stackTop;
|
|
thread->r[14] = (u32)threadEnd;
|
|
thread->r[15] = (u32)mainFunc;
|
|
thread->cpsr = /*0x13*/0x1F | (((u32)mainFunc & 1) ? 0x20 : 0); //cpsr, svc mode, irq and fiq on
|
|
thread->next = NULL;
|
|
thread->prev = NULL;
|
|
thread->state = RTOS_THREAD_STATE_SLEEPING;
|
|
thread->priority = priority;
|
|
thread->objListHead = NULL;
|
|
thread->inQueue = NULL;
|
|
thread->joinQueue.head = NULL;
|
|
}
|
|
|
|
void rtos_wakeupThread(rtos_thread_t* thread)
|
|
{
|
|
u32 irq = rtos_disableIrqs();
|
|
|
|
if (thread->state != RTOS_THREAD_STATE_SLEEPING)
|
|
{
|
|
rtos_restoreIrqs(irq);
|
|
return;
|
|
}
|
|
|
|
insertReadyList(thread);
|
|
|
|
reschedule();
|
|
|
|
rtos_restoreIrqs(irq);
|
|
}
|
|
|
|
void rtos_sleepThread(rtos_thread_t* thread)
|
|
{
|
|
u32 irq = rtos_disableIrqs();
|
|
|
|
if (thread == NULL)
|
|
thread = gRtosState.curThread;
|
|
|
|
if (thread->state == RTOS_THREAD_STATE_DEAD || thread->state == RTOS_THREAD_STATE_SLEEPING)
|
|
{
|
|
rtos_restoreIrqs(irq);
|
|
return;
|
|
}
|
|
|
|
thread->state = RTOS_THREAD_STATE_SLEEPING;
|
|
|
|
if (!thread->prev)
|
|
{
|
|
gRtosState.threadReadyList = thread->next;
|
|
thread->next->prev = NULL;
|
|
thread->next = NULL;
|
|
thread->prev = NULL;
|
|
reschedule();
|
|
}
|
|
else
|
|
{
|
|
thread->prev->next = thread->next;
|
|
thread->next->prev = thread->prev;
|
|
thread->next = NULL;
|
|
thread->prev = NULL;
|
|
}
|
|
|
|
rtos_restoreIrqs(irq);
|
|
}
|
|
|
|
void rtos_joinThread(rtos_thread_t* thread)
|
|
{
|
|
rtos_queueThread(rtos_getCurThread(), &thread->joinQueue);
|
|
}
|
|
|
|
void rtos_queueThread(rtos_thread_t* thread, rtos_thread_queue_t* queue)
|
|
{
|
|
u32 irq = rtos_disableIrqs();
|
|
|
|
thread->state = RTOS_THREAD_STATE_SLEEPING;
|
|
thread->inQueue = queue;
|
|
|
|
if (!thread->prev)
|
|
{
|
|
gRtosState.threadReadyList = thread->next;
|
|
thread->next->prev = NULL;
|
|
|
|
thread->next = queue->head;
|
|
if (queue->head)
|
|
queue->head->prev = thread;
|
|
queue->head = thread;
|
|
thread->prev = NULL;
|
|
reschedule();
|
|
}
|
|
else
|
|
{
|
|
thread->prev->next = thread->next;
|
|
thread->next->prev = thread->prev;
|
|
|
|
thread->next = queue->head;
|
|
if (queue->head)
|
|
queue->head->prev = thread;
|
|
queue->head = thread;
|
|
thread->prev = NULL;
|
|
}
|
|
|
|
rtos_restoreIrqs(irq);
|
|
}
|
|
|
|
void rtos_wakeupQueue(rtos_thread_queue_t* queue)
|
|
{
|
|
u32 irq = rtos_disableIrqs();
|
|
|
|
wakeupQueueWithoutReschedule(queue);
|
|
reschedule();
|
|
|
|
rtos_restoreIrqs(irq);
|
|
} |