ovr_sdk

view LibOVR/Src/Kernel/OVR_Lockless.h @ 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 source
1 /************************************************************************************
3 PublicHeader: OVR_Kernel.h
4 Filename : OVR_Lockless.h
5 Content : Lock-less classes for producer/consumer communication
6 Created : November 9, 2013
7 Authors : John Carmack
9 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
11 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
12 you may not use the Oculus VR Rift SDK except in compliance with the License,
13 which is provided at the time of installation or download, or which
14 otherwise accompanies this software in either electronic or hard copy form.
16 You may obtain a copy of the License at
18 http://www.oculusvr.com/licenses/LICENSE-3.2
20 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
21 distributed under the License is distributed on an "AS IS" BASIS,
22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23 See the License for the specific language governing permissions and
24 limitations under the License.
26 *************************************************************************************/
28 #ifndef OVR_Lockless_h
29 #define OVR_Lockless_h
31 #include "OVR_Atomic.h"
33 // Define this to compile-in Lockless test logic
34 //#define OVR_LOCKLESS_TEST
36 namespace OVR {
39 // ***** LocklessUpdater
41 // For single producer cases where you only care about the most recent update, not
42 // necessarily getting every one that happens (vsync timing, SensorFusion updates).
43 //
44 // This is multiple consumer safe, but is currently only used with a single consumer.
45 //
46 // The SlotType can be the same as T, but should probably be a larger fixed size.
47 // This allows for forward compatibility when the updater is shared between processes.
49 // FIXME: ExchangeAdd_Sync() should be replaced with a portable read-only primitive,
50 // so that the lockless pose state can be read-only on remote processes and to reduce
51 // false sharing between processes and improve performance.
53 template<class T, class SlotType>
54 class LocklessUpdater
55 {
56 public:
57 LocklessUpdater() : UpdateBegin( 0 ), UpdateEnd( 0 )
58 {
59 OVR_COMPILER_ASSERT(sizeof(T) <= sizeof(SlotType));
60 }
62 T GetState() const
63 {
64 // Copy the state out, then retry with the alternate slot
65 // if we determine that our copy may have been partially
66 // stepped on by a new update.
67 T state;
68 int begin, end, final;
70 for(;;)
71 {
72 // We are adding 0, only using these as atomic memory barriers, so it
73 // is ok to cast off the const, allowing GetState() to remain const.
74 end = UpdateEnd.Load_Acquire();
75 state = Slots[ end & 1 ];
76 begin = UpdateBegin.Load_Acquire();
77 if ( begin == end ) {
78 break;
79 }
81 // The producer is potentially blocked while only having partially
82 // written the update, so copy out the other slot.
83 state = Slots[ (begin & 1) ^ 1 ];
84 final = UpdateBegin.Load_Acquire();
85 if ( final == begin ) {
86 break;
87 }
89 // The producer completed the last update and started a new one before
90 // we got it copied out, so try fetching the current buffer again.
91 }
92 return state;
93 }
95 void SetState( const T& state )
96 {
97 const int slot = UpdateBegin.ExchangeAdd_Sync(1) & 1;
98 // Write to (slot ^ 1) because ExchangeAdd returns 'previous' value before add.
99 Slots[slot ^ 1] = state;
100 UpdateEnd.ExchangeAdd_Sync(1);
101 }
103 AtomicInt<int> UpdateBegin;
104 AtomicInt<int> UpdateEnd;
105 SlotType Slots[2];
106 };
109 #ifdef OVR_LOCKLESS_TEST
110 void StartLocklessTest();
111 #endif
114 } // namespace OVR
116 #endif // OVR_Lockless_h