ovr_sdk

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