From 9fa0a7f1da1b70bee995f53c6c96c43189018772 Mon Sep 17 00:00:00 2001 From: mrb0nk500 Date: Wed, 1 Feb 2023 18:45:02 -0400 Subject: global: Import Dolphin SDK This version comes from the Metroid Prime decompilation project. https://github.com/PrimeDecomp/prime --- src/Dolphin/os/OSMutex.c | 223 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 src/Dolphin/os/OSMutex.c (limited to 'src/Dolphin/os/OSMutex.c') diff --git a/src/Dolphin/os/OSMutex.c b/src/Dolphin/os/OSMutex.c new file mode 100644 index 0000000..f853729 --- /dev/null +++ b/src/Dolphin/os/OSMutex.c @@ -0,0 +1,223 @@ +#include "dolphin/os.h" + +#define PushTail(queue, mutex, link) \ + do { \ + OSMutex* __prev; \ + \ + __prev = (queue)->tail; \ + if (__prev == NULL) \ + (queue)->head = (mutex); \ + else \ + __prev->link.next = (mutex); \ + (mutex)->link.prev = __prev; \ + (mutex)->link.next = NULL; \ + (queue)->tail = (mutex); \ + } while (0) + +#define PopHead(queue, mutex, link) \ + do { \ + OSMutex* __next; \ + \ + (mutex) = (queue)->head; \ + __next = (mutex)->link.next; \ + if (__next == NULL) \ + (queue)->tail = NULL; \ + else \ + __next->link.prev = NULL; \ + (queue)->head = __next; \ + } while (0) + +#define PopItem(queue, mutex, link) \ + do { \ + OSMutex* __next; \ + OSMutex* __prev; \ + \ + __next = (mutex)->link.next; \ + __prev = (mutex)->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) + +void OSInitMutex(OSMutex* mutex) { + OSInitThreadQueue(&mutex->queue); + mutex->thread = 0; + mutex->count = 0; +} + +void OSLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + OSThread* ownerThread; + + while (TRUE) { + ownerThread = ((OSMutex*)mutex)->thread; + if (ownerThread == 0) { + mutex->thread = currentThread; + mutex->count++; + PushTail(¤tThread->queueMutex, mutex, link); + break; + } else if (ownerThread == currentThread) { + mutex->count++; + break; + } else { + currentThread->mutex = mutex; + __OSPromoteThread(mutex->thread, currentThread->priority); + OSSleepThread(&mutex->queue); + currentThread->mutex = 0; + } + } + OSRestoreInterrupts(enabled); +} + +void OSUnlockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + + if (mutex->thread == currentThread && --mutex->count == 0) { + PopItem(¤tThread->queueMutex, mutex, link); + mutex->thread = NULL; + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + + OSWakeupThread(&mutex->queue); + } + OSRestoreInterrupts(enabled); +} + +void __OSUnlockAllMutex(OSThread* thread) { + OSMutex* mutex; + + while (thread->queueMutex.head) { + PopHead(&thread->queueMutex, mutex, link); + mutex->count = 0; + mutex->thread = NULL; + OSWakeupThread(&mutex->queue); + } +} + +BOOL OSTryLockMutex(OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + BOOL locked; + if (mutex->thread == 0) { + mutex->thread = currentThread; + mutex->count++; + PushTail(¤tThread->queueMutex, mutex, link); + locked = TRUE; + } else if (mutex->thread == currentThread) { + mutex->count++; + locked = TRUE; + } else { + locked = FALSE; + } + OSRestoreInterrupts(enabled); + return locked; +} + +void OSInitCond(OSCond* cond) { OSInitThreadQueue(&cond->queue); } + +void OSWaitCond(OSCond* cond, OSMutex* mutex) { + BOOL enabled = OSDisableInterrupts(); + OSThread* currentThread = OSGetCurrentThread(); + s32 count; + + if (mutex->thread == currentThread) { + count = mutex->count; + mutex->count = 0; + PopItem(¤tThread->queueMutex, mutex, link); + mutex->thread = NULL; + + if (currentThread->priority < currentThread->base) { + currentThread->priority = __OSGetEffectivePriority(currentThread); + } + + OSDisableScheduler(); + OSWakeupThread(&mutex->queue); + OSEnableScheduler(); + OSSleepThread(&cond->queue); + OSLockMutex(mutex); + mutex->count = count; + } + + OSRestoreInterrupts(enabled); +} + +void OSSignalCond(OSCond* cond) { OSWakeupThread(&cond->queue); } + +static BOOL IsMember(OSMutexQueue* queue, OSMutex* mutex) { + OSMutex* member; + + for (member = queue->head; member; member = member->link.next) { + if (mutex == member) + return TRUE; + } + return FALSE; +} + +BOOL __OSCheckMutex(OSMutex* mutex) { + OSThread* thread; + OSThreadQueue* queue; + OSPriority priority = 0; + + queue = &mutex->queue; + if (!(queue->head == NULL || queue->head->link.prev == NULL)) + return FALSE; + if (!(queue->tail == NULL || queue->tail->link.next == NULL)) + return FALSE; + for (thread = queue->head; thread; thread = thread->link.next) { + if (!(thread->link.next == NULL || thread == thread->link.next->link.prev)) + return FALSE; + if (!(thread->link.prev == NULL || thread == thread->link.prev->link.next)) + return FALSE; + + if (thread->state != OS_THREAD_STATE_WAITING) + return FALSE; + + if (thread->priority < priority) + return FALSE; + priority = thread->priority; + } + + if (mutex->thread) { + if (mutex->count <= 0) + return FALSE; + } else { + if (0 != mutex->count) + return FALSE; + } + + return TRUE; +} + +BOOL __OSCheckDeadLock(OSThread* thread) { + OSMutex* mutex; + + mutex = thread->mutex; + while (mutex && mutex->thread) { + if (mutex->thread == thread) + return TRUE; + mutex = mutex->thread->mutex; + } + return FALSE; +} + +BOOL __OSCheckMutexes(OSThread* thread) { + OSMutex* mutex; + + for (mutex = thread->queueMutex.head; mutex; mutex = mutex->link.next) { + if (mutex->thread != thread) + return FALSE; + if (!__OSCheckMutex(mutex)) + return FALSE; + } + return TRUE; +} -- cgit v1.2.3-13-gbd6f