ovr_sdk
diff LibOVR/Src/Kernel/OVR_Atomic.cpp @ 0:1b39a1b46319
initial 0.4.4
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 14 Jan 2015 06:51:16 +0200 |
parents | |
children |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_Atomic.cpp Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,139 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +Filename : OVR_Atomic.cpp 1.7 +Content : Contains atomic operations and inline fastest locking 1.8 + functionality. Will contain #ifdefs for OS efficiency. 1.9 + Have non-thread-safe implementation if not available. 1.10 +Created : September 19, 2012 1.11 +Notes : 1.12 + 1.13 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.14 + 1.15 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.16 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.17 +which is provided at the time of installation or download, or which 1.18 +otherwise accompanies this software in either electronic or hard copy form. 1.19 + 1.20 +You may obtain a copy of the License at 1.21 + 1.22 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.23 + 1.24 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.25 +distributed under the License is distributed on an "AS IS" BASIS, 1.26 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.27 +See the License for the specific language governing permissions and 1.28 +limitations under the License. 1.29 + 1.30 +************************************************************************************/ 1.31 + 1.32 +#include "OVR_Atomic.h" 1.33 +#include "OVR_Allocator.h" 1.34 + 1.35 +#ifdef OVR_ENABLE_THREADS 1.36 + 1.37 +// Include Windows 8-Metro compatible Synchronization API 1.38 +#if defined(OVR_OS_MS) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8) 1.39 +#include <synchapi.h> 1.40 +#endif 1.41 + 1.42 + 1.43 +namespace OVR { 1.44 + 1.45 +// ***** Windows Lock implementation 1.46 + 1.47 +#if defined(OVR_OS_MS) 1.48 + 1.49 +// ***** Standard Win32 Lock implementation 1.50 + 1.51 +// Constructors 1.52 +Lock::Lock(unsigned spinCount) 1.53 +{ 1.54 + #if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8) 1.55 + // On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility 1.56 + InitializeCriticalSectionEx(&cs, (DWORD)spinCount, 1.57 + OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO)); 1.58 + #else 1.59 + ::InitializeCriticalSectionAndSpinCount(&cs, (DWORD)spinCount); // This is available with WindowsXP+. 1.60 + #endif 1.61 +} 1.62 + 1.63 + 1.64 +Lock::~Lock() 1.65 +{ 1.66 + DeleteCriticalSection(&cs); 1.67 +} 1.68 + 1.69 + 1.70 +#endif 1.71 + 1.72 + 1.73 +//------------------------------------------------------------------------------------- 1.74 +// ***** SharedLock 1.75 + 1.76 +// This is a general purpose globally shared Lock implementation that should probably be 1.77 +// moved to Kernel. 1.78 +// May in theory busy spin-wait if we hit contention on first lock creation, 1.79 +// but this shouldn't matter in practice since Lock* should be cached. 1.80 + 1.81 + 1.82 +enum { LockInitMarker = 0xFFFFFFFF }; 1.83 + 1.84 +Lock* SharedLock::GetLockAddRef() 1.85 +{ 1.86 + int oldUseCount; 1.87 + 1.88 + do { 1.89 + oldUseCount = UseCount; 1.90 + if (oldUseCount == (int)LockInitMarker) 1.91 + continue; 1.92 + 1.93 + if (oldUseCount == 0) 1.94 + { 1.95 + // Initialize marker 1.96 + if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 0, LockInitMarker)) 1.97 + { 1.98 + Construct<Lock>(Buffer); 1.99 + do { } 1.100 + while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 1)); 1.101 + return toLock(); 1.102 + } 1.103 + continue; 1.104 + } 1.105 + 1.106 + } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1)); 1.107 + 1.108 + return toLock(); 1.109 +} 1.110 + 1.111 +void SharedLock::ReleaseLock(Lock* plock) 1.112 +{ 1.113 + OVR_UNUSED(plock); 1.114 + OVR_ASSERT(plock == toLock()); 1.115 + 1.116 + int oldUseCount; 1.117 + 1.118 + do { 1.119 + oldUseCount = UseCount; 1.120 + OVR_ASSERT(oldUseCount != (int)LockInitMarker); 1.121 + 1.122 + if (oldUseCount == 1) 1.123 + { 1.124 + // Initialize marker 1.125 + if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 1, LockInitMarker)) 1.126 + { 1.127 + Destruct<Lock>(toLock()); 1.128 + 1.129 + do { } 1.130 + while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 0)); 1.131 + 1.132 + return; 1.133 + } 1.134 + continue; 1.135 + } 1.136 + 1.137 + } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1)); 1.138 +} 1.139 + 1.140 +} // OVR 1.141 + 1.142 +#endif // OVR_ENABLE_THREADS