#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; }