/*---------------------------------------------------------------------------* Project: MP library File: MPSync.h Copyright (C) 2010-2011 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. *---------------------------------------------------------------------------*/ /* MPSpinLock is an inline smp spinlock implementation, which has very low overhead. This basic spinlock must be used carefully. The intended use is to guard access to shared memory between equal priority threads each running on a different core. 1) It is possible to get a deadlock condition. If thread holding a spinlock gets preempted by a higher priority thread on the same core who wants the same spinlock. 2) It is possible to get slower performance than expected. If a thread holding a spinlock gets preempted other cores will have to wait until the holding thread resumes and releases the lock. Important usage notes while holding a spinlock: - Do not cause a thread to sleep (for example, OSSleep) - Do not cause a thread rescheduling - Do not share a spinlock between threads of different priorities - Do not do any I/O while holding the spinlock OSSpinlock is designed to handle thread priority inversion issues. However, OSSpinlock still busy-waits, if a thread wants to sleep one needs to use an OSMutex. */ #ifndef __MPSYNC_H__ #define __MPSYNC_H__ #include #include #include #ifdef __cplusplus extern "C" { #endif typedef struct { OSAtomicVar var; } MPSpinLock; inline void MPInitSpinLock(MPSpinLock *spinlock) { spinlock->var.u.u32 = 0; } inline void MPAcquireSpinLock(MPSpinLock *spinlock) { while(1) { if(OSCompareAndSwapAtomic(&spinlock->var, 0, 1)) { __ISYNC(); break; } } } inline BOOL MPTryAcquireSpinLock(MPSpinLock *spinlock) { if(OSCompareAndSwapAtomic(&spinlock->var, 0, 1)) { __ISYNC(); return TRUE; } return FALSE; } inline void MPReleaseSpinLock(MPSpinLock *spinlock) { // sync is used to ensure any memory changed under the lock is coherent // before the lock is released. __SYNC(); spinlock->var.u.u32 = 0; } #ifdef __cplusplus } #endif #endif // __MPSYNC_H__