ctr_firmware/trunk/bootrom/build/libraries/os/common/os_mutex.c
nakasima 4f7ade393f mutex追加。
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-09-30%20-%20paladin.7z/paladin/ctr_firmware@150 b871894f-2f95-9b40-918c-086798483c85
2009-01-05 09:04:05 +00:00

704 lines
19 KiB
C

/*---------------------------------------------------------------------------*
Project: CtrBrom - libraries - OS
File: os_mutex.c
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Date:: $
$Rev$
$Author$
*---------------------------------------------------------------------------*/
#include <brom/types.h>
#include <brom.h>
void i_osUnlockMutexCore(OSMutex *mutex, u32 type);
void i_osEnqueueTail(OSThread *thread, OSMutex *mutex);
void i_osDequeueItem(OSThread *thread, OSMutex *mutex);
OSMutex *i_osDequeueHead(OSThread *thread);
/*---------------------------------------------------------------------------*
Name: osInitMutex
Description: initialize mutex
Arguments: mutex pointer to mutex structure
to be initialized
Returns: None
*---------------------------------------------------------------------------*/
void osInitMutex(OSMutex *mutex)
{
SDK_ASSERT(mutex);
osInitThreadQueue(&mutex->queue);
mutex->thread = NULL;
osSetMutexCount( mutex, 0 );
osSetMutexType( mutex, OS_MUTEX_TYPE_NONE );
}
/*---------------------------------------------------------------------------*
Name: osLockMutex
Description: lock mutex
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osLockMutex(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
while(1)
{
//---- try lock mutex
if ( osTryLockMutex(mutex) )
{
break;
}
currentThread->mutex = mutex;
osSleepThread(&mutex->queue);
currentThread->mutex = NULL;
}
(void)osRestoreInterrupts(e);
}
/*---------------------------------------------------------------------------*
Name: osUnlockMutex
Description: unlock mutex
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osUnlockMutex(OSMutex *mutex)
{
i_osUnlockMutexCore(mutex, OS_MUTEX_TYPE_STD);
}
/*---------------------------------------------------------------------------*
Name: i_osUnlockAllMutex
Description: unlocks all the mutexes locked by the thread
Arguments: mutex pointer to mutex structure
Returns: None.
*---------------------------------------------------------------------------*/
void i_osUnlockAllMutex(OSThread *thread)
{
OSMutex *mutex;
SDK_ASSERT(thread);
#ifndef SDK_THREAD_INFINITY
while (thread->mutexQueueHead)
{
mutex = i_osDequeueHead(thread);
SDK_ASSERT(mutex->thread == thread);
osSetMutexCount( mutex, 0 );
mutex->thread = NULL;
osSetMutexType( mutex, OS_MUTEX_TYPE_NONE );
osWakeupThread(&(mutex->queue));
}
#else
while (thread->mutexQueue.head)
{
mutex = i_osRemoveMutexLinkFromQueue(&thread->mutexQueue);
SDK_ASSERT(mutex->thread == thread);
osSetMutexCount( mutex, 0 );
mutex->thread = NULL;
osSetMutexType( mutex, OS_MUTEX_TYPE_NONE );
osWakeupThread(&mutex->queue);
}
#endif
}
/*---------------------------------------------------------------------------*
Name: osTryLockMutex
Description: try to lock mutex
Arguments: mutex pointer to mutex structure
Returns: True if lock
*---------------------------------------------------------------------------*/
BOOL osTryLockMutex(OSMutex *mutex)
{
OSIntrMode saved = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
BOOL locked;
SDK_ASSERT(mutex);
// ---- able to lock mutex
if (mutex->thread == NULL)
{
mutex->thread = currentThread;
osSetMutexType( mutex, OS_MUTEX_TYPE_STD );
osIncreaseMutexCount(mutex);
i_osEnqueueTail(currentThread, mutex);
locked = TRUE;
}
// ---- current thread is same with thread locking mutex
else if (mutex->thread == currentThread)
{
osIncreaseMutexCount(mutex);
locked = TRUE;
}
// ---- current thread is different from locking mutex
else
{
locked = FALSE;
}
(void)osRestoreInterrupts(saved);
return locked;
}
//================================================================================
// Read / Write Lock
//================================================================================
/*---------------------------------------------------------------------------*
Name: osLockMutexR
Description: lock RW mutex as READ access
Arguments: mutex pointer to RW mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osLockMutexR(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
while(1)
{
//---- try lock by READ
if ( osTryLockMutexR(mutex) )
{
break;
}
currentThread->mutex = mutex;
osSleepThread(&mutex->queue);
currentThread->mutex = NULL;
}
(void)osRestoreInterrupts(e);
}
/*---------------------------------------------------------------------------*
Name: osLockMutexW
Description: lock RW mutex as WRITE access
Arguments: mutex pointer to RW mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osLockMutexW(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
while(1)
{
//---- try lock by WRITE
if ( osTryLockMutexW(mutex) )
{
break;
}
currentThread->mutex = mutex;
osSleepThread(&mutex->queue);
currentThread->mutex = NULL;
}
(void)osRestoreInterrupts(e);
}
/*---------------------------------------------------------------------------*
Name: osTryLockMutexR
Description: try to lock RW mutex as READ access
Arguments: mutex pointer to RW mutex structure
Returns: TRUE if locked
*---------------------------------------------------------------------------*/
BOOL osTryLockMutexR(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
BOOL locked = FALSE;
OSThread * currentThread = osGetCurrentThread();
switch( osGetMutexType(mutex) )
{
case OS_MUTEX_TYPE_NONE:
mutex->thread = currentThread;
osSetMutexType( mutex, OS_MUTEX_TYPE_R );
osSetMutexCount( mutex, 1 );
i_osEnqueueTail(currentThread, mutex);
locked = TRUE;
break;
case OS_MUTEX_TYPE_R:
osIncreaseMutexCount(mutex);
locked = TRUE;
break;
case OS_MUTEX_TYPE_W:
default:
break;
}
(void)osRestoreInterrupts(e);
return locked;
}
/*---------------------------------------------------------------------------*
Name: osTryLockMutexW
Description: try to lock RW mutex as WRITE access
Arguments: mutex pointer to RW mutex structure
Returns: TRUE if locked
*---------------------------------------------------------------------------*/
BOOL osTryLockMutexW(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
BOOL locked = FALSE;
OSThread * currentThread = osGetCurrentThread();
switch( osGetMutexType(mutex) )
{
case OS_MUTEX_TYPE_NONE:
mutex->thread = currentThread;
osSetMutexType( mutex, OS_MUTEX_TYPE_W );
osSetMutexCount( mutex, 1 );
i_osEnqueueTail(currentThread, mutex);
locked = TRUE;
break;
case OS_MUTEX_TYPE_W:
if ( mutex->thread == currentThread )
{
osIncreaseMutexCount(mutex);
locked = TRUE;
}
break;
case OS_MUTEX_TYPE_R:
default:
break;
}
(void)osRestoreInterrupts(e);
return locked;
}
/*---------------------------------------------------------------------------*
Name: i_osUnlockMutexCore
Description: core routine to unlock mutex
Arguments: mutex pointer to RW mutex structure
type mutex type. if different from osGetMutexType(), error.
OS_MUTEX_TYPE_STD
OS_MUTEX_TYPE_R
OS_MUTEX_TYPE_W
OS_MUTEX_TYPE_NONE (no check)
Returns: None
*---------------------------------------------------------------------------*/
void i_osUnlockMutexCore(OSMutex *mutex, u32 type )
{
OSIntrMode e = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
BOOL unlocked = FALSE;
SDK_ASSERT(mutex);
//---- check unlock type
if ( type != OS_MUTEX_TYPE_NONE && type != osGetMutexType(mutex) )
{
//osTPanic("Illegal unlock mutex\n");
osTWarning("Illegal unlock mutex");
(void)osRestoreInterrupts(e);
return;
}
switch( osGetMutexType(mutex) )
{
case OS_MUTEX_TYPE_STD:
case OS_MUTEX_TYPE_W:
if ( mutex->thread == currentThread )
{
osDecreaseMutexCount(mutex);
if ( osGetMutexCount(mutex) == 0 )
{
unlocked = TRUE;
}
}
break;
case OS_MUTEX_TYPE_R:
osDecreaseMutexCount(mutex);
if ( osGetMutexCount(mutex) == 0 )
{
unlocked = TRUE;
}
break;
default:
osTWarning("Illegal unlock mutex");
(void)osRestoreInterrupts(e);
return;
//osTPanic("Illegal unlock mutex\n");
//break;
}
//---- unlock mutex
if ( unlocked )
{
i_osDequeueItem(currentThread, mutex);
mutex->thread = NULL;
osSetMutexType( mutex, OS_MUTEX_TYPE_NONE );
osWakeupThread(&mutex->queue);
}
(void)osRestoreInterrupts(e);
}
/*---------------------------------------------------------------------------*
Name: osUnlockMutexR
Description: unlock mutex locked as READ access
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osUnlockMutexR(OSMutex *mutex)
{
i_osUnlockMutexCore( mutex, OS_MUTEX_TYPE_R );
}
/*---------------------------------------------------------------------------*
Name: osUnlockMutexW
Description: unlock mutex locked as WRITE access
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osUnlockMutexW(OSMutex *mutex)
{
i_osUnlockMutexCore( mutex, OS_MUTEX_TYPE_W );
}
/*---------------------------------------------------------------------------*
Name: osUnlockMutexRW
Description: unlock mutex locked as READ/WRITE access
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osUnlockMutexRW(OSMutex *mutex)
{
i_osUnlockMutexCore( mutex, OS_MUTEX_TYPE_NONE );
}
/*---------------------------------------------------------------------------*
Name: osLockMutexFromRToW
Description: Promote mutexR lock to mutexW lock without unlock.
Wait till success.
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osLockMutexFromRToW(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
while(1)
{
if ( osTryLockMutexFromRToW(mutex) )
{
break;
}
currentThread->mutex = mutex;
osSleepThread(&mutex->queue);
currentThread->mutex = NULL;
}
(void)osRestoreInterrupts(e);
}
/*---------------------------------------------------------------------------*
Name: osTryLockMutexFromRToW
Description: Try to promote mutexR lock to mutexW lock without unlock.
Arguments: mutex pointer to mutex structure
Returns: TRUE if success
*---------------------------------------------------------------------------*/
BOOL osTryLockMutexFromRToW(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
BOOL locked = FALSE;
//---- change mutex type if no other thread is locked. and mutex is R
if ( osGetMutexCount(mutex) == 1 && mutex->queue.head == NULL && osGetMutexType(mutex) == OS_MUTEX_TYPE_R )
{
osSetMutexType( mutex, OS_MUTEX_TYPE_W );
locked = TRUE;
}
(void)osRestoreInterrupts(e);
return locked;
}
/*---------------------------------------------------------------------------*
Name: osLockMutexFromWToR
Description: Demote mutexW lock to mutexR lock without unlock.
Wait till success.
Arguments: mutex pointer to mutex structure
Returns: None
*---------------------------------------------------------------------------*/
void osLockMutexFromWToR(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
OSThread *currentThread = osGetCurrentThread();
while(1)
{
if ( osTryLockMutexFromWToR(mutex) )
{
break;
}
currentThread->mutex = mutex;
osSleepThread(&mutex->queue);
currentThread->mutex = NULL;
}
(void)osRestoreInterrupts(e);
}
/*---------------------------------------------------------------------------*
Name: osTryLockMutexFromWToR
Description: Try to demote mutexW lock to mutexR lock without unlock.
Arguments: mutex pointer to mutex structure
Returns: TRUE if success
*---------------------------------------------------------------------------*/
BOOL osTryLockMutexFromWToR(OSMutex *mutex)
{
OSIntrMode e = osDisableInterrupts();
BOOL locked = FALSE;
//---- change mutex type if no other thread is locked. and mutex is W
if ( osGetMutexCount(mutex) == 1 && mutex->queue.head == NULL && osGetMutexType(mutex) == OS_MUTEX_TYPE_W )
{
osSetMutexType( mutex, OS_MUTEX_TYPE_R );
locked = TRUE;
}
(void)osRestoreInterrupts(e);
return locked;
}
//===========================================================================
// MUTEX QUEUE
//===========================================================================
/*---------------------------------------------------------------------------*
Name: i_osEnqueueTail
Description: internal function.
add mutex to thread's mutex list
Arguments: thread pointer to thread
mutex pointer to mutex to be add
Returns: None.
*---------------------------------------------------------------------------*/
void i_osEnqueueTail(OSThread *thread, OSMutex *mutex)
{
#ifndef SDK_THREAD_INFINITY
OSMutex *prev = thread->mutexQueueTail;
SDK_ASSERT(thread && mutex);
if (!prev)
{
thread->mutexQueueHead = mutex;
}
else
{
prev->next = mutex;
}
mutex->prev = prev;
mutex->next = NULL;
thread->mutexQueueTail = mutex;
#else
OSMutex *prev = thread->mutexQueue.tail;
SDK_ASSERT(thread && mutex);
if (!prev)
{
thread->mutexQueue.head = mutex;
}
else
{
prev->link.next = mutex;
}
mutex->link.prev = prev;
mutex->link.next = NULL;
thread->mutexQueue.tail = mutex;
#endif
}
/*---------------------------------------------------------------------------*
Name: i_osDequeueItem
Description: internal function.
remove specified mutex from thread's mutex list
Arguments: thread pointer to thread
mutex pointer to mutex to be remove
Returns: None.
*---------------------------------------------------------------------------*/
void i_osDequeueItem(OSThread *thread, OSMutex *mutex)
{
#ifndef SDK_THREAD_INFINITY
OSMutex *next = mutex->next;
OSMutex *prev = mutex->prev;
SDK_ASSERT(thread && mutex);
if (!next)
{
thread->mutexQueueTail = prev;
}
else
{
next->prev = prev;
}
if (!prev)
{
thread->mutexQueueHead = next;
}
else
{
prev->next = next;
}
#else
OSMutex *next = mutex->link.next;
OSMutex *prev = mutex->link.prev;
SDK_ASSERT(thread && mutex);
if (!next)
{
thread->mutexQueue.tail = prev;
}
else
{
next->link.prev = prev;
}
if (!prev)
{
thread->mutexQueue.head = next;
}
else
{
prev->link.next = next;
}
#endif
}
/*---------------------------------------------------------------------------*
Name: i_osDequeueHead
Description: remove top mutex from thread's list, and return mutex
Arguments: thread pointer to thread
Returns: mutex which listed at top of thread
*---------------------------------------------------------------------------*/
OSMutex *i_osDequeueHead(OSThread *thread)
{
#ifndef SDK_THREAD_INFINITY
OSMutex *mutex = thread->mutexQueueHead;
OSMutex *next = mutex->next;
SDK_ASSERT(thread);
if (!next)
{
thread->mutexQueueTail = NULL;
}
else
{
next->prev = NULL;
}
thread->mutexQueueHead = next;
#else
OSMutex *mutex = thread->mutexQueue.head;
OSMutex *next = mutex->link.next;
SDK_ASSERT(thread);
if (!next)
{
thread->mutexQueue.tail = NULL;
}
else
{
next->link.prev = NULL;
}
thread->mutexQueue.head = next;
#endif
return mutex;
}