mirror of
https://github.com/zeldaret/tww.git
synced 2026-07-09 14:05:28 -04:00
935 lines
30 KiB
C
935 lines
30 KiB
C
//
|
|
// Generated By: dol2asm
|
|
// Translation Unit: OSThread
|
|
//
|
|
|
|
#include "global.h"
|
|
#include "dolphin/os/OSThread.h"
|
|
#include "dolphin/os/OS.h"
|
|
|
|
OSThread* __OSCurrentThread AT_ADDRESS(OS_BASE_CACHED + 0x00E4);
|
|
OSThreadQueue __OSActiveThreadQueue AT_ADDRESS(OS_BASE_CACHED + 0x00DC);
|
|
volatile OSContext __OSCurrentContext AT_ADDRESS(OS_BASE_CACHED + 0x00D4);
|
|
volatile OSContext* __OSFPUContext AT_ADDRESS(OS_BASE_CACHED + 0x00D8);
|
|
|
|
#define AddTail(queue, thread, link) \
|
|
do { \
|
|
OSThread* prev; \
|
|
\
|
|
prev = (queue)->tail; \
|
|
if (prev == NULL) \
|
|
(queue)->head = (thread); \
|
|
else \
|
|
prev->link.next = (thread); \
|
|
(thread)->link.prev = prev; \
|
|
(thread)->link.next = NULL; \
|
|
(queue)->tail = (thread); \
|
|
} while (0)
|
|
|
|
#define AddPrio(queue, thread, link) \
|
|
do { \
|
|
OSThread *prev, *next; \
|
|
\
|
|
for (next = (queue)->head; next && next->effective_priority <= thread->effective_priority; \
|
|
next = next->link.next) \
|
|
; \
|
|
if (next == NULL) \
|
|
AddTail(queue, thread, 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 RemoveItem(queue, thread, link) \
|
|
do { \
|
|
OSThread *next, *prev; \
|
|
next = (thread)->link.next; \
|
|
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 RemoveHead(queue, thread, link) \
|
|
do { \
|
|
OSThread* __next; \
|
|
(thread) = (queue)->head; \
|
|
__next = (thread)->link.next; \
|
|
if (__next == NULL) \
|
|
(queue)->tail = NULL; \
|
|
else \
|
|
__next->link.prev = NULL; \
|
|
(queue)->head = __next; \
|
|
} while (0)
|
|
|
|
//
|
|
// External References:
|
|
//
|
|
|
|
extern OSErrorHandler __OSErrorTable[EXCEPTION_MAX];
|
|
extern u32 __OSFpscrEnableBits;
|
|
void _epilog();
|
|
|
|
//
|
|
// Declarations:
|
|
//
|
|
|
|
static void DefaultSwitchThreadCallback(OSThread* from, OSThread* to) {}
|
|
|
|
static OSSwitchThreadCallback SwitchThreadCallback = DefaultSwitchThreadCallback;
|
|
|
|
OSSwitchThreadCallback OSSetSwitchThreadCallback(OSSwitchThreadCallback func) {
|
|
BOOL enable = OSDisableInterrupts();
|
|
OSSwitchThreadCallback prev = SwitchThreadCallback;
|
|
OSSwitchThreadCallback temp;
|
|
if (func) {
|
|
temp = func;
|
|
} else {
|
|
temp = DefaultSwitchThreadCallback;
|
|
}
|
|
SwitchThreadCallback = temp;
|
|
|
|
OSRestoreInterrupts(enable);
|
|
if (prev == DefaultSwitchThreadCallback) {
|
|
return NULL;
|
|
}
|
|
|
|
return prev;
|
|
}
|
|
|
|
static OSThreadQueue RunQueue[32];
|
|
|
|
#pragma push
|
|
#pragma force_active on
|
|
static OSThread IdleThread;
|
|
#pragma pop
|
|
|
|
#pragma push
|
|
#pragma force_active on
|
|
static OSThread DefaultThread;
|
|
#pragma pop
|
|
|
|
#pragma push
|
|
#pragma force_active on
|
|
static OSContext IdleContext;
|
|
#pragma pop
|
|
|
|
static vu32 RunQueueBits;
|
|
|
|
static volatile BOOL RunQueueHint;
|
|
|
|
static volatile s32 Reschedule;
|
|
|
|
extern u8 _stack_end[];
|
|
extern u8 _stack_addr[];
|
|
|
|
static inline void OSInitMutexQueue(OSMutexQueue* queue) {
|
|
queue->head = queue->tail = NULL;
|
|
}
|
|
|
|
static inline void OSSetCurrentThread(OSThread* thread) {
|
|
SwitchThreadCallback(__OSCurrentThread, thread);
|
|
__OSCurrentThread = thread;
|
|
}
|
|
|
|
void __OSThreadInit() {
|
|
OSThread* thread = &DefaultThread;
|
|
int prio;
|
|
|
|
thread->state = OS_THREAD_STATE_RUNNING;
|
|
thread->attributes = OS_THREAD_ATTR_DETACH;
|
|
thread->effective_priority = thread->base_priority = 16;
|
|
thread->suspend_count = 0;
|
|
thread->exit_value = (void*)-1;
|
|
thread->mutex = NULL;
|
|
OSInitThreadQueue(&thread->join_queue);
|
|
OSInitMutexQueue(&thread->owned_mutexes);
|
|
|
|
__OSFPUContext = &thread->context;
|
|
|
|
OSClearContext(&thread->context);
|
|
OSSetCurrentContext(&thread->context);
|
|
thread->stack_base = (void*)_stack_addr;
|
|
thread->stack_end = (void*)_stack_end;
|
|
*(thread->stack_end) = OS_THREAD_STACK_MAGIC;
|
|
|
|
OSSetCurrentThread(thread);
|
|
OSClearStack(0);
|
|
|
|
RunQueueBits = 0;
|
|
RunQueueHint = FALSE;
|
|
for (prio = OS_PRIORITY_MIN; prio <= OS_PRIORITY_MAX; ++prio) {
|
|
OSInitThreadQueue(&RunQueue[prio]);
|
|
}
|
|
|
|
OSInitThreadQueue(&__OSActiveThreadQueue);
|
|
AddTail(&__OSActiveThreadQueue, thread, active_threads_link);
|
|
OSClearContext(&IdleContext);
|
|
Reschedule = 0;
|
|
}
|
|
|
|
void OSInitThreadQueue(OSThreadQueue* queue) {
|
|
queue->tail = NULL;
|
|
queue->head = NULL;
|
|
}
|
|
|
|
OSThread* OSGetCurrentThread(void) {
|
|
return OS_CURRENT_THREAD;
|
|
}
|
|
|
|
BOOL OSIsThreadTerminated(OSThread* thread) {
|
|
return thread->state == OS_THREAD_STATE_DEAD || thread->state == OS_THREAD_STATE_UNINITIALIZED ?
|
|
TRUE :
|
|
FALSE;
|
|
}
|
|
|
|
static BOOL __OSIsThreadActive(OSThread* thread) {
|
|
OSThread* active;
|
|
|
|
if (thread->state == 0) {
|
|
return FALSE;
|
|
}
|
|
|
|
for (active = __OSActiveThreadQueue.head; active; active = active->active_threads_link.next) {
|
|
if (thread == active) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
s32 OSDisableScheduler(void) {
|
|
BOOL intr = OSDisableInterrupts();
|
|
s32 ret = Reschedule++;
|
|
OSRestoreInterrupts(intr);
|
|
return ret;
|
|
}
|
|
|
|
s32 OSEnableScheduler(void) {
|
|
BOOL intr = OSDisableInterrupts();
|
|
s32 ret = Reschedule--;
|
|
OSRestoreInterrupts(intr);
|
|
return ret;
|
|
}
|
|
|
|
static inline void SetRun(OSThread* thread) {
|
|
thread->queue = &RunQueue[thread->effective_priority];
|
|
AddTail(thread->queue, thread, link);
|
|
RunQueueBits |= 1u << (OS_PRIORITY_MAX - thread->effective_priority);
|
|
RunQueueHint = TRUE;
|
|
}
|
|
|
|
#pragma dont_inline on
|
|
static void UnsetRun(OSThread* thread) {
|
|
OSThreadQueue* queue;
|
|
OSThread* next;
|
|
OSThread* prev;
|
|
|
|
prev = thread->link.next;
|
|
queue = thread->queue;
|
|
next = thread->link.prev;
|
|
|
|
if (prev == NULL) {
|
|
queue->tail = next;
|
|
} else {
|
|
prev->link.prev = next;
|
|
}
|
|
|
|
if (next == NULL) {
|
|
queue->head = prev;
|
|
} else {
|
|
next->link.next = prev;
|
|
}
|
|
|
|
if (queue->head == NULL) {
|
|
RunQueueBits &= ~(1 << (31 - thread->effective_priority));
|
|
}
|
|
|
|
thread->queue = NULL;
|
|
}
|
|
#pragma dont_inline reset
|
|
|
|
s32 __OSGetEffectivePriority(OSThread* thread) {
|
|
s32 prio = thread->base_priority;
|
|
|
|
OSMutex* mutex;
|
|
for (mutex = thread->owned_mutexes.head; mutex != NULL; mutex = mutex->link.next) {
|
|
OSThread* mutexThread = mutex->queue.head;
|
|
if (mutexThread != NULL && mutexThread->effective_priority < prio) {
|
|
prio = mutexThread->effective_priority;
|
|
}
|
|
}
|
|
|
|
return prio;
|
|
}
|
|
|
|
static OSThread* SetEffectivePriority(OSThread* thread, s32 priority) {
|
|
switch (thread->state) {
|
|
case OS_THREAD_STATE_READY:
|
|
UnsetRun(thread);
|
|
thread->effective_priority = priority;
|
|
SetRun(thread);
|
|
break;
|
|
case OS_THREAD_STATE_WAITING:
|
|
RemoveItem(thread->queue, thread, link);
|
|
thread->effective_priority = priority;
|
|
AddPrio(thread->queue, thread, link);
|
|
if (thread->mutex) {
|
|
return thread->mutex->thread;
|
|
}
|
|
break;
|
|
case OS_THREAD_STATE_RUNNING:
|
|
RunQueueHint = TRUE;
|
|
thread->effective_priority = priority;
|
|
break;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void UpdatePriority(OSThread* thread) {
|
|
OSPriority priority;
|
|
|
|
do {
|
|
if (0 < thread->suspend_count) {
|
|
break;
|
|
}
|
|
priority = __OSGetEffectivePriority(thread);
|
|
if (thread->effective_priority == priority) {
|
|
break;
|
|
}
|
|
thread = SetEffectivePriority(thread, priority);
|
|
} while (thread);
|
|
}
|
|
|
|
void __OSPromoteThread(OSThread* thread, s32 priority) {
|
|
do {
|
|
if (thread->suspend_count > 0 || thread->effective_priority <= priority) {
|
|
break;
|
|
}
|
|
|
|
thread = SetEffectivePriority(thread, priority);
|
|
} while (thread != NULL);
|
|
}
|
|
|
|
static inline void __OSSwitchThread(OSThread* nextThread) {
|
|
OSSetCurrentThread(nextThread);
|
|
OSSetCurrentContext(&nextThread->context);
|
|
OSLoadContext(&nextThread->context);
|
|
}
|
|
|
|
static OSThread* SelectThread(BOOL yield) {
|
|
OSContext* currentContext;
|
|
OSThread* currentThread;
|
|
OSThread* nextThread;
|
|
OSPriority priority;
|
|
OSThreadQueue* queue;
|
|
|
|
if (0 < Reschedule) {
|
|
return 0;
|
|
}
|
|
|
|
currentContext = OSGetCurrentContext();
|
|
currentThread = OSGetCurrentThread();
|
|
if (currentContext != ¤tThread->context) {
|
|
return 0;
|
|
}
|
|
|
|
if (currentThread) {
|
|
if (currentThread->state == OS_THREAD_STATE_RUNNING) {
|
|
if (!yield) {
|
|
priority = __cntlzw(RunQueueBits);
|
|
if (currentThread->effective_priority <= priority) {
|
|
return 0;
|
|
}
|
|
}
|
|
currentThread->state = OS_THREAD_STATE_READY;
|
|
SetRun(currentThread);
|
|
}
|
|
|
|
if (!(currentThread->context.state & OS_CONTEXT_STATE_EXC) &&
|
|
OSSaveContext(¤tThread->context))
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
OSSetCurrentThread(NULL);
|
|
|
|
if (RunQueueBits == 0) {
|
|
OSSetCurrentContext(&IdleContext);
|
|
do {
|
|
OSEnableInterrupts();
|
|
while (RunQueueBits == 0)
|
|
;
|
|
OSDisableInterrupts();
|
|
} while (RunQueueBits == 0);
|
|
|
|
OSClearContext(&IdleContext);
|
|
}
|
|
|
|
RunQueueHint = FALSE;
|
|
|
|
priority = __cntlzw(RunQueueBits);
|
|
queue = &RunQueue[priority];
|
|
RemoveHead(queue, nextThread, link);
|
|
if (queue->head == 0) {
|
|
RunQueueBits &= ~(1u << (OS_PRIORITY_MAX - priority));
|
|
}
|
|
nextThread->queue = NULL;
|
|
nextThread->state = OS_THREAD_STATE_RUNNING;
|
|
__OSSwitchThread(nextThread);
|
|
return nextThread;
|
|
}
|
|
|
|
void __OSReschedule(void) {
|
|
if (!RunQueueHint) {
|
|
return;
|
|
}
|
|
|
|
SelectThread(FALSE);
|
|
}
|
|
|
|
void OSYieldThread(void) {
|
|
BOOL enabled;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
SelectThread(TRUE);
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
BOOL OSCreateThread(OSThread* thread_, void* func, void* param, void* stackBase, u32 stackSize,
|
|
s32 priority, u16 attribute) {
|
|
BOOL enabled;
|
|
u32 i;
|
|
u32* stack;
|
|
OSThread* thread;
|
|
u32 stack1, stack2;
|
|
|
|
if (priority < 0 || priority > 31) {
|
|
return FALSE;
|
|
}
|
|
|
|
thread = thread_;
|
|
|
|
thread->state = OS_THREAD_STATE_READY;
|
|
thread->attributes = attribute & 1;
|
|
thread->base_priority = priority;
|
|
thread->effective_priority = priority;
|
|
thread->suspend_count = 1;
|
|
thread->exit_value = (void*)-1;
|
|
thread->mutex = NULL;
|
|
thread->join_queue.tail = NULL;
|
|
thread->join_queue.head = NULL;
|
|
thread->owned_mutexes.tail = NULL;
|
|
thread->owned_mutexes.head = NULL;
|
|
stack = (u32*)((u32)stackBase & 0xfffffff8);
|
|
stack[-2] = 0;
|
|
stack[-1] = 0;
|
|
OSInitContext(&thread->context, (u32)func, (u32)stack - 8);
|
|
thread->context.lr = (u32)OSExitThread;
|
|
thread->context.gpr[3] = (u32)param;
|
|
thread->stack_base = (u8*)stackBase;
|
|
thread->stack_end = (void*)((u32)stackBase - stackSize);
|
|
*(u32*)thread->stack_end = OS_THREAD_STACK_MAGIC;
|
|
thread->error_code = NULL;
|
|
thread->data[0] = NULL;
|
|
thread->data[1] = NULL;
|
|
enabled = OSDisableInterrupts();
|
|
if (__OSErrorTable[16]) {
|
|
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.ps[i] = (u64)0xffffffffffffffffLL;
|
|
}
|
|
}
|
|
|
|
AddTail(&OS_THREAD_QUEUE, thread, active_threads_link);
|
|
OSRestoreInterrupts(enabled);
|
|
return TRUE;
|
|
}
|
|
|
|
void OSExitThread(void* exitValue) {
|
|
OSThread* currentThread;
|
|
BOOL enabled;
|
|
enabled = OSDisableInterrupts();
|
|
currentThread = OS_CURRENT_THREAD;
|
|
OSClearContext(¤tThread->context);
|
|
|
|
if (currentThread->attributes & OS_THREAD_ATTR_DETACH) {
|
|
RemoveItem(&OS_THREAD_QUEUE, currentThread, active_threads_link);
|
|
currentThread->state = OS_THREAD_STATE_UNINITIALIZED;
|
|
} else {
|
|
currentThread->state = OS_THREAD_STATE_DEAD;
|
|
currentThread->exit_value = exitValue;
|
|
}
|
|
|
|
__OSUnlockAllMutex(currentThread);
|
|
OSWakeupThread(¤tThread->join_queue);
|
|
RunQueueHint = TRUE;
|
|
|
|
if (RunQueueHint) {
|
|
SelectThread(FALSE);
|
|
}
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
void OSCancelThread(OSThread* thread) {
|
|
BOOL enabled;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
|
|
switch (thread->state) {
|
|
case OS_THREAD_STATE_READY:
|
|
if (!(0 < thread->suspend_count)) {
|
|
UnsetRun(thread);
|
|
}
|
|
break;
|
|
case OS_THREAD_STATE_RUNNING:
|
|
RunQueueHint = TRUE;
|
|
break;
|
|
case OS_THREAD_STATE_WAITING:
|
|
RemoveItem(thread->queue, thread, link);
|
|
thread->queue = NULL;
|
|
if (!(0 < thread->suspend_count) && thread->mutex) {
|
|
UpdatePriority(thread->mutex->thread);
|
|
}
|
|
break;
|
|
default:
|
|
OSRestoreInterrupts(enabled);
|
|
return;
|
|
}
|
|
|
|
OSClearContext(&thread->context);
|
|
if (thread->attributes & OS_THREAD_ATTR_DETACH) {
|
|
RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link);
|
|
thread->state = 0;
|
|
} else {
|
|
thread->state = OS_THREAD_STATE_DEAD;
|
|
}
|
|
|
|
__OSUnlockAllMutex(thread);
|
|
|
|
OSWakeupThread(&thread->join_queue);
|
|
|
|
__OSReschedule();
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
BOOL OSJoinThread(struct OSThread * thread, void * val) {
|
|
int enabled = OSDisableInterrupts();
|
|
|
|
if (!(thread->attributes & 1) && (thread->state != 8) && (thread->join_queue.head == NULL)) {
|
|
OSSleepThread(&thread->join_queue);
|
|
if (__OSIsThreadActive(thread) == 0) {
|
|
OSRestoreInterrupts(enabled);
|
|
return 0;
|
|
}
|
|
}
|
|
if (thread->state == 8) {
|
|
if (val) {
|
|
*(s32*)val = (s32)thread->exit_value;
|
|
}
|
|
RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link);
|
|
thread->state = 0;
|
|
OSRestoreInterrupts(enabled);
|
|
return 1;
|
|
}
|
|
OSRestoreInterrupts(enabled);
|
|
return 0;
|
|
}
|
|
|
|
void OSDetachThread(OSThread* thread) {
|
|
BOOL enabled;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
thread->attributes |= OS_THREAD_ATTR_DETACH;
|
|
|
|
if (thread->state == OS_THREAD_STATE_DEAD) {
|
|
RemoveItem(&__OSActiveThreadQueue, thread, active_threads_link);
|
|
thread->state = OS_THREAD_STATE_UNINITIALIZED;
|
|
}
|
|
|
|
OSWakeupThread(&thread->join_queue);
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
s32 OSResumeThread(OSThread* thread) {
|
|
BOOL enabled;
|
|
s32 suspendCount;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
suspendCount = thread->suspend_count--;
|
|
if (thread->suspend_count < 0) {
|
|
thread->suspend_count = 0;
|
|
} else if (thread->suspend_count == 0) {
|
|
switch (thread->state) {
|
|
case OS_THREAD_STATE_READY:
|
|
thread->effective_priority = __OSGetEffectivePriority(thread);
|
|
SetRun(thread);
|
|
break;
|
|
case OS_THREAD_STATE_WAITING:
|
|
RemoveItem(thread->queue, thread, link);
|
|
thread->effective_priority = __OSGetEffectivePriority(thread);
|
|
AddPrio(thread->queue, thread, link);
|
|
if (thread->mutex) {
|
|
UpdatePriority(thread->mutex->thread);
|
|
}
|
|
break;
|
|
}
|
|
__OSReschedule();
|
|
}
|
|
OSRestoreInterrupts(enabled);
|
|
return suspendCount;
|
|
}
|
|
|
|
s32 OSSuspendThread(OSThread* thread) {
|
|
BOOL enabled;
|
|
s32 suspendCount;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
suspendCount = thread->suspend_count++;
|
|
if (suspendCount == 0) {
|
|
switch (thread->state) {
|
|
case OS_THREAD_STATE_RUNNING:
|
|
RunQueueHint = TRUE;
|
|
thread->state = OS_THREAD_STATE_READY;
|
|
break;
|
|
case OS_THREAD_STATE_READY:
|
|
UnsetRun(thread);
|
|
break;
|
|
case OS_THREAD_STATE_WAITING:
|
|
RemoveItem(thread->queue, thread, link);
|
|
thread->effective_priority = 32;
|
|
AddTail(thread->queue, thread, link);
|
|
if (thread->mutex) {
|
|
UpdatePriority(thread->mutex->thread);
|
|
}
|
|
break;
|
|
}
|
|
|
|
__OSReschedule();
|
|
}
|
|
OSRestoreInterrupts(enabled);
|
|
return suspendCount;
|
|
}
|
|
|
|
void OSSleepThread(OSThreadQueue* queue) {
|
|
BOOL enabled;
|
|
OSThread* currentThread;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
currentThread = OSGetCurrentThread();
|
|
|
|
currentThread->state = OS_THREAD_STATE_WAITING;
|
|
currentThread->queue = queue;
|
|
AddPrio(queue, currentThread, link);
|
|
RunQueueHint = TRUE;
|
|
__OSReschedule();
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
void OSWakeupThread(OSThreadQueue* queue) {
|
|
BOOL enabled;
|
|
OSThread* thread;
|
|
|
|
enabled = OSDisableInterrupts();
|
|
while (queue->head) {
|
|
RemoveHead(queue, thread, link);
|
|
thread->state = OS_THREAD_STATE_READY;
|
|
if (!(0 < thread->suspend_count)) {
|
|
SetRun(thread);
|
|
}
|
|
}
|
|
__OSReschedule();
|
|
OSRestoreInterrupts(enabled);
|
|
}
|
|
|
|
s32 OSSetThreadPriority(OSThread* thread, s32 priority) {
|
|
BOOL enabled;
|
|
|
|
if (priority < 0 || priority > 31) {
|
|
return FALSE;
|
|
}
|
|
|
|
enabled = OSDisableInterrupts();
|
|
if ((s32)thread->base_priority != priority) {
|
|
thread->base_priority = priority;
|
|
|
|
UpdatePriority(thread);
|
|
__OSReschedule();
|
|
}
|
|
OSRestoreInterrupts(enabled);
|
|
return TRUE;
|
|
}
|
|
|
|
s32 OSGetThreadPriority(OSThread* thread) {
|
|
return thread->base_priority;
|
|
}
|
|
|
|
s32 CheckThreadQueue(OSThreadQueue* thread) {
|
|
OSThread* current;
|
|
if (thread->head && thread->head->link.prev) {
|
|
return 0;
|
|
}
|
|
|
|
if (thread->tail && thread->tail->link.next) {
|
|
return 0;
|
|
}
|
|
|
|
current = thread->head;
|
|
|
|
while (current) {
|
|
if (current->link.next && current != current->link.next->link.prev) {
|
|
return 0;
|
|
}
|
|
|
|
if (current->link.prev && current != current->link.prev->link.next) {
|
|
return 0;
|
|
}
|
|
|
|
current = current->link.next;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static BOOL isMember(OSThreadQueue* queue, OSThread* thread) {
|
|
OSThread* current = queue->head;
|
|
while (current != NULL) {
|
|
if (thread == current) {
|
|
return TRUE;
|
|
}
|
|
|
|
current = current->link.next;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
s32 OSCheckActiveThreads(void) {
|
|
s32 i;
|
|
OSThread* thread;
|
|
s32 rv = 0;
|
|
BOOL enabled;
|
|
enabled = OSDisableInterrupts();
|
|
|
|
for (i = 0; i <= 31; i++) {
|
|
if (RunQueueBits & (1 << (31 - i))) {
|
|
if (RunQueue[i].head == NULL || RunQueue[i].tail == NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed RunQueue[prio].head != NULL && "
|
|
"RunQueue[prio].tail != NULL in %d\n",
|
|
0x5be);
|
|
OSPanic(__FILE__, 0x5be, "");
|
|
}
|
|
} else {
|
|
if (RunQueue[i].head != NULL || RunQueue[i].tail != NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed RunQueue[prio].head == NULL && "
|
|
"RunQueue[prio].tail == NULL in %d\n",
|
|
0x5c3);
|
|
OSPanic(__FILE__, 0x5c3, "");
|
|
}
|
|
}
|
|
|
|
if (CheckThreadQueue(&RunQueue[i]) == 0) {
|
|
OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(&RunQueue[prio]) in %d\n",
|
|
0x5c5);
|
|
OSPanic(__FILE__, 0x5c5, "");
|
|
}
|
|
}
|
|
|
|
if (OS_THREAD_QUEUE.head != NULL && OS_THREAD_QUEUE.head->active_threads_link.prev != NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed __OSActiveThreadQueue.head == NULL || "
|
|
"__OSActiveThreadQueue.head->linkActive.prev == NULL in %d\n",
|
|
0x5ca);
|
|
OSPanic(__FILE__, 0x5ca, "");
|
|
}
|
|
|
|
if (OS_THREAD_QUEUE.tail != NULL && OS_THREAD_QUEUE.tail->active_threads_link.next != NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed __OSActiveThreadQueue.tail == NULL || "
|
|
"__OSActiveThreadQueue.tail->linkActive.next == NULL in %d\n",
|
|
0x5cc);
|
|
OSPanic(__FILE__, 0x5cc, "");
|
|
}
|
|
|
|
thread = OS_THREAD_QUEUE.head;
|
|
|
|
while (thread != NULL) {
|
|
rv++;
|
|
if (thread->active_threads_link.next != NULL &&
|
|
thread != thread->active_threads_link.next->active_threads_link.prev)
|
|
{
|
|
OSReport("OSCheckActiveThreads: Failed thread->linkActive.next == NULL || thread == "
|
|
"thread->linkActive.next->linkActive.prev in %d\n",
|
|
0x5d4);
|
|
OSPanic(__FILE__, 0x5d4, "");
|
|
}
|
|
|
|
if (thread->active_threads_link.prev != NULL &&
|
|
thread != thread->active_threads_link.prev->active_threads_link.next)
|
|
{
|
|
OSReport("OSCheckActiveThreads: Failed thread->linkActive.prev == NULL || thread == "
|
|
"thread->linkActive.prev->linkActive.next in %d\n",
|
|
0x5d6);
|
|
OSPanic(__FILE__, 0x5d6, "");
|
|
}
|
|
|
|
if (*(u32*)thread->stack_end != OS_THREAD_STACK_MAGIC) {
|
|
OSReport(
|
|
"OSCheckActiveThreads: Failed *(thread->stackEnd) == OS_THREAD_STACK_MAGIC in %d\n",
|
|
0x5d9);
|
|
OSPanic(__FILE__, 0x5d9, "");
|
|
}
|
|
|
|
if (OS_PRIORITY_MIN > thread->effective_priority ||
|
|
thread->effective_priority > OS_PRIORITY_MAX + 1)
|
|
{
|
|
OSReport("OSCheckActiveThreads: Failed OS_PRIORITY_MIN <= thread->priority && "
|
|
"thread->priority <= OS_PRIORITY_MAX+1 in %d\n",
|
|
0x5dc);
|
|
OSPanic(__FILE__, 0x5dc, "");
|
|
}
|
|
|
|
if (thread->suspend_count < 0) {
|
|
OSReport("OSCheckActiveThreads: Failed 0 <= thread->suspend in %d\n", 0x5dd);
|
|
OSPanic(__FILE__, 0x5dd, "");
|
|
}
|
|
|
|
if (!CheckThreadQueue(&thread->join_queue)) {
|
|
OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(&thread->queueJoin) in %d\n",
|
|
0x5de);
|
|
OSPanic(__FILE__, 0x5de, "");
|
|
}
|
|
|
|
switch (thread->state) {
|
|
case OS_THREAD_STATE_READY:
|
|
if (thread->suspend_count <= 0) {
|
|
if (thread->queue != &RunQueue[thread->effective_priority]) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->queue == "
|
|
"&RunQueue[thread->priority] in %d\n",
|
|
0x5e4);
|
|
OSPanic(__FILE__, 0x5e4, "");
|
|
}
|
|
|
|
if (!isMember(&RunQueue[thread->effective_priority], thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed IsMember(&RunQueue[thread->priority], "
|
|
"thread) in %d\n",
|
|
0x5e5);
|
|
OSPanic(__FILE__, 0x5e5, "");
|
|
}
|
|
|
|
if (thread->effective_priority != __OSGetEffectivePriority(thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->priority == "
|
|
"__OSGetEffectivePriority(thread) in %d\n",
|
|
0x5e6);
|
|
OSPanic(__FILE__, 0x5e6, "");
|
|
}
|
|
}
|
|
break;
|
|
case OS_THREAD_STATE_RUNNING:
|
|
if (thread->suspend_count > 0) {
|
|
OSReport("OSCheckActiveThreads: Failed !IsSuspended(thread->suspend) in %d\n",
|
|
0x5ea);
|
|
OSPanic(__FILE__, 0x5ea, "");
|
|
}
|
|
|
|
if (thread->queue != NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->queue == NULL in %d\n", 0x5eb);
|
|
OSPanic(__FILE__, 0x5eb, "");
|
|
}
|
|
|
|
if (thread->effective_priority != __OSGetEffectivePriority(thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->priority == "
|
|
"__OSGetEffectivePriority(thread) in %d\n",
|
|
0x5ec);
|
|
OSPanic(__FILE__, 0x5ec, "");
|
|
}
|
|
break;
|
|
case OS_THREAD_STATE_WAITING:
|
|
if (thread->queue == NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->queue != NULL in %d\n", 0x5ef);
|
|
OSPanic(__FILE__, 0x5ef, "");
|
|
}
|
|
|
|
if (CheckThreadQueue(thread->queue) == 0) {
|
|
OSReport("OSCheckActiveThreads: Failed CheckThreadQueue(thread->queue) in %d\n",
|
|
0x5f0);
|
|
OSPanic(__FILE__, 0x5f0, "");
|
|
}
|
|
|
|
if (!isMember(thread->queue, thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed IsMember(thread->queue, thread) in %d\n",
|
|
0x5f1);
|
|
OSPanic(__FILE__, 0x5f1, "");
|
|
}
|
|
|
|
if (thread->suspend_count <= 0) {
|
|
if (thread->effective_priority != __OSGetEffectivePriority(thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->priority == "
|
|
"__OSGetEffectivePriority(thread) in %d\n",
|
|
0x5f4);
|
|
OSPanic(__FILE__, 0x5f4, "");
|
|
}
|
|
} else if (thread->effective_priority != 32) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->priority == 32 in %d\n", 0x5f8);
|
|
OSPanic(__FILE__, 0x5f8, "");
|
|
}
|
|
|
|
if (__OSCheckDeadLock(thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed !__OSCheckDeadLock(thread) in %d\n", 0x5fa);
|
|
OSPanic(__FILE__, 0x5fa, "");
|
|
}
|
|
break;
|
|
case OS_THREAD_STATE_DEAD:
|
|
if (thread->owned_mutexes.head != NULL || thread->owned_mutexes.tail != NULL) {
|
|
OSReport("OSCheckActiveThreads: Failed thread->queueMutex.head == NULL && "
|
|
"thread->queueMutex.tail == NULL in %d\n",
|
|
0x5fe);
|
|
OSPanic(__FILE__, 0x5fe, "");
|
|
}
|
|
break;
|
|
default:
|
|
OSReport("OSCheckActiveThreads: Failed. unkown thread state (%d) of thread %p\n",
|
|
thread->state, thread);
|
|
OSPanic(__FILE__, 0x604, "");
|
|
break;
|
|
}
|
|
|
|
if (!__OSCheckMutexes(thread)) {
|
|
OSReport("OSCheckActiveThreads: Failed __OSCheckMutexes(thread) in %d\n", 0x609);
|
|
OSPanic(__FILE__, 0x609, "");
|
|
}
|
|
|
|
thread = thread->active_threads_link.next;
|
|
}
|
|
|
|
OSRestoreInterrupts(enabled);
|
|
return rv;
|
|
}
|
|
|
|
void OSClearStack(u8 val) {
|
|
u32* sp;
|
|
u32* p;
|
|
u32 pattern;
|
|
|
|
pattern = ((u32)val << 24) | ((u32)val << 16) | ((u32)val << 8) | (u32)val;
|
|
sp = (u32*)OSGetStackPointer();
|
|
for (p = ((u32*)__OSCurrentThread->stack_end) + 1; p < sp; ++p) {
|
|
*p = pattern;
|
|
}
|
|
}
|