aboutsummaryrefslogtreecommitdiffstats
path: root/LibOVR/Src/Kernel/OVR_Lockless.h
diff options
context:
space:
mode:
Diffstat (limited to 'LibOVR/Src/Kernel/OVR_Lockless.h')
-rw-r--r--LibOVR/Src/Kernel/OVR_Lockless.h107
1 files changed, 107 insertions, 0 deletions
diff --git a/LibOVR/Src/Kernel/OVR_Lockless.h b/LibOVR/Src/Kernel/OVR_Lockless.h
new file mode 100644
index 0000000..a12f824
--- /dev/null
+++ b/LibOVR/Src/Kernel/OVR_Lockless.h
@@ -0,0 +1,107 @@
+/************************************************************************************
+
+PublicHeader: OVR.h
+Filename : OVR_Lockless.h
+Content : Lock-less classes for producer/consumer communication
+Created : November 9, 2013
+Authors : John Carmack
+
+Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved.
+
+Licensed under the Oculus VR Rift SDK License Version 3.1 (the "License");
+you may not use the Oculus VR Rift SDK except in compliance with the License,
+which is provided at the time of installation or download, or which
+otherwise accompanies this software in either electronic or hard copy form.
+
+You may obtain a copy of the License at
+
+http://www.oculusvr.com/licenses/LICENSE-3.1
+
+Unless required by applicable law or agreed to in writing, the Oculus VR SDK
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*************************************************************************************/
+
+#ifndef OVR_Lockless_h
+#define OVR_Lockless_h
+
+#include "OVR_Atomic.h"
+
+// Define this to compile-in Lockless test logic
+//#define OVR_LOCKLESS_TEST
+
+namespace OVR {
+
+
+// ***** LocklessUpdater
+
+// For single producer cases where you only care about the most recent update, not
+// necessarily getting every one that happens (vsync timing, SensorFusion updates).
+//
+// This is multiple consumer safe, but is currently only used with a single consumer.
+
+template<class T>
+class LocklessUpdater
+{
+public:
+ LocklessUpdater() : UpdateBegin( 0 ), UpdateEnd( 0 ) {}
+
+ T GetState() const
+ {
+ // Copy the state out, then retry with the alternate slot
+ // if we determine that our copy may have been partially
+ // stepped on by a new update.
+ T state;
+ int begin, end, final;
+
+ for(;;)
+ {
+ // We are adding 0, only using these as atomic memory barriers, so it
+ // is ok to cast off the const, allowing GetState() to remain const.
+ end = UpdateEnd.ExchangeAdd_Sync(0);
+ state = Slots[ end & 1 ];
+ begin = UpdateBegin.ExchangeAdd_Sync(0);
+ if ( begin == end ) {
+ break;
+ }
+
+ // The producer is potentially blocked while only having partially
+ // written the update, so copy out the other slot.
+ state = Slots[ (begin & 1) ^ 1 ];
+ final = UpdateBegin.ExchangeAdd_NoSync(0);
+ if ( final == begin ) {
+ break;
+ }
+
+ // The producer completed the last update and started a new one before
+ // we got it copied out, so try fetching the current buffer again.
+ }
+ return state;
+ }
+
+ void SetState( T state )
+ {
+ const int slot = UpdateBegin.ExchangeAdd_Sync(1) & 1;
+ // Write to (slot ^ 1) because ExchangeAdd returns 'previous' value before add.
+ Slots[slot ^ 1] = state;
+ UpdateEnd.ExchangeAdd_Sync(1);
+ }
+
+ mutable AtomicInt<int> UpdateBegin;
+ mutable AtomicInt<int> UpdateEnd;
+ T Slots[2];
+};
+
+
+#ifdef OVR_LOCKLESS_TEST
+void StartLocklessTest();
+#endif
+
+
+} // namespace OVR
+
+#endif // OVR_Lockless_h
+