mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-08-16 20:27:36 -04:00
Reorganize library code into libs/ (#3119)
* Reorganize files into libs/{dolphin,JSystem,PowerPC_EABI_Support,revolution,TRK_MINNOW_DOLPHIN}
* Update configure.py and project.py for new libs structure
* Refactor `#include <dolphin/x.h>` -> `<x.h>`
* Remove `__REVOLUTION_SDK__` forwards from dolphin
* Fix dolphin/ references in revolution
* Wrap `#include <dolphin.h>` in `!__REVOLUTION_SDK__`
* Always build TRK against dolphin headers
* Resolve revolution SDK header resolution issues
This commit is contained in:
@@ -0,0 +1,876 @@
|
||||
#include <revolution.h>
|
||||
#include <revolution/os.h>
|
||||
|
||||
#include "__os.h"
|
||||
|
||||
#define ENQUEUE_THREAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __prev = (queue)->tail; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (thread); \
|
||||
} else { \
|
||||
__prev->link.next = (thread); \
|
||||
} \
|
||||
(thread)->link.prev = __prev; \
|
||||
(thread)->link.next = 0; \
|
||||
(queue)->tail = (thread); \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_THREAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __next = (thread)->link.next; \
|
||||
OSThread* __prev = (thread)->link.prev; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = __prev; \
|
||||
} else { \
|
||||
__next->link.prev = __prev; \
|
||||
} \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = __next; \
|
||||
} else { \
|
||||
__prev->link.next = __next; \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define ENQUEUE_THREAD_PRIO(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __prev; \
|
||||
OSThread* __next; \
|
||||
for(__next = (queue)->head; __next \
|
||||
&& (__next->priority <= (thread)->priority); \
|
||||
__next = __next->link.next) ; \
|
||||
\
|
||||
if (__next == NULL) { \
|
||||
ENQUEUE_THREAD(thread, queue, link); \
|
||||
} else { \
|
||||
(thread)->link.next = __next; \
|
||||
__prev = __next->link.prev; \
|
||||
__next->link.prev = (thread); \
|
||||
(thread)->link.prev = __prev; \
|
||||
if (__prev == NULL) { \
|
||||
(queue)->head = (thread); \
|
||||
} else { \
|
||||
__prev->link.next = (thread); \
|
||||
} \
|
||||
} \
|
||||
} while(0);
|
||||
|
||||
#define DEQUEUE_HEAD(thread, queue, link) \
|
||||
do { \
|
||||
OSThread* __next = thread->link.next; \
|
||||
if (__next == NULL) { \
|
||||
(queue)->tail = 0; \
|
||||
} else { \
|
||||
__next->link.prev = 0; \
|
||||
} \
|
||||
(queue)->head = __next; \
|
||||
} while(0);
|
||||
|
||||
// defined in linkscript
|
||||
extern u8 _stack_end[];
|
||||
extern u8 _stack_addr[];
|
||||
|
||||
static OSThreadQueue RunQueue[32];
|
||||
static OSThread IdleThread;
|
||||
static OSThread DefaultThread;
|
||||
static OSContext IdleContext;
|
||||
static volatile u32 RunQueueBits;
|
||||
static volatile int RunQueueHint;
|
||||
static volatile s32 Reschedule;
|
||||
|
||||
#define ALIGN4(val) (((val) + 0x3) & ~0x3)
|
||||
#define ALIGN8(val) (((val) + 0x7) & ~0x7)
|
||||
|
||||
// prototypes
|
||||
static void OSInitMutexQueue(OSMutexQueue* queue);
|
||||
static void __OSSwitchThread(OSThread* nextThread);
|
||||
static int __OSIsThreadActive(OSThread* thread);
|
||||
static void SetRun(OSThread* thread);
|
||||
static void UnsetRun(OSThread* thread);
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, s32 priority);
|
||||
static void UpdatePriority(OSThread* thread);
|
||||
static OSThread* SelectThread(int yield);
|
||||
static int CheckThreadQueue(OSThreadQueue* queue);
|
||||
static int IsMember(OSThreadQueue* queue, OSThread* thread);
|
||||
static void OSSetCurrentThread(OSThread* thread);
|
||||
|
||||
static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {}
|
||||
static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback;
|
||||
|
||||
OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback callback) {
|
||||
OSSwitchThreadCallback prev;
|
||||
BOOL enabled;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
prev = SwitchThreadCallback;
|
||||
|
||||
SwitchThreadCallback = callback ? callback : DefaultSwitchThreadCallback;
|
||||
OSRestoreInterrupts(enabled);
|
||||
|
||||
return prev == DefaultSwitchThreadCallback ? NULL : prev;
|
||||
}
|
||||
|
||||
void __OSThreadInit() {
|
||||
OSThread* thread = &DefaultThread;
|
||||
OSPriority prio;
|
||||
|
||||
thread->state = OS_THREAD_STATE_RUNNING;
|
||||
thread->attr = 1;
|
||||
thread->priority = thread->base = 0x10;
|
||||
thread->suspend = 0;
|
||||
thread->val = (void*)-1; // wut
|
||||
thread->mutex = 0;
|
||||
|
||||
OSInitThreadQueue(&thread->queueJoin);
|
||||
#if DEBUG
|
||||
OSInitMutexQueue(&thread->queueMutex);
|
||||
#else
|
||||
thread->queueMutex.head = thread->queueMutex.tail = 0; // it got inlined? cant reproduce the inline...
|
||||
#endif
|
||||
|
||||
ASSERTLINE(372, PPCMfmsr() & MSR_FP);
|
||||
|
||||
__gUnkThread1 = thread;
|
||||
OSClearContext(&thread->context);
|
||||
OSSetCurrentContext(&thread->context);
|
||||
thread->stackBase = (u8*)&_stack_addr;
|
||||
thread->stackEnd = (u32*)&_stack_end;
|
||||
*(u32*)thread->stackEnd = OS_THREAD_STACK_MAGIC;
|
||||
OSSetCurrentThread(thread);
|
||||
OSClearStack(0);
|
||||
RunQueueBits = 0;
|
||||
RunQueueHint = 0;
|
||||
|
||||
for (prio = 0; prio <= 31; prio++) {
|
||||
OSInitThreadQueue(&RunQueue[prio]);
|
||||
}
|
||||
OSInitThreadQueue(&__OSActiveThreadQueue);
|
||||
|
||||
ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
|
||||
OSClearContext(&IdleContext);
|
||||
Reschedule = 0;
|
||||
}
|
||||
|
||||
void OSSetCurrentThread(OSThread* thread) {
|
||||
SwitchThreadCallback(__OSCurrentThread, thread);
|
||||
__OSCurrentThread = thread;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
static void OSInitMutexQueue(OSMutexQueue* queue) {
|
||||
queue->head = queue->tail = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void OSInitThreadQueue(OSThreadQueue* queue) {
|
||||
queue->head = queue->tail = 0;
|
||||
}
|
||||
|
||||
OSThread* OSGetCurrentThread() {
|
||||
return __OSCurrentThread;
|
||||
}
|
||||
|
||||
static void __OSSwitchThread(OSThread* nextThread) {
|
||||
OSSetCurrentThread(nextThread);
|
||||
OSSetCurrentContext(&nextThread->context);
|
||||
OSLoadContext(&nextThread->context);
|
||||
}
|
||||
|
||||
BOOL OSIsThreadSuspended(OSThread* thread) {
|
||||
if (thread->suspend > 0) {
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL OSIsThreadTerminated(OSThread* thread) {
|
||||
return (thread->state == OS_THREAD_STATE_MORIBUND || thread->state == 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static BOOL __OSIsThreadActive(OSThread* thread) {
|
||||
OSThread* active;
|
||||
|
||||
if (thread->state == 0) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (active = __OSActiveThreadQueue.head; active; active = active->linkActive.next) {
|
||||
if (thread == active) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
s32 OSDisableScheduler(void) {
|
||||
BOOL enabled;
|
||||
s32 count;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
count = Reschedule++;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return count;
|
||||
}
|
||||
|
||||
s32 OSEnableScheduler(void) {
|
||||
BOOL enabled;
|
||||
s32 count;
|
||||
|
||||
enabled = OSDisableInterrupts();
|
||||
count = Reschedule--;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void SetRun(OSThread* thread) {
|
||||
ASSERTLINE(569, !IsSuspended(thread->suspend));
|
||||
ASSERTLINE(570, thread->state == OS_THREAD_STATE_READY);
|
||||
|
||||
ASSERTLINE(572, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX);
|
||||
|
||||
thread->queue = &RunQueue[thread->priority];
|
||||
|
||||
ENQUEUE_THREAD(thread, thread->queue, link);
|
||||
|
||||
RunQueueBits |= 1 << (OS_PRIORITY_MAX - thread->priority);
|
||||
RunQueueHint = 1;
|
||||
}
|
||||
|
||||
static void UnsetRun(OSThread* thread) {
|
||||
OSThreadQueue* queue;
|
||||
|
||||
ASSERTLINE(593, thread->state == OS_THREAD_STATE_READY);
|
||||
|
||||
ASSERTLINE(595, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX);
|
||||
ASSERTLINE(596, thread->queue == &RunQueue[thread->priority]);
|
||||
|
||||
queue = thread->queue;
|
||||
|
||||
DEQUEUE_THREAD(thread, queue, link);
|
||||
|
||||
if (!queue->head) {
|
||||
RunQueueBits &= ~(1 << (OS_PRIORITY_MAX - thread->priority));
|
||||
}
|
||||
thread->queue = NULL;
|
||||
}
|
||||
|
||||
s32 __OSGetEffectivePriority(OSThread* thread) {
|
||||
s32 priority = thread->base;
|
||||
OSMutex* mutex;
|
||||
OSThread* blocked;
|
||||
|
||||
for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) {
|
||||
blocked = mutex->queue.head;
|
||||
if (blocked && blocked->priority < priority) {
|
||||
priority = blocked->priority;
|
||||
}
|
||||
}
|
||||
return priority;
|
||||
}
|
||||
|
||||
static OSThread* SetEffectivePriority(OSThread* thread, s32 priority) {
|
||||
ASSERTLINE(647, !IsSuspended(thread->suspend));
|
||||
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
UnsetRun(thread);
|
||||
thread->priority = priority;
|
||||
SetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = priority;
|
||||
|
||||
ENQUEUE_THREAD_PRIO(thread, thread->queue, link);
|
||||
|
||||
if (thread->mutex) {
|
||||
ASSERTLINE(662, thread->mutex->thread);
|
||||
return thread->mutex->thread;
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = 1;
|
||||
thread->priority = priority;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void UpdatePriority(OSThread* thread) {
|
||||
s32 priority;
|
||||
|
||||
while (1) {
|
||||
if(thread->suspend > 0) {
|
||||
break;
|
||||
}
|
||||
priority = __OSGetEffectivePriority(thread);
|
||||
if (thread->priority == priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
if (thread == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void __OSPromoteThread(OSThread* thread, s32 priority) {
|
||||
while (1) {
|
||||
if (thread->suspend > 0 || thread->priority <= priority) {
|
||||
break;
|
||||
}
|
||||
thread = SetEffectivePriority(thread, priority);
|
||||
if (thread == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static OSThread* SelectThread(int yield) {
|
||||
OSContext* currentContext;
|
||||
OSThread* currentThread;
|
||||
OSThread* nextThread;
|
||||
OSPriority priority;
|
||||
OSThreadQueue* queue;
|
||||
|
||||
if (Reschedule > 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
currentContext = OSGetCurrentContext();
|
||||
currentThread = OSGetCurrentThread();
|
||||
|
||||
if (currentContext != ¤tThread->context) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (currentThread) {
|
||||
if (currentThread->state == 2) {
|
||||
if (yield == 0) {
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
if (currentThread->priority <= priority)
|
||||
return NULL;
|
||||
}
|
||||
currentThread->state = OS_THREAD_STATE_READY;
|
||||
SetRun(currentThread);
|
||||
}
|
||||
if (!(currentThread->context.state & 2) && (OSSaveContext(¤tThread->context) != 0)) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (RunQueueBits == 0) {
|
||||
OSSetCurrentThread(NULL);
|
||||
OSSetCurrentContext(&IdleContext);
|
||||
do {
|
||||
OSEnableInterrupts();
|
||||
while (RunQueueBits == 0) ;
|
||||
OSDisableInterrupts();
|
||||
} while (RunQueueBits == 0);
|
||||
OSClearContext(&IdleContext);
|
||||
}
|
||||
|
||||
RunQueueHint = 0;
|
||||
priority = __cntlzw(RunQueueBits);
|
||||
|
||||
ASSERTLINE(823, OS_PRIORITY_MIN <= priority && priority <= OS_PRIORITY_MAX);
|
||||
|
||||
queue = &RunQueue[priority];
|
||||
nextThread = queue->head;
|
||||
|
||||
DEQUEUE_HEAD(nextThread, queue, link);
|
||||
|
||||
ASSERTLINE(826, nextThread->priority == priority);
|
||||
|
||||
if (!queue->head) {
|
||||
RunQueueBits &= ~(1 << (OS_PRIORITY_MAX - priority));
|
||||
}
|
||||
nextThread->queue = 0;
|
||||
nextThread->state = OS_THREAD_STATE_RUNNING;
|
||||
__OSSwitchThread(nextThread);
|
||||
return nextThread;
|
||||
}
|
||||
|
||||
void __OSReschedule(void) {
|
||||
if (RunQueueHint != 0) {
|
||||
SelectThread(0);
|
||||
}
|
||||
}
|
||||
|
||||
void OSYieldThread(void) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
SelectThread(1);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, void* stack, u32 stackSize, OSPriority priority, u16 attr) {
|
||||
BOOL enabled;
|
||||
u32 sp;
|
||||
int i;
|
||||
|
||||
ASSERTMSGLINE(910, ((priority >= OS_PRIORITY_MIN) && (priority <= OS_PRIORITY_MAX)), "OSCreateThread(): priority out of range (0 <= priority <= 31).");
|
||||
|
||||
// why check this for an assert just to check it again right after?
|
||||
if ((priority < OS_PRIORITY_MIN) || (priority > OS_PRIORITY_MAX)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
thread->attr = attr & 1U;
|
||||
thread->base = priority;
|
||||
thread->priority = priority;
|
||||
thread->suspend = 1;
|
||||
thread->val = (void*)-1;
|
||||
thread->mutex = 0;
|
||||
OSInitThreadQueue(&thread->queueJoin);
|
||||
#if DEBUG
|
||||
OSInitMutexQueue(&thread->queueMutex);
|
||||
#else
|
||||
OSInitThreadQueue((void*)&thread->queueMutex); // why
|
||||
#endif
|
||||
sp = (u32)stack;
|
||||
sp &= ~7;
|
||||
sp -= 8;
|
||||
((u32*)sp)[0] = 0;
|
||||
((u32*)sp)[1] = 0;
|
||||
OSInitContext(&thread->context, (u32)func, sp);
|
||||
thread->context.lr = (u32)&OSExitThread;
|
||||
thread->context.gpr[3] = (u32)param;
|
||||
thread->stackBase = stack;
|
||||
thread->stackEnd = (void*)((unsigned int)stack - stackSize);
|
||||
*thread->stackEnd = OS_THREAD_STACK_MAGIC;
|
||||
thread->error = 0;
|
||||
for (i = 0; i < 2; i++) {
|
||||
thread->specific[i] = NULL;
|
||||
}
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
if (__OSErrorTable[16] != NULL) {
|
||||
thread->context.srr1 |= 0x900;
|
||||
thread->context.state |= 1;
|
||||
thread->context.fpscr = (__OSFpscrEnableBits & 0xf8) | 4;
|
||||
for (i = 0; i < 32; ++i) {
|
||||
*(u64*)&thread->context.fpr[i] = (u64)0xffffffffffffffffLL;
|
||||
*(u64*)&thread->context.psf[i] = (u64)0xffffffffffffffffLL;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERTMSG1LINE(964, __OSIsThreadActive(thread) == 0L, "OSCreateThread(): thread %p is still active.", thread);
|
||||
|
||||
ENQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void OSExitThread(void* val) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(989, currentThread,
|
||||
"OSExitThread(): current thread does not exist.");
|
||||
ASSERTMSGLINE(991, currentThread->state == OS_THREAD_STATE_RUNNING,
|
||||
"OSExitThread(): current thread is not running.");
|
||||
ASSERTMSGLINE(993, __OSIsThreadActive(currentThread) != 0,
|
||||
"OSExitThread(): current thread is not active.");
|
||||
|
||||
OSClearContext(¤tThread->context);
|
||||
if (currentThread->attr & 1) {
|
||||
DEQUEUE_THREAD(currentThread, &__OSActiveThreadQueue, linkActive);
|
||||
currentThread->state = 0;
|
||||
} else {
|
||||
currentThread->state = 8;
|
||||
currentThread->val = val;
|
||||
}
|
||||
__OSUnlockAllMutex(currentThread);
|
||||
OSWakeupThread(¤tThread->queueJoin);
|
||||
RunQueueHint = 1;
|
||||
#if DEBUG
|
||||
__OSReschedule();
|
||||
#else
|
||||
if (RunQueueHint != 0) {
|
||||
SelectThread(0);
|
||||
}
|
||||
#endif
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSCancelThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1031, __OSIsThreadActive(thread) != 0,
|
||||
"OSExitThread(): thread %p is not active.", thread);
|
||||
|
||||
__OSCancelInternalAlarms(thread);
|
||||
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
if (thread->suspend <= 0) {
|
||||
UnsetRun(thread);
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = 1;
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->queue = 0;
|
||||
if ((thread->suspend <= 0) && (thread->mutex)) {
|
||||
ASSERTLINE(1053, thread->mutex->thread);
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
OSRestoreInterrupts(enabled);
|
||||
return;
|
||||
}
|
||||
OSClearContext(&thread->context);
|
||||
if (thread->attr & 1) {
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
} else {
|
||||
thread->state = 8;
|
||||
}
|
||||
__OSUnlockAllMutex(thread);
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSJoinThread(OSThread* thread, void* val) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1061, __OSIsThreadActive(thread) != 0, "OSJoinThread(): thread %p is not active.", thread);
|
||||
|
||||
if (!(thread->attr & 1) && (thread->state != OS_THREAD_STATE_MORIBUND) && (thread->queueJoin.head == NULL)) {
|
||||
OSSleepThread(&thread->queueJoin);
|
||||
if (__OSIsThreadActive(thread) == 0) {
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (thread->state == OS_THREAD_STATE_MORIBUND) {
|
||||
if (val) {
|
||||
*(s32*)val = (s32)thread->val;
|
||||
}
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void OSDetachThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1160, __OSIsThreadActive(thread) != 0, "OSDetachThread(): thread %p is not active.", thread);
|
||||
|
||||
thread->attr |= 1;
|
||||
if (thread->state == OS_THREAD_STATE_MORIBUND) {
|
||||
DEQUEUE_THREAD(thread, &__OSActiveThreadQueue, linkActive);
|
||||
thread->state = 0;
|
||||
}
|
||||
OSWakeupThread(&thread->queueJoin);
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
s32 OSResumeThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
s32 suspendCount;
|
||||
|
||||
ASSERTMSG1LINE(1189, __OSIsThreadActive(thread) != 0, "OSResumeThread(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(1191, thread->state != OS_THREAD_STATE_MORIBUND, "OSResumeThread(): thread %p is terminated.", thread);
|
||||
|
||||
suspendCount = thread->suspend--;
|
||||
if (thread->suspend < 0) {
|
||||
thread->suspend = 0;
|
||||
} else if (thread->suspend == 0) {
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
thread->priority = __OSGetEffectivePriority(thread);
|
||||
SetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
ASSERTLINE(1206, thread->queue);
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = __OSGetEffectivePriority(thread);
|
||||
ENQUEUE_THREAD_PRIO(thread, thread->queue, link);
|
||||
if (thread->mutex) {
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
s32 OSSuspendThread(OSThread* thread) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
s32 suspendCount;
|
||||
|
||||
ASSERTMSG1LINE(1240, __OSIsThreadActive(thread) != 0, "OSSuspendThread(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(1242, thread->state != OS_THREAD_STATE_MORIBUND, "OSSuspendThread(): thread %p is terminated.", thread);
|
||||
|
||||
suspendCount = thread->suspend++;
|
||||
if (suspendCount == 0) {
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
RunQueueHint = 1;
|
||||
thread->state = 1;
|
||||
break;
|
||||
case OS_THREAD_STATE_READY:
|
||||
UnsetRun(thread);
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
DEQUEUE_THREAD(thread, thread->queue, link);
|
||||
thread->priority = 0x20;
|
||||
ENQUEUE_THREAD(thread, thread->queue, link);
|
||||
if (thread->mutex) {
|
||||
ASSERTLINE(1263, thread->mutex->thread);
|
||||
UpdatePriority(thread->mutex->thread);
|
||||
}
|
||||
break;
|
||||
}
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return suspendCount;
|
||||
}
|
||||
|
||||
void OSSleepThread(OSThreadQueue* queue) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
OSThread* currentThread = OSGetCurrentThread();
|
||||
|
||||
ASSERTMSGLINE(1296, currentThread, "OSSleepThread(): current thread does not exist.");
|
||||
ASSERTMSG1LINE(1298, __OSIsThreadActive(currentThread) != 0, "OSSleepThread(): current thread %p is not active.", currentThread);
|
||||
ASSERTMSG1LINE(1300, currentThread->state == OS_THREAD_STATE_RUNNING, "OSSleepThread(): current thread %p is not running.", currentThread);
|
||||
ASSERTMSG1LINE(1302, !(currentThread->suspend > 0), "OSSleepThread(): current thread %p is suspended.", currentThread);
|
||||
|
||||
currentThread->state = OS_THREAD_STATE_WAITING;
|
||||
currentThread->queue = queue;
|
||||
ENQUEUE_THREAD_PRIO(currentThread, queue, link);
|
||||
RunQueueHint = 1;
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
void OSWakeupThread(OSThreadQueue* queue) {
|
||||
BOOL enabled = OSDisableInterrupts();
|
||||
|
||||
while (queue->head) {
|
||||
OSThread* thread = queue->head;
|
||||
|
||||
DEQUEUE_HEAD(thread, queue, link);
|
||||
|
||||
ASSERTLINE(1331, __OSIsThreadActive(thread));
|
||||
ASSERTLINE(1332, thread->state != OS_THREAD_STATE_MORIBUND);
|
||||
ASSERTLINE(1333, thread->queue == queue);
|
||||
thread->state = OS_THREAD_STATE_READY;
|
||||
if (thread->suspend <= 0) {
|
||||
SetRun(thread);
|
||||
}
|
||||
}
|
||||
__OSReschedule();
|
||||
OSRestoreInterrupts(enabled);
|
||||
}
|
||||
|
||||
int OSSetThreadPriority(OSThread* thread, s32 priority) {
|
||||
BOOL enabled;
|
||||
|
||||
ASSERTMSGLINE(1359, (priority >= OS_PRIORITY_MIN) && (priority <= OS_PRIORITY_MAX), "OSSetThreadPriority(): priority out of range (0 <= priority <= 31).");
|
||||
|
||||
if ((priority < OS_PRIORITY_MIN) || (priority > OS_PRIORITY_MAX)) {
|
||||
return 0;
|
||||
}
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
ASSERTMSG1LINE(1366, __OSIsThreadActive(thread) != 0, "OSSetThreadPriority(): thread %p is not active.", thread);
|
||||
ASSERTMSG1LINE(1368, thread->state != 8, "OSSetThreadPriority(): thread %p is terminated.", thread);
|
||||
|
||||
if (thread->base != priority) {
|
||||
thread->base = priority;
|
||||
UpdatePriority(thread);
|
||||
__OSReschedule();
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return 1;
|
||||
}
|
||||
|
||||
s32 OSGetThreadPriority(OSThread* thread) {
|
||||
return thread->base;
|
||||
}
|
||||
|
||||
OSThread* OSSetIdleFunction(OSIdleFunction idleFunction, void* param, void* stack, u32 stackSize) {
|
||||
if (idleFunction) {
|
||||
if (IdleThread.state == 0) {
|
||||
OSCreateThread(&IdleThread, (void*)idleFunction, param, stack, stackSize, OS_PRIORITY_MAX, 1);
|
||||
OSResumeThread(&IdleThread);
|
||||
return &IdleThread;
|
||||
}
|
||||
} else if (IdleThread.state != 0) {
|
||||
OSCancelThread(&IdleThread);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
OSThread* OSGetIdleFunction(void) {
|
||||
if (IdleThread.state != 0) {
|
||||
return &IdleThread;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int CheckThreadQueue(OSThreadQueue* queue) {
|
||||
OSThread* thread;
|
||||
|
||||
if ((queue->head != NULL) && (queue->head->link.prev != NULL)) {
|
||||
return 0;
|
||||
}
|
||||
if ((queue->tail != NULL) && (queue->tail->link.next != NULL)) {
|
||||
return 0;
|
||||
}
|
||||
thread = queue->head;
|
||||
while (thread) {
|
||||
if ((thread->link.next != NULL) && (thread != thread->link.next->link.prev)) {
|
||||
return 0;
|
||||
}
|
||||
if ((thread->link.prev != NULL) && (thread != thread->link.prev->link.next)) {
|
||||
return 0;
|
||||
}
|
||||
thread = thread->link.next;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static BOOL IsMember(OSThreadQueue* queue, OSThread* thread) {
|
||||
OSThread* member = queue->head;
|
||||
|
||||
while (member) {
|
||||
if (thread == member) {
|
||||
return TRUE;
|
||||
}
|
||||
member = member->link.next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// custom macro for OSCheckActiveThreads?
|
||||
#define ASSERTREPORT(line, cond) \
|
||||
if (!(cond)) { \
|
||||
OSReport("OSCheckActiveThreads: Failed " #cond " in %d\n", line); \
|
||||
OSPanic(__FILE__, line, ""); \
|
||||
}
|
||||
|
||||
s32 OSCheckActiveThreads(void) {
|
||||
OSThread* thread;
|
||||
s32 prio;
|
||||
s32 cThread;
|
||||
BOOL enabled;
|
||||
|
||||
cThread = 0;
|
||||
enabled = OSDisableInterrupts();
|
||||
|
||||
for (prio = 0; prio <= OS_PRIORITY_MAX; prio++) {
|
||||
if (RunQueueBits & (1 << (OS_PRIORITY_MAX - prio))) {
|
||||
ASSERTREPORT(1522, RunQueue[prio].head != NULL && RunQueue[prio].tail != NULL);
|
||||
} else {
|
||||
ASSERTREPORT(1527, RunQueue[prio].head == NULL && RunQueue[prio].tail == NULL);
|
||||
}
|
||||
ASSERTREPORT(1529, CheckThreadQueue(&RunQueue[prio]));
|
||||
}
|
||||
|
||||
ASSERTREPORT(1534, __OSActiveThreadQueue.head == NULL || __OSActiveThreadQueue.head->linkActive.prev == NULL);
|
||||
ASSERTREPORT(1536, __OSActiveThreadQueue.tail == NULL || __OSActiveThreadQueue.tail->linkActive.next == NULL);
|
||||
|
||||
thread = __OSActiveThreadQueue.head;
|
||||
while (thread) {
|
||||
cThread++;
|
||||
ASSERTREPORT(1544, thread->linkActive.next == NULL || thread == thread->linkActive.next->linkActive.prev);
|
||||
ASSERTREPORT(1546, thread->linkActive.prev == NULL || thread == thread->linkActive.prev->linkActive.next);
|
||||
ASSERTREPORT(1549, *(thread->stackEnd) == OS_THREAD_STACK_MAGIC);
|
||||
ASSERTREPORT(1552, OS_PRIORITY_MIN <= thread->priority && thread->priority <= OS_PRIORITY_MAX+1);
|
||||
ASSERTREPORT(1553, 0 <= thread->suspend);
|
||||
ASSERTREPORT(1554, CheckThreadQueue(&thread->queueJoin));
|
||||
|
||||
switch(thread->state) {
|
||||
case OS_THREAD_STATE_READY:
|
||||
if (thread->suspend <= 0) {
|
||||
ASSERTREPORT(1560, thread->queue == &RunQueue[thread->priority]);
|
||||
ASSERTREPORT(1561, IsMember(&RunQueue[thread->priority], thread));
|
||||
ASSERTREPORT(1562, thread->priority == __OSGetEffectivePriority(thread));
|
||||
}
|
||||
break;
|
||||
case OS_THREAD_STATE_RUNNING:
|
||||
ASSERTREPORT(1566, !IsSuspended(thread->suspend));
|
||||
ASSERTREPORT(1567, thread->queue == NULL);
|
||||
ASSERTREPORT(1568, thread->priority == __OSGetEffectivePriority(thread));
|
||||
break;
|
||||
case OS_THREAD_STATE_WAITING:
|
||||
ASSERTREPORT(1571, thread->queue != NULL);
|
||||
ASSERTREPORT(1572, CheckThreadQueue(thread->queue));
|
||||
ASSERTREPORT(1573, IsMember(thread->queue, thread));
|
||||
if (thread->suspend <= 0) {
|
||||
ASSERTREPORT(1576, thread->priority == __OSGetEffectivePriority(thread));
|
||||
} else {
|
||||
ASSERTREPORT(1580, thread->priority == 32);
|
||||
}
|
||||
ASSERTREPORT(1582, !__OSCheckDeadLock(thread));
|
||||
break;
|
||||
case OS_THREAD_STATE_MORIBUND:
|
||||
ASSERTREPORT(1586, thread->queueMutex.head == NULL && thread->queueMutex.tail == NULL);
|
||||
break;
|
||||
default:
|
||||
OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n", thread->state, thread);
|
||||
OSPanic(__FILE__, 1592, "");
|
||||
}
|
||||
ASSERTREPORT(1597, __OSCheckMutexes(thread));
|
||||
thread = thread->linkActive.next;
|
||||
}
|
||||
OSRestoreInterrupts(enabled);
|
||||
return cThread;
|
||||
}
|
||||
|
||||
void OSClearStack(u8 val) {
|
||||
__REGISTER u32 sp;
|
||||
__REGISTER u32* p;
|
||||
__REGISTER u32 pattern;
|
||||
|
||||
pattern = (val << 24) | (val << 16) | (val << 8) | val;
|
||||
sp = OSGetStackPointer();
|
||||
for (p = __OSCurrentThread->stackEnd + 1; (u32)p < sp; ++p) {
|
||||
*p = pattern;
|
||||
}
|
||||
}
|
||||
|
||||
void OSSetThreadSpecific(s32 index, void* ptr) {
|
||||
OSThread* thread;
|
||||
|
||||
thread = __OSCurrentThread;
|
||||
ASSERTLINE(1573, 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
|
||||
|
||||
if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
|
||||
thread->specific[index] = ptr;
|
||||
}
|
||||
}
|
||||
|
||||
void* OSGetThreadSpecific(s32 index) {
|
||||
OSThread* thread;
|
||||
|
||||
thread = __OSCurrentThread;
|
||||
ASSERTLINE(1584, 0 <= index && index < OS_THREAD_SPECIFIC_MAX);
|
||||
|
||||
if (thread != 0 && index >= 0 && index < OS_THREAD_SPECIFIC_MAX) {
|
||||
return thread->specific[index];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#include "global.h"
|
||||
extern u8 Debug_BBA_804516D0;
|
||||
u8 Debug_BBA_804516D0 ATTRIBUTE_ALIGN(8);
|
||||
Reference in New Issue
Block a user