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
|