mirror of
https://github.com/pret/pokediamond.git
synced 2026-10-06 17:10:30 -04:00
610 lines
14 KiB
C
610 lines
14 KiB
C
#include "OS_thread.h"
|
|
#include "function_target.h"
|
|
#include "OS_system.h"
|
|
#include "consts.h"
|
|
#include "OS_terminate_proc.h"
|
|
#include "OS_mutex.h"
|
|
#include "OS_alarm.h"
|
|
#include "OS_context.h"
|
|
#include "nitro/OS_systemWork_shared.h"
|
|
#include "MI_memory.h"
|
|
|
|
extern void SDK_SYS_STACKSIZE(void);
|
|
extern void SDK_IRQ_STACKSIZE(void);
|
|
|
|
u32 OSi_RescheduleCount = 0;
|
|
|
|
void *OSi_StackForDestructor = NULL;
|
|
|
|
OSThreadInfo OSi_ThreadInfo;
|
|
|
|
BOOL OSi_IsThreadInitialized = FALSE;
|
|
|
|
OSThread **OSi_CurrentThreadPtr = NULL;
|
|
|
|
void *OSi_SystemCallbackInSwitchThread = NULL;
|
|
|
|
static s32 OSi_ThreadIdCount = 0;
|
|
|
|
OSThread OSi_LauncherThread;
|
|
OSThread OSi_IdleThread;
|
|
|
|
static s32 OSi_GetUnusedThreadId(void);
|
|
static void OSi_InsertLinkToQueue(OSThreadQueue *queue, OSThread *thread);
|
|
static OSThread *OSi_RemoveLinkFromQueue(OSThreadQueue *queue);
|
|
static OSThread *OSi_RemoveSpecifiedLinkFromQueue(OSThreadQueue *queue, OSThread *thread);
|
|
static void OSi_InsertThreadToList(OSThread *thread);
|
|
static void OSi_RemoveThreadFromList(OSThread *thread);
|
|
static void OSi_RescheduleThread(void);
|
|
static void OSi_ExitThread_ArgSpecified(OSThread *thread, void *arg);
|
|
static void OSi_ExitThread(void *arg);
|
|
static void OSi_ExitThread_Destroy(void);
|
|
static void OSi_SleepAlarmCallback(void *arg);
|
|
|
|
ARM_FUNC static s32 OSi_GetUnusedThreadId(void)
|
|
{
|
|
return ++OSi_ThreadIdCount;
|
|
}
|
|
|
|
ARM_FUNC static void OSi_InsertLinkToQueue(OSThreadQueue *queue, OSThread *thread)
|
|
{
|
|
OSThread *next = queue->head;
|
|
|
|
while (next && next->priority <= thread->priority)
|
|
{
|
|
if (next == thread)
|
|
return;
|
|
next = next->link.next;
|
|
}
|
|
|
|
if (!next)
|
|
{
|
|
OSThread *prev = queue->tail;
|
|
|
|
if (!prev)
|
|
{
|
|
queue->head = thread;
|
|
}
|
|
else
|
|
{
|
|
prev->link.next = thread;
|
|
}
|
|
|
|
thread->link.prev = prev;
|
|
thread->link.next = NULL;
|
|
queue->tail = thread;
|
|
}
|
|
else
|
|
{
|
|
OSThread *prev = next->link.prev;
|
|
|
|
if (!prev)
|
|
{
|
|
queue->head = thread;
|
|
}
|
|
else
|
|
{
|
|
prev->link.next = thread;
|
|
}
|
|
|
|
thread->link.prev = prev;
|
|
thread->link.next = next;
|
|
next->link.prev = thread;
|
|
}
|
|
}
|
|
|
|
ARM_FUNC static OSThread *OSi_RemoveLinkFromQueue(OSThreadQueue *queue)
|
|
{
|
|
OSThread *thread = queue->head;
|
|
|
|
if (thread)
|
|
{
|
|
OSThread *next = thread->link.next;
|
|
|
|
queue->head = next;
|
|
|
|
if (next)
|
|
{
|
|
next->link.prev = NULL;
|
|
}
|
|
else
|
|
{
|
|
queue->tail = NULL;
|
|
thread->queue = NULL;
|
|
}
|
|
}
|
|
|
|
return thread;
|
|
}
|
|
|
|
ARM_FUNC static OSThread *OSi_RemoveSpecifiedLinkFromQueue(OSThreadQueue *queue, OSThread *thread)
|
|
{
|
|
OSThread *queueHead = queue->head;
|
|
|
|
while (queueHead)
|
|
{
|
|
OSThread *next = queueHead->link.next;
|
|
|
|
if (queueHead == thread)
|
|
{
|
|
OSThread *prev = queueHead->link.prev;
|
|
|
|
if (queue->head == queueHead)
|
|
{
|
|
queue->head = next;
|
|
}
|
|
else
|
|
{
|
|
prev->link.next = next;
|
|
}
|
|
|
|
if (queue->tail == queueHead)
|
|
{
|
|
queue->tail = prev;
|
|
}
|
|
else
|
|
{
|
|
next->link.prev = prev;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
queueHead = next;
|
|
}
|
|
|
|
return queueHead;
|
|
}
|
|
|
|
ARM_FUNC OSMutex *OSi_RemoveMutexLinkFromQueue(OSMutexQueue *queue)
|
|
{
|
|
OSMutex *mutexHead = queue->head;
|
|
|
|
if (mutexHead)
|
|
{
|
|
OSMutex *next = mutexHead->link.next;
|
|
|
|
queue->head = next;
|
|
|
|
if (next)
|
|
{
|
|
next->link.prev = NULL;
|
|
}
|
|
else
|
|
{
|
|
queue->tail = NULL;
|
|
}
|
|
}
|
|
|
|
return mutexHead;
|
|
}
|
|
|
|
ARM_FUNC static void OSi_InsertThreadToList(OSThread *thread)
|
|
{
|
|
OSThread *t = OSi_ThreadInfo.list;
|
|
OSThread *pre = NULL;
|
|
|
|
while(t && t->priority < thread->priority)
|
|
{
|
|
pre = t;
|
|
t = t->next;
|
|
}
|
|
|
|
if (!pre)
|
|
{
|
|
thread->next = OSi_ThreadInfo.list;
|
|
OSi_ThreadInfo.list = thread;
|
|
}
|
|
else
|
|
{
|
|
thread->next = pre->next;
|
|
pre->next = thread;
|
|
}
|
|
}
|
|
|
|
ARM_FUNC static void OSi_RemoveThreadFromList(OSThread *thread)
|
|
{
|
|
OSThread *t = OSi_ThreadInfo.list;
|
|
OSThread *pre = NULL;
|
|
|
|
while (t && t != thread)
|
|
{
|
|
pre = t;
|
|
t = t-> next;
|
|
}
|
|
|
|
if (!pre)
|
|
{
|
|
OSi_ThreadInfo.list = thread->next;
|
|
}
|
|
else
|
|
{
|
|
pre->next = thread->next;
|
|
}
|
|
}
|
|
|
|
ARM_FUNC static void OSi_RescheduleThread(void)
|
|
{
|
|
if (OSi_RescheduleCount <= 0)
|
|
{
|
|
OSThreadInfo *info = &OSi_ThreadInfo;
|
|
if (info->irqDepth > 0 || OS_GetProcMode() == OS_PROCMODE_IRQ)
|
|
{
|
|
info->isNeedRescheduling = TRUE;
|
|
}
|
|
else
|
|
{
|
|
OSThread *currentThread = OSi_GetCurrentThread();
|
|
OSThread *nextThread = OS_SelectThread();
|
|
|
|
if (currentThread == nextThread || !nextThread)
|
|
return;
|
|
|
|
if (currentThread->state != OS_THREAD_STATE_TERMINATED
|
|
&& OS_SaveContext(¤tThread->context))
|
|
return;
|
|
|
|
if (OSi_SystemCallbackInSwitchThread)
|
|
{
|
|
((OSSwitchThreadCallback)OSi_SystemCallbackInSwitchThread) (currentThread, nextThread);
|
|
}
|
|
|
|
if (info->switchCallback)
|
|
{
|
|
((OSSwitchThreadCallback)info->switchCallback) (currentThread, nextThread);
|
|
}
|
|
|
|
OS_SetCurrentThread(nextThread);
|
|
|
|
OS_LoadContext(&nextThread->context);
|
|
}
|
|
}
|
|
}
|
|
|
|
ARM_FUNC void OS_InitThread(void)
|
|
{
|
|
if (OSi_IsThreadInitialized)
|
|
return;
|
|
OSi_IsThreadInitialized = TRUE;
|
|
|
|
OSi_CurrentThreadPtr = &(OSi_ThreadInfo.current);
|
|
|
|
OSi_LauncherThread.priority = OS_THREAD_LAUNCHER_PRIORITY;
|
|
OSi_LauncherThread.id = 0;
|
|
OSi_LauncherThread.state = OS_THREAD_STATE_READY;
|
|
OSi_LauncherThread.next = NULL;
|
|
|
|
OSi_LauncherThread.profiler = NULL;
|
|
|
|
OSi_ThreadInfo.list = &OSi_LauncherThread;
|
|
|
|
OS_SetCurrentThread(&OSi_LauncherThread);
|
|
|
|
void *stackLo = (((s32)SDK_SYS_STACKSIZE) <= 0) ?
|
|
(void *)((u32)HW_WRAM - (s32)SDK_SYS_STACKSIZE) :
|
|
(void *)((u32)(HW_PRV_WRAM_IRQ_STACK_END - (s32)SDK_IRQ_STACKSIZE) - (s32)SDK_SYS_STACKSIZE);
|
|
|
|
OSi_LauncherThread.stackBottom = (u32)(HW_PRV_WRAM_IRQ_STACK_END - (s32)SDK_IRQ_STACKSIZE);
|
|
OSi_LauncherThread.stackTop = (u32)stackLo;
|
|
OSi_LauncherThread.stackWarningOffset = 0;
|
|
|
|
//checksums
|
|
*(u32 *)(OSi_LauncherThread.stackBottom - sizeof(u32)) = 0xd73bfdf7UL;
|
|
*(u32 *)OSi_LauncherThread.stackTop = 0xfbdd37bbUL;
|
|
|
|
OS_InitThreadQueue(&OSi_LauncherThread.joinQueue);
|
|
|
|
OSi_ThreadInfo.isNeedRescheduling = FALSE;
|
|
OSi_ThreadInfo.irqDepth = 0;
|
|
|
|
OS_GetSystemWork()->threadinfo_subp = &OSi_ThreadInfo;
|
|
|
|
(void)OS_SetSwitchThreadCallback(NULL);
|
|
}
|
|
|
|
ARM_FUNC void OS_CreateThread(OSThread *thread, void (*func) (void *), void *arg, void *stack, u32 stackSize, u32 prio)
|
|
{
|
|
OSIntrMode enable = OS_DisableInterrupts();
|
|
|
|
s32 index = OSi_GetUnusedThreadId();
|
|
|
|
thread->priority = prio;
|
|
thread->id = (u32)index;
|
|
thread->state = OS_THREAD_STATE_WAITING;
|
|
|
|
thread->profiler = NULL;
|
|
|
|
OSi_InsertThreadToList(thread);
|
|
|
|
thread->stackBottom = (u32)stack;
|
|
thread->stackTop = (u32)stack - stackSize;
|
|
thread->stackWarningOffset = 0;
|
|
|
|
*(u32 *)(thread->stackBottom - sizeof(u32)) = 0xd73bfdf7UL;
|
|
*(u32 *)thread->stackTop = 0xfbdd37bbUL;
|
|
|
|
OS_InitThreadQueue(&thread->joinQueue);
|
|
|
|
OS_InitContext(&thread->context, (u32)func, (u32)stack - 4);
|
|
|
|
thread->context.r[0] = (u32)arg;
|
|
thread->context.lr = (u32)OS_ExitThread;
|
|
|
|
MI_CpuClear32((void *)((u32)stack - stackSize + 4), stackSize - 8);
|
|
|
|
thread->mutex = NULL;
|
|
thread->mutexQueue.head = NULL;
|
|
thread->mutexQueue.tail = NULL;
|
|
|
|
OS_SetThreadDestructor(thread, NULL);
|
|
|
|
thread->queue = NULL;
|
|
thread->link.prev = thread->link.next = NULL;
|
|
|
|
MI_CpuClear32(&thread->specific[0], sizeof(void *) * OS_THREAD_SPECIFIC_MAX);
|
|
|
|
thread->alarmForSleep = NULL;
|
|
|
|
(void)OS_RestoreInterrupts(enable);
|
|
}
|
|
|
|
ARM_FUNC void OS_ExitThread(void)
|
|
{
|
|
(void)OS_DisableInterrupts();
|
|
OSi_ExitThread_ArgSpecified(OS_GetCurrentThread(), 0);
|
|
}
|
|
|
|
ARM_FUNC static void OSi_ExitThread_ArgSpecified(OSThread *thread, void *arg)
|
|
{
|
|
if (OSi_StackForDestructor)
|
|
{
|
|
OS_InitContext(&thread->context, (u32)OSi_ExitThread, (u32)OSi_StackForDestructor);
|
|
thread->context.r[0] = (u32)arg;
|
|
thread->context.cpsr |= HW_PSR_DISABLE_IRQ;
|
|
thread->state = OS_THREAD_STATE_READY;
|
|
OS_LoadContext(&thread->context);
|
|
}
|
|
else
|
|
{
|
|
OSi_ExitThread(arg);
|
|
}
|
|
}
|
|
|
|
ARM_FUNC static void OSi_ExitThread(void *arg)
|
|
{
|
|
OSThread *currentThread = OSi_GetCurrentThread();
|
|
OSThreadDestructor destructor = currentThread->destructor;
|
|
|
|
if (destructor)
|
|
{
|
|
currentThread->destructor = NULL;
|
|
destructor(arg);
|
|
(void)OS_DisableInterrupts();
|
|
}
|
|
|
|
OSi_ExitThread_Destroy();
|
|
}
|
|
|
|
ARM_FUNC static void OSi_ExitThread_Destroy(void)
|
|
{
|
|
OSThread *currentThread = OSi_GetCurrentThread();
|
|
(void)OS_DisableScheduler();
|
|
|
|
OSi_UnlockAllMutex(currentThread);
|
|
|
|
if (currentThread->queue)
|
|
{
|
|
(void)OSi_RemoveSpecifiedLinkFromQueue(currentThread->queue, currentThread);
|
|
}
|
|
|
|
OSi_RemoveThreadFromList(currentThread);
|
|
|
|
currentThread->state = OS_THREAD_STATE_TERMINATED;
|
|
|
|
OS_WakeupThread(¤tThread->joinQueue);
|
|
|
|
(void)OS_EnableScheduler();
|
|
|
|
OS_RescheduleThread();
|
|
|
|
OS_Terminate();
|
|
}
|
|
|
|
ARM_FUNC void OS_JoinThread(OSThread *thread)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
|
|
if (thread->state != OS_THREAD_STATE_TERMINATED)
|
|
{
|
|
OS_SleepThread(&thread->joinQueue);
|
|
}
|
|
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
}
|
|
|
|
ARM_FUNC BOOL OS_IsThreadTerminated(const OSThread *thread)
|
|
{
|
|
return (thread->state == OS_THREAD_STATE_TERMINATED) ? TRUE : FALSE;
|
|
}
|
|
|
|
ARM_FUNC void OS_SleepThread(OSThreadQueue *queue)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
OSThread *currentThread = OSi_GetCurrentThread();
|
|
|
|
if (queue)
|
|
{
|
|
currentThread->queue = queue;
|
|
OSi_InsertLinkToQueue(queue, currentThread);
|
|
}
|
|
|
|
currentThread->state = OS_THREAD_STATE_WAITING;
|
|
OSi_RescheduleThread();
|
|
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
}
|
|
|
|
ARM_FUNC void OS_WakeupThread(OSThreadQueue *queue)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
|
|
if (queue->head)
|
|
{
|
|
while (queue->head)
|
|
{
|
|
OSThread *thread = OSi_RemoveLinkFromQueue(queue);
|
|
|
|
thread->state = OS_THREAD_STATE_READY;
|
|
thread->queue = NULL;
|
|
thread->link.prev = thread->link.next = NULL;
|
|
}
|
|
|
|
OS_InitThreadQueue(queue);
|
|
OSi_RescheduleThread();
|
|
}
|
|
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
}
|
|
|
|
ARM_FUNC void OS_WakeupThreadDirect(OSThread *thread)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
|
|
thread->state = OS_THREAD_STATE_READY;
|
|
OSi_RescheduleThread();
|
|
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
}
|
|
|
|
ARM_FUNC OSThread *OS_SelectThread(void)
|
|
{
|
|
OSThread *thread = OSi_ThreadInfo.list;
|
|
|
|
while (thread && !OS_IsThreadRunnable(thread))
|
|
{
|
|
thread = thread->next;
|
|
}
|
|
|
|
return thread;
|
|
}
|
|
|
|
ARM_FUNC void OS_RescheduleThread(void)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
OSi_RescheduleThread();
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
}
|
|
|
|
ARM_FUNC BOOL OS_SetThreadPriority(OSThread *thread, u32 prio)
|
|
{
|
|
OSThread *t = OSi_ThreadInfo.list;
|
|
OSThread *pre = NULL;
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
|
|
while (t && t != thread)
|
|
{
|
|
pre = t;
|
|
t = t->next;
|
|
}
|
|
|
|
if (!t || t == &OSi_IdleThread)
|
|
{
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
return FALSE;
|
|
}
|
|
|
|
if (t->priority != prio)
|
|
{
|
|
if (!pre)
|
|
{
|
|
OSi_ThreadInfo.list = thread->next;
|
|
}
|
|
else
|
|
{
|
|
pre->next = thread->next;
|
|
}
|
|
|
|
thread->priority = prio;
|
|
OSi_InsertThreadToList(thread);
|
|
|
|
OSi_RescheduleThread();
|
|
}
|
|
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
ARM_FUNC void OS_Sleep(u32 msec)
|
|
{
|
|
OSAlarm alarm;
|
|
|
|
OS_CreateAlarm(&alarm);
|
|
OSThread *volatile p_thread = OSi_GetCurrentThread();
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
|
|
p_thread->alarmForSleep = &alarm;
|
|
|
|
OS_SetAlarm(&alarm, OS_MilliSecondsToTicks(msec), &OSi_SleepAlarmCallback,
|
|
(void*)&p_thread);
|
|
while (p_thread != NULL)
|
|
{
|
|
OS_SleepThread(NULL);
|
|
}
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
}
|
|
|
|
ARM_FUNC static void OSi_SleepAlarmCallback(void *arg)
|
|
{
|
|
OSThread **pp_thread = (OSThread **)arg;
|
|
OSThread *p_thread = *pp_thread;
|
|
*pp_thread = NULL;
|
|
|
|
p_thread->alarmForSleep = NULL;
|
|
|
|
OS_WakeupThreadDirect(p_thread);
|
|
}
|
|
|
|
ARM_FUNC OSSwitchThreadCallback OS_SetSwitchThreadCallback(OSSwitchThreadCallback callback)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
OSSwitchThreadCallback prev = OSi_ThreadInfo.switchCallback;
|
|
OSi_ThreadInfo.switchCallback = callback;
|
|
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
return prev;
|
|
}
|
|
|
|
ARM_FUNC u32 OS_DisableScheduler(void)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
u32 count;
|
|
|
|
if (OSi_RescheduleCount < (u32)-1)
|
|
{
|
|
count = OSi_RescheduleCount++;
|
|
}
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
|
|
return count;
|
|
}
|
|
|
|
ARM_FUNC u32 OS_EnableScheduler(void)
|
|
{
|
|
OSIntrMode enabled = OS_DisableInterrupts();
|
|
u32 count = 0;
|
|
|
|
if (OSi_RescheduleCount > 0)
|
|
{
|
|
count = OSi_RescheduleCount--;
|
|
}
|
|
(void)OS_RestoreInterrupts(enabled);
|
|
|
|
return count;
|
|
}
|
|
|
|
ARM_FUNC void OS_SetThreadDestructor(OSThread *thread, OSThreadDestructor dtor)
|
|
{
|
|
thread->destructor = dtor;
|
|
}
|