244 lines
11 KiB
C
244 lines
11 KiB
C
#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;
|
|
}
|