ovr_sdk
diff 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 diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/LibOVR/Src/Kernel/OVR_Lockless.h Wed Jan 14 06:51:16 2015 +0200 1.3 @@ -0,0 +1,117 @@ 1.4 +/************************************************************************************ 1.5 + 1.6 +PublicHeader: OVR_Kernel.h 1.7 +Filename : OVR_Lockless.h 1.8 +Content : Lock-less classes for producer/consumer communication 1.9 +Created : November 9, 2013 1.10 +Authors : John Carmack 1.11 + 1.12 +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. 1.13 + 1.14 +Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License"); 1.15 +you may not use the Oculus VR Rift SDK except in compliance with the License, 1.16 +which is provided at the time of installation or download, or which 1.17 +otherwise accompanies this software in either electronic or hard copy form. 1.18 + 1.19 +You may obtain a copy of the License at 1.20 + 1.21 +http://www.oculusvr.com/licenses/LICENSE-3.2 1.22 + 1.23 +Unless required by applicable law or agreed to in writing, the Oculus VR SDK 1.24 +distributed under the License is distributed on an "AS IS" BASIS, 1.25 +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1.26 +See the License for the specific language governing permissions and 1.27 +limitations under the License. 1.28 + 1.29 +*************************************************************************************/ 1.30 + 1.31 +#ifndef OVR_Lockless_h 1.32 +#define OVR_Lockless_h 1.33 + 1.34 +#include "OVR_Atomic.h" 1.35 + 1.36 +// Define this to compile-in Lockless test logic 1.37 +//#define OVR_LOCKLESS_TEST 1.38 + 1.39 +namespace OVR { 1.40 + 1.41 + 1.42 +// ***** LocklessUpdater 1.43 + 1.44 +// For single producer cases where you only care about the most recent update, not 1.45 +// necessarily getting every one that happens (vsync timing, SensorFusion updates). 1.46 +// 1.47 +// This is multiple consumer safe, but is currently only used with a single consumer. 1.48 +// 1.49 +// The SlotType can be the same as T, but should probably be a larger fixed size. 1.50 +// This allows for forward compatibility when the updater is shared between processes. 1.51 + 1.52 +// FIXME: ExchangeAdd_Sync() should be replaced with a portable read-only primitive, 1.53 +// so that the lockless pose state can be read-only on remote processes and to reduce 1.54 +// false sharing between processes and improve performance. 1.55 + 1.56 +template<class T, class SlotType> 1.57 +class LocklessUpdater 1.58 +{ 1.59 +public: 1.60 + LocklessUpdater() : UpdateBegin( 0 ), UpdateEnd( 0 ) 1.61 + { 1.62 + OVR_COMPILER_ASSERT(sizeof(T) <= sizeof(SlotType)); 1.63 + } 1.64 + 1.65 + T GetState() const 1.66 + { 1.67 + // Copy the state out, then retry with the alternate slot 1.68 + // if we determine that our copy may have been partially 1.69 + // stepped on by a new update. 1.70 + T state; 1.71 + int begin, end, final; 1.72 + 1.73 + for(;;) 1.74 + { 1.75 + // We are adding 0, only using these as atomic memory barriers, so it 1.76 + // is ok to cast off the const, allowing GetState() to remain const. 1.77 + end = UpdateEnd.Load_Acquire(); 1.78 + state = Slots[ end & 1 ]; 1.79 + begin = UpdateBegin.Load_Acquire(); 1.80 + if ( begin == end ) { 1.81 + break; 1.82 + } 1.83 + 1.84 + // The producer is potentially blocked while only having partially 1.85 + // written the update, so copy out the other slot. 1.86 + state = Slots[ (begin & 1) ^ 1 ]; 1.87 + final = UpdateBegin.Load_Acquire(); 1.88 + if ( final == begin ) { 1.89 + break; 1.90 + } 1.91 + 1.92 + // The producer completed the last update and started a new one before 1.93 + // we got it copied out, so try fetching the current buffer again. 1.94 + } 1.95 + return state; 1.96 + } 1.97 + 1.98 + void SetState( const T& state ) 1.99 + { 1.100 + const int slot = UpdateBegin.ExchangeAdd_Sync(1) & 1; 1.101 + // Write to (slot ^ 1) because ExchangeAdd returns 'previous' value before add. 1.102 + Slots[slot ^ 1] = state; 1.103 + UpdateEnd.ExchangeAdd_Sync(1); 1.104 + } 1.105 + 1.106 + AtomicInt<int> UpdateBegin; 1.107 + AtomicInt<int> UpdateEnd; 1.108 + SlotType Slots[2]; 1.109 +}; 1.110 + 1.111 + 1.112 +#ifdef OVR_LOCKLESS_TEST 1.113 +void StartLocklessTest(); 1.114 +#endif 1.115 + 1.116 + 1.117 +} // namespace OVR 1.118 + 1.119 +#endif // OVR_Lockless_h 1.120 +