ovr_sdk

annotate 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
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 Filename : OVR_Atomic.cpp
nuclear@0 4 Content : Contains atomic operations and inline fastest locking
nuclear@0 5 functionality. Will contain #ifdefs for OS efficiency.
nuclear@0 6 Have non-thread-safe implementation if not available.
nuclear@0 7 Created : September 19, 2012
nuclear@0 8 Notes :
nuclear@0 9
nuclear@0 10 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 11
nuclear@0 12 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 13 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 14 which is provided at the time of installation or download, or which
nuclear@0 15 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 16
nuclear@0 17 You may obtain a copy of the License at
nuclear@0 18
nuclear@0 19 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 20
nuclear@0 21 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 22 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 23 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 24 See the License for the specific language governing permissions and
nuclear@0 25 limitations under the License.
nuclear@0 26
nuclear@0 27 ************************************************************************************/
nuclear@0 28
nuclear@0 29 #include "OVR_Atomic.h"
nuclear@0 30 #include "OVR_Allocator.h"
nuclear@0 31
nuclear@0 32 #ifdef OVR_ENABLE_THREADS
nuclear@0 33
nuclear@0 34 // Include Windows 8-Metro compatible Synchronization API
nuclear@0 35 #if defined(OVR_OS_MS) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
nuclear@0 36 #include <synchapi.h>
nuclear@0 37 #endif
nuclear@0 38
nuclear@0 39
nuclear@0 40 namespace OVR {
nuclear@0 41
nuclear@0 42 // ***** Windows Lock implementation
nuclear@0 43
nuclear@0 44 #if defined(OVR_OS_MS)
nuclear@0 45
nuclear@0 46 // ***** Standard Win32 Lock implementation
nuclear@0 47
nuclear@0 48 // Constructors
nuclear@0 49 Lock::Lock(unsigned spinCount)
nuclear@0 50 {
nuclear@0 51 #if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8)
nuclear@0 52 // On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility
nuclear@0 53 InitializeCriticalSectionEx(&cs, (DWORD)spinCount,
nuclear@0 54 OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO));
nuclear@0 55 #else
nuclear@0 56 ::InitializeCriticalSectionAndSpinCount(&cs, (DWORD)spinCount); // This is available with WindowsXP+.
nuclear@0 57 #endif
nuclear@0 58 }
nuclear@0 59
nuclear@0 60
nuclear@0 61 Lock::~Lock()
nuclear@0 62 {
nuclear@0 63 DeleteCriticalSection(&cs);
nuclear@0 64 }
nuclear@0 65
nuclear@0 66
nuclear@0 67 #endif
nuclear@0 68
nuclear@0 69
nuclear@0 70 //-------------------------------------------------------------------------------------
nuclear@0 71 // ***** SharedLock
nuclear@0 72
nuclear@0 73 // This is a general purpose globally shared Lock implementation that should probably be
nuclear@0 74 // moved to Kernel.
nuclear@0 75 // May in theory busy spin-wait if we hit contention on first lock creation,
nuclear@0 76 // but this shouldn't matter in practice since Lock* should be cached.
nuclear@0 77
nuclear@0 78
nuclear@0 79 enum { LockInitMarker = 0xFFFFFFFF };
nuclear@0 80
nuclear@0 81 Lock* SharedLock::GetLockAddRef()
nuclear@0 82 {
nuclear@0 83 int oldUseCount;
nuclear@0 84
nuclear@0 85 do {
nuclear@0 86 oldUseCount = UseCount;
nuclear@0 87 if (oldUseCount == (int)LockInitMarker)
nuclear@0 88 continue;
nuclear@0 89
nuclear@0 90 if (oldUseCount == 0)
nuclear@0 91 {
nuclear@0 92 // Initialize marker
nuclear@0 93 if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 0, LockInitMarker))
nuclear@0 94 {
nuclear@0 95 Construct<Lock>(Buffer);
nuclear@0 96 do { }
nuclear@0 97 while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 1));
nuclear@0 98 return toLock();
nuclear@0 99 }
nuclear@0 100 continue;
nuclear@0 101 }
nuclear@0 102
nuclear@0 103 } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1));
nuclear@0 104
nuclear@0 105 return toLock();
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 void SharedLock::ReleaseLock(Lock* plock)
nuclear@0 109 {
nuclear@0 110 OVR_UNUSED(plock);
nuclear@0 111 OVR_ASSERT(plock == toLock());
nuclear@0 112
nuclear@0 113 int oldUseCount;
nuclear@0 114
nuclear@0 115 do {
nuclear@0 116 oldUseCount = UseCount;
nuclear@0 117 OVR_ASSERT(oldUseCount != (int)LockInitMarker);
nuclear@0 118
nuclear@0 119 if (oldUseCount == 1)
nuclear@0 120 {
nuclear@0 121 // Initialize marker
nuclear@0 122 if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 1, LockInitMarker))
nuclear@0 123 {
nuclear@0 124 Destruct<Lock>(toLock());
nuclear@0 125
nuclear@0 126 do { }
nuclear@0 127 while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 0));
nuclear@0 128
nuclear@0 129 return;
nuclear@0 130 }
nuclear@0 131 continue;
nuclear@0 132 }
nuclear@0 133
nuclear@0 134 } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1));
nuclear@0 135 }
nuclear@0 136
nuclear@0 137 } // OVR
nuclear@0 138
nuclear@0 139 #endif // OVR_ENABLE_THREADS