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 +