diff options
Diffstat (limited to 'LibOVRKernel/Src/Kernel')
62 files changed, 34195 insertions, 0 deletions
diff --git a/LibOVRKernel/Src/Kernel/OVR_Alg.cpp b/LibOVRKernel/Src/Kernel/OVR_Alg.cpp new file mode 100644 index 0000000..c087777 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Alg.cpp @@ -0,0 +1,57 @@ +/************************************************************************************ + +Filename : OVR_Alg.cpp +Content : Static lookup tables for Alg functions +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Types.h" + +namespace OVR { namespace Alg { + +//------------------------------------------------------------------------ +extern const uint8_t UpperBitTable[256] = +{ + 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7 +}; + +extern const uint8_t LowerBitTable[256] = +{ + 8,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 7,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 6,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0, + 5,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0,4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0 +}; + + +}} // OVE::Alg diff --git a/LibOVRKernel/Src/Kernel/OVR_Alg.h b/LibOVRKernel/Src/Kernel/OVR_Alg.h new file mode 100644 index 0000000..f7f461f --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Alg.h @@ -0,0 +1,1062 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Alg.h +Content : Simple general purpose algorithms: Sort, Binary Search, etc. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Alg_h +#define OVR_Alg_h + +#include "OVR_Types.h" +#include <string.h> + +namespace OVR { namespace Alg { + + +//----------------------------------------------------------------------------------- +// ***** Operator extensions + +template <typename T> OVR_FORCE_INLINE void Swap(T &a, T &b) +{ T temp(a); a = b; b = temp; } + + +// ***** min/max are not implemented in Visual Studio 6 standard STL + +template <typename T> OVR_FORCE_INLINE const T Min(const T a, const T b) +{ return (a < b) ? a : b; } + +template <typename T> OVR_FORCE_INLINE const T Max(const T a, const T b) +{ return (b < a) ? a : b; } + +template <typename T> OVR_FORCE_INLINE const T Clamp(const T v, const T minVal, const T maxVal) +{ return Max<T>(minVal, Min<T>(v, maxVal)); } + +template <typename T> OVR_FORCE_INLINE int Chop(T f) +{ return (int)f; } + +template <typename T> OVR_FORCE_INLINE T Lerp(T a, T b, T f) +{ return (b - a) * f + a; } + + +// These functions stand to fix a stupid VC++ warning (with /Wp64 on): +// "warning C4267: 'argument' : conversion from 'size_t' to 'const unsigned', possible loss of data" +// Use these functions instead of gmin/gmax if the argument has size +// of the pointer to avoid the warning. Though, functionally they are +// absolutelly the same as regular gmin/gmax. +template <typename T> OVR_FORCE_INLINE const T PMin(const T a, const T b) +{ + OVR_COMPILER_ASSERT(sizeof(T) == sizeof(size_t)); + return (a < b) ? a : b; +} +template <typename T> OVR_FORCE_INLINE const T PMax(const T a, const T b) +{ + OVR_COMPILER_ASSERT(sizeof(T) == sizeof(size_t)); + return (b < a) ? a : b; +} + + +template <typename T> OVR_FORCE_INLINE const T Abs(const T v) +{ return (v>=0) ? v : -v; } + + +//----------------------------------------------------------------------------------- +// ***** OperatorLess +// +template<class T> struct OperatorLess +{ + static bool Compare(const T& a, const T& b) + { + return a < b; + } +}; + + +//----------------------------------------------------------------------------------- +// ***** QuickSortSliced +// +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. +// The range is specified with start, end, where "end" is exclusive! +// The comparison predicate must be specified. +template<class Array, class Less> +void QuickSortSliced(Array& arr, size_t start, size_t end, Less less) +{ + enum + { + Threshold = 9 + }; + + if(end - start < 2) return; + + intptr_t stack[80]; + intptr_t* top = stack; + intptr_t base = (intptr_t)start; + intptr_t limit = (intptr_t)end; + + for(;;) + { + intptr_t len = limit - base; + intptr_t i, j, pivot; + + if(len > Threshold) + { + // we use base + len/2 as the pivot + pivot = base + len / 2; + Swap(arr[base], arr[pivot]); + + i = base + 1; + j = limit - 1; + + // now ensure that *i <= *base <= *j + if(less(arr[j], arr[i])) Swap(arr[j], arr[i]); + if(less(arr[base], arr[i])) Swap(arr[base], arr[i]); + if(less(arr[j], arr[base])) Swap(arr[j], arr[base]); + + for(;;) + { + do i++; while( less(arr[i], arr[base]) ); + do j--; while( less(arr[base], arr[j]) ); + + if( i > j ) + { + break; + } + + Swap(arr[i], arr[j]); + } + + Swap(arr[base], arr[j]); + + // now, push the largest sub-array + if(j - base > limit - i) + { + top[0] = base; + top[1] = j; + base = i; + } + else + { + top[0] = i; + top[1] = limit; + limit = j; + } + top += 2; + } + else + { + // the sub-array is small, perform insertion sort + j = base; + i = j + 1; + + for(; i < limit; j = i, i++) + { + for(; less(arr[j + 1], arr[j]); j--) + { + Swap(arr[j + 1], arr[j]); + if(j == base) + { + break; + } + } + } + if(top > stack) + { + top -= 2; + base = top[0]; + limit = top[1]; + } + else + { + break; + } + } + } +} + + +//----------------------------------------------------------------------------------- +// ***** QuickSortSliced +// +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. +// The range is specified with start, end, where "end" is exclusive! +// The data type must have a defined "<" operator. +template<class Array> +void QuickSortSliced(Array& arr, size_t start, size_t end) +{ + typedef typename Array::ValueType ValueType; + QuickSortSliced(arr, start, end, OperatorLess<ValueType>::Compare); +} + +// Same as corresponding G_QuickSortSliced but with checking array limits to avoid +// crash in the case of wrong comparator functor. +template<class Array, class Less> +bool QuickSortSlicedSafe(Array& arr, size_t start, size_t end, Less less) +{ + enum + { + Threshold = 9 + }; + + if(end - start < 2) return true; + + intptr_t stack[80]; + intptr_t* top = stack; + intptr_t base = (intptr_t)start; + intptr_t limit = (intptr_t)end; + + for(;;) + { + intptr_t len = limit - base; + intptr_t i, j, pivot; + + if(len > Threshold) + { + // we use base + len/2 as the pivot + pivot = base + len / 2; + Swap(arr[base], arr[pivot]); + + i = base + 1; + j = limit - 1; + + // now ensure that *i <= *base <= *j + if(less(arr[j], arr[i])) Swap(arr[j], arr[i]); + if(less(arr[base], arr[i])) Swap(arr[base], arr[i]); + if(less(arr[j], arr[base])) Swap(arr[j], arr[base]); + + for(;;) + { + do + { + i++; + if (i >= limit) + return false; + } while( less(arr[i], arr[base]) ); + do + { + j--; + if (j < 0) + return false; + } while( less(arr[base], arr[j]) ); + + if( i > j ) + { + break; + } + + Swap(arr[i], arr[j]); + } + + Swap(arr[base], arr[j]); + + // now, push the largest sub-array + if(j - base > limit - i) + { + top[0] = base; + top[1] = j; + base = i; + } + else + { + top[0] = i; + top[1] = limit; + limit = j; + } + top += 2; + } + else + { + // the sub-array is small, perform insertion sort + j = base; + i = j + 1; + + for(; i < limit; j = i, i++) + { + for(; less(arr[j + 1], arr[j]); j--) + { + Swap(arr[j + 1], arr[j]); + if(j == base) + { + break; + } + } + } + if(top > stack) + { + top -= 2; + base = top[0]; + limit = top[1]; + } + else + { + break; + } + } + } + return true; +} + +template<class Array> +bool QuickSortSlicedSafe(Array& arr, size_t start, size_t end) +{ + typedef typename Array::ValueType ValueType; + return QuickSortSlicedSafe(arr, start, end, OperatorLess<ValueType>::Compare); +} + +//----------------------------------------------------------------------------------- +// ***** QuickSort +// +// Sort an array Array, ArrayPaged, ArrayUnsafe. +// The array must have GetSize() function. +// The comparison predicate must be specified. +template<class Array, class Less> +void QuickSort(Array& arr, Less less) +{ + QuickSortSliced(arr, 0, arr.GetSize(), less); +} + +// checks for boundaries +template<class Array, class Less> +bool QuickSortSafe(Array& arr, Less less) +{ + return QuickSortSlicedSafe(arr, 0, arr.GetSize(), less); +} + + +//----------------------------------------------------------------------------------- +// ***** QuickSort +// +// Sort an array Array, ArrayPaged, ArrayUnsafe. +// The array must have GetSize() function. +// The data type must have a defined "<" operator. +template<class Array> +void QuickSort(Array& arr) +{ + typedef typename Array::ValueType ValueType; + QuickSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare); +} + +template<class Array> +bool QuickSortSafe(Array& arr) +{ + typedef typename Array::ValueType ValueType; + return QuickSortSlicedSafe(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare); +} + +//----------------------------------------------------------------------------------- +// ***** InsertionSortSliced +// +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. +// The range is specified with start, end, where "end" is exclusive! +// The comparison predicate must be specified. +// Unlike Quick Sort, the Insertion Sort works much slower in average, +// but may be much faster on almost sorted arrays. Besides, it guarantees +// that the elements will not be swapped if not necessary. For example, +// an array with all equal elements will remain "untouched", while +// Quick Sort will considerably shuffle the elements in this case. +template<class Array, class Less> +void InsertionSortSliced(Array& arr, size_t start, size_t end, Less less) +{ + size_t j = start; + size_t i = j + 1; + size_t limit = end; + + for(; i < limit; j = i, i++) + { + for(; less(arr[j + 1], arr[j]); j--) + { + Swap(arr[j + 1], arr[j]); + if(j <= start) + { + break; + } + } + } +} + + +//----------------------------------------------------------------------------------- +// ***** InsertionSortSliced +// +// Sort any part of any array: plain, Array, ArrayPaged, ArrayUnsafe. +// The range is specified with start, end, where "end" is exclusive! +// The data type must have a defined "<" operator. +template<class Array> +void InsertionSortSliced(Array& arr, size_t start, size_t end) +{ + typedef typename Array::ValueType ValueType; + InsertionSortSliced(arr, start, end, OperatorLess<ValueType>::Compare); +} + +//----------------------------------------------------------------------------------- +// ***** InsertionSort +// +// Sort an array Array, ArrayPaged, ArrayUnsafe. +// The array must have GetSize() function. +// The comparison predicate must be specified. + +template<class Array, class Less> +void InsertionSort(Array& arr, Less less) +{ + InsertionSortSliced(arr, 0, arr.GetSize(), less); +} + +//----------------------------------------------------------------------------------- +// ***** InsertionSort +// +// Sort an array Array, ArrayPaged, ArrayUnsafe. +// The array must have GetSize() function. +// The data type must have a defined "<" operator. +template<class Array> +void InsertionSort(Array& arr) +{ + typedef typename Array::ValueType ValueType; + InsertionSortSliced(arr, 0, arr.GetSize(), OperatorLess<ValueType>::Compare); +} + +//----------------------------------------------------------------------------------- +// ***** Median +// Returns a median value of the input array. +// Caveats: partially sorts the array, returns a reference to the array element +// TBD: This needs to be optimized and generalized +// +template<class Array> +typename Array::ValueType& Median(Array& arr) +{ + size_t count = arr.GetSize(); + size_t mid = (count - 1) / 2; + OVR_ASSERT(count > 0); + + for (size_t j = 0; j <= mid; j++) + { + size_t min = j; + for (size_t k = j + 1; k < count; k++) + if (arr[k] < arr[min]) + min = k; + Swap(arr[j], arr[min]); + } + return arr[mid]; +} + +//----------------------------------------------------------------------------------- +// ***** LowerBoundSliced +// +template<class Array, class Value, class Less> +size_t LowerBoundSliced(const Array& arr, size_t start, size_t end, const Value& val, Less less) +{ + intptr_t first = (intptr_t)start; + intptr_t len = (intptr_t)(end - start); + intptr_t half; + intptr_t middle; + + while(len > 0) + { + half = len >> 1; + middle = first + half; + if(less(arr[middle], val)) + { + first = middle + 1; + len = len - half - 1; + } + else + { + len = half; + } + } + return (size_t)first; +} + + +//----------------------------------------------------------------------------------- +// ***** LowerBoundSliced +// +template<class Array, class Value> +size_t LowerBoundSliced(const Array& arr, size_t start, size_t end, const Value& val) +{ + return LowerBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare); +} + +//----------------------------------------------------------------------------------- +// ***** LowerBoundSized +// +template<class Array, class Value> +size_t LowerBoundSized(const Array& arr, size_t size, const Value& val) +{ + return LowerBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare); +} + +//----------------------------------------------------------------------------------- +// ***** LowerBound +// +template<class Array, class Value, class Less> +size_t LowerBound(const Array& arr, const Value& val, Less less) +{ + return LowerBoundSliced(arr, 0, arr.GetSize(), val, less); +} + + +//----------------------------------------------------------------------------------- +// ***** LowerBound +// +template<class Array, class Value> +size_t LowerBound(const Array& arr, const Value& val) +{ + return LowerBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare); +} + + + +//----------------------------------------------------------------------------------- +// ***** UpperBoundSliced +// +template<class Array, class Value, class Less> +size_t UpperBoundSliced(const Array& arr, size_t start, size_t end, const Value& val, Less less) +{ + intptr_t first = (intptr_t)start; + intptr_t len = (intptr_t)(end - start); + intptr_t half; + intptr_t middle; + + while(len > 0) + { + half = len >> 1; + middle = first + half; + if(less(val, arr[middle])) + { + len = half; + } + else + { + first = middle + 1; + len = len - half - 1; + } + } + return (size_t)first; +} + + +//----------------------------------------------------------------------------------- +// ***** UpperBoundSliced +// +template<class Array, class Value> +size_t UpperBoundSliced(const Array& arr, size_t start, size_t end, const Value& val) +{ + return UpperBoundSliced(arr, start, end, val, OperatorLess<Value>::Compare); +} + + +//----------------------------------------------------------------------------------- +// ***** UpperBoundSized +// +template<class Array, class Value> +size_t UpperBoundSized(const Array& arr, size_t size, const Value& val) +{ + return UpperBoundSliced(arr, 0, size, val, OperatorLess<Value>::Compare); +} + + +//----------------------------------------------------------------------------------- +// ***** UpperBound +// +template<class Array, class Value, class Less> +size_t UpperBound(const Array& arr, const Value& val, Less less) +{ + return UpperBoundSliced(arr, 0, arr.GetSize(), val, less); +} + + +//----------------------------------------------------------------------------------- +// ***** UpperBound +// +template<class Array, class Value> +size_t UpperBound(const Array& arr, const Value& val) +{ + return UpperBoundSliced(arr, 0, arr.GetSize(), val, OperatorLess<Value>::Compare); +} + + +//----------------------------------------------------------------------------------- +// ***** ReverseArray +// +template<class Array> void ReverseArray(Array& arr) +{ + intptr_t from = 0; + intptr_t to = arr.GetSize() - 1; + while(from < to) + { + Swap(arr[from], arr[to]); + ++from; + --to; + } +} + + +// ***** AppendArray +// +template<class CDst, class CSrc> +void AppendArray(CDst& dst, const CSrc& src) +{ + size_t i; + for(i = 0; i < src.GetSize(); i++) + dst.PushBack(src[i]); +} + +//----------------------------------------------------------------------------------- +// ***** ArrayAdaptor +// +// A simple adapter that provides the GetSize() method and overloads +// operator []. Used to wrap plain arrays in QuickSort and such. +template<class T> class ArrayAdaptor +{ +public: + typedef T ValueType; + ArrayAdaptor() : Data(0), Size(0) {} + ArrayAdaptor(T* ptr, size_t size) : Data(ptr), Size(size) {} + size_t GetSize() const { return Size; } + int GetSizeI() const { return (int)GetSize(); } + const T& operator [] (size_t i) const { return Data[i]; } + T& operator [] (size_t i) { return Data[i]; } +private: + T* Data; + size_t Size; +}; + + +//----------------------------------------------------------------------------------- +// ***** GConstArrayAdaptor +// +// A simple const adapter that provides the GetSize() method and overloads +// operator []. Used to wrap plain arrays in LowerBound and such. +template<class T> class ConstArrayAdaptor +{ +public: + typedef T ValueType; + ConstArrayAdaptor() : Data(0), Size(0) {} + ConstArrayAdaptor(const T* ptr, size_t size) : Data(ptr), Size(size) {} + size_t GetSize() const { return Size; } + int GetSizeI() const { return (int)GetSize(); } + const T& operator [] (size_t i) const { return Data[i]; } +private: + const T* Data; + size_t Size; +}; + + + +//----------------------------------------------------------------------------------- +extern const uint8_t UpperBitTable[256]; +extern const uint8_t LowerBitTable[256]; + + + +//----------------------------------------------------------------------------------- +inline uint8_t UpperBit(size_t val) +{ +#ifndef OVR_64BIT_POINTERS + + if (val & 0xFFFF0000) + { + return (val & 0xFF000000) ? + UpperBitTable[(val >> 24) ] + 24: + UpperBitTable[(val >> 16) & 0xFF] + 16; + } + return (val & 0xFF00) ? + UpperBitTable[(val >> 8) & 0xFF] + 8: + UpperBitTable[(val ) & 0xFF]; + +#else + + if (val & 0xFFFFFFFF00000000) + { + if (val & 0xFFFF000000000000) + { + return (val & 0xFF00000000000000) ? + UpperBitTable[(val >> 56) ] + 56: + UpperBitTable[(val >> 48) & 0xFF] + 48; + } + return (val & 0xFF0000000000) ? + UpperBitTable[(val >> 40) & 0xFF] + 40: + UpperBitTable[(val >> 32) & 0xFF] + 32; + } + else + { + if (val & 0xFFFF0000) + { + return (val & 0xFF000000) ? + UpperBitTable[(val >> 24) ] + 24: + UpperBitTable[(val >> 16) & 0xFF] + 16; + } + return (val & 0xFF00) ? + UpperBitTable[(val >> 8) & 0xFF] + 8: + UpperBitTable[(val ) & 0xFF]; + } + +#endif +} + +//----------------------------------------------------------------------------------- +inline uint8_t LowerBit(size_t val) +{ +#ifndef OVR_64BIT_POINTERS + + if (val & 0xFFFF) + { + return (val & 0xFF) ? + LowerBitTable[ val & 0xFF]: + LowerBitTable[(val >> 8) & 0xFF] + 8; + } + return (val & 0xFF0000) ? + LowerBitTable[(val >> 16) & 0xFF] + 16: + LowerBitTable[(val >> 24) & 0xFF] + 24; + +#else + + if (val & 0xFFFFFFFF) + { + if (val & 0xFFFF) + { + return (val & 0xFF) ? + LowerBitTable[ val & 0xFF]: + LowerBitTable[(val >> 8) & 0xFF] + 8; + } + return (val & 0xFF0000) ? + LowerBitTable[(val >> 16) & 0xFF] + 16: + LowerBitTable[(val >> 24) & 0xFF] + 24; + } + else + { + if (val & 0xFFFF00000000) + { + return (val & 0xFF00000000) ? + LowerBitTable[(val >> 32) & 0xFF] + 32: + LowerBitTable[(val >> 40) & 0xFF] + 40; + } + return (val & 0xFF000000000000) ? + LowerBitTable[(val >> 48) & 0xFF] + 48: + LowerBitTable[(val >> 56) & 0xFF] + 56; + } + +#endif +} + + + +// ******* Special (optimized) memory routines +// Note: null (bad) pointer is not tested +class MemUtil +{ +public: + + // Memory compare + static int Cmp (const void* p1, const void* p2, size_t byteCount) { return memcmp(p1, p2, byteCount); } + static int Cmp16(const void* p1, const void* p2, size_t int16Count); + static int Cmp32(const void* p1, const void* p2, size_t int32Count); + static int Cmp64(const void* p1, const void* p2, size_t int64Count); +}; + +// ** Inline Implementation + +inline int MemUtil::Cmp16(const void* p1, const void* p2, size_t int16Count) +{ + int16_t* pa = (int16_t*)p1; + int16_t* pb = (int16_t*)p2; + unsigned ic = 0; + if (int16Count == 0) + return 0; + while (pa[ic] == pb[ic]) + if (++ic==int16Count) + return 0; + return pa[ic] > pb[ic] ? 1 : -1; +} +inline int MemUtil::Cmp32(const void* p1, const void* p2, size_t int32Count) +{ + int32_t* pa = (int32_t*)p1; + int32_t* pb = (int32_t*)p2; + unsigned ic = 0; + if (int32Count == 0) + return 0; + while (pa[ic] == pb[ic]) + if (++ic==int32Count) + return 0; + return pa[ic] > pb[ic] ? 1 : -1; +} +inline int MemUtil::Cmp64(const void* p1, const void* p2, size_t int64Count) +{ + int64_t* pa = (int64_t*)p1; + int64_t* pb = (int64_t*)p2; + unsigned ic = 0; + if (int64Count == 0) + return 0; + while (pa[ic] == pb[ic]) + if (++ic==int64Count) + return 0; + return pa[ic] > pb[ic] ? 1 : -1; +} + +// ** End Inline Implementation + + +//----------------------------------------------------------------------------------- +// ******* Byte Order Conversions +namespace ByteUtil { + + // *** Swap Byte Order + + // Swap the byte order of a byte array + inline void SwapOrder(void* pv, int size) + { + uint8_t* pb = (uint8_t*)pv; + uint8_t temp; + for (int i = 0; i < size>>1; i++) + { + temp = pb[size-1-i]; + pb[size-1-i] = pb[i]; + pb[i] = temp; + } + } + + // Swap the byte order of primitive types + inline uint8_t SwapOrder(uint8_t v) { return v; } + inline int8_t SwapOrder(int8_t v) { return v; } + inline uint16_t SwapOrder(uint16_t v) { return uint16_t(v>>8)|uint16_t(v<<8); } + inline int16_t SwapOrder(int16_t v) { return int16_t((uint16_t(v)>>8)|(v<<8)); } + inline uint32_t SwapOrder(uint32_t v) { return (v>>24)|((v&0x00FF0000)>>8)|((v&0x0000FF00)<<8)|(v<<24); } + inline int32_t SwapOrder(int32_t p) { return (int32_t)SwapOrder(uint32_t(p)); } + inline uint64_t SwapOrder(uint64_t v) + { + return (v>>56) | + ((v&uint64_t(0x00FF000000000000ULL))>>40) | + ((v&uint64_t(0x0000FF0000000000ULL))>>24) | + ((v&uint64_t(0x000000FF00000000ULL))>>8) | + ((v&uint64_t(0x00000000FF000000ULL))<<8) | + ((v&uint64_t(0x0000000000FF0000ULL))<<24) | + ((v&uint64_t(0x000000000000FF00ULL))<<40) | + (v<<56); + } + inline int64_t SwapOrder(int64_t v) { return (int64_t)SwapOrder(uint64_t(v)); } + inline float SwapOrder(float p) + { + union { + float p; + uint32_t v; + } u; + u.p = p; + u.v = SwapOrder(u.v); + return u.p; + } + + inline double SwapOrder(double p) + { + union { + double p; + uint64_t v; + } u; + u.p = p; + u.v = SwapOrder(u.v); + return u.p; + } + + // *** Byte-order conversion + +#if (OVR_BYTE_ORDER == OVR_LITTLE_ENDIAN) + // Little Endian to System (LE) + inline uint8_t LEToSystem(uint8_t v) { return v; } + inline int8_t LEToSystem(int8_t v) { return v; } + inline uint16_t LEToSystem(uint16_t v) { return v; } + inline int16_t LEToSystem(int16_t v) { return v; } + inline uint32_t LEToSystem(uint32_t v) { return v; } + inline int32_t LEToSystem(int32_t v) { return v; } + inline uint64_t LEToSystem(uint64_t v) { return v; } + inline int64_t LEToSystem(int64_t v) { return v; } + inline float LEToSystem(float v) { return v; } + inline double LEToSystem(double v) { return v; } + + // Big Endian to System (LE) + inline uint8_t BEToSystem(uint8_t v) { return SwapOrder(v); } + inline int8_t BEToSystem(int8_t v) { return SwapOrder(v); } + inline uint16_t BEToSystem(uint16_t v) { return SwapOrder(v); } + inline int16_t BEToSystem(int16_t v) { return SwapOrder(v); } + inline uint32_t BEToSystem(uint32_t v) { return SwapOrder(v); } + inline int32_t BEToSystem(int32_t v) { return SwapOrder(v); } + inline uint64_t BEToSystem(uint64_t v) { return SwapOrder(v); } + inline int64_t BEToSystem(int64_t v) { return SwapOrder(v); } + inline float BEToSystem(float v) { return SwapOrder(v); } + inline double BEToSystem(double v) { return SwapOrder(v); } + + // System (LE) to Little Endian + inline uint8_t SystemToLE(uint8_t v) { return v; } + inline int8_t SystemToLE(int8_t v) { return v; } + inline uint16_t SystemToLE(uint16_t v) { return v; } + inline int16_t SystemToLE(int16_t v) { return v; } + inline uint32_t SystemToLE(uint32_t v) { return v; } + inline int32_t SystemToLE(int32_t v) { return v; } + inline uint64_t SystemToLE(uint64_t v) { return v; } + inline int64_t SystemToLE(int64_t v) { return v; } + inline float SystemToLE(float v) { return v; } + inline double SystemToLE(double v) { return v; } + + // System (LE) to Big Endian + inline uint8_t SystemToBE(uint8_t v) { return SwapOrder(v); } + inline int8_t SystemToBE(int8_t v) { return SwapOrder(v); } + inline uint16_t SystemToBE(uint16_t v) { return SwapOrder(v); } + inline int16_t SystemToBE(int16_t v) { return SwapOrder(v); } + inline uint32_t SystemToBE(uint32_t v) { return SwapOrder(v); } + inline int32_t SystemToBE(int32_t v) { return SwapOrder(v); } + inline uint64_t SystemToBE(uint64_t v) { return SwapOrder(v); } + inline int64_t SystemToBE(int64_t v) { return SwapOrder(v); } + inline float SystemToBE(float v) { return SwapOrder(v); } + inline double SystemToBE(double v) { return SwapOrder(v); } + +#elif (OVR_BYTE_ORDER == OVR_BIG_ENDIAN) + // Little Endian to System (BE) + inline uint8_t LEToSystem(uint8_t v) { return SwapOrder(v); } + inline int8_t LEToSystem(int8_t v) { return SwapOrder(v); } + inline uint16_t LEToSystem(uint16_t v) { return SwapOrder(v); } + inline int16_t LEToSystem(int16_t v) { return SwapOrder(v); } + inline uint32_t LEToSystem(uint32_t v) { return SwapOrder(v); } + inline int32_t LEToSystem(int32_t v) { return SwapOrder(v); } + inline uint64_t LEToSystem(uint64_t v) { return SwapOrder(v); } + inline int64_t LEToSystem(int64_t v) { return SwapOrder(v); } + inline float LEToSystem(float v) { return SwapOrder(v); } + inline double LEToSystem(double v) { return SwapOrder(v); } + + // Big Endian to System (BE) + inline uint8_t BEToSystem(uint8_t v) { return v; } + inline int8_t BEToSystem(int8_t v) { return v; } + inline uint16_t BEToSystem(uint16_t v) { return v; } + inline int16_t BEToSystem(int16_t v) { return v; } + inline uint32_t BEToSystem(uint32_t v) { return v; } + inline int32_t BEToSystem(int32_t v) { return v; } + inline uint64_t BEToSystem(uint64_t v) { return v; } + inline int64_t BEToSystem(int64_t v) { return v; } + inline float BEToSystem(float v) { return v; } + inline double BEToSystem(double v) { return v; } + + // System (BE) to Little Endian + inline uint8_t SystemToLE(uint8_t v) { return SwapOrder(v); } + inline int8_t SystemToLE(int8_t v) { return SwapOrder(v); } + inline uint16_t SystemToLE(uint16_t v) { return SwapOrder(v); } + inline int16_t SystemToLE(int16_t v) { return SwapOrder(v); } + inline uint32_t SystemToLE(uint32_t v) { return SwapOrder(v); } + inline int32_t SystemToLE(int32_t v) { return SwapOrder(v); } + inline uint64_t SystemToLE(uint64_t v) { return SwapOrder(v); } + inline int64_t SystemToLE(int64_t v) { return SwapOrder(v); } + inline float SystemToLE(float v) { return SwapOrder(v); } + inline double SystemToLE(double v) { return SwapOrder(v); } + + // System (BE) to Big Endian + inline uint8_t SystemToBE(uint8_t v) { return v; } + inline int8_t SystemToBE(int8_t v) { return v; } + inline uint16_t SystemToBE(uint16_t v) { return v; } + inline int16_t SystemToBE(int16_t v) { return v; } + inline uint32_t SystemToBE(uint32_t v) { return v; } + inline int32_t SystemToBE(int32_t v) { return v; } + inline uint64_t SystemToBE(uint64_t v) { return v; } + inline int64_t SystemToBE(int64_t v) { return v; } + inline float SystemToBE(float v) { return v; } + inline double SystemToBE(double v) { return v; } + +#else + #error "OVR_BYTE_ORDER must be defined to OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN" +#endif + +} // namespace ByteUtil + + + +// Used primarily for hardware interfacing such as sensor reports, firmware, etc. +// Reported data is all little-endian. +inline uint16_t DecodeUInt16(const uint8_t* buffer) +{ + return ByteUtil::LEToSystem ( *(const uint16_t*)buffer ); +} + +inline int16_t DecodeSInt16(const uint8_t* buffer) +{ + return ByteUtil::LEToSystem ( *(const int16_t*)buffer ); +} + +inline uint32_t DecodeUInt32(const uint8_t* buffer) +{ + return ByteUtil::LEToSystem ( *(const uint32_t*)buffer ); +} + +inline int32_t DecodeSInt32(const uint8_t* buffer) +{ + return ByteUtil::LEToSystem ( *(const int32_t*)buffer ); +} + +inline float DecodeFloat(const uint8_t* buffer) +{ + union { + uint32_t U; + float F; + }; + + U = DecodeUInt32(buffer); + return F; +} + +inline void EncodeUInt16(uint8_t* buffer, uint16_t val) +{ + *(uint16_t*)buffer = ByteUtil::SystemToLE ( val ); +} + +inline void EncodeSInt16(uint8_t* buffer, int16_t val) +{ + *(int16_t*)buffer = ByteUtil::SystemToLE ( val ); +} + +inline void EncodeUInt32(uint8_t* buffer, uint32_t val) +{ + *(uint32_t*)buffer = ByteUtil::SystemToLE ( val ); +} + +inline void EncodeSInt32(uint8_t* buffer, int32_t val) +{ + *(int32_t*)buffer = ByteUtil::SystemToLE ( val ); +} + +inline void EncodeFloat(uint8_t* buffer, float val) +{ + union { + uint32_t U; + float F; + }; + + F = val; + EncodeUInt32(buffer, U); +} + +// Converts an 8-bit binary-coded decimal +inline int8_t DecodeBCD(uint8_t byte) +{ + uint8_t digit1 = (byte >> 4) & 0x0f; + uint8_t digit2 = byte & 0x0f; + int decimal = digit1 * 10 + digit2; // maximum value = 99 + return (int8_t)decimal; +} + + +}} // OVR::Alg + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp b/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp new file mode 100644 index 0000000..c4f2ad9 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Allocator.cpp @@ -0,0 +1,842 @@ +/************************************************************************************ + +Filename : OVR_Allocator.cpp +Content : Installable memory allocator implementation +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Allocator.h" +#include "OVR_DebugHelp.h" +#include <stdlib.h> + +#ifdef OVR_OS_MAC + #include <stdlib.h> + #include <malloc/malloc.h> +#else + #include <malloc.h> +#endif + +#if defined(OVR_OS_MS) + #include "OVR_Win32_IncludeWindows.h" +#elif defined(OVR_OS_MAC) || defined(OVR_OS_UNIX) + #include <unistd.h> + #include <sys/mman.h> +#endif + +namespace OVR { + + +//----------------------------------------------------------------------------------- +// ***** Allocator + +Allocator* Allocator::pInstance = 0; + +// Default AlignedAlloc implementation will delegate to Alloc/Free after doing rounding. +void* Allocator::AllocAligned(size_t size, size_t align) +{ + OVR_ASSERT((align & (align-1)) == 0); + align = (align > sizeof(size_t)) ? align : sizeof(size_t); + size_t p = (size_t)Alloc(size+align); + size_t aligned = 0; + if (p) + { + aligned = (size_t(p) + align-1) & ~(align-1); + if (aligned == p) + aligned += align; + *(((size_t*)aligned)-1) = aligned-p; + } + + trackAlloc((void*)aligned, size); + + return (void*)aligned; +} + +void Allocator::FreeAligned(void* p) +{ + untrackAlloc((void*)p); + + size_t src = size_t(p) - *(((size_t*)p) - 1); + Free((void*)src); +} + + +//------------------------------------------------------------------------ +// ***** Default Allocator + +// This allocator is created and used if no other allocator is installed. +// Default allocator delegates to system malloc. + +void* DefaultAllocator::Alloc(size_t size) +{ + void* p = malloc(size); + trackAlloc(p, size); + return p; +} +void* DefaultAllocator::AllocDebug(size_t size, const char* file, unsigned line) +{ + OVR_UNUSED2(file, line); // should be here for debugopt config + void* p; +#if defined(OVR_CC_MSVC) && defined(_CRTDBG_MAP_ALLOC) + p = _malloc_dbg(size, _NORMAL_BLOCK, file, line); +#else + p = malloc(size); +#endif + trackAlloc(p, size); + return p; +} + +void* DefaultAllocator::Realloc(void* p, size_t newSize) +{ + void* newP = realloc(p, newSize); + + // This used to more efficiently check if (newp != p) but static analyzers were erroneously flagging this. + if(newP) // Need to check newP because realloc doesn't free p unless it returns a valid newP. + { + #if !defined(__clang_analyzer__) // The analyzer complains that we are using p after it was freed. + untrackAlloc(p); + #endif + } + trackAlloc(newP, newSize); + return newP; +} + +void DefaultAllocator::Free(void *p) +{ + untrackAlloc(p); + return free(p); +} + + +// System block allocator: + +void* SafeMMapAlloc(size_t size) +{ + #if defined(OVR_OS_MS) + return VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); // size is rounded up to a page. // Returned memory is 0-filled. + + #elif defined(OVR_OS_MAC) || defined(OVR_OS_UNIX) + #if !defined(MAP_FAILED) + #define MAP_FAILED ((void*)-1) + #endif + + void* result = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); // Returned memory is 0-filled. + if(result == MAP_FAILED) // mmap returns MAP_FAILED (-1) upon failure. + result = nullptr; + return result; + #endif +} + +void SafeMMapFree(const void* memory, size_t size) +{ + #if defined(OVR_OS_MS) + OVR_UNUSED(size); + VirtualFree(const_cast<void*>(memory), 0, MEM_RELEASE); + + #elif defined(OVR_OS_MAC) || defined(OVR_OS_UNIX) + size_t pageSize = getpagesize(); + size = (((size + (pageSize - 1)) / pageSize) * pageSize); + munmap(const_cast<void*>(memory), size); // Must supply the size to munmap. + #endif +} + + +//------------------------------------------------------------------------ +// ***** Track Allocations + +struct TrackedAlloc +{ + TrackedAlloc* pNext; + TrackedAlloc* pPrev; + void* pAlloc; + void* Callstack[64]; + uint32_t FrameCount; + uint32_t Size; +}; + +static TrackedAlloc* TrackHead = nullptr; +static SymbolLookup Symbols; +static bool IsLeakTracking = false; + +void Allocator::SetLeakTracking(bool enabled) +{ +#if defined(OVR_OS_WIN32) && !defined(OVR_OS_WIN64) + // HACK: Currently 32-bit leak tracing is too slow to run in real-time on Windows. + // Note: We can possibly fix this by making a custom Win32 backtrace function which + // takes advantage of the fact that we have enabled stack frames in all builds. + enabled = false; +#endif + + IsLeakTracking = enabled; +} + +bool Allocator::IsTrackingLeaks() +{ + return IsLeakTracking; +} + +void Allocator::trackAlloc(void* p, size_t size) +{ + if (!p || !IsLeakTracking) + return; + + Lock::Locker locker(&TrackLock); + + TrackedAlloc* tracked = (TrackedAlloc*)malloc(sizeof(TrackedAlloc)); + if (tracked) + { + memset(tracked, 0, sizeof(TrackedAlloc)); + + tracked->pAlloc = p; + tracked->pPrev = nullptr; + tracked->FrameCount = (uint32_t)Symbols.GetBacktrace(tracked->Callstack, OVR_ARRAY_COUNT(tracked->Callstack), 2); + tracked->Size = (uint32_t)size; + + tracked->pNext = TrackHead; + if (TrackHead) + { + TrackHead->pPrev = tracked; + } + TrackHead = tracked; + } +} + +void Allocator::untrackAlloc(void* p) +{ + if (!p || !IsLeakTracking) + return; + + Lock::Locker locker(&TrackLock); + + for (TrackedAlloc* t = TrackHead; t; t = t->pNext) + { + if (t->pAlloc == p) + { + if (t->pPrev) + { + t->pPrev->pNext = t->pNext; + } + if (t->pNext) + { + t->pNext->pPrev = t->pPrev; + } + if (TrackHead == t) + { + TrackHead = t->pNext; + } + free(t); + + break; + } + } +} + +int DumpMemory() +{ + const bool symbolLookupWasInitialized = SymbolLookup::IsInitialized(); + const bool symbolLookupAvailable = SymbolLookup::Initialize(); + + if(!symbolLookupWasInitialized) // If SymbolLookup::Initialize was the first time being initialized, we need to refresh the Symbols view of modules, etc. + Symbols.Refresh(); + + // If we're dumping while LibOVR is running, then we should hold the lock. + Allocator* pAlloc = Allocator::GetInstance(); + + // It's possible this is being called after the Allocator was shut down, at which + // point we assume we are the only instance that can be executing at his time. + Lock* lock = pAlloc ? &pAlloc->TrackLock : nullptr; + if (lock) + lock->DoLock(); + + int leakCount = 0; + + for (TrackedAlloc* t = TrackHead; t; t = t->pNext) + { + LogError("[Leak] ** Detected leaked allocation at %p (size = %u) (%d frames)", t->pAlloc, (unsigned)t->Size, (unsigned)t->FrameCount); + + for (size_t i = 0; i < t->FrameCount; ++i) + { + SymbolInfo symbolInfo; + + if (symbolLookupAvailable && Symbols.LookupSymbol((uint64_t)t->Callstack[i], symbolInfo) && (symbolInfo.filePath[0] || symbolInfo.function[0])) + { + if(symbolInfo.filePath[0]) + LogText("%s(%d): %s\n", symbolInfo.filePath, symbolInfo.fileLineNumber, symbolInfo.function[0] ? symbolInfo.function : "(unknown function)"); + else + LogText("%p (unknown source file): %s\n", t->Callstack[i], symbolInfo.function); + } + else + { + LogText("%p (symbols unavailable)\n", t->Callstack[i]); + } + } + + ++leakCount; + } + + if (lock) + lock->Unlock(); + + if(symbolLookupAvailable) + SymbolLookup::Shutdown(); + + return leakCount; +} + + + +//------------------------------------------------------------------------ +// ***** DebugPageAllocator + +static size_t AlignSizeUp(size_t value, size_t alignment) +{ + return ((value + (alignment - 1)) & ~(alignment - 1)); +} + +static size_t AlignSizeDown(size_t value, size_t alignment) +{ + return (value & ~(alignment - 1)); +} + +template <typename Pointer> +Pointer AlignPointerUp(Pointer p, size_t alignment) +{ + return reinterpret_cast<Pointer>(((reinterpret_cast<size_t>(p) + (alignment - 1)) & ~(alignment - 1))); +} + +template <typename Pointer> +Pointer AlignPointerDown(Pointer p, size_t alignment) +{ + return reinterpret_cast<Pointer>(reinterpret_cast<size_t>(p) & ~(alignment-1)); +} + + +const size_t kFreedBlockArrayMaxSizeDefault = 16384; + + +DebugPageAllocator::DebugPageAllocator() + : FreedBlockArray(nullptr) + , FreedBlockArrayMaxSize(0) + , FreedBlockArraySize(0) + , FreedBlockArrayOldest(0) + , AllocationCount(0) + , OverrunPageEnabled(true) + #if defined(OVR_BUILD_DEBUG) + , OverrunGuardBytesEnabled(true) + #else + , OverrunGuardBytesEnabled(false) + #endif + //PageSize(0) + , Lock() +{ + #if defined(_WIN32) + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + PageSize = (size_t)systemInfo.dwPageSize; + #else + PageSize = 4096; + #endif + + SetDelayedFreeCount(kFreedBlockArrayMaxSizeDefault); +} + + +DebugPageAllocator::~DebugPageAllocator() +{ + Shutdown(); +} + + +void DebugPageAllocator::Init() +{ + // Nothing to do. +} + +void DebugPageAllocator::Shutdown() +{ + Lock::Locker autoLock(&Lock); + + for(size_t i = 0; i < FreedBlockArraySize; i++) + { + if(FreedBlockArray[i].BlockPtr) + { + FreePageMemory(FreedBlockArray[i].BlockPtr, FreedBlockArray[i].BlockSize); + FreedBlockArray[i].Clear(); + } + } + + SetDelayedFreeCount(0); + FreedBlockArraySize = 0; + FreedBlockArrayOldest = 0; +} + + +void DebugPageAllocator::EnableOverrunDetection(bool enableOverrunDetection, bool enableOverrunGuardBytes) +{ + OVR_ASSERT(AllocationCount == 0); + + OverrunPageEnabled = enableOverrunDetection; + OverrunGuardBytesEnabled = (enableOverrunDetection && enableOverrunGuardBytes); // Set OverrunGuardBytesEnabled to false if enableOverrunDetection is false. +} + + +void DebugPageAllocator::SetDelayedFreeCount(size_t delayedFreeCount) +{ + OVR_ASSERT(AllocationCount == 0); + + if(FreedBlockArray) + { + SafeMMapFree(FreedBlockArray, FreedBlockArrayMaxSize * sizeof(Block)); + FreedBlockArrayMaxSize = 0; + } + + if(delayedFreeCount) + { + FreedBlockArray = (Block*)SafeMMapAlloc(delayedFreeCount * sizeof(Block)); + OVR_ASSERT(FreedBlockArray); + + if(FreedBlockArray) + { + FreedBlockArrayMaxSize = delayedFreeCount; + #if defined(OVR_BUILD_DEBUG) + memset(FreedBlockArray, 0, delayedFreeCount * sizeof(Block)); + #endif + } + } +} + + +size_t DebugPageAllocator::GetDelayedFreeCount() const +{ + return FreedBlockArrayMaxSize; +} + + +void* DebugPageAllocator::Alloc(size_t size) +{ + #if defined(_WIN32) + return AllocAligned(size, DefaultAlignment); + #else + void* p = malloc(size); + trackAlloc(p, size); + return p; + #endif +} + + +void* DebugPageAllocator::AllocAligned(size_t size, size_t align) +{ + #if defined(_WIN32) + OVR_ASSERT(align <= PageSize); + + Lock::Locker autoLock(&Lock); + + if(align < DefaultAlignment) + align = DefaultAlignment; + + // The actual needed size may be a little less than this, but it's hard to tell how the size and alignments will play out. + size_t maxRequiredSize = AlignSizeUp(size, align) + SizeStorageSize; + + if(align > SizeStorageSize) + { + // Must do: more sophisticated fitting, as maxRequiredSize is potentially too small. + OVR_ASSERT(SizeStorageSize <= align); + } + + size_t blockSize = AlignSizeUp(maxRequiredSize, PageSize); + + if(OverrunPageEnabled) + blockSize += PageSize; // We add another page which will be uncommitted, so any read or write with it will except. + + void* pBlockPtr; + + if((FreedBlockArraySize == FreedBlockArrayMaxSize) && FreedBlockArrayMaxSize && // If there is an old block we can recycle... + (FreedBlockArray[FreedBlockArrayOldest].BlockSize == blockSize)) // We require it to be the exact size, as there would be some headaches for us if it was over-sized. + { + pBlockPtr = EnablePageMemory(FreedBlockArray[FreedBlockArrayOldest].BlockPtr, blockSize); // Convert this memory from PAGE_NOACCESS back to PAGE_READWRITE. + FreedBlockArray[FreedBlockArrayOldest].Clear(); + + if(++FreedBlockArrayOldest == FreedBlockArrayMaxSize) + FreedBlockArrayOldest = 0; + } + else + { + pBlockPtr = AllocCommittedPageMemory(blockSize); // Allocate a new block of one or more pages (via VirtualAlloc). + } + + if(pBlockPtr) + { + void* pUserPtr = GetUserPosition(pBlockPtr, blockSize, size, align); + size_t* pSizePos = GetSizePosition(pUserPtr); + + pSizePos[UserSizeIndex] = size; + pSizePos[BlockSizeIndex] = blockSize; + AllocationCount++; + trackAlloc(pUserPtr, size); + + return pUserPtr; + } + + return nullptr; + #else + OVR_ASSERT_AND_UNUSED(align <= DefaultAlignment, align); + return DebugPageAllocator::Alloc(size); + #endif +} + + +size_t DebugPageAllocator::GetUserSize(const void* p) +{ + #if defined(_WIN32) + return GetSizePosition(p)[UserSizeIndex]; + #elif defined(__APPLE__) + return malloc_size(p); + #else + return malloc_usable_size(const_cast<void*>(p)); + #endif +} + + +size_t DebugPageAllocator::GetBlockSize(const void* p) +{ + #if defined(_WIN32) + return GetSizePosition(p)[BlockSizeIndex]; + #else + OVR_UNUSED(p); + return 0; + #endif +} + + +size_t* DebugPageAllocator::GetSizePosition(const void* p) +{ + // No thread safety required as per our design, as we assume that anybody + // who owns a pointer returned by Alloc cannot have another thread take it away. + + // We assume the pointer is a valid pointer allocated by this allocator. + // We store some size values into the memory returned to the user, a few bytes before it. + size_t value = reinterpret_cast<size_t>(p); + size_t valuePos = (value - SizeStorageSize); + size_t* pSize = reinterpret_cast<size_t*>(valuePos); + + return pSize; +} + + +void* DebugPageAllocator::Realloc(void* p, size_t newSize) +{ + #if defined(_WIN32) + return ReallocAligned(p, newSize, DefaultAlignment); + #else + void* newP = realloc(p, newSize); + + if(newP) // Need to check newP because realloc doesn't free p unless it returns a valid newP. + { + #if !defined(__clang_analyzer__) // The analyzer complains that we are using p after it was freed. + untrackAlloc(p); + #endif + } + trackAlloc(newP, newSize); + return newP; + #endif +} + + +void* DebugPageAllocator::ReallocAligned(void* p, size_t newSize, size_t newAlign) +{ + #if defined(_WIN32) + // The ISO C99 standard states: + // The realloc function deallocates the old object pointed to by ptr and + // returns a pointer to a new object that has the size specified by size. + // The contents of the new object shall be the same as that of the old + // object prior to deallocation, up to the lesser of the new and old sizes. + // Any bytes in the new object beyond the size of the old object have + // indeterminate values. + // + // If ptr is a null pointer, the realloc function behaves like the malloc + // function for the specified size. Otherwise, if ptr does not match a + // pointer earlier returned by the calloc, malloc, or realloc function, + // or if the space has been deallocated by a call to the free or realloc + // function, the behavior is undefined. If memory for the new object + // cannot be allocated, the old object is not deallocated and its value + // is unchanged. + // + // The realloc function returns a pointer to the new object (which may have + // the same value as a pointer to the old object), or a null pointer if + // the new object could not be allocated. + + // A mutex lock isn't required, as the functions below will handle it internally. + // But having it here is a little more efficient because it woudl otherwise be + // locked and unlocked multiple times below, with possible context switches in between. + Lock::Locker autoLock(&Lock); + + void* pReturn = nullptr; + + if(p) + { + if(newSize) + { + pReturn = AllocAligned(newSize, newAlign); + + if(pReturn) + { + size_t prevSize = GetUserSize(p); + + if(newSize > prevSize) + newSize = prevSize; + + memcpy(pReturn, p, newSize); + Free(p); + } // Else fall through, leaving p's memory unmodified and returning nullptr. + } + else + { + Free(p); + } + } + else if(newSize) + { + pReturn = AllocAligned(newSize, newAlign); + } + + return pReturn; + #else + OVR_ASSERT_AND_UNUSED(newAlign <= DefaultAlignment, newAlign); + return DebugPageAllocator::Realloc(p, newSize); + #endif +} + + +void DebugPageAllocator::Free(void *p) +{ + #if defined(_WIN32) + if(p) + { + Lock::Locker autoLock(&Lock); + + if(FreedBlockArrayMaxSize) // If we have a delayed free list... + { + // We don't free the page(s) associated with this but rather put them in the FreedBlockArray in an inaccessible state for later freeing. + // We do this because we don't want those pages to be available again in the near future, so we can detect use-after-free misakes. + Block* pBlockNew; + + if(FreedBlockArraySize == FreedBlockArrayMaxSize) // If we have reached freed block capacity... we can start purging old elements from it as a circular queue. + { + pBlockNew = &FreedBlockArray[FreedBlockArrayOldest]; + + // The oldest element in the container is FreedBlockArrayOldest. + if(pBlockNew->BlockPtr) // Currently this should always be true. + { + FreePageMemory(pBlockNew->BlockPtr, pBlockNew->BlockSize); + pBlockNew->Clear(); + } + + if(++FreedBlockArrayOldest == FreedBlockArrayMaxSize) + FreedBlockArrayOldest = 0; + } + else // Else we are still building the container and not yet treating it a circular. + { + pBlockNew = &FreedBlockArray[FreedBlockArraySize++]; + } + + pBlockNew->BlockPtr = GetBlockPtr(p); + pBlockNew->BlockSize = GetBlockSize(p); + + #if defined(OVR_BUILD_DEBUG) + if(OverrunGuardBytesEnabled) // If we have extra bytes at the end of the user's allocation between it and an inaccessible guard page... + { + const size_t userSize = GetUserSize(p); + const uint8_t* pUserEnd = (static_cast<uint8_t*>(p) + userSize); + const uint8_t* pPageEnd = AlignPointerUp(pUserEnd, PageSize); + + while(pUserEnd != pPageEnd) + { + if(*pUserEnd++ != GuardFillByte) + { + OVR_FAIL(); + break; + } + } + } + #endif + + DisablePageMemory(pBlockNew->BlockPtr, pBlockNew->BlockSize); // Make it so that future attempts to use this memory result in an exception. + } + else + { + FreePageMemory(GetBlockPtr(p), GetBlockSize(p)); + } + + untrackAlloc(p); + AllocationCount--; + } + #else + untrackAlloc(p); + return free(p); + #endif +} + + +void DebugPageAllocator::FreeAligned(void* p) +{ + return Free(p); +} + + +// Converts a user pointer to the beginning of its page. +void* DebugPageAllocator::GetBlockPtr(void* p) +{ + // We store size info before p in memory, and this will, by design, be always somewhere within + // the first page of a block of pages. So just align down to the beginning of its page. + return AlignPointerDown(GetSizePosition(p), PageSize); +} + + +void* DebugPageAllocator::GetUserPosition(void* pPageMemory, size_t blockSize, size_t userSize, size_t userAlignment) +{ + uint8_t* pUserPosition; + + if(OverrunPageEnabled) + { + // We need to return the highest position within the page memory that fits the user size while being aligned to userAlignment. + const size_t pageEnd = reinterpret_cast<size_t>(pPageMemory) + (blockSize - PageSize); // pageEnd points to the beginning of the final guard page. + const size_t userPosition = AlignSizeDown(pageEnd - userSize, userAlignment); + pUserPosition = reinterpret_cast<uint8_t*>(userPosition); + OVR_ASSERT((userPosition + userSize) <= pageEnd); + + // If userSize is not a multiple of userAlignment then there will be (userAlignment - userSize) bytes + // of unused memory between the user allocated space and the end of the page. There is no way around having this. + // For example, a user allocation of 3 bytes with 8 byte alignment will leave 5 unused bytes at the end of the page. + // We optionally fill those unused bytes with a pattern and upon Free verify that the pattern is undisturbed. + // This won't detect reads or writes in that area immediately as with reads or writes beyond that, but it will + // at least detect them at some point (e.g. upon Free). + #if defined(OVR_BUILD_DEBUG) + if(OverrunGuardBytesEnabled) + { + uint8_t* const pUserEnd = (pUserPosition + userSize); + const size_t remainingByteCount = (reinterpret_cast<uint8_t*>(pageEnd) - pUserEnd); + if(remainingByteCount) // If there are any left-over bytes... + memset(pUserEnd, GuardFillByte, remainingByteCount); + } + #endif + } + else + { + // We need to return the first position in the first page after SizeStorageSize bytes which is aligned to userAlignment. + const size_t lowestPossiblePos = reinterpret_cast<size_t>(pPageMemory) + SizeStorageSize; + const size_t userPosition = AlignSizeUp(lowestPossiblePos, userAlignment); + pUserPosition = reinterpret_cast<uint8_t*>(userPosition); + OVR_ASSERT((userPosition + userSize) <= (reinterpret_cast<size_t>(pPageMemory) + blockSize)); + } + + // Assert that the returned user pointer (actually the size info before it) will be within the first page. + // This is important because it verifieds that we haven't wasted memory and because + // our functionality for telling the start of the page block depends on it. + OVR_ASSERT(AlignPointerDown(GetSizePosition(pUserPosition), PageSize) == pPageMemory); + + return pUserPosition; +} + + +void* DebugPageAllocator::AllocCommittedPageMemory(size_t blockSize) +{ + #if defined(_WIN32) + void* p; + + if(OverrunPageEnabled) + { + // We need to make it so that last page is MEM_RESERVE and the previous pages are MEM_COMMIT + PAGE_READWRITE. + OVR_ASSERT(blockSize > PageSize); // There should always be at least one extra page. + + // Reserve blockSize amount of pages. + // We could possibly use PAGE_GUARD here for the last page. This differs from simply leaving it reserved + // because the OS will generate a one-time-only gaurd page exception. We probabl don't want this, as it's + // more useful for maintaining your own stack than for catching unintended overruns. + p = VirtualAlloc(nullptr, blockSize, MEM_RESERVE, PAGE_READWRITE); + OVR_ASSERT(p); + + if(p) + { + // Commit all but the last page. Leave the last page as merely reserved so that reads from or writes + // to it result in an immediate exception. + p = VirtualAlloc(p, blockSize - PageSize, MEM_COMMIT, PAGE_READWRITE); + OVR_ASSERT(p); + } + } + else + { + // We need to make it so that all pages are MEM_COMMIT + PAGE_READWRITE. + + p = VirtualAlloc(nullptr, blockSize, MEM_COMMIT, PAGE_READWRITE); + } + + return p; + #else + OVR_UNUSED2(blockSize, OverrunPageEnabled); + return nullptr; + #endif +} + + +// We convert disabled page memory (see DisablePageMemory) to enabled page memory. The output is the same +// as with AllocPageMemory. +void* DebugPageAllocator::EnablePageMemory(void* pPageMemory, size_t blockSize) +{ + #if defined(_WIN32) + // Make sure the entire range of memory is of type PAGE_READWRITE. + DWORD dwPrevAccess = 0; + BOOL result = VirtualProtect(pPageMemory, OverrunPageEnabled ? (blockSize - PageSize) : blockSize, PAGE_READWRITE, &dwPrevAccess); + OVR_ASSERT_AND_UNUSED(result, result); + #else + OVR_UNUSED3(pPageMemory, blockSize, OverrunPageEnabled); + #endif + + return pPageMemory; +} + + +void DebugPageAllocator::DisablePageMemory(void* pPageMemory, size_t blockSize) +{ + #if defined(_WIN32) + // Disable access to the page(s). It's faster for us to change the page access than it is to decommit or free the pages. + // However, this results in more committed physical memory usage than we would need if we instead decommitted the memory. + DWORD dwPrevAccesss = 0; + BOOL result = VirtualProtect(pPageMemory, OverrunPageEnabled ? (blockSize - PageSize) : blockSize, PAGE_NOACCESS, &dwPrevAccesss); + OVR_ASSERT_AND_UNUSED(result, result); + #else + OVR_UNUSED2(pPageMemory, blockSize); + #endif +} + + +void DebugPageAllocator::FreePageMemory(void* pPageMemory, size_t /*blockSize*/) +{ + #if defined(_WIN32) + BOOL result = VirtualFree(pPageMemory, 0, MEM_RELEASE); + OVR_ASSERT_AND_UNUSED(result, result); + #else + OVR_UNUSED(pPageMemory); + #endif +} + + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_Allocator.h b/LibOVRKernel/Src/Kernel/OVR_Allocator.h new file mode 100644 index 0000000..4eb152b --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Allocator.h @@ -0,0 +1,708 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Allocator.h +Content : Installable memory allocator +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Allocator_h +#define OVR_Allocator_h + +#include "OVR_Types.h" +#include "OVR_Atomic.h" +#include "stdlib.h" +#include "stdint.h" + + +//----------------------------------------------------------------------------------- + +// ***** Disable template-unfriendly MS VC++ warnings +#if defined(OVR_CC_MSVC) +#pragma warning(push) +// Pragma to prevent long name warnings in in VC++ +#pragma warning(disable : 4503) +#pragma warning(disable : 4786) +// In MSVC 7.1, warning about placement new POD default initializer +#pragma warning(disable : 4345) +#endif + +// Un-define new so that placement constructors work +#undef new + + +//----------------------------------------------------------------------------------- +// ***** Placement new overrides + +// Calls constructor on own memory created with "new(ptr) type" +#ifndef __PLACEMENT_NEW_INLINE +#define __PLACEMENT_NEW_INLINE + +# if defined(OVR_CC_MWERKS) || defined(OVR_CC_BORLAND) || defined(OVR_CC_GNU) +# include <new> +# else + // Useful on MSVC + OVR_FORCE_INLINE void* operator new (size_t n, void *ptr) { OVR_UNUSED(n); return ptr; } + OVR_FORCE_INLINE void operator delete (void *, void *) { } +# endif + +#endif // __PLACEMENT_NEW_INLINE + + + +//------------------------------------------------------------------------ +// ***** Macros to redefine class new/delete operators + +// Types specifically declared to allow disambiguation of address in +// class member operator new. + +#define OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, check_delete) \ + void* operator new(size_t sz) \ + { void* p = OVR_ALLOC_DEBUG(sz, __FILE__, __LINE__); return p; } \ + void* operator new(size_t sz, const char* file, int line) \ + { OVR_UNUSED2(file, line); void* p = OVR_ALLOC_DEBUG(sz, file, line); return p; } \ + void operator delete(void* p) \ + { check_delete(class_name, p); OVR_FREE(p); } \ + void operator delete(void* p, const char*, int) \ + { check_delete(class_name, p); OVR_FREE(p); } + +#define OVR_MEMORY_DEFINE_PLACEMENT_NEW \ + void* operator new (size_t n, void* ptr) { OVR_UNUSED(n); return ptr; } \ + void operator delete (void* ptr, void* ptr2) { OVR_UNUSED2(ptr, ptr2); } + + +#define OVR_MEMORY_CHECK_DELETE_NONE(class_name, p) + +// Redefined all delete/new operators in a class without custom memory initialization +#define OVR_MEMORY_REDEFINE_NEW(class_name) \ + OVR_MEMORY_REDEFINE_NEW_IMPL(class_name, OVR_MEMORY_CHECK_DELETE_NONE) + + +namespace OVR { + + +//----------------------------------------------------------------------------------- +// ***** Construct / Destruct + +// Construct/Destruct functions are useful when new is redefined, as they can +// be called instead of placement new constructors. + + +template <class T> +OVR_FORCE_INLINE T* Construct(void *p) +{ + return ::new(p) T(); +} + +template <class T> +OVR_FORCE_INLINE T* Construct(void *p, const T& source) +{ + return ::new(p) T(source); +} + +// Same as above, but allows for a different type of constructor. +template <class T, class S> +OVR_FORCE_INLINE T* ConstructAlt(void *p, const S& source) +{ + return ::new(p) T(source); +} + +template <class T, class S1, class S2> +OVR_FORCE_INLINE T* ConstructAlt(void *p, const S1& src1, const S2& src2) +{ + return ::new(p) T(src1, src2); +} + +// Note: These ConstructArray functions don't properly support the case of a C++ exception occurring midway +// during construction, as they don't deconstruct the successfully constructed array elements before returning. +template <class T> +OVR_FORCE_INLINE void ConstructArray(void *p, size_t count) +{ + uint8_t *pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + { + Construct<T>(pdata); + } +} + +template <class T> +OVR_FORCE_INLINE void ConstructArray(void *p, size_t count, const T& source) +{ + uint8_t *pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + { + Construct<T>(pdata, source); + } +} + +template <class T> +OVR_FORCE_INLINE void Destruct(T *pobj) +{ + pobj->~T(); + OVR_UNUSED1(pobj); // Fix incorrect 'unused variable' MSVC warning. +} + +template <class T> +OVR_FORCE_INLINE void DestructArray(T *pobj, size_t count) +{ + for (size_t i=0; i<count; ++i, ++pobj) + pobj->~T(); +} + + +//----------------------------------------------------------------------------------- +// ***** Allocator + +// Allocator defines a memory allocation interface that developers can override +// to to provide memory for OVR; an instance of this class is typically created on +// application startup and passed into System or OVR::System constructor. +// +// +// Users implementing this interface must provide three functions: Alloc, Free, +// and Realloc. Implementations of these functions must honor the requested alignment. +// Although arbitrary alignment requests are possible, requested alignment will +// typically be small, such as 16 bytes or less. + +class Allocator +{ + friend class System; + +public: + virtual ~Allocator() + { + } + + // Returns the pointer to the current globally installed Allocator instance. + // This pointer is used for most of the memory allocations. + static Allocator* GetInstance() + { + return pInstance; + } + + + // *** Standard Alignment Alloc/Free + + // Allocate memory of specified size with default alignment. + // Alloc of size==0 will allocate a tiny block & return a valid pointer; + // this makes it suitable for new operator. + virtual void* Alloc(size_t size) = 0; + + // Same as Alloc, but provides an option of passing debug data. + virtual void* AllocDebug(size_t size, const char* /*file*/, unsigned /*line*/) + { return Alloc(size); } + + // Reallocate memory block to a new size, copying data if necessary. Returns the pointer to + // new memory block, which may be the same as original pointer. Will return 0 if reallocation + // failed, in which case previous memory is still valid. + // Realloc to decrease size will never fail. + // Realloc of pointer == 0 is equivalent to Alloc + // Realloc to size == 0, shrinks to the minimal size, pointer remains valid and requires Free(). + virtual void* Realloc(void* p, size_t newSize) = 0; + + // Frees memory allocated by Alloc/Realloc. + // Free of null pointer is valid and will do nothing. + virtual void Free(void *p) = 0; + + + // *** Standard Alignment Alloc/Free + + // Allocate memory of specified alignment. + // Memory allocated with AllocAligned MUST be freed with FreeAligned. + // Default implementation will delegate to Alloc/Free after doing rounding. + virtual void* AllocAligned(size_t size, size_t align); + // Frees memory allocated with AllocAligned. + virtual void FreeAligned(void* p); + +protected: + // *** Tracking of allocations w/ callstacks for debug builds. + + // Add the allocation & the callstack to the tracking database + void trackAlloc(void* p, size_t size); + // Remove the allocation from the tracking database + void untrackAlloc(void* p); + +protected: + // onSystemShutdown is called on the allocator during System::Shutdown. + // At this point, all allocations should've been freed. + virtual void onSystemShutdown() + { } + +public: + static void setInstance(Allocator* palloc) + { + OVR_ASSERT((pInstance == 0) || (palloc == 0)); + pInstance = palloc; + } + +private: + static Allocator* pInstance; + +public: + // Lock used during LibOVR execution to guard the tracked allocation list. + Lock TrackLock; + + static void SetLeakTracking(bool enabled); + static bool IsTrackingLeaks(); +}; + + +//------------------------------------------------------------------------ +// ***** Allocator_SingletonSupport + +// Allocator_SingletonSupport is a Allocator wrapper class that implements +// the InitSystemSingleton static function, used to create a global singleton +// used for the OVR::System default argument initialization. +// +// End users implementing custom Allocator interface don't need to make use of this base +// class; they can just create an instance of their own class on stack and pass it to System. + +template<class D> +class Allocator_SingletonSupport : public Allocator +{ + struct AllocContainer + { + size_t Data[(sizeof(D) + sizeof(size_t)-1) / sizeof(size_t)]; + bool Initialized; + AllocContainer() : Initialized(0) { } + }; + + AllocContainer* pContainer; + +public: + Allocator_SingletonSupport() : pContainer(0) + { } + + // Creates a singleton instance of this Allocator class used + // on OVR_DEFAULT_ALLOCATOR during System initialization. + static D* InitSystemSingleton() + { + static AllocContainer Container; + OVR_ASSERT(Container.Initialized == false); + + Allocator_SingletonSupport<D> *presult = Construct<D>((void*)Container.Data); + presult->pContainer = &Container; + Container.Initialized = true; + return (D*)presult; + } + +protected: + virtual void onSystemShutdown() + { + Allocator::onSystemShutdown(); + if (pContainer) + { + pContainer->Initialized = false; + pContainer = nullptr; + Destruct((D*)this); + } + } +}; + + +//------------------------------------------------------------------------ +// ***** DefaultAllocator + +// This allocator is created and used if no other allocator is installed. +// Default allocator delegates to system malloc. + +class DefaultAllocator : public Allocator_SingletonSupport<DefaultAllocator> +{ +public: + virtual void* Alloc(size_t size); + virtual void* AllocDebug(size_t size, const char* file, unsigned line); + virtual void* Realloc(void* p, size_t newSize); + virtual void Free(void *p); +}; + + +//------------------------------------------------------------------------ +// ***** DebugPageAllocator +// +// Implements a page-protected allocator: +// Detects use-after-free and memory overrun bugs immediately at the time of usage via an exception. +// Can detect a memory read or write beyond the valid memory immediately at the +// time of usage via an exception (if EnableOverrunDetection is enabled). +// This doesn't replace valgrind but implements a subset of its functionality +// in a way that performs well enough to avoid interfering with app execution. +// The point of this is that immediately detects these two classes of errors while +// being much faster than external tools such as valgrind, etc. This is at a cost of +// as much as a page of extra bytes per allocation (two if EnableOverrunDetection is enabled). +// On Windows the Alloc and Free functions average about 12000 cycles each. This isn't small but +// it should be low enough for many testing circumstances with apps that are prudent with +// memory allocation volume. +// The amount of system memory needed for this isn't as high as one might initially guess, as it +// takes hundreds of thousands of memory allocations in order to make a dent in the gigabytes of +// memory most computers have. +// +// +// Technical design for the Windows platform: +// Every Alloc is satisfied via a VirtualAlloc return of a memory block of one or more pages; +// the minimum needed to satisy the user's size and alignment requirements. +// Upon Free the memory block (which is one or more pages) is not passed to VirtualFree but rather +// is converted to PAGE_NOACCESS and put into a delayed free list (FreedBlockArray) to be passed +// to VirtualFree later. The result of this is that any further attempts to read or write the +// memory will result in an exception. +// The delayed-free list increases each time Free is called until it reached maximum capacity, +// at which point the oldest memory block in the list is passed to VirtualFree and its +// entry in the list is filled with this newly Freed (PAGE_NOACCESS) memory block. +// Once the delayed-free list reaches maximum capacity it thus acts as a ring buffer of blocks. +// The maximum size of this list is currently determined at compile time as a constant. +// The EnableOverrunDetection is an additional feature which allows reads or writes beyond valid +// memory to be detected as they occur. This is implemented by adding an allocating an additional +// page of memory at the end of the usual pages and leaving it uncommitted (MEM_RESERVE). +// When this option is used, we return a pointer to the user that's at the end of the valid +// memory block as opposed to at the beginning. This is so that the space right after the +// user space is invalid. If there are some odd bytes remaining between the end of the user's +// space and the page (due to alignment requirements), we optionally fill these with guard bytes. +// We do not currently support memory underrun detection, which could be implemented via an +// extra un-accessible page before the user page(s). In practice this is rarely needed. +// Currently the choice to use EnableOverrunDetection must be done before any calls to Alloc, etc. +// as the logic is simpler and faster if we don't have to dynamically handle either case at runtime. +// We store within the memory block the size of the block and the size of the original user Alloc +// request. This is done as two size_t values written before the memory returned to the user. +// Thus the pointer returned to the user will never be at the very beginning of the memory block, +// because there will be two size_t's before it. +// This class itself allocates no memory, as that could interfere with its ability to supply +// memory, especially if the global malloc and new functions are replaced with this class. +// We could in fact support this class allocating memory as long as it used a system allocator +// and not malloc, new, etc. +// As of this writing we don't do debug fill patterns in the returned memory, because we mostly +// don't need it because memory exceptions take the place of unexpected fill value validation. +// However, there is some value in doing a small debug fill of the last few bytes after the +// user's bytes but before the next page, which will happen for odd sizes passed to Alloc. +// +// Technical design for Mac and Linux platforms: +// Apple's XCode malloc functionality includes something called MallocGuardEdges which is similar +// to DebugPageAllocator, though it protects only larger sized allocations and not smaller ones. +// Our approach for this on Mac and Linux is to use mmap and mprotect in a way similar to VirtualAlloc and +// VirtualProtect. Unix doesn't have the concept of Windows MEM_RESERVE vs. MEM_COMMIT, but we can +// simulate MEM_RESERVE by having an extra page that's PROT_NONE instead of MEM_RESERVE. Since Unix +// platforms don't commit pages pages to physical memory until they are first accessed, this extra +// page will in practice act similar to Windows MEM_RESERVE at runtime. +// +// Allocation inteface: +// Alloc sizes can be any size_t >= 0. +// An alloc size of 0 returns a non-nullptr. +// Alloc functions may fail (usually due to insufficent memory), in which case they return nullptr. +// All returned allocations are aligned on a power-of-two boundary of at least DebugPageAllocator::DefaultAlignment. +// AllocAligned supports any alignment power-of-two value from 1 to 256. Other values result in undefined behavior. +// AllocAligned may return a pointer that's aligned greater than the requested alignment. +// Realloc acts as per the C99 Standard realloc. +// Free requires the supplied pointer to be a valid pointer returned by this allocator's Alloc functions, else the behavior is undefined. +// You may not Free a pointer a second time, else the behavior is undefined. +// Free otherwise always succeeds. +// Allocations made with AllocAligned or ReallocAligned must be Freed via FreeAligned, as per the base class requirement. +// + +class DebugPageAllocator : public Allocator_SingletonSupport<DebugPageAllocator> +{ +public: + DebugPageAllocator(); + virtual ~DebugPageAllocator(); + + void Init(); + void Shutdown(); + + void SetDelayedFreeCount(size_t delayedFreeCount); // Sets how many freed blocks we should save before purging the oldest of them. + size_t GetDelayedFreeCount() const; + void EnableOverrunDetection(bool enableOverrunDetection, bool enableOverrunGuardBytes); // enableOverrunDetection is by default. enableOverrunGuardBytes is enabled by default in debug builds. + + void* Alloc(size_t size); + void* AllocAligned(size_t size, size_t align); + void* Realloc(void* p, size_t newSize); + void* ReallocAligned(void* p, size_t newSize, size_t newAlign); + void Free(void* p); + void FreeAligned(void* p); + size_t GetAllocSize(const void* p) const { return GetUserSize(p); } + size_t GetPageSize() const { return PageSize; } + +protected: + struct Block + { + void* BlockPtr; // The pointer to the first page of the contiguous set of pages that make up this block. + size_t BlockSize; // (page size) * (page count). Will be >= (SizeStorageSize + UserSize). + + void Clear() { BlockPtr = nullptr; BlockSize = 0; } + }; + + Block* FreedBlockArray; // Currently a very simple array-like container that acts as a ring buffer of delay-freed (but inaccessible) blocks. + size_t FreedBlockArrayMaxSize; // The max number of Freed blocks to put into FreedBlockArray before they start getting purged. Must be <= kFreedBlockArrayCapacity. + size_t FreedBlockArraySize; // The amount of valid elements within FreedBlockArray. Increases as elements are added until it reaches kFreedBlockArrayCapacity. Then stays that way until Shutdown. + size_t FreedBlockArrayOldest; // The oldest entry in the FreedBlockArray ring buffer. + size_t AllocationCount; // Number of currently live Allocations. Incremented by successful calls to Alloc (etc.) Decremented by successful calss to Free. + bool OverrunPageEnabled; // If true then we implement memory overrun detection, at the cost of an extra page per user allocation. + bool OverrunGuardBytesEnabled; // If true then any remaining bytes between the end of the user's allocation and the end of the page are filled with guard bytes and verified upon Free. Valid only if OverrunPageEnabled is true. + size_t PageSize; // The current default platform memory page size (e.g. 4096). We allocated blocks in multiples of pages. + OVR::Lock Lock; // Mutex which allows an instance of this class to be used by multiple threads simultaneously. + +public: + #if defined(_WIN64) || defined(_M_IA64) || defined(__LP64__) || defined(__LP64__) || defined(__arch64__) || defined(__APPLE__) + static const size_t DefaultAlignment = 16; // 64 bit platforms and all Apple platforms. + #else + static const size_t DefaultAlignment = 8; // 32 bit platforms. We want DefaultAlignment as low as possible because that means less unused bytes between a user allocation and the end of the page. + #endif + #if defined(_WIN32) + static const size_t MaxAlignment = 2048; // Half a page size. + #else + static const size_t MaxAlignment = DefaultAlignment; // Currently a low limit because we don't have full page allocator support yet. + #endif + +protected: + static const size_t SizeStorageSize = DefaultAlignment; // Where the user size and block size is stored. Needs to be at least 2 * sizeof(size_t). + static const size_t UserSizeIndex = 0; // We store block sizes within the memory itself, and this serves to identify it. + static const size_t BlockSizeIndex = 1; + static const uint8_t GuardFillByte = 0xfd; // Same value VC++ uses for heap guard bytes. + + static size_t GetUserSize(const void* p); // Returns the size that the user requested in Alloc, etc. + static size_t GetBlockSize(const void* p); // Returns the actual number of bytes in the returned block. Will be a multiple of PageSize. + static size_t* GetSizePosition(const void* p); // We store the user and block size as two size_t values within the returned memory to the user, before the user pointer. This gets that location. + + void* GetBlockPtr(void* p); + void* GetUserPosition(void* pPageMemory, size_t blockSize, size_t userSize, size_t userAlignment); + void* AllocCommittedPageMemory(size_t blockSize); + void* EnablePageMemory(void* pPageMemory, size_t blockSize); + void DisablePageMemory(void* pPageMemory, size_t blockSize); + void FreePageMemory(void* pPageMemory, size_t blockSize); +}; + + + + +///------------------------------------------------------------------------ +/// ***** OVR_malloca / OVR_freea +/// +/// Implements a safer version of alloca. However, see notes below. +/// +/// Allocates memory from the stack via alloca (or similar) for smaller +/// allocation sizes, else falls back to operator new. This is very similar +/// to the Microsoft _malloca and _freea functions, and the implementation +/// is nearly the same aside from using operator new instead of malloc. +/// +/// Unlike alloca, calls to OVR_malloca must be matched by calls to OVR_freea, +/// and the OVR_freea call must be in the same function scope as the original +/// call to OVR_malloca. +/// +/// Note: +/// While this function reduces the likelihood of a stack overflow exception, +/// it cannot guarantee it, as even small allocation sizes done by alloca +/// can exhaust the stack when it is nearly full. However, the majority of +/// stack overflows due to alloca usage are due to large allocation size +/// requests. +/// +/// Declarations: +/// void* OVR_malloca(size_t size); +/// void OVR_freea(void* p); +/// +/// Example usage: +/// void TestMalloca() +/// { +/// char* charArray = (char*)OVR_malloca(37000); +/// +/// if(charArray) +/// { +/// // <use charArray> +/// OVR_freea(charArray); +/// } +/// } +/// +#if !defined(OVR_malloca) + #define OVR_MALLOCA_ALLOCA_ID UINT32_C(0xcccccccc) + #define OVR_MALLOCA_MALLOC_ID UINT32_C(0xdddddddd) + #define OVR_MALLOCA_ID_SIZE 16 // Needs to be at least 2 * sizeof(uint32_t) and at least the minimum alignment for malloc on the platform. 16 works for all platforms. + #if defined(_MSC_VER) + #define OVR_MALLOCA_SIZE_THRESHOLD 8192 + #else + #define OVR_MALLOCA_SIZE_THRESHOLD 1024 // Non-Microsoft platforms tend to exhaust stack space sooner due to non-automatic stack expansion. + #endif + + #define OVR_malloca(size) \ + ((((size) + OVR_MALLOCA_ID_SIZE) < OVR_MALLOCA_SIZE_THRESHOLD) ? \ + OVR::malloca_SetId(static_cast<char*>(alloca((size) + OVR_MALLOCA_ID_SIZE)), OVR_MALLOCA_ALLOCA_ID) : \ + OVR::malloca_SetId(static_cast<char*>(new char[(size) + OVR_MALLOCA_ID_SIZE]), OVR_MALLOCA_MALLOC_ID)) + + inline void* malloca_SetId(char* p, uint32_t id) + { + if(p) + { + *reinterpret_cast<uint32_t*>(p) = id; + p = reinterpret_cast<char*>(p) + OVR_MALLOCA_ID_SIZE; + } + + return p; + } +#endif + +#if !defined(OVR_freea) + #define OVR_freea(p) OVR::freea_Impl(reinterpret_cast<char*>(p)) + + inline void freea_Impl(char* p) + { + if (p) + { + // We store the allocation type id at the first uint32_t in the returned memory. + static_assert(OVR_MALLOCA_ID_SIZE >= sizeof(uint32_t), "Insufficient OVR_MALLOCA_ID_SIZE size."); + p -= OVR_MALLOCA_ID_SIZE; + uint32_t id = *reinterpret_cast<uint32_t*>(p); + + if(id == OVR_MALLOCA_MALLOC_ID) + delete[] p; + #if defined(OVR_BUILD_DEBUG) + else if(id != OVR_MALLOCA_ALLOCA_ID) + OVR_FAIL_M("OVR_freea memory corrupt or not allocated by OVR_alloca."); + #endif + } + } +#endif + + +///------------------------------------------------------------------------ +/// ***** OVR_newa / OVR_deletea +/// +/// Implements a C++ array version of OVR_malloca/OVR_freea. +/// Expresses failure via a nullptr return value and not via a C++ exception. +/// If a handled C++ exception occurs midway during construction in OVR_newa, +// there is no automatic destruction of the successfully constructed elements. +/// +/// Declarations: +/// T* OVR_newa(T, size_t count); +/// void OVR_deletea(T, T* pTArray); +/// +/// Example usage: +/// void TestNewa() +/// { +/// Widget* pWidgetArray = OVR_newa(Widget, 37000); +/// +/// if(pWidgetArray) +/// { +/// // <use pWidgetArray> +/// OVR_deletea(Widget, pWidgetArray); +/// } +/// } +/// + +#if !defined(OVR_newa) + #define OVR_newa(T, count) OVR::newa_Impl<T>(static_cast<char*>(OVR_malloca(count * sizeof(T))), count) +#endif + +template<class T> +T* newa_Impl(char* pTArray, size_t count) +{ + if(pTArray) + { + OVR::ConstructArray<T>(pTArray, count); + + // We store the count at the second uint32_t in the returned memory. + static_assert(OVR_MALLOCA_ID_SIZE >= (2 * sizeof(uint32_t)), "Insufficient OVR_MALLOCA_ID_SIZE size."); + reinterpret_cast<uint32_t*>((reinterpret_cast<char*>(pTArray) - OVR_MALLOCA_ID_SIZE))[1] = (uint32_t)count; + } + return reinterpret_cast<T*>(pTArray); +} + +#if !defined(OVR_deletea) + #define OVR_deletea(T, pTArray) OVR::deletea_Impl<T>(pTArray) +#endif + +template<class T> +void deletea_Impl(T* pTArray) +{ + if(pTArray) + { + uint32_t count = reinterpret_cast<uint32_t*>((reinterpret_cast<char*>(pTArray) - OVR_MALLOCA_ID_SIZE))[1]; + OVR::DestructArray<T>(pTArray, count); + OVR_freea(pTArray); + } +} + + + + + +//------------------------------------------------------------------------ +// ***** Memory Allocation Macros + +// These macros should be used for global allocation. In the future, these +// macros will allows allocation to be extended with debug file/line information +// if necessary. + +#define OVR_REALLOC(p,s) OVR::Allocator::GetInstance()->Realloc((p),(s)) +#define OVR_FREE(p) OVR::Allocator::GetInstance()->Free((p)) +#define OVR_ALLOC_ALIGNED(s,a) OVR::Allocator::GetInstance()->AllocAligned((s),(a)) +#define OVR_FREE_ALIGNED(p) OVR::Allocator::GetInstance()->FreeAligned((p)) + +#ifdef OVR_BUILD_DEBUG +#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->AllocDebug((s), __FILE__, __LINE__) +#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->AllocDebug((s), f, l) +#else +#define OVR_ALLOC(s) OVR::Allocator::GetInstance()->Alloc((s)) +#define OVR_ALLOC_DEBUG(s,f,l) OVR::Allocator::GetInstance()->Alloc((s)) +#endif + + +//------------------------------------------------------------------------ + +// Base class that overrides the new and delete operators. +// Deriving from this class, even as a multiple base, incurs no space overhead. +class NewOverrideBase +{ +public: + + // Redefine all new & delete operators. + OVR_MEMORY_REDEFINE_NEW(NewOverrideBase) +}; + + +//------------------------------------------------------------------------ +// ***** DumpMemory + +// Displays information about outstanding allocations, typically for the +// purpose of reporting leaked memory on application or module shutdown. +// This should be used instead of, for example, VC++ _CrtDumpMemoryLeaks +// because it allows us to dump additional information about our allocations. +// Returns the number of currently outstanding heap allocations. +int DumpMemory(); + + +//------------------------------------------------------------------------ +// ***** Mapped memory allocation +// +// Equates to VirtualAlloc/VirtualFree on Windows, mmap/munmap on Unix. +// These are useful for when you need system-supplied memory pages. +// These are also useful for when you need to allocate memory in a way +// that doesn't affect the application heap. + +void* SafeMMapAlloc(size_t size); +void SafeMMapFree (const void* memory, size_t size); + + +} // OVR + + +// Redefine operator 'new' if necessary. +#if defined(OVR_DEFINE_NEW) +#define new OVR_DEFINE_NEW +#endif + +#if defined(OVR_CC_MSVC) +#pragma warning(pop) +#endif + +#endif // OVR_Memory diff --git a/LibOVRKernel/Src/Kernel/OVR_Array.h b/LibOVRKernel/Src/Kernel/OVR_Array.h new file mode 100644 index 0000000..28c2fac --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Array.h @@ -0,0 +1,837 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Array.h +Content : Template implementation for Array +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Array_h +#define OVR_Array_h + +#include "OVR_ContainerAllocator.h" + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** ArrayDefaultPolicy +// +// Default resize behavior. No minimal capacity, Granularity=4, +// Shrinking as needed. ArrayConstPolicy actually is the same as +// ArrayDefaultPolicy, but parametrized with constants. +// This struct is used only in order to reduce the template "matroska". +struct ArrayDefaultPolicy +{ + ArrayDefaultPolicy() : Capacity(0) {} + ArrayDefaultPolicy(const ArrayDefaultPolicy&) : Capacity(0) {} + + size_t GetMinCapacity() const { return 0; } + size_t GetGranularity() const { return 4; } + bool NeverShrinking() const { return 1; } + + size_t GetCapacity() const { return Capacity; } + void SetCapacity(size_t capacity) { Capacity = capacity; } +private: + size_t Capacity; +}; + + +//----------------------------------------------------------------------------------- +// ***** ArrayConstPolicy +// +// Statically parametrized resizing behavior: +// MinCapacity, Granularity, and Shrinking flag. +template<int MinCapacity=0, int Granularity=4, bool NeverShrink=false> +struct ArrayConstPolicy +{ + typedef ArrayConstPolicy<MinCapacity, Granularity, NeverShrink> SelfType; + + ArrayConstPolicy() : Capacity(0) {} + ArrayConstPolicy(const SelfType&) : Capacity(0) {} + + size_t GetMinCapacity() const { return MinCapacity; } + size_t GetGranularity() const { return Granularity; } + bool NeverShrinking() const { return NeverShrink; } + + size_t GetCapacity() const { return Capacity; } + void SetCapacity(size_t capacity) { Capacity = capacity; } +private: + size_t Capacity; +}; + +//----------------------------------------------------------------------------------- +// ***** ArrayDataBase +// +// Basic operations with array data: Reserve, Resize, Free, ArrayPolicy. +// For internal use only: ArrayData,ArrayDataCC and others. +template<class T, class Allocator, class SizePolicy> +struct ArrayDataBase +{ + typedef T ValueType; + typedef Allocator AllocatorType; + typedef SizePolicy SizePolicyType; + typedef ArrayDataBase<T, Allocator, SizePolicy> SelfType; + + ArrayDataBase() + : Data(0), Size(0), Policy() {} + + ArrayDataBase(const SizePolicy& p) + : Data(0), Size(0), Policy(p) {} + + ~ArrayDataBase() + { + Allocator::DestructArray(Data, Size); + Allocator::Free(Data); + } + + size_t GetCapacity() const + { + return Policy.GetCapacity(); + } + + void ClearAndRelease() + { + Allocator::DestructArray(Data, Size); + Allocator::Free(Data); + Data = 0; + Size = 0; + Policy.SetCapacity(0); + } + + void Reserve(size_t newCapacity) + { + if (Policy.NeverShrinking() && newCapacity < GetCapacity()) + return; + + if (newCapacity < Policy.GetMinCapacity()) + newCapacity = Policy.GetMinCapacity(); + + // Resize the buffer. + if (newCapacity == 0) + { + if (Data) + { + Allocator::Free(Data); + Data = 0; + } + Policy.SetCapacity(0); + } + else + { + size_t gran = Policy.GetGranularity(); + newCapacity = (newCapacity + gran - 1) / gran * gran; + if (Data) + { + if (Allocator::IsMovable()) + { + Data = (T*)Allocator::Realloc(Data, sizeof(T) * newCapacity); + } + else + { + T* newData = (T*)Allocator::Alloc(sizeof(T) * newCapacity); + size_t i, s; + s = (Size < newCapacity) ? Size : newCapacity; + for (i = 0; i < s; ++i) + { + Allocator::Construct(&newData[i], Data[i]); + Allocator::Destruct(&Data[i]); + } + for (i = s; i < Size; ++i) + { + Allocator::Destruct(&Data[i]); + } + Allocator::Free(Data); + Data = newData; + } + } + else + { + Data = (T*)Allocator::Alloc(sizeof(T) * newCapacity); + //memset(Buffer, 0, (sizeof(ValueType) * newSize)); // Do we need this? + } + Policy.SetCapacity(newCapacity); + // OVR_ASSERT(Data); // need to throw (or something) on alloc failure! + } + } + + // This version of Resize DOES NOT construct the elements. + // It's done to optimize PushBack, which uses a copy constructor + // instead of the default constructor and assignment + void ResizeNoConstruct(size_t newSize) + { + size_t oldSize = Size; + + if (newSize < oldSize) + { + Allocator::DestructArray(Data + newSize, oldSize - newSize); + if (newSize < (Policy.GetCapacity() >> 1)) + { + Reserve(newSize); + } + } + else if(newSize >= Policy.GetCapacity()) + { + Reserve(newSize + (newSize >> 2)); + } + //! IMPORTANT to modify Size only after Reserve completes, because garbage collectable + // array may use this array and may traverse it during Reserve (in the case, if + // collection occurs because of heap limit exceeded). + Size = newSize; + } + + ValueType* Data; + size_t Size; + SizePolicy Policy; +}; + + + +//----------------------------------------------------------------------------------- +// ***** ArrayData +// +// General purpose array data. +// For internal use only in Array, ArrayLH, ArrayPOD and so on. +template<class T, class Allocator, class SizePolicy> +struct ArrayData : ArrayDataBase<T, Allocator, SizePolicy> +{ + typedef T ValueType; + typedef Allocator AllocatorType; + typedef SizePolicy SizePolicyType; + typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType; + typedef ArrayData <T, Allocator, SizePolicy> SelfType; + + ArrayData() + : BaseType() { } + + ArrayData(size_t size) + : BaseType() { Resize(size); } + + ArrayData(const SelfType& a) + : BaseType(a.Policy) { Append(a.Data, a.Size); } + + + void Resize(size_t newSize) + { + size_t oldSize = this->Size; + BaseType::ResizeNoConstruct(newSize); + if(newSize > oldSize) + Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize); + } + + void PushBack(const ValueType& val) + { + BaseType::ResizeNoConstruct(this->Size + 1); + OVR_ASSERT(this->Data != NULL); + Allocator::Construct(this->Data + this->Size - 1, val); + } + + template<class S> + void PushBackAlt(const S& val) + { + BaseType::ResizeNoConstruct(this->Size + 1); + Allocator::ConstructAlt(this->Data + this->Size - 1, val); + } + + // Append the given data to the array. + void Append(const ValueType other[], size_t count) + { + if (count) + { + size_t oldSize = this->Size; + BaseType::ResizeNoConstruct(this->Size + count); + Allocator::ConstructArray(this->Data + oldSize, count, other); + } + } +}; + + + +//----------------------------------------------------------------------------------- +// ***** ArrayDataCC +// +// A modification of ArrayData that always copy-constructs new elements +// using a specified DefaultValue. For internal use only in ArrayCC. +template<class T, class Allocator, class SizePolicy> +struct ArrayDataCC : ArrayDataBase<T, Allocator, SizePolicy> +{ + typedef T ValueType; + typedef Allocator AllocatorType; + typedef SizePolicy SizePolicyType; + typedef ArrayDataBase<T, Allocator, SizePolicy> BaseType; + typedef ArrayDataCC <T, Allocator, SizePolicy> SelfType; + + ArrayDataCC(const ValueType& defval) + : BaseType(), DefaultValue(defval) { } + + ArrayDataCC(const ValueType& defval, size_t size) + : BaseType(), DefaultValue(defval) { Resize(size); } + + ArrayDataCC(const SelfType& a) + : BaseType(a.Policy), DefaultValue(a.DefaultValue) { Append(a.Data, a.Size); } + + + void Resize(size_t newSize) + { + size_t oldSize = this->Size; + BaseType::ResizeNoConstruct(newSize); + if(newSize > oldSize) + Allocator::ConstructArray(this->Data + oldSize, newSize - oldSize, DefaultValue); + } + + void PushBack(const ValueType& val) + { + BaseType::ResizeNoConstruct(this->Size + 1); + Allocator::Construct(this->Data + this->Size - 1, val); + } + + template<class S> + void PushBackAlt(const S& val) + { + BaseType::ResizeNoConstruct(this->Size + 1); + Allocator::ConstructAlt(this->Data + this->Size - 1, val); + } + + // Append the given data to the array. + void Append(const ValueType other[], size_t count) + { + if (count) + { + size_t oldSize = this->Size; + BaseType::ResizeNoConstruct(this->Size + count); + Allocator::ConstructArray(this->Data + oldSize, count, other); + } + } + + ValueType DefaultValue; +}; + + + + + +//----------------------------------------------------------------------------------- +// ***** ArrayBase +// +// Resizable array. The behavior can be POD (suffix _POD) and +// Movable (no suffix) depending on the allocator policy. +// In case of _POD the constructors and destructors are not called. +// +// Arrays can't handle non-movable objects! Don't put anything in here +// that can't be moved around by bitwise copy. +// +// The addresses of elements are not persistent! Don't keep the address +// of an element; the array contents will move around as it gets resized. +template<class ArrayData> +class ArrayBase +{ +public: + typedef typename ArrayData::ValueType ValueType; + typedef typename ArrayData::AllocatorType AllocatorType; + typedef typename ArrayData::SizePolicyType SizePolicyType; + typedef ArrayBase<ArrayData> SelfType; + + +#undef new + OVR_MEMORY_REDEFINE_NEW(ArrayBase) +// Redefine operator 'new' if necessary. +#if defined(OVR_DEFINE_NEW) +#define new OVR_DEFINE_NEW +#endif + + + ArrayBase() + : Data() {} + ArrayBase(size_t size) + : Data(size) {} + ArrayBase(const SelfType& a) + : Data(a.Data) {} + + ArrayBase(const ValueType& defval) + : Data(defval) {} + ArrayBase(const ValueType& defval, size_t size) + : Data(defval, size) {} + + SizePolicyType* GetSizePolicy() const { return Data.Policy; } + void SetSizePolicy(const SizePolicyType& p) { Data.Policy = p; } + + bool NeverShrinking()const { return Data.Policy.NeverShrinking(); } + size_t GetSize() const { return Data.Size; } + int GetSizeI() const { return (int)Data.Size; } + bool IsEmpty() const { return Data.Size == 0; } + size_t GetCapacity() const { return Data.GetCapacity(); } + size_t GetNumBytes() const { return Data.GetCapacity() * sizeof(ValueType); } + + void ClearAndRelease() { Data.ClearAndRelease(); } + void Clear() { Data.Resize(0); } + void Resize(size_t newSize) { Data.Resize(newSize); } + + // Reserve can only increase the capacity + void Reserve(size_t newCapacity) + { + if (newCapacity > Data.GetCapacity()) + Data.Reserve(newCapacity); + } + + // Basic access. + ValueType& At(size_t index) + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); // Asserting that Data.Data is valid helps static analysis tools. + return Data.Data[index]; + } + const ValueType& At(size_t index) const + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); + return Data.Data[index]; + } + + ValueType ValueAt(size_t index) const + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); + return Data.Data[index]; + } + + // Basic access. + ValueType& operator [] (size_t index) + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); + return Data.Data[index]; + } + const ValueType& operator [] (size_t index) const + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); + return Data.Data[index]; + } + + // Raw pointer to the data. Use with caution! + const ValueType* GetDataPtr() const { return Data.Data; } + ValueType* GetDataPtr() { return Data.Data; } + + // Insert the given element at the end of the array. + void PushBack(const ValueType& val) + { + // DO NOT pass elements of your own vector into + // push_back()! Since we're using references, + // resize() may munge the element storage! + // OVR_ASSERT(&val < &Buffer[0] || &val > &Buffer[BufferSize]); + Data.PushBack(val); + } + + template<class S> + void PushBackAlt(const S& val) + { + Data.PushBackAlt(val); + } + + // Remove the last element. + void PopBack(size_t count = 1) + { + OVR_ASSERT(Data.Size >= count); + Data.Resize(Data.Size - count); + } + + ValueType& PushDefault() + { + Data.PushBack(ValueType()); + return Back(); + } + + ValueType Pop() + { + OVR_ASSERT((Data.Data) && (Data.Size > 0)); + ValueType t = Back(); + PopBack(); + return t; + } + + + // Access the first element. + ValueType& Front() { return At(0); } + const ValueType& Front() const { return At(0); } + + // Access the last element. + ValueType& Back() { return At(Data.Size - 1); } + const ValueType& Back() const { return At(Data.Size - 1); } + + // Array copy. Copies the contents of a into this array. + const SelfType& operator = (const SelfType& a) + { + Resize(a.GetSize()); + OVR_ASSERT((Data.Data != NULL) || (Data.Size == 0)); + for (size_t i = 0; i < Data.Size; i++) { + *(Data.Data + i) = a[i]; + } + return *this; + } + + // Removing multiple elements from the array. + void RemoveMultipleAt(size_t index, size_t num) + { + OVR_ASSERT(index + num <= Data.Size); + if (Data.Size == num) + { + Clear(); + } + else + { + AllocatorType::DestructArray(Data.Data + index, num); + AllocatorType::CopyArrayForward( + Data.Data + index, + Data.Data + index + num, + Data.Size - num - index); + Data.Size -= num; + } + } + + // Removing an element from the array is an expensive operation! + // It compacts only after removing the last element. + // If order of elements in the array is not important then use + // RemoveAtUnordered, that could be much faster than the regular + // RemoveAt. + void RemoveAt(size_t index) + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); + if (Data.Size == 1) + { + Clear(); + } + else + { + AllocatorType::Destruct(Data.Data + index); + AllocatorType::CopyArrayForward( + Data.Data + index, + Data.Data + index + 1, + Data.Size - 1 - index); + --Data.Size; + } + } + + // Removes an element from the array without respecting of original order of + // elements for better performance. Do not use on array where order of elements + // is important, otherwise use it instead of regular RemoveAt(). + void RemoveAtUnordered(size_t index) + { + OVR_ASSERT((Data.Data) && (index < Data.Size)); + if (Data.Size == 1) + { + Clear(); + } + else + { + // copy the last element into the 'index' position + // and decrement the size (instead of moving all elements + // in [index + 1 .. size - 1] range). + const size_t lastElemIndex = Data.Size - 1; + if (index < lastElemIndex) + { + AllocatorType::Destruct(Data.Data + index); + AllocatorType::Construct(Data.Data + index, Data.Data[lastElemIndex]); + } + AllocatorType::Destruct(Data.Data + lastElemIndex); + --Data.Size; + } + } + + // Insert the given object at the given index shifting all the elements up. + void InsertAt(size_t index, const ValueType& val = ValueType()) + { + OVR_ASSERT(index <= Data.Size); + + Data.Resize(Data.Size + 1); + if (index < Data.Size - 1) + { + AllocatorType::CopyArrayBackward( + Data.Data + index + 1, + Data.Data + index, + Data.Size - 1 - index); + } + AllocatorType::Construct(Data.Data + index, val); + } + + // Insert the given object at the given index shifting all the elements up. + void InsertMultipleAt(size_t index, size_t num, const ValueType& val = ValueType()) + { + OVR_ASSERT(index <= Data.Size); + + Data.Resize(Data.Size + num); + if (index < Data.Size - num) + { + AllocatorType::CopyArrayBackward( + Data.Data + index + num, + Data.Data + index, + Data.Size - num - index); + } + for (size_t i = 0; i < num; ++i) + AllocatorType::Construct(Data.Data + index + i, val); + } + + // Append the given data to the array. + void Append(const SelfType& other) + { + Append(other.Data.Data, other.GetSize()); + } + + // Append the given data to the array. + void Append(const ValueType other[], size_t count) + { + Data.Append(other, count); + } + + class Iterator + { + SelfType* pArray; + intptr_t CurIndex; + + public: + Iterator() : pArray(0), CurIndex(-1) {} + Iterator(SelfType* parr, intptr_t idx = 0) : pArray(parr), CurIndex(idx) {} + + bool operator==(const Iterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; } + bool operator!=(const Iterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; } + + Iterator& operator++() + { + if (pArray) + { + if (CurIndex < (intptr_t)pArray->GetSize()) + ++CurIndex; + } + return *this; + } + Iterator operator++(int) + { + Iterator it(*this); + operator++(); + return it; + } + Iterator& operator--() + { + if (pArray) + { + if (CurIndex >= 0) + --CurIndex; + } + return *this; + } + Iterator operator--(int) + { + Iterator it(*this); + operator--(); + return it; + } + Iterator operator+(int delta) const + { + return Iterator(pArray, CurIndex + delta); + } + Iterator operator-(int delta) const + { + return Iterator(pArray, CurIndex - delta); + } + intptr_t operator-(const Iterator& right) const + { + OVR_ASSERT(pArray == right.pArray); + return CurIndex - right.CurIndex; + } + ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; } + ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; } + ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; } + + bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); } + + void Remove() + { + if (!IsFinished()) + pArray->RemoveAt(CurIndex); + } + + intptr_t GetIndex() const { return CurIndex; } + }; + + Iterator Begin() { return Iterator(this); } + Iterator End() { return Iterator(this, (intptr_t)GetSize()); } + Iterator Last() { return Iterator(this, (intptr_t)GetSize() - 1); } + + class ConstIterator + { + const SelfType* pArray; + intptr_t CurIndex; + + public: + ConstIterator() : pArray(0), CurIndex(-1) {} + ConstIterator(const SelfType* parr, intptr_t idx = 0) : pArray(parr), CurIndex(idx) {} + + bool operator==(const ConstIterator& it) const { return pArray == it.pArray && CurIndex == it.CurIndex; } + bool operator!=(const ConstIterator& it) const { return pArray != it.pArray || CurIndex != it.CurIndex; } + + ConstIterator& operator++() + { + if (pArray) + { + if (CurIndex < (int)pArray->GetSize()) + ++CurIndex; + } + return *this; + } + ConstIterator operator++(int) + { + ConstIterator it(*this); + operator++(); + return it; + } + ConstIterator& operator--() + { + if (pArray) + { + if (CurIndex >= 0) + --CurIndex; + } + return *this; + } + ConstIterator operator--(int) + { + ConstIterator it(*this); + operator--(); + return it; + } + ConstIterator operator+(int delta) const + { + return ConstIterator(pArray, CurIndex + delta); + } + ConstIterator operator-(int delta) const + { + return ConstIterator(pArray, CurIndex - delta); + } + intptr_t operator-(const ConstIterator& right) const + { + OVR_ASSERT(pArray == right.pArray); + return CurIndex - right.CurIndex; + } + const ValueType& operator*() const { OVR_ASSERT(pArray); return (*pArray)[CurIndex]; } + const ValueType* operator->() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; } + const ValueType* GetPtr() const { OVR_ASSERT(pArray); return &(*pArray)[CurIndex]; } + + bool IsFinished() const { return !pArray || CurIndex < 0 || CurIndex >= (int)pArray->GetSize(); } + + intptr_t GetIndex() const { return CurIndex; } + }; + ConstIterator Begin() const { return ConstIterator(this); } + ConstIterator End() const { return ConstIterator(this, (intptr_t)GetSize()); } + ConstIterator Last() const { return ConstIterator(this, (intptr_t)GetSize() - 1); } + +protected: + ArrayData Data; +}; + + + +//----------------------------------------------------------------------------------- +// ***** Array +// +// General purpose array for movable objects that require explicit +// construction/destruction. +template<class T, class SizePolicy=ArrayDefaultPolicy> +class Array : public ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> > +{ +public: + typedef T ValueType; + typedef ContainerAllocator<T> AllocatorType; + typedef SizePolicy SizePolicyType; + typedef Array<T, SizePolicy> SelfType; + typedef ArrayBase<ArrayData<T, ContainerAllocator<T>, SizePolicy> > BaseType; + + Array() : BaseType() {} + explicit Array(size_t size) : BaseType(size) {} + Array(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); } + Array(const SelfType& a) : BaseType(a) {} + const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; } +}; + +// ***** ArrayPOD +// +// General purpose array for movable objects that DOES NOT require +// construction/destruction. Constructors and destructors are not called! +// Global heap is in use. +template<class T, class SizePolicy=ArrayDefaultPolicy> +class ArrayPOD : public ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> > +{ +public: + typedef T ValueType; + typedef ContainerAllocator_POD<T> AllocatorType; + typedef SizePolicy SizePolicyType; + typedef ArrayPOD<T, SizePolicy> SelfType; + typedef ArrayBase<ArrayData<T, ContainerAllocator_POD<T>, SizePolicy> > BaseType; + + ArrayPOD() : BaseType() {} + explicit ArrayPOD(size_t size) : BaseType(size) {} + ArrayPOD(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); } + ArrayPOD(const SelfType& a) : BaseType(a) {} + const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; } +}; + + +// ***** ArrayCPP +// +// General purpose, fully C++ compliant array. Can be used with non-movable data. +// Global heap is in use. +template<class T, class SizePolicy=ArrayDefaultPolicy> +class ArrayCPP : public ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> > +{ +public: + typedef T ValueType; + typedef ContainerAllocator_CPP<T> AllocatorType; + typedef SizePolicy SizePolicyType; + typedef ArrayCPP<T, SizePolicy> SelfType; + typedef ArrayBase<ArrayData<T, ContainerAllocator_CPP<T>, SizePolicy> > BaseType; + + ArrayCPP() : BaseType() {} + explicit ArrayCPP(size_t size) : BaseType(size) {} + ArrayCPP(const SizePolicyType& p) : BaseType() { SetSizePolicy(p); } + ArrayCPP(const SelfType& a) : BaseType(a) {} + const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; } +}; + + +// ***** ArrayCC +// +// A modification of the array that uses the given default value to +// construct the elements. The constructors and destructors are +// properly called, the objects must be movable. + +template<class T, class SizePolicy=ArrayDefaultPolicy> +class ArrayCC : public ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> > +{ +public: + typedef T ValueType; + typedef ContainerAllocator<T> AllocatorType; + typedef SizePolicy SizePolicyType; + typedef ArrayCC<T, SizePolicy> SelfType; + typedef ArrayBase<ArrayDataCC<T, ContainerAllocator<T>, SizePolicy> > BaseType; + + ArrayCC(const ValueType& defval) : BaseType(defval) {} + ArrayCC(const ValueType& defval, size_t size) : BaseType(defval, size) {} + ArrayCC(const ValueType& defval, const SizePolicyType& p) : BaseType(defval) { SetSizePolicy(p); } + ArrayCC(const SelfType& a) : BaseType(a) {} + const SelfType& operator=(const SelfType& a) { BaseType::operator=(a); return *this; } +}; + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Atomic.cpp b/LibOVRKernel/Src/Kernel/OVR_Atomic.cpp new file mode 100644 index 0000000..f7cf9a6 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Atomic.cpp @@ -0,0 +1,139 @@ +/************************************************************************************ + +Filename : OVR_Atomic.cpp +Content : Contains atomic operations and inline fastest locking + functionality. Will contain #ifdefs for OS efficiency. + Have non-thread-safe implementation if not available. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Atomic.h" +#include "OVR_Allocator.h" + +#ifdef OVR_ENABLE_THREADS + +// Include Windows 8-Metro compatible Synchronization API +#if defined(OVR_OS_MS) && defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8) +#include <synchapi.h> +#endif + + +namespace OVR { + +// ***** Windows Lock implementation + +#if defined(OVR_OS_MS) + +// ***** Standard Win32 Lock implementation + +// Constructors +Lock::Lock(unsigned spinCount) +{ + #if defined(NTDDI_WIN8) && (NTDDI_VERSION >= NTDDI_WIN8) + // On Windows 8 we use InitializeCriticalSectionEx due to Metro-Compatibility + InitializeCriticalSectionEx(&cs, (DWORD)spinCount, + OVR_DEBUG_SELECT(NULL, CRITICAL_SECTION_NO_DEBUG_INFO)); + #else + ::InitializeCriticalSectionAndSpinCount(&cs, (DWORD)spinCount); // This is available with WindowsXP+. + #endif +} + + +Lock::~Lock() +{ + DeleteCriticalSection(&cs); +} + + +#endif + + +//------------------------------------------------------------------------------------- +// ***** SharedLock + +// This is a general purpose globally shared Lock implementation that should probably be +// moved to Kernel. +// May in theory busy spin-wait if we hit contention on first lock creation, +// but this shouldn't matter in practice since Lock* should be cached. + + +enum { LockInitMarker = 0xFFFFFFFF }; + +Lock* SharedLock::GetLockAddRef() +{ + int oldUseCount; + + do { + oldUseCount = UseCount; + if (oldUseCount == (int)LockInitMarker) + continue; + + if (oldUseCount == 0) + { + // Initialize marker + if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 0, LockInitMarker)) + { + Construct<Lock>(Buffer); + do { } + while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 1)); + return toLock(); + } + continue; + } + + } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount + 1)); + + return toLock(); +} + +void SharedLock::ReleaseLock(Lock* plock) +{ + OVR_UNUSED(plock); + OVR_ASSERT(plock == toLock()); + + int oldUseCount; + + do { + oldUseCount = UseCount; + OVR_ASSERT(oldUseCount != (int)LockInitMarker); + + if (oldUseCount == 1) + { + // Initialize marker + if (AtomicOps<int>::CompareAndSet_Sync(&UseCount, 1, LockInitMarker)) + { + Destruct<Lock>(toLock()); + + do { } + while (!AtomicOps<int>::CompareAndSet_Sync(&UseCount, LockInitMarker, 0)); + + return; + } + continue; + } + + } while (!AtomicOps<int>::CompareAndSet_NoSync(&UseCount, oldUseCount, oldUseCount - 1)); +} + +} // OVR + +#endif // OVR_ENABLE_THREADS diff --git a/LibOVRKernel/Src/Kernel/OVR_Atomic.h b/LibOVRKernel/Src/Kernel/OVR_Atomic.h new file mode 100644 index 0000000..0606157 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Atomic.h @@ -0,0 +1,912 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Atomic.h +Content : Contains atomic operations and inline fastest locking + functionality. Will contain #ifdefs for OS efficiency. + Have non-thread-safe implementaion if not available. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Atomic_h +#define OVR_Atomic_h + +#include "OVR_Types.h" + +// Include System thread functionality. +#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE) +#include "OVR_Win32_IncludeWindows.h" +#else +#include <pthread.h> +#endif + +#ifdef OVR_CC_MSVC +#include <intrin.h> +#pragma intrinsic(_ReadBarrier, _WriteBarrier, _ReadWriteBarrier) +#endif + +namespace OVR { + + +// ****** Declared classes + +// If there is NO thread support we implement AtomicOps and +// Lock objects as no-ops. The other classes are not defined. +template<class C> class AtomicOps; +template<class T> class AtomicInt; +template<class T> class AtomicPtr; + +class Lock; + + +//----------------------------------------------------------------------------------- +// ***** AtomicOps + +// Atomic operations are provided by the AtomicOps templates class, +// implemented through system-specific AtomicOpsRaw specializations. +// It provides several fundamental operations such as Exchange, ExchangeAdd +// CompareAndSet, and Store_Release. Each function includes several memory +// synchronization versions, important for multiprocessing CPUs with weak +// memory consistency. The following memory fencing strategies are supported: +// +// - NoSync. No memory synchronization is done for atomic op. +// - Release. All other memory writes are completed before atomic op +// writes its results. +// - Acquire. Further memory reads are forced to wait until atomic op +// executes, guaranteeing that the right values will be seen. +// - Sync. A combination of Release and Acquire. + + +// *** AtomicOpsRaw + +// AtomicOpsRaw is a specialized template that provides atomic operations +// used by AtomicOps. This class has two fundamental qualities: (1) it +// defines a type T of correct size, and (2) provides operations that work +// atomically, such as Exchange_Sync and CompareAndSet_Release. + +// AtomicOpsRawBase class contains shared constants/classes for AtomicOpsRaw. +// The primary thing is does is define sync class objects, whose destructor and +// constructor provide places to insert appropriate synchronization calls, on +// systems where such calls are necessary. So far, the breakdown is as follows: +// +// - X86 systems don't need custom syncs, since their exchange/atomic +// instructions are implicitly synchronized. +// - PowerPC requires lwsync/isync instructions that can use this mechanism. +// - If some other systems require a mechanism where syncing type is associated +// with a particular instruction, the default implementation (which implements +// all Sync, Acquire, and Release modes in terms of NoSync and fence) may not +// work. Ii that case it will need to be #ifdef-ed conditionally. + +struct AtomicOpsRawBase +{ +#if !defined(OVR_ENABLE_THREADS) || defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + // Need to have empty constructor to avoid class 'unused' variable warning. + struct FullSync { inline FullSync() { } }; + struct AcquireSync { inline AcquireSync() { } }; + struct ReleaseSync { inline ReleaseSync() { } }; + +#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC) + struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("isync\n"); } }; + struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("isync\n"); } }; + struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } }; + +#elif defined(OVR_CPU_MIPS) + struct FullSync { inline FullSync() { asm volatile("sync\n"); } ~FullSync() { asm volatile("sync\n"); } }; + struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("sync\n"); } }; + struct ReleaseSync { inline ReleaseSync() { asm volatile("sync\n"); } }; + +#elif defined(OVR_CPU_ARM) // Includes Android and iOS. + struct FullSync { inline FullSync() { asm volatile("dmb\n"); } ~FullSync() { asm volatile("dmb\n"); } }; + struct AcquireSync { inline AcquireSync() { } ~AcquireSync() { asm volatile("dmb\n"); } }; + struct ReleaseSync { inline ReleaseSync() { asm volatile("dmb\n"); } }; + +#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4) + // __sync functions are already full sync + struct FullSync { inline FullSync() { } }; + struct AcquireSync { inline AcquireSync() { } }; + struct ReleaseSync { inline ReleaseSync() { } }; +#endif +}; + + +// 4-Byte raw data atomic op implementation class. +struct AtomicOpsRaw_4ByteImpl : public AtomicOpsRawBase +{ +#if !defined(OVR_ENABLE_THREADS) + + // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl. + typedef uint32_t T; + + // *** Thread - Safe Atomic Versions. + +#elif defined(OVR_OS_MS) + + // Use special defined for VC6, where volatile is not used and + // InterlockedCompareExchange is declared incorrectly. + typedef LONG T; +#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC < 1300) + typedef T* InterlockTPtr; + typedef LPVOID ET; + typedef ET* InterlockETPtr; +#else + typedef volatile T* InterlockTPtr; + typedef T ET; + typedef InterlockTPtr InterlockETPtr; +#endif + inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange((InterlockTPtr)p, val); } + inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd((InterlockTPtr)p, val); } + inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange((InterlockETPtr)p, (ET)val, (ET)c) == (ET)c; } + +#elif defined(OVR_CPU_PPC64) || defined(OVR_CPU_PPC) + typedef uint32_t T; + static inline uint32_t Exchange_NoSync(volatile uint32_t *i, uint32_t j) + { + uint32_t ret; + + asm volatile("1:\n\t" + "lwarx %[r],0,%[i]\n\t" + "stwcx. %[j],0,%[i]\n\t" + "bne- 1b\n" + : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [j] "b" (j) : "cc", "memory"); + + return ret; + } + + static inline uint32_t ExchangeAdd_NoSync(volatile uint32_t *i, uint32_t j) + { + uint32_t dummy, ret; + + asm volatile("1:\n\t" + "lwarx %[r],0,%[i]\n\t" + "add %[o],%[r],%[j]\n\t" + "stwcx. %[o],0,%[i]\n\t" + "bne- 1b\n" + : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc", "memory"); + + return ret; + } + + static inline bool CompareAndSet_NoSync(volatile uint32_t *i, uint32_t c, uint32_t value) + { + uint32_t ret; + + asm volatile("1:\n\t" + "lwarx %[r],0,%[i]\n\t" + "cmpw 0,%[r],%[cmp]\n\t" + "mfcr %[r]\n\t" + "bne- 2f\n\t" + "stwcx. %[val],0,%[i]\n\t" + "bne- 1b\n\t" + "2:\n" + : "+m" (*i), [r] "=&b" (ret) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc", "memory"); + + return (ret & 0x20000000) ? 1 : 0; + } + +#elif defined(OVR_CPU_MIPS) + typedef uint32_t T; + + static inline uint32_t Exchange_NoSync(volatile uint32_t *i, uint32_t j) + { + uint32_t ret; + + asm volatile("1:\n\t" + "ll %[r],0(%[i])\n\t" + "sc %[j],0(%[i])\n\t" + "beq %[j],$0,1b\n\t" + "nop \n" + : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory"); + + return ret; + } + + static inline uint32_t ExchangeAdd_NoSync(volatile uint32_t *i, uint32_t j) + { + uint32_t ret; + + asm volatile("1:\n\t" + "ll %[r],0(%[i])\n\t" + "addu %[j],%[r],%[j]\n\t" + "sc %[j],0(%[i])\n\t" + "beq %[j],$0,1b\n\t" + "nop \n" + : "+m" (*i), [r] "=&d" (ret) : [i] "d" (i), [j] "d" (j) : "cc", "memory"); + + return ret; + } + + static inline bool CompareAndSet_NoSync(volatile uint32_t *i, uint32_t c, uint32_t value) + { + uint32_t ret, dummy; + + asm volatile("1:\n\t" + "move %[r],$0\n\t" + "ll %[o],0(%[i])\n\t" + "bne %[o],%[c],2f\n\t" + "move %[r],%[v]\n\t" + "sc %[r],0(%[i])\n\t" + "beq %[r],$0,1b\n\t" + "nop \n\t" + "2:\n" + : "+m" (*i),[r] "=&d" (ret), [o] "=&d" (dummy) : [i] "d" (i), [c] "d" (c), [v] "d" (value) + : "cc", "memory"); + + return ret; + } + +#elif defined(OVR_CPU_ARM) && defined(OVR_CC_ARM) + typedef uint32_t T; + + static inline uint32_t Exchange_NoSync(volatile uint32_t *i, uint32_t j) + { + for(;;) + { + T r = __ldrex(i); + if (__strex(j, i) == 0) + return r; + } + } + static inline uint32_t ExchangeAdd_NoSync(volatile uint32_t *i, uint32_t j) + { + for(;;) + { + T r = __ldrex(i); + if (__strex(r + j, i) == 0) + return r; + } + } + + static inline bool CompareAndSet_NoSync(volatile uint32_t *i, uint32_t c, uint32_t value) + { + for(;;) + { + T r = __ldrex(i); + if (r != c) + return 0; + if (__strex(value, i) == 0) + return 1; + } + } + +#elif defined(OVR_CPU_ARM) + typedef uint32_t T; + + static inline uint32_t Exchange_NoSync(volatile uint32_t *i, uint32_t j) + { + uint32_t ret, dummy; + + asm volatile("1:\n\t" + "ldrex %[r],[%[i]]\n\t" + "strex %[t],%[j],[%[i]]\n\t" + "cmp %[t],#0\n\t" + "bne 1b\n\t" + : "+m" (*i), [r] "=&r" (ret), [t] "=&r" (dummy) : [i] "r" (i), [j] "r" (j) : "cc", "memory"); + + return ret; + } + + static inline uint32_t ExchangeAdd_NoSync(volatile uint32_t *i, uint32_t j) + { + uint32_t ret, dummy, test; + + asm volatile("1:\n\t" + "ldrex %[r],[%[i]]\n\t" + "add %[o],%[r],%[j]\n\t" + "strex %[t],%[o],[%[i]]\n\t" + "cmp %[t],#0\n\t" + "bne 1b\n\t" + : "+m" (*i), [r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [j] "r" (j) : "cc", "memory"); + + return ret; + } + + static inline bool CompareAndSet_NoSync(volatile uint32_t *i, uint32_t c, uint32_t value) + { + uint32_t ret = 1, dummy, test; + + asm volatile("1:\n\t" + "ldrex %[o],[%[i]]\n\t" + "cmp %[o],%[c]\n\t" + "bne 2f\n\t" + "strex %[r],%[v],[%[i]]\n\t" + "cmp %[r],#0\n\t" + "bne 1b\n\t" + "2:\n" + : "+m" (*i),[r] "=&r" (ret), [o] "=&r" (dummy), [t] "=&r" (test) : [i] "r" (i), [c] "r" (c), [v] "r" (value) + : "cc", "memory"); + + return !ret; + } + +#elif defined(OVR_CPU_X86) + typedef uint32_t T; + + static inline uint32_t Exchange_NoSync(volatile uint32_t *i, uint32_t j) + { + asm volatile("xchgl %1,%[i]\n" + : "+m" (*i), "=q" (j) : [i] "m" (*i), "1" (j) : "cc", "memory"); + + return j; + } + + static inline uint32_t ExchangeAdd_NoSync(volatile uint32_t *i, uint32_t j) + { + asm volatile("lock; xaddl %1,%[i]\n" + : "+m" (*i), "+q" (j) : [i] "m" (*i) : "cc", "memory"); + + return j; + } + + static inline bool CompareAndSet_NoSync(volatile uint32_t *i, uint32_t c, uint32_t value) + { + uint32_t ret; + + asm volatile("lock; cmpxchgl %[v],%[i]\n" + : "+m" (*i), "=a" (ret) : [i] "m" (*i), "1" (c), [v] "q" (value) : "cc", "memory"); + + return (ret == c); + } + +#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1) + + typedef uint32_t T; + + static inline T Exchange_NoSync(volatile T *i, T j) + { + T v; + do { + v = *i; + } while (!__sync_bool_compare_and_swap(i, v, j)); + return v; + } + + static inline T ExchangeAdd_NoSync(volatile T *i, T j) + { + return __sync_fetch_and_add(i, j); + } + + static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value) + { + return __sync_bool_compare_and_swap(i, c, value); + } + +#endif // OS +}; + + +// 8-Byte raw data data atomic op implementation class. +// Currently implementation is provided only on systems with 64-bit pointers. +struct AtomicOpsRaw_8ByteImpl : public AtomicOpsRawBase +{ +#if !defined(OVR_64BIT_POINTERS) || !defined(OVR_ENABLE_THREADS) + + // Provide a type for no-thread-support cases. Used by AtomicOpsRaw_DefImpl. + typedef uint64_t T; + + // *** Thread - Safe OS specific versions. +#elif defined(OVR_OS_MS) + + // This is only for 64-bit systems. + typedef LONG64 T; + typedef volatile T* InterlockTPtr; + inline static T Exchange_NoSync(volatile T* p, T val) { return InterlockedExchange64((InterlockTPtr)p, val); } + inline static T ExchangeAdd_NoSync(volatile T* p, T val) { return InterlockedExchangeAdd64((InterlockTPtr)p, val); } + inline static bool CompareAndSet_NoSync(volatile T* p, T c, T val) { return InterlockedCompareExchange64((InterlockTPtr)p, val, c) == c; } + +#elif defined(OVR_CPU_PPC64) + + typedef uint64_t T; + + static inline uint64_t Exchange_NoSync(volatile uint64_t *i, uint64_t j) + { + uint64_t dummy, ret; + + asm volatile("1:\n\t" + "ldarx %[r],0,%[i]\n\t" + "mr %[o],%[j]\n\t" + "stdcx. %[o],0,%[i]\n\t" + "bne- 1b\n" + : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc"); + + return ret; + } + + static inline uint64_t ExchangeAdd_NoSync(volatile uint64_t *i, uint64_t j) + { + uint64_t dummy, ret; + + asm volatile("1:\n\t" + "ldarx %[r],0,%[i]\n\t" + "add %[o],%[r],%[j]\n\t" + "stdcx. %[o],0,%[i]\n\t" + "bne- 1b\n" + : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [j] "b" (j) : "cc"); + + return ret; + } + + static inline bool CompareAndSet_NoSync(volatile uint64_t *i, uint64_t c, uint64_t value) + { + uint64_t ret, dummy; + + asm volatile("1:\n\t" + "ldarx %[r],0,%[i]\n\t" + "cmpw 0,%[r],%[cmp]\n\t" + "mfcr %[r]\n\t" + "bne- 2f\n\t" + "stdcx. %[val],0,%[i]\n\t" + "bne- 1b\n\t" + "2:\n" + : "+m" (*i), [r] "=&b" (ret), [o] "=&r" (dummy) : [i] "b" (i), [cmp] "b" (c), [val] "b" (value) : "cc"); + + return (ret & 0x20000000) ? 1 : 0; + } + +#elif defined(OVR_CC_GNU) && (__GNUC__ >= 4 && __GNUC_MINOR__ >= 1) + + typedef uint64_t T; + + static inline T Exchange_NoSync(volatile T *i, T j) + { + T v; + do { + v = *i; + } while (!__sync_bool_compare_and_swap(i, v, j)); + return v; + } + + static inline T ExchangeAdd_NoSync(volatile T *i, T j) + { + return __sync_fetch_and_add(i, j); + } + + static inline bool CompareAndSet_NoSync(volatile T *i, T c, T value) + { + return __sync_bool_compare_and_swap(i, c, value); + } + +#endif // OS +}; + + +// Default implementation for AtomicOpsRaw; provides implementation of mem-fenced +// atomic operations where fencing is done with a sync object wrapped around a NoSync +// operation implemented in the base class. If such implementation is not possible +// on a given platform, #ifdefs can be used to disable it and then op functions can be +// implemented individually in the appropriate AtomicOpsRaw<size> class. + +template<class O> +struct AtomicOpsRaw_DefImpl : public O +{ + typedef typename O::T O_T; + typedef typename O::FullSync O_FullSync; + typedef typename O::AcquireSync O_AcquireSync; + typedef typename O::ReleaseSync O_ReleaseSync; + + // If there is no thread support, provide the default implementation. In this case, + // the base class (0) must still provide the T declaration. +#ifndef OVR_ENABLE_THREADS + + // Atomic exchange of val with argument. Returns old val. + inline static O_T Exchange_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p = val; return old; } + // Adds a new val to argument; returns its old val. + inline static O_T ExchangeAdd_NoSync(volatile O_T* p, O_T val) { O_T old = *p; *p += val; return old; } + // Compares the argument data with 'c' val. + // If succeeded, stores val int '*p' and returns true; otherwise returns false. + inline static bool CompareAndSet_NoSync(volatile O_T* p, O_T c, O_T val) { if (*p==c) { *p = val; return 1; } return 0; } + +#endif + + // If NoSync wrapped implementation may not be possible, it this block should be + // replaced with per-function implementation in O. + // "AtomicOpsRaw_DefImpl<O>::" prefix in calls below. + inline static O_T Exchange_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); } + inline static O_T Exchange_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); } + inline static O_T Exchange_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::Exchange_NoSync(p, val); } + inline static O_T ExchangeAdd_Sync(volatile O_T* p, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); } + inline static O_T ExchangeAdd_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); } + inline static O_T ExchangeAdd_Acquire(volatile O_T* p, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::ExchangeAdd_NoSync(p, val); } + inline static bool CompareAndSet_Sync(volatile O_T* p, O_T c, O_T val) { O_FullSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); } + inline static bool CompareAndSet_Release(volatile O_T* p, O_T c, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); } + inline static bool CompareAndSet_Acquire(volatile O_T* p, O_T c, O_T val) { O_AcquireSync sync; OVR_UNUSED(sync); return AtomicOpsRaw_DefImpl<O>::CompareAndSet_NoSync(p,c,val); } + + // Loads and stores with memory fence. These have only the relevant versions. +#ifdef OVR_CPU_X86 + // On X86, Store_Release is implemented as exchange. Note that we can also + // consider 'sfence' in the future, although it is not as compatible with older CPUs. + inline static void Store_Release(volatile O_T* p, O_T val) { Exchange_Release(p, val); } +#else + inline static void Store_Release(volatile O_T* p, O_T val) { O_ReleaseSync sync; OVR_UNUSED(sync); *p = val; } +#endif + inline static O_T Load_Acquire(const volatile O_T* p) + { + O_AcquireSync sync; + OVR_UNUSED(sync); + +#if defined(OVR_CC_MSVC) + _ReadBarrier(); // Compiler fence and load barrier +#elif defined(OVR_CC_INTEL) + __memory_barrier(); // Compiler fence +#else + // GCC-compatible: + asm volatile ("" : : : "memory"); // Compiler fence +#endif + + return *p; + } +}; + + +template<int size> +struct AtomicOpsRaw : public AtomicOpsRawBase { }; + +template<> +struct AtomicOpsRaw<4> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl> +{ + // Ensure that assigned type size is correct. + AtomicOpsRaw() + { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_4ByteImpl>::T) == 4); } +}; +template<> +struct AtomicOpsRaw<8> : public AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl> +{ + AtomicOpsRaw() + { OVR_COMPILER_ASSERT(sizeof(AtomicOpsRaw_DefImpl<AtomicOpsRaw_8ByteImpl>::T) == 8); } +}; + + +// *** AtomicOps - implementation of atomic Ops for specified class + +// Implements atomic ops on a class, provided that the object is either +// 4 or 8 bytes in size (depending on the AtomicOpsRaw specializations +// available). Relies on AtomicOpsRaw for much of implementation. + +template<class C> +class AtomicOps +{ + typedef AtomicOpsRaw<sizeof(C)> Ops; + typedef typename Ops::T T; + typedef volatile typename Ops::T* PT; + // We cast through unions to (1) avoid pointer size compiler warnings + // and (2) ensure that there are no problems with strict pointer aliasing. + union C2T_union { C c; T t; }; + +public: + // General purpose implementation for standard syncs. + inline static C Exchange_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Sync((PT)p, u.t); return u.c; } + inline static C Exchange_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Release((PT)p, u.t); return u.c; } + inline static C Exchange_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_Acquire((PT)p, u.t); return u.c; } + inline static C Exchange_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::Exchange_NoSync((PT)p, u.t); return u.c; } + inline static C ExchangeAdd_Sync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Sync((PT)p, u.t); return u.c; } + inline static C ExchangeAdd_Release(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Release((PT)p, u.t); return u.c; } + inline static C ExchangeAdd_Acquire(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_Acquire((PT)p, u.t); return u.c; } + inline static C ExchangeAdd_NoSync(volatile C* p, C val) { C2T_union u; u.c = val; u.t = Ops::ExchangeAdd_NoSync((PT)p, u.t); return u.c; } + inline static bool CompareAndSet_Sync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Sync((PT)p, cu.t, u.t); } + inline static bool CompareAndSet_Release(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Release((PT)p, cu.t, u.t); } + inline static bool CompareAndSet_Acquire(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); } + inline static bool CompareAndSet_NoSync(volatile C* p, C c, C val) { C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_NoSync((PT)p, cu.t, u.t); } + + // Loads and stores with memory fence. These have only the relevant versions. + inline static void Store_Release(volatile C* p, C val) { C2T_union u; u.c = val; Ops::Store_Release((PT)p, u.t); } + inline static C Load_Acquire(const volatile C* p) { C2T_union u; u.t = Ops::Load_Acquire((PT)p); return u.c; } + + // Deprecated typo error: + inline static bool CompareAndSet_Relse(volatile C* p, C c, C val){ C2T_union u,cu; u.c = val; cu.c = c; return Ops::CompareAndSet_Acquire((PT)p, cu.t, u.t); } +}; + + + +// Atomic value base class - implements operations shared for integers and pointers. +template<class T> +class AtomicValueBase +{ +protected: + typedef AtomicOps<T> Ops; +public: + + volatile T Value; + + inline AtomicValueBase() { } + explicit inline AtomicValueBase(T val) { Ops::Store_Release(&Value, val); } + + // Most libraries (TBB and Joshua Scholar's) library do not do Load_Acquire + // here, since most algorithms do not require atomic loads. Needs some research. + inline operator T() const { return Value; } + + // *** Standard Atomic inlines + inline T Exchange_Sync(T val) { return Ops::Exchange_Sync(&Value, val); } + inline T Exchange_Release(T val) { return Ops::Exchange_Release(&Value, val); } + inline T Exchange_Acquire(T val) { return Ops::Exchange_Acquire(&Value, val); } + inline T Exchange_NoSync(T val) { return Ops::Exchange_NoSync(&Value, val); } + inline bool CompareAndSet_Sync(T c, T val) { return Ops::CompareAndSet_Sync(&Value, c, val); } + inline bool CompareAndSet_Release(T c, T val) { return Ops::CompareAndSet_Release(&Value, c, val); } + inline bool CompareAndSet_Acquire(T c, T val) { return Ops::CompareAndSet_Acquire(&Value, c, val); } + inline bool CompareAndSet_NoSync(T c, T val) { return Ops::CompareAndSet_NoSync(&Value, c, val); } + // Load & Store. + inline void Store_Release(T val) { Ops::Store_Release(&Value, val); } + inline T Load_Acquire() const { return Ops::Load_Acquire(&Value); } +}; + + +// ***** AtomicPtr - Atomic pointer template + +// This pointer class supports atomic assignments with release, +// increment / decrement operations, and conditional compare + set. + +template<class T> +class AtomicPtr : public AtomicValueBase<T*> +{ + typedef typename AtomicValueBase<T*>::Ops Ops; + +public: + // Initialize pointer value to 0 by default; use Store_Release only with explicit constructor. + inline AtomicPtr() : AtomicValueBase<T*>() { this->Value = 0; } + explicit inline AtomicPtr(T* val) : AtomicValueBase<T*>(val) { } + + // Pointer access. + inline T* operator -> () const { return this->Load_Acquire(); } + + // It looks like it is convenient to have Load_Acquire characteristics + // for this, since that is convenient for algorithms such as linked + // list traversals that can be added to bu another thread. + inline operator T* () const { return this->Load_Acquire(); } + + + // *** Standard Atomic inlines (applicable to pointers) + + // ExhangeAdd considers pointer size for pointers. + template<class I> + inline T* ExchangeAdd_Sync(I incr) { return Ops::ExchangeAdd_Sync(&this->Value, ((T*)0) + incr); } + template<class I> + inline T* ExchangeAdd_Release(I incr) { return Ops::ExchangeAdd_Release(&this->Value, ((T*)0) + incr); } + template<class I> + inline T* ExchangeAdd_Acquire(I incr) { return Ops::ExchangeAdd_Acquire(&this->Value, ((T*)0) + incr); } + template<class I> + inline T* ExchangeAdd_NoSync(I incr) { return Ops::ExchangeAdd_NoSync(&this->Value, ((T*)0) + incr); } + + // *** Atomic Operators + + inline T* operator = (T* val) { this->Store_Release(val); return val; } + + template<class I> + inline T* operator += (I val) { return ExchangeAdd_Sync(val) + val; } + template<class I> + inline T* operator -= (I val) { return operator += (-val); } + + inline T* operator ++ () { return ExchangeAdd_Sync(1) + 1; } + inline T* operator -- () { return ExchangeAdd_Sync(-1) - 1; } + inline T* operator ++ (int) { return ExchangeAdd_Sync(1); } + inline T* operator -- (int) { return ExchangeAdd_Sync(-1); } +}; + + +// ***** AtomicInt - Atomic integer template + +// Implements an atomic integer type; the exact type to use is provided +// as an argument. Supports atomic Acquire / Release semantics, atomic +// arithmetic operations, and atomic conditional compare + set. + +template<class T> +class AtomicInt : public AtomicValueBase<T> +{ + typedef typename AtomicValueBase<T>::Ops Ops; + +public: + inline AtomicInt() : AtomicValueBase<T>() { } + explicit inline AtomicInt(T val) : AtomicValueBase<T>(val) { } + + + // *** Standard Atomic inlines (applicable to int) + inline T ExchangeAdd_Sync(T val) { return Ops::ExchangeAdd_Sync(&this->Value, val); } + inline T ExchangeAdd_Release(T val) { return Ops::ExchangeAdd_Release(&this->Value, val); } + inline T ExchangeAdd_Acquire(T val) { return Ops::ExchangeAdd_Acquire(&this->Value, val); } + inline T ExchangeAdd_NoSync(T val) { return Ops::ExchangeAdd_NoSync(&this->Value, val); } + // These increments could be more efficient because they don't return a value. + inline void Increment_Sync() { ExchangeAdd_Sync((T)1); } + inline void Increment_Release() { ExchangeAdd_Release((T)1); } + inline void Increment_Acquire() { ExchangeAdd_Acquire((T)1); } + inline void Increment_NoSync() { ExchangeAdd_NoSync((T)1); } + + // *** Atomic Operators + + inline T operator = (T val) { this->Store_Release(val); return val; } + inline T operator += (T val) { return ExchangeAdd_Sync(val) + val; } + inline T operator -= (T val) { return ExchangeAdd_Sync(0 - val) - val; } + + inline T operator ++ () { return ExchangeAdd_Sync((T)1) + 1; } + inline T operator -- () { return ExchangeAdd_Sync(((T)0)-1) - 1; } + inline T operator ++ (int) { return ExchangeAdd_Sync((T)1); } + inline T operator -- (int) { return ExchangeAdd_Sync(((T)0)-1); } + + // More complex atomic operations. Leave it to compiler whether to optimize them or not. + T operator &= (T arg) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp & arg; + } while(!this->CompareAndSet_Sync(comp, newVal)); + return newVal; + } + + T operator |= (T arg) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp | arg; + } while(!this->CompareAndSet_Sync(comp, newVal)); + return newVal; + } + + T operator ^= (T arg) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp ^ arg; + } while(!this->CompareAndSet_Sync(comp, newVal)); + return newVal; + } + + T operator *= (T arg) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp * arg; + } while(!this->CompareAndSet_Sync(comp, newVal)); + return newVal; + } + + T operator /= (T arg) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp / arg; + } while(!CompareAndSet_Sync(comp, newVal)); + return newVal; + } + + T operator >>= (unsigned bits) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp >> bits; + } while(!CompareAndSet_Sync(comp, newVal)); + return newVal; + } + + T operator <<= (unsigned bits) + { + T comp, newVal; + do { + comp = this->Value; + newVal = comp << bits; + } while(!this->CompareAndSet_Sync(comp, newVal)); + return newVal; + } +}; + + +//----------------------------------------------------------------------------------- +// ***** Lock + +// Lock is a simplest and most efficient mutual-exclusion lock class. +// Unlike Mutex, it cannot be waited on. + +class Lock +{ + // NOTE: Locks are not allocatable and they themselves should not allocate + // memory by standard means. This is the case because StandardAllocator + // relies on this class. + // Make 'delete' private. Don't do this for 'new' since it can be redefined. + void operator delete(void*) {} + + + // *** Lock implementation for various platforms. + +#if !defined(OVR_ENABLE_THREADS) + +public: + // With no thread support, lock does nothing. + inline Lock() { } + inline Lock(unsigned) { } + inline ~Lock() { } + inline void DoLock() { } + inline void Unlock() { } + + // Windows. +#elif defined(OVR_OS_MS) + + CRITICAL_SECTION cs; +public: + Lock(unsigned spinCount = 10000); // Mutexes with non-zero spin counts usually result in better performance. + ~Lock(); + // Locking functions. + inline void DoLock() { ::EnterCriticalSection(&cs); } + inline void Unlock() { ::LeaveCriticalSection(&cs); } + +#else + pthread_mutex_t mutex; + +public: + static pthread_mutexattr_t RecursiveAttr; + static bool RecursiveAttrInit; + + Lock (unsigned spinCount = 0) // To do: Support spin count, probably via a custom lock implementation. + { + OVR_UNUSED(spinCount); + if (!RecursiveAttrInit) + { + pthread_mutexattr_init(&RecursiveAttr); + pthread_mutexattr_settype(&RecursiveAttr, PTHREAD_MUTEX_RECURSIVE); + RecursiveAttrInit = 1; + } + pthread_mutex_init(&mutex,&RecursiveAttr); + } + ~Lock () { pthread_mutex_destroy(&mutex); } + inline void DoLock() { pthread_mutex_lock(&mutex); } + inline void Unlock() { pthread_mutex_unlock(&mutex); } + +#endif // OVR_ENABLE_THREDS + + +public: + // Locker class, used for automatic locking + class Locker + { + public: + Lock *pLock; + inline Locker(Lock *plock) + { pLock = plock; pLock->DoLock(); } + inline ~Locker() + { pLock->Unlock(); } + }; +}; + + +//------------------------------------------------------------------------------------- +// Globally shared Lock implementation used for MessageHandlers, etc. + +class SharedLock +{ +public: + SharedLock() : UseCount(0) {} + + Lock* GetLockAddRef(); + void ReleaseLock(Lock* plock); + +private: + Lock* toLock() { return (Lock*)Buffer; } + + // UseCount and max alignment. + volatile int UseCount; + uint64_t Buffer[(sizeof(Lock)+sizeof(uint64_t)-1)/sizeof(uint64_t)]; +}; + + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_CRC32.cpp b/LibOVRKernel/Src/Kernel/OVR_CRC32.cpp new file mode 100644 index 0000000..82cbe7f --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_CRC32.cpp @@ -0,0 +1,85 @@ +/************************************************************************************ + +Filename : OVR_CRC32.cpp +Content : CRC-32 with polynomial used for sensor devices +Created : June 20, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_CRC32.h" + +namespace OVR { + + +static const uint32_t CRC_Table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + + +//// CRC-32 + +uint32_t CRC32_Calculate(const void* data, int bytes, uint32_t accumulator) +{ + const uint8_t* inputBytes = reinterpret_cast<const uint8_t*>( data ); + + for (int j = 0; j < bytes; ++j) + { + int i = ((uint32_t)(accumulator >> 24) ^ *inputBytes++) & 0xFF; + + accumulator = (accumulator << 8) ^ CRC_Table[i]; + } + + return ~accumulator; +} + + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_CRC32.h b/LibOVRKernel/Src/Kernel/OVR_CRC32.h new file mode 100644 index 0000000..e4edd65 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_CRC32.h @@ -0,0 +1,45 @@ +/************************************************************************************ + +PublicHeader: OVR +Filename : OVR_CRC32.h +Content : CRC-32 with polynomial used for sensor devices +Created : June 20, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_CRC32_h +#define OVR_CRC32_h + +#include "OVR_Types.h" + +namespace OVR { + + +//----------------------------------------------------------------------------------- +// ***** CRC-32 + +// Polynomial used and algorithm details are proprietary to our sensor board +uint32_t CRC32_Calculate(const void* data, int bytes, uint32_t prevCRC = 0); + + +} // namespace OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Callbacks.cpp b/LibOVRKernel/Src/Kernel/OVR_Callbacks.cpp new file mode 100644 index 0000000..69d6557 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Callbacks.cpp @@ -0,0 +1,41 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_Callbacks.cpp +Content : Callback library +Created : Nov 17, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Callbacks.h" + +namespace OVR { + + +// Global emitter lock +// +// Add/remove operations on callbacks happen infrequently, and are already fairly +// serialized in order of construction by design. Therefore contention for this +// lock between call()/shutdown() is the main concern and is also rare. +Lock CallbackEmitterBase::EmitterLock; + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_Callbacks.h b/LibOVRKernel/Src/Kernel/OVR_Callbacks.h new file mode 100644 index 0000000..b02c4ff --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Callbacks.h @@ -0,0 +1,320 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_Callbacks.h +Content : Callback library +Created : June 20, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Callbacks_h +#define OVR_Callbacks_h + +#include "OVR_CallbacksInternal.h" + +#include "OVR_String.h" // For CallbackHash +#include "OVR_Hash.h" // For CallbackHash + +namespace OVR { + + +//----------------------------------------------------------------------------- +// CallbackEmitter +// +// Emitter of callbacks. +// Thread-safety: All public members may be safely called concurrently. +template<class DelegateT> +class CallbackEmitter : public NewOverrideBase +{ +public: + CallbackEmitter(); + ~CallbackEmitter(); + + // Add a listener. + bool AddListener(CallbackListener<DelegateT>* listener); + + // Get the current number of listeners. Note that this can change as other threads + // add listeners to the emitter. + int GetListenerCount() const; + + void Call() + { + Emitter->Call(); + } + template<class Param1> + void Call(Param1* p1) + { + Emitter->Call(p1); + } + template<class Param1> + void Call(Param1& p1) + { + Emitter->Call(p1); + } + template<class Param1, class Param2> + void Call(Param1* p1, Param2* p2) + { + Emitter->Call(p1, p2); + } + template<class Param1, class Param2> + void Call(Param1& p1, Param2& p2) + { + Emitter->Call(p1, p2); + } + template<class Param1, class Param2, class Param3> + void Call(Param1* p1, Param2* p2, Param3* p3) + { + Emitter->Call(p1, p2, p3); + } + template<class Param1, class Param2, class Param3> + void Call(Param1& p1, Param2& p2, Param3& p3) + { + Emitter->Call(p1, p2, p3); + } + + // Remove all listeners and prevent further listeners from being added. + void Shutdown(); + +protected: + Ptr< FloatingCallbackEmitter<DelegateT> > Emitter; +}; + + +//----------------------------------------------------------------------------- +// CallbackListener +// +// Listener for callbacks. +// Thread-safety: Operations on a listener are not thread-safe. +// The listener may only listen to *one emitter* at a time. +template<class DelegateT> +class CallbackListener : public NewOverrideBase +{ + friend class CallbackEmitter<DelegateT>; + +public: + CallbackListener(); + ~CallbackListener(); + + // Stop listening to callbacks. + // And set a new handler for callbacks. + void SetHandler(DelegateT handler); + + // Is listening to an emitter at this instant? + // If the Emitter has shutdown, then this may inaccurately return true. + bool IsListening() const; + + // Stops listening to callbacks. + void Cancel(); + +protected: + /// Internal data: + + // Reference to the associated listener. + Ptr< FloatingCallbackListener<DelegateT> > FloatingListener; + + // Reference to the associated emitter. + Ptr< FloatingCallbackEmitter<DelegateT> > FloatingEmitter; + + DelegateT Handler; +}; + + +//----------------------------------------------------------------------------- +// Template Implementation: CallbackEmitter + +template<class DelegateT> +CallbackEmitter<DelegateT>::CallbackEmitter() +{ + Emitter = *new FloatingCallbackEmitter<DelegateT>; +} + +template<class DelegateT> +CallbackEmitter<DelegateT>::~CallbackEmitter() +{ + Emitter->Shutdown(); + // Emitter goes out of scope here. +} + +template<class DelegateT> +bool CallbackEmitter<DelegateT>::AddListener(CallbackListener<DelegateT>* listener) +{ + // The listener object can only be attached to one emitter at a time. + // The caller should explicitly Cancel() a listener before listening + // to a new emitter, even if it is the same emitter. + OVR_ASSERT(!listener->FloatingEmitter && !listener->FloatingListener); + + if (listener->FloatingEmitter || listener->FloatingListener) + { + // Cancel any previous listening + listener->Cancel(); + } + + // Set the floating listener and emitter + listener->FloatingListener = *new FloatingCallbackListener<DelegateT>(listener->Handler); + listener->FloatingEmitter = Emitter.GetPtr(); + + // The remaining input checks are performed inside. + return Emitter->AddListener(listener->FloatingListener); +} + +template<class DelegateT> +int CallbackEmitter<DelegateT>::GetListenerCount() const +{ + return Emitter->Listeners.GetSizeI(); +} + +template<class DelegateT> +void CallbackEmitter<DelegateT>::Shutdown() +{ + Emitter->Shutdown(); +} + + +//----------------------------------------------------------------------------- +// Template Implementation: CallbackListener + +template<class DelegateT> +CallbackListener<DelegateT>::CallbackListener() +{ + // Listener is null until a handler is set. +} + +template<class DelegateT> +CallbackListener<DelegateT>::~CallbackListener() +{ + Cancel(); +} + +template<class DelegateT> +void CallbackListener<DelegateT>::Cancel() +{ + if (FloatingListener) + { + FloatingListener->EnterCancelState(); + } + + if (FloatingEmitter) + { + if (FloatingListener) + { + FloatingEmitter->OnListenerCancel(FloatingListener); + } + } + + // FloatingEmitter goes out of scope here. + FloatingEmitter = nullptr; + + // FloatingListener goes out of scope here. + FloatingListener = nullptr; +} + +template<class DelegateT> +void CallbackListener<DelegateT>::SetHandler(DelegateT handler) +{ + Cancel(); + + Handler = handler; +} + +template<class DelegateT> +bool CallbackListener<DelegateT>::IsListening() const +{ + if (!FloatingListener.GetPtr()) + { + return false; + } + + return FloatingListener->IsValid(); +} + + +//----------------------------------------------------------------------------- +// CallbackHash +// +// A hash containing CallbackEmitters +template<class DelegateT> +class CallbackHash : public NewOverrideBase +{ + typedef Hash<String, CallbackEmitter<DelegateT>*, String::HashFunctor> HashTable; + +public: + ~CallbackHash() + { + Clear(); + } + + void Clear() + { + for (auto ii = Table.Begin(); ii != Table.End(); ++ii) + { + delete ii->Second; + } + + Table.Clear(); + } + + CallbackEmitter<DelegateT>* GetKey(String key) + { + CallbackEmitter<DelegateT>** emitter = Table.Get(key); + if (emitter) + { + return *emitter; + } + return nullptr; + } + + void AddListener(String key, CallbackListener<DelegateT>* listener) + { + CallbackEmitter<DelegateT>** pEmitter = Table.Get(key); + CallbackEmitter<DelegateT>* emitter = nullptr; + + if (!pEmitter) + { + emitter = new CallbackEmitter<DelegateT>; + Table.Add(key, emitter); + } + else + { + emitter = *pEmitter; + } + + emitter->AddListener(listener); + } + + void RemoveKey(String key) + { + CallbackEmitter<DelegateT>** emitter = Table.Get(key); + + if (emitter) + { + delete *emitter; + Table.Remove(key); + } + } + +protected: + HashTable Table; // Hash table +}; + + +} // namespace OVR + +#endif // OVR_Callbacks_h diff --git a/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h b/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h new file mode 100644 index 0000000..a0c0a31 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_CallbacksInternal.h @@ -0,0 +1,331 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_CallbacksInternal.h +Content : Callback library +Created : Nov 11, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_CallbacksInternal_h +#define OVR_CallbacksInternal_h + +#include "OVR_Atomic.h" +#include "OVR_RefCount.h" +#include "OVR_Delegates.h" +#include "OVR_Array.h" + +namespace OVR { + +template<class DelegateT> class FloatingCallbackEmitter; // Floating emitter object +template<class DelegateT> class CallbackEmitter; +template<class DelegateT> class FloatingCallbackListener; // Floating listener object +template<class DelegateT> class CallbackListener; + + +//----------------------------------------------------------------------------- +// FloatingCallbackEmitter +// +// The Call() function is not thread-safe. +// TBD: Should we add a thread-safe Call() option to constructor? + +class CallbackEmitterBase +{ +protected: + static Lock EmitterLock; +}; + +template<class DelegateT> +class FloatingCallbackEmitter : public CallbackEmitterBase, public RefCountBase< FloatingCallbackEmitter<DelegateT> > +{ + friend class CallbackEmitter<DelegateT>; + + FloatingCallbackEmitter() : + IsShutdown(false), + DirtyListenersCache(0) + { + } + +public: + typedef Array< Ptr< FloatingCallbackListener<DelegateT> > > ListenerPtrArray; + + ~FloatingCallbackEmitter() + { + OVR_ASSERT(Listeners.GetSizeI() == 0); + // ListenersCache will be emptied here. + } + + bool AddListener(FloatingCallbackListener<DelegateT>* listener); + void Shutdown(); + + // Called from the listener object as it is transitioning to canceled state. + // The listener's mutex is not held during this call. + void OnListenerCancel(FloatingCallbackListener<DelegateT>* listener); + +public: + void Call(); + + template<class Param1> + void Call(Param1* p1); + + template<class Param1> + void Call(Param1& p1); + + template<class Param1, class Param2> + void Call(Param1* p1, Param2* p2); + + template<class Param1, class Param2> + void Call(Param1& p1, Param2& p2); + + template<class Param1, class Param2, class Param3> + void Call(Param1* p1, Param2* p2, Param3* p3); + + template<class Param1, class Param2, class Param3> + void Call(Param1& p1, Param2& p2, Param3& p3); + +protected: + // Is the emitter shut down? This prevents more listeners from being added during shutdown. + bool IsShutdown; + + // Array of added listeners. + ListenerPtrArray Listeners; + + // Is the cache dirty? This avoids locking and memory allocation in steady state. + AtomicInt<uint32_t> DirtyListenersCache; + + // Cache of listeners used by the Call() function. + ListenerPtrArray ListenersCacheForCalls; + + // Update the ListenersCache array in response to an insertion or removal. + // This is how AddListener() insertions get rolled into the listeners array. + // This is how RemoveListener() removals get purged from the cache. + void updateListenersCache() + { + if (DirtyListenersCache != 0) + { + Lock::Locker locker(&EmitterLock); + + // TBD: Should memory allocation be further reduced here? + ListenersCacheForCalls = Listeners; + DirtyListenersCache = 0; + } + } + + // Without holding a lock, find and remove the given listener from the array of listeners. + void noLockFindAndRemoveListener(FloatingCallbackListener<DelegateT>* listener) + { + const int count = Listeners.GetSizeI(); + for (int i = 0; i < count; ++i) + { + if (Listeners[i] == listener) + { + Listeners.RemoveAt(i); + + // After removing it from the array, set the dirty flag. + // Note: Because the flag is atomic, a portable memory fence is implied. + DirtyListenersCache = 1; + + break; + } + } + } +}; + + +//----------------------------------------------------------------------------- +// FloatingCallbackListener +// +// Internal implementation class for the CallbackListener. +// This can only be associated with one CallbackListener object for its lifetime. +template<class DelegateT> +class FloatingCallbackListener : public RefCountBase< FloatingCallbackListener<DelegateT> > +{ +public: + FloatingCallbackListener(DelegateT handler); + ~FloatingCallbackListener(); + + void EnterCancelState(); + + bool IsValid() const + { + return Handler.IsValid(); + } + + // TBD: Should these be binned to reduce the lock count? + // Boost does not do that. And I am worried about deadlocks when misused. + mutable Lock ListenerLock; + + // Handler function + DelegateT Handler; +}; + + +//----------------------------------------------------------------------------- +// Template Implementation: FloatingCallbackEmitter + +template<class DelegateT> +bool FloatingCallbackEmitter<DelegateT>::AddListener(FloatingCallbackListener<DelegateT>* listener) +{ + Lock::Locker locker(&EmitterLock); + + if (IsShutdown) + { + return false; + } + + // Add the listener to our list + Listeners.PushBack(listener); + + // After adding it to the array, set the dirty flag. + // Note: Because the flag is atomic, a portable memory fence is implied. + DirtyListenersCache = 1; + + return true; +} + +// Called from the listener object as it is transitioning to canceled state. +// The listener's mutex is not held during this call. +template<class DelegateT> +void FloatingCallbackEmitter<DelegateT>::OnListenerCancel(FloatingCallbackListener<DelegateT>* listener) +{ + Lock::Locker emitterLocker(&EmitterLock); + + // If not shut down, + // Note that if it is shut down then there will be no listeners in the array. + if (!IsShutdown) + { + // Remove it. + noLockFindAndRemoveListener(listener); + } +} + +template<class DelegateT> +void FloatingCallbackEmitter<DelegateT>::Shutdown() +{ + Lock::Locker locker(&EmitterLock); + + IsShutdown = true; + + Listeners.ClearAndRelease(); + + // Note: Because the flag is atomic, a portable memory fence is implied. + DirtyListenersCache = 1; +} + +//----------------------------------------------------------------------------- +// Call function +// +// (1) Update the cache of listener references, if it has changed. +// (2) For each listener, +// (a) Hold ListenerLock. +// (b) If listener handler is valid, call the handler. +#define OVR_EMITTER_CALL_BODY(params) \ + updateListenersCache(); \ + if (IsShutdown) return; /* Pure optimization. It is fine if this races. */ \ + const int count = ListenersCacheForCalls.GetSizeI(); \ + for (int i = 0; i < count; ++i) \ + { \ + Lock::Locker locker(&ListenersCacheForCalls[i]->ListenerLock); \ + if (ListenersCacheForCalls[i]->Handler.IsValid()) \ + { \ + ListenersCacheForCalls[i]->Handler params; /* Using a macro for this line. */ \ + } \ + } + +template<class DelegateT> +void FloatingCallbackEmitter<DelegateT>::Call() +{ + OVR_EMITTER_CALL_BODY(()) +} + +template<class DelegateT> +template<class Param1> +void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1) +{ + OVR_EMITTER_CALL_BODY((p1)) +} + +template<class DelegateT> +template<class Param1> +void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1) +{ + OVR_EMITTER_CALL_BODY((p1)) +} + +template<class DelegateT> +template<class Param1, class Param2> +void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2) +{ + OVR_EMITTER_CALL_BODY((p1, p2)) +} + +template<class DelegateT> +template<class Param1, class Param2> +void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2) +{ + OVR_EMITTER_CALL_BODY((p1, p2)) +} + +template<class DelegateT> +template<class Param1, class Param2, class Param3> +void FloatingCallbackEmitter<DelegateT>::Call(Param1* p1, Param2* p2, Param3* p3) +{ + OVR_EMITTER_CALL_BODY((p1, p2, p3)) +} + +template<class DelegateT> +template<class Param1, class Param2, class Param3> +void FloatingCallbackEmitter<DelegateT>::Call(Param1& p1, Param2& p2, Param3& p3) +{ + OVR_EMITTER_CALL_BODY((p1, p2, p3)) +} + +#undef OVR_EMITTER_CALL_BODY + + +//----------------------------------------------------------------------------- +// Template Implementation: FloatingCallbackListener + +template<class DelegateT> +FloatingCallbackListener<DelegateT>::FloatingCallbackListener(DelegateT handler) : + Handler(handler) +{ + OVR_ASSERT(Handler.IsValid()); +} + +template<class DelegateT> +FloatingCallbackListener<DelegateT>::~FloatingCallbackListener() +{ + OVR_ASSERT(!Handler.IsValid()); +} + +template<class DelegateT> +void FloatingCallbackListener<DelegateT>::EnterCancelState() +{ + ListenerLock.DoLock(); + Handler.Invalidate(); + ListenerLock.Unlock(); +} + + +} // namespace OVR + +#endif // OVR_CallbacksInternal_h diff --git a/LibOVRKernel/Src/Kernel/OVR_Color.h b/LibOVRKernel/Src/Kernel/OVR_Color.h new file mode 100644 index 0000000..7b5e966 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Color.h @@ -0,0 +1,73 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Color.h +Content : Contains color struct. +Created : February 7, 2013 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Color_h +#define OVR_Color_h + +#include "OVR_Types.h" + +namespace OVR { + + +struct Color +{ + uint8_t R,G,B,A; + + Color() + { + #if defined(OVR_BUILD_DEBUG) + R = G = B = A = 0; + #endif + } + + // Constructs color by channel. Alpha is set to 0xFF (fully visible) + // if not specified. + Color(unsigned char r,unsigned char g,unsigned char b, unsigned char a = 0xFF) + : R(r), G(g), B(b), A(a) { } + + // 0xAARRGGBB - Common HTML color Hex layout + Color(unsigned c) + : R((unsigned char)(c>>16)), G((unsigned char)(c>>8)), + B((unsigned char)c), A((unsigned char)(c>>24)) { } + + bool operator==(const Color& b) const + { + return R == b.R && G == b.G && B == b.B && A == b.A; + } + + void GetRGBA(float *r, float *g, float *b, float* a) const + { + *r = R / 255.0f; + *g = G / 255.0f; + *b = B / 255.0f; + *a = A / 255.0f; + } +}; + + +} // namespace OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Compiler.h b/LibOVRKernel/Src/Kernel/OVR_Compiler.h new file mode 100644 index 0000000..4541795 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Compiler.h @@ -0,0 +1,1543 @@ +/************************************************************************************ + +PublicHeader: OVR_Types.h +Filename : OVR_Compiler.h +Content : Compiler-specific feature identification and utilities +Created : June 19, 2014 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Compiler_h +#define OVR_Compiler_h + +#pragma once + + +// References +// https://gcc.gnu.org/projects/cxx0x.html +// https://gcc.gnu.org/projects/cxx1y.html +// http://clang.llvm.org/cxx_status.html +// http://msdn.microsoft.com/en-us/library/hh567368.aspx +// https://docs.google.com/spreadsheet/pub?key=0AoBblDsbooe4dHZuVTRoSTFBejk5eFBfVk1GWlE5UlE&output=html +// http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros + + +//----------------------------------------------------------------------------------- +// ***** Compiler +// +// The following compilers are defined: (OVR_CC_x) +// +// MSVC - Microsoft Visual C/C++ +// INTEL - Intel C++ for Linux / Windows +// GNU - GNU C++ +// ARM - ARM C/C++ + +#if defined(__INTEL_COMPILER) +// Intel 4.0 = 400 +// Intel 5.0 = 500 +// Intel 6.0 = 600 +// Intel 8.0 = 800 +// Intel 9.0 = 900 +# define OVR_CC_INTEL __INTEL_COMPILER + +#elif defined(_MSC_VER) +// MSVC 5.0 = 1100 +// MSVC 6.0 = 1200 +// MSVC 7.0 (VC2002) = 1300 +// MSVC 7.1 (VC2003) = 1310 +// MSVC 8.0 (VC2005) = 1400 +// MSVC 9.0 (VC2008) = 1500 +// MSVC 10.0 (VC2010) = 1600 +// MSVC 11.0 (VC2012) = 1700 +// MSVC 12.0 (VC2013) = 1800 +# define OVR_CC_MSVC _MSC_VER + +#if _MSC_VER == 0x1600 +# if _MSC_FULL_VER < 160040219 +# error "Oculus does not support VS2010 without SP1 installed." +# endif +#endif + +#elif defined(__GNUC__) +# define OVR_CC_GNU + +#elif defined(__clang__) +# define OVR_CC_CLANG + +#elif defined(__CC_ARM) +# define OVR_CC_ARM + +#else +# error "Oculus does not support this Compiler" +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CC_VERSION +// +// M = major version +// m = minor version +// p = patch release +// b = build number +// +// Compiler Format Example +// ---------------------------- +// OVR_CC_GNU Mmm 408 means GCC 4.8 +// OVR_CC_CLANG Mmm 305 means clang 3.5 +// OVR_CC_MSVC MMMM 1700 means VS2012 +// OVR_CC_ARM Mmpbbb 401677 means 4.0, patch 1, build 677 +// OVR_CC_INTEL MMmm 1210 means 12.10 +// OVR_CC_EDG Mmm 407 means EDG 4.7 +// +#if defined(OVR_CC_GNU) + #define OVR_CC_VERSION ((__GNUC__ * 100) + __GNUC_MINOR__) +#elif defined(OVR_CC_CLANG) + #define OVR_CC_VERSION ((__clang_major__ * 100) + __clang_minor__) +#elif defined(OVR_CC_MSVC) + #define OVR_CC_VERSION _MSC_VER // Question: Should we recognize _MSC_FULL_VER? +#elif defined(OVR_CC_ARM) + #define OVR_CC_VERSION __ARMCC_VERSION +#elif defined(OVR_CC_INTEL) + #if defined(__INTEL_COMPILER) + #define OVR_CC_VERSION __INTEL_COMPILER + #elif defined(__ICL) + #define OVR_CC_VERSION __ICL + #elif defined(__ICC) + #define OVR_CC_VERSION __ICC + #elif defined(__ECC) + #define OVR_CC_VERSION __ECC + #endif +#elif defined(OVR_CC_EDG) + #define OVR_CC_VERSION __EDG_VERSION__ // This is a generic fallback for EDG-based compilers which aren't specified above (e.g. as OVR_CC_ARM) +#endif + + + +// ----------------------------------------------------------------------------------- +// ***** OVR_DISABLE_OPTIMIZATION / OVR_RESTORE_OPTIMIZATION +// +// Allows for the dynamic disabling and restoring of compiler optimizations in code. +// This is useful for helping deal with potential compiler code generation problems. +// With VC++ the usage must be outside of function bodies. This can be used only to +// temporarily disable optimization for a block of code and not to temporarily enable +// optimization for a block of code. +// +// Clang doesn't support this as of June 2014, though function __attribute__((optimize(0)) +// is supposedly supported by clang in addition to GCC. To consider: Make a wrapper for +// this attribute-based functionality. +// +// Example usage: +// OVR_DISABLE_OPTIMIZATION() +// void Test() { ... } +// OVR_RESTORE_OPTIMIZATION() +// +#if !defined(OVR_DISABLE_OPTIMIZATION) + #if defined(OVR_CC_GNU) && (OVR_CC_VERSION > 404) && (defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64)) + #define OVR_DISABLE_OPTIMIZATION() \ + _Pragma("GCC push_options") \ + _Pragma("GCC optimize 0") + #elif defined(OVR_CC_MSVC) + #define OVR_DISABLE_OPTIMIZATION() __pragma(optimize("", off)) + #else + #define OVR_DISABLE_OPTIMIZATION() + #endif +#endif + +#if !defined(OVR_RESTORE_OPTIMIZATION) + #if defined(OVR_CC_GNU) && (OVR_CC_VERSION > 404) && (defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64)) + #define OVR_RESTORE_OPTIMIZATION() _Pragma("GCC pop_options") + #elif defined(OVR_CC_MSVC) + #define OVR_RESTORE_OPTIMIZATION() __pragma(optimize("", on)) + #else + #define OVR_RESTORE_OPTIMIZATION() + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_DISABLE_GNU_WARNING / OVR_RESTORE_GNU_WARNING +// +// Portable wrapper for disabling GCC compiler warnings, one at a time. See example +// usage for usage by example. +// +// Example usage: +// OVR_DISABLE_GNU_WARNING(-Wmissing-braces) // Only one warning per usage. +// OVR_DISABLE_GNU_WARNING(-Wunused-variable) +// <code> +// OVR_RESTORE_GNU_WARNINGS() +// OVR_RESTORE_GNU_WARNINGS() // Must match each disable with a restore. +// +#if !defined(OVR_DISABLE_GNU_WARNING) + #if defined(OVR_CC_GNU) + #define ODGW1(x) #x + #define ODGW2(x) ODGW1(GCC diagnostic ignored x) + #define ODGW3(x) ODGW2(#x) + #endif + + #if defined(OVR_CC_GNU) && (OVR_CC_VERSION >= 406) + #define OVR_DISABLE_GNU_WARNING(w) \ + _Pragma("GCC diagnostic push") \ + _Pragma(ODGW3(w)) + #elif defined(OVR_CC_GNU) && (OVR_CC_VERSION >= 404) // GCC 4.4 doesn't support diagnostic push, but supports disabling warnings. + #define OVR_DISABLE_GNU_WARNING(w) \ + _Pragma(ODGW3(w)) + #else + #define OVR_DISABLE_GNU_WARNING(w) + #endif +#endif + +#if !defined(OVR_RESTORE_GNU_WARNING) + #if defined(OVR_CC_GNU) && (OVR_CC_VERSION >= 4006) + #define OVR_RESTORE_GNU_WARNINGS() \ + _Pragma("GCC diagnostic pop") + #else + #define OVR_RESTORE_GNU_WARNING() + #endif +#endif + + + +// ----------------------------------------------------------------------------------- +// ***** OVR_DISABLE_CLANG_WARNING / OVR_RESTORE_CLANG_WARNING +// +// Portable wrapper for disabling GCC compiler warnings, one at a time. See example +// usage for usage by example. +// +// Example usage: +// OVR_DISABLE_CLANG_WARNING(-Wmissing-braces) // Only one warning per usage. +// OVR_DISABLE_CLANG_WARNING(-Wunused-variable) +// <code> +// OVR_RESTORE_CLANG_WARNINGS() +// OVR_RESTORE_CLANG_WARNINGS() // Must match each disable with a restore. +// +// +#if !defined(OVR_DISABLE_CLANG_WARNING) + #if defined(OVR_CC_CLANG) + #define ODCW1(x) #x + #define ODCW2(x) ODCW1(clang diagnostic ignored x) + #define ODCW3(x) ODCW2(#x) + + #define OVR_DISABLE_CLANG_WARNING(w) \ + _Pragma("clang diagnostic push") \ + _Pragma(ODCW3(w)) + #else + #define OVR_DISABLE_CLANG_WARNING(w) + #endif +#endif + +#if !defined(OVR_RESTORE_CLANG_WARNING) + #if defined(OVR_CC_CLANG) + #define OVR_RESTORE_CLANG_WARNING() \ + _Pragma("clang diagnostic pop") + #else + #define OVR_RESTORE_CLANG_WARNING() + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_DISABLE_MSVC_WARNING / OVR_RESTORE_MSVC_WARNING +// +// Portable wrapper for disabling VC++ compiler warnings. See example usage for usage +// by example. +// +// Example usage: +// OVR_DISABLE_MSVC_WARNING(4556 4782 4422) +// <code> +// OVR_RESTORE_MSVC_WARNING() +// +#if !defined(OVR_DISABLE_MSVC_WARNING) + #if defined(OVR_CC_MSVC) + #define OVR_DISABLE_MSVC_WARNING(w) \ + __pragma(warning(push)) \ + __pragma(warning(disable:w)) + #else + #define OVR_DISABLE_MSVC_WARNING(w) + #endif +#endif + +#if !defined(OVR_RESTORE_MSVC_WARNING) + #if defined(OVR_CC_MSVC) + #define OVR_RESTORE_MSVC_WARNING() \ + __pragma(warning(pop)) + #else + #define OVR_RESTORE_MSVC_WARNING() + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_DISABLE_ALL_MSVC_WARNINGS / OVR_RESTORE_ALL_MSVC_WARNINGS +// +// Portable wrapper for disabling all VC++ compiler warnings. +// OVR_RESTORE_ALL_MSVC_WARNINGS restores warnings that were disabled by +// OVR_DISABLE_ALL_MSVC_WARNINGS. Any previously enabled warnings will still be +// enabled after OVR_RESTORE_ALL_MSVC_WARNINGS. +// +// Example usage: +// OVR_DISABLE_ALL_MSVC_WARNINGS() +// <code> +// OVR_RESTORE_ALL_MSVC_WARNINGS() + +#if !defined(OVR_DISABLE_ALL_MSVC_WARNINGS) + #if defined(OVR_CC_MSVC) + #define OVR_DISABLE_ALL_MSVC_WARNINGS() \ + __pragma(warning(push, 0)) \ + __pragma(warning(disable: 4263 4264 4266)) + #else + #define OVR_DISABLE_ALL_MSVC_WARNINGS() + #endif +#endif + +#if !defined(OVR_RESTORE_ALL_MSVC_WARNINGS) + #if defined(OVR_CC_MSVC) + #define OVR_RESTORE_ALL_MSVC_WARNINGS() \ + __pragma(warning(pop)) + #else + #define OVR_RESTORE_ALL_MSVC_WARNINGS() + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CC_HAS_FEATURE +// +// This is a portable way to use compile-time feature identification available +// with some compilers in a clean way. Direct usage of __has_feature in preprocessing +// statements of non-supporting compilers results in a preprocessing error. +// +// Example usage: +// #if OVR_CC_HAS_FEATURE(is_pod) +// if(__is_pod(T)) // If the type is plain data then we can safely memcpy it. +// memcpy(&destObject, &srcObject, sizeof(object)); +// #endif +// +#if !defined(OVR_CC_HAS_FEATURE) + #if defined(__clang__) // http://clang.llvm.org/docs/LanguageExtensions.html#id2 + #define OVR_CC_HAS_FEATURE(x) __has_feature(x) + #else + #define OVR_CC_HAS_FEATURE(x) 0 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CC_HAS_BUILTIN +// +// +// This is a portable way to use compile-time builtin identification available +// with some compilers in a clean way. Direct usage of __has_builtin in preprocessing +// statements of non-supporting compilers results in a preprocessing error. +// +// Example usage: +// #if OVR_CC_HAS_BUILTIN(__builtin_trap) +// #define DEBUG_BREAK __builtin_trap +// #endif +// +#if !defined(OVR_CC_HAS_BUILTIN) + #if defined(__clang__) + #define OVR_CC_HAS_BUILTIN(x) __has_builtin(x) // http://clang.llvm.org/docs/LanguageExtensions.html#id2 + #else + #define OVR_CC_HAS_BUILTIN(x) 0 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP11_ENABLED / OVR_CPP_CPP14_ENABLED +// +// Defined as 1 if the compiler has its available C++11 support enabled, else undefined. +// This does not mean that all of C++11 or any particular feature of C++11 is supported +// by the compiler. It means that whatever C++11 support the compiler has is enabled. +// This also includes existing and older compilers that still identify C++11 as C++0x. +// +#if !defined(OVR_CPP11_ENABLED) && defined(__cplusplus) + #if defined(__GNUC__) && defined(__GXX_EXPERIMENTAL_CXX0X__) + #define OVR_CPP11_ENABLED 1 + #elif defined(_MSC_VER) && (_MSC_VER >= 1500) // VS2010+, the first version with any significant C++11 support. + #define OVR_CPP11_ENABLED 1 + #elif (__cplusplus >= 201103L) // 201103 is the first C++11 version. + #define OVR_CPP11_ENABLED 1 + #else + // Leave undefined + #endif +#endif + +#if !defined(OVR_CPP_CPP14_ENABLED) && defined(__cplusplus) + #if defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+, the first version with any significant C++14 support. + #define OVR_CPP_CPP14_ENABLED 1 + #elif (__cplusplus > 201103L) + #define OVR_CPP_CPP14_ENABLED 1 + #else + // Leave undefined + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_EXCEPTIONS / OVR_CPP_NO_UNWIND +// +// OVR_CPP_NO_EXCEPTIONS is defined as 1 if the compiler doesn't support C++ +// exceptions or is configured to disable support for them. Else not defined. +// If OVR_CPP_NO_EXCEPTIONS is defined then attempts to use try/catch +// related C++ statements result in a compilation error with many +// compilers. +// +// OVR_CPP_NO_UNWIND is defined as 1 if the compiler supports exceptions but +// doesn't support stack unwinding in the presence of an exception. Else not defined. +// For the Microsoft compiler, disabling exceptions means disabling stack unwinding +// and not disabling exceptions themselves. +// +// Example usage: +// void Test() { +// #if !defined(OVR_CPP_NO_EXCEPTIONS) +// try { +// #endif +// void* ptr = new Object; +// #if !defined(OVR_CPP_NO_EXCEPTIONS) +// catch(...) { ... } +// #endif + +#if !defined(OVR_CPP_NO_EXCEPTIONS) + #if defined(OVR_CPP_GNUC) && defined(_NO_EX) + #define OVR_CPP_NO_EXCEPTIONS 1 + #elif (defined(OVR_CC_GNU) || defined(OVR_CC_CLANG) || defined(OVR_CC_INTEL) || defined(OVR_CC_ARM)) && !defined(__EXCEPTIONS) + #define OVR_CPP_NO_EXCEPTIONS 1 + #elif defined(OVR_CC_MSVC) && !defined(_CPPUNWIND) + #define OVR_CPP_NO_UNWIND 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_RTTI +// +// Defined as 1 if C++ run-time type information support is unavailable or disabled +// by the compiler. Else undefined. Allows you to write portable code in the face +// of the possibility that RTTI is disabled. +// +// Example usage: +// #if !OVR_CPP_NO_RTTI +// #include <typeinfo> +// int x = std::dynamic_cast<int>(3.4f); +// #endif + +#if defined(__clang__) && !OVR_CC_HAS_FEATURE(cxx_rtti) + #define OVR_CPP_NO_RTTI 1 +#elif defined(__GNUC__) && !defined(__GXX_RTTI) + #define OVR_CPP_NO_RTTI 1 +#elif defined(_MSC_VER) && !defined(_CPPRTTI) + #define OVR_CPP_NO_RTTI 1 +#elif defined(__CC_ARM) && defined(__TARGET_CPU_MPCORE) && !defined(__RTTI) + #define OVR_CPP_NO_RTTI 1 +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_STATIC_ASSERT +// +// Defined as 1 if C++ run-time type information support is available and enabled +// by the compiler. Else undefined. +// +// Example usage: +// #if OVR_CPP_NO_STATIC_ASSERT +// #define MY_ASSERT(x) { int zero = 0; switch(zero) {case 0: case (x):;} } +// #else +// #define MY_ASSERT(x) static_assert((x), #x) +// #endif + +#if !defined(OVR_CPP_NO_STATIC_ASSERT) + #if !(defined(__GNUC__) && (defined(__GXX_EXPERIMENTAL_CXX0X__) || (defined(__cplusplus) && (__cplusplus >= 201103L)))) && \ + !(defined(__clang__) && defined(__cplusplus) && OVR_CC_HAS_FEATURE(cxx_static_assert)) && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600) && defined(__cplusplus)) && /* VS2010+ */ \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401) && defined(OVR_CPP11_ENABLED)) /* EDG 4.1+ */ + #define OVR_CPP_NO_STATIC_ASSERT 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_NULLPTR +// +// Defined as 1 if the compiler doesn't support C++11 nullptr built in type. +// Otherwise undefined. Does not identify if the standard library defines +// std::nullptr_t, as some standard libraries are further behind in standardization +// than the compilers using them (e.g. Apple clang with the supplied libstdc++). +// +// OVR_Nullptr.h provides a portable nullptr and std::nullptr_t for when the +// compiler or standard library do not. + +#if !defined(OVR_CPP_NO_NULLPTR) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_nullptr)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) /* EDG 4.3+ */ + #define OVR_CPP_NO_NULLPTR 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_RVALUE_REFERENCES +// +// Defined as 1 if the compiler doesn't support C++11 rvalue references and move semantics. +// Otherwise undefined. + +#if !defined(OVR_CPP_NO_RVALUE_REFERENCES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_rvalue_references)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) /* EDG 4.3+ */ + #define OVR_CPP_NO_RVALUE_REFERENCES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_AUTO +// +// Defined as 1 if the compiler doesn't support C++11 auto keyword. Otherwise undefined. + +#if !defined(OVR_CPP_NO_AUTO) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_auto_type)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 309))) /* EDG 3.9+ */ + #define OVR_CPP_NO_AUTO 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_RANGE_BASED_FOR_LOOP +// +// Defined as 1 if the compiler doesn't support C++11 range-based for loops. +// Otherwise undefined. + +#if !defined(OVR_CPP_NO_RANGE_BASED_FOR_LOOP) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_range_for)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1700)) /* VS2012+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 405))) /* EDG 4.5+ */ + #define OVR_CPP_NO_RANGE_BASED_FOR_LOOP 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_CONSTEXPR / OVR_CPP_NO_RELAXED_CONSTEXPR +// +// OVR_CPP_NO_CONSTEXPR is defined as 1 if the compiler doesn't support C++11 constexpr. +// OVR_CPP_NO_RELAXED_CONSTEXPR is defined as 1 if the compiler doesn't support C++14 constexpr. +// Otherwise undefined. +// See the OVR_CONSTEXPR / OVR_CONSTEXPR_OR_CONST macros for portable wrappers of this functionality. + +#if !defined(OVR_CPP_NO_CONSTEXPR) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_constexpr)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 406))) /* EDG 4.6+ */ + // Not supported by VC++ through at least VS2013. + #define OVR_CPP_NO_CONSTEXPR 1 + #endif +#endif + +#if !defined(OVR_CPP_NO_RELAXED_CONSTEXPR) + #if !defined(OVR_CPP14_ENABLED) || \ + !(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_relaxed_constexpr)) /* clang */ + // Supported only by clang as of this writing. + #define OVR_CPP_NO_RELAXED_CONSTEXPR 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_LAMBDA_EXPRESSIONS +// +// Defined as 1 if the compiler doesn't support C++11 lambda expressions. Otherwise undefined. +// Some compilers have slightly crippled versions of this. + +#if !defined(OVR_CPP_NO_LAMBDA_EXPRESSIONS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_lambdas)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + // Conversion of lambdas to function pointers is not supported until EDG 4.5. + #define OVR_CPP_NO_LAMBDA_EXPRESSIONS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_ALIGNOF +// +// Defined as 1 if the compiler supports C++11 alignof. Otherwise undefined. +// Some compilers support __alignof__ instead of alignof, so for portability you +// should use OVR_ALIGNOF instead of directly using C++11 alignof. + +#if !defined(OVR_CPP_NO_ALIGNOF) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 300)) /* Apple clang 3.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 401)) /* GCC 4.1+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1900)) /* VS2014+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 400))) /* EDG 4.0+ */ + #define OVR_CPP_NO_ALIGNOF 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_ALIGNAS +// +// Defined as 1 if the compiler supports C++11 alignas. Otherwise undefined. +// See the OVR_ALIGNAS for a portable wrapper for alignas functionality. + +#if !defined(OVR_CPP_NO_ALIGNAS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 300)) /* clang 3.0+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 408)) /* GCC 4.8+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1900)) /* VS2014+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + #define OVR_CPP_NO_ALIGNAS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_OVERRIDE +// +// Defined as 1 if the compiler doesn't support C++11 override. Otherwise undefined. +// See the OVR_OVERRIDE and OVR_FINALOVERRIDE macros for a portable wrapper. + +#if !defined(OVR_CPP_NO_OVERRIDE) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 400)) /* Apple clang 4.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1500)) /* VS2008+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + #define OVR_CPP_NO_OVERRIDE 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_FINAL +// +// Defined as 1 if the compiler doesn't support C++11 final attribute. Otherwise undefined. +// See the OVR_FINAL and OVR_FINALOVERRIDE macros for a portable wrapper. + +#if !defined(OVR_CPP_NO_FINAL) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 400)) /* Apple clang 4.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1500)) /* VS2008+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + #define OVR_CPP_NO_FINAL 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_EXTERN_TEMPLATE +// +// Defined as 1 if the compiler doesn't support C++11 extern template. +// Otherwise undefined. See OVR_EXTERN_TEMPLATE for wrapper macro. + +#if !defined(OVR_CPP_NO_EXTERN_TEMPLATE) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1700)) /* VS2012+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + #define OVR_CPP_NO_EXTERN_TEMPLATE 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_VARIADIC_TEMPLATES +// +// Defined as 1 if the compiler doesn't support C++11 variadic templates. Otherwise undefined. + +#if !defined(OVR_CPP_NO_VARIADIC_TEMPLATES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_variadic_templates)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) /* EDG 4.3+ */ + #define OVR_CPP_NO_VARIADIC_TEMPLATES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_NOEXCEPT +// +// Defined as 1 if the compiler supports C++11 noexcept. Otherwise undefined. +// http://en.cppreference.com/w/cpp/language/noexcept +// See OVR_NOEXCEPT / OVR_NOEXCEPT_IF / OVR_NOEXCEPT_EXPR for a portable wrapper +// for noexcept functionality. + +#if !defined(OVR_CPP_NO_NOEXCEPT) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_noexcept)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1900)) /* VS2014+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 405))) /* EDG 4.5+ */ + #define OVR_CPP_NO_NOEXCEPT 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_DECLTYPE +// +// Defined as 1 if the compiler doesn't support C++11 decltype. Otherwise undefined. +// Some compilers (e.g. VS2012) support most uses of decltype but don't support +// decltype with incomplete types (which is an uncommon usage seen usually in +// template metaprogramming). We don't include this support as a requirement for +// our definition of decltype support here. + +#if !defined(OVR_CPP_NO_DECLTYPE) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_decltype)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 403)) /* GCC 4.3+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 402))) /* EDG 4.2+ */ + // VC++ fails to support decltype for incomplete types until VS2013. + // EDG fails to support decltype for incomplete types until v4.8. + #define OVR_CPP_NO_DECLTYPE 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_DEFAULTED_FUNCTIONS +// +// Defined as 1 if the compiler doesn't support C++11 defaulted functions. Otherwise undefined. +// Some compilers have slightly crippled versions of this. + +#if !defined(OVR_CPP_NO_DEFAULTED_FUNCTIONS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_defaulted_functions))/* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + // Up through at least VS2013 it's unsupported for defaulted move constructors and move assignment operators. + // Until EDG 4.8 it's unsupported for defaulted move constructors and move assigment operators. + #define OVR_CPP_NO_DEFAULTED_FUNCTIONS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_DELETED_FUNCTIONS +// +// Defined as 1 if the compiler doesn't support C++11 deleted functions. Otherwise undefined. +// Some compilers have slightly crippled versions of this. + +#if !defined(OVR_CPP_NO_DELETED_FUNCTIONS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_defaulted_functions)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + // Up through at least VS2013 it's unsupported for defaulted move constructors and move assignment operators. + // Until EDG 4.8 it's unsupported for defaulted move constructors and move assigment operators. + #define OVR_CPP_NO_DELETED_FUNCTIONS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_STANDARD_LAYOUT_TYPES +// +// Defined as 1 if the compiler doesn't support C++11 standard layout (relaxed POD). Otherwise undefined. +// http://en.cppreference.com/w/cpp/types/is_standard_layout + +#if !defined(OVR_CPP_NO_STANDARD_LAYOUT_TYPES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 300)) /* clang 3.0+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1700)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 406))) /* EDG 4.6+ */ + #define OVR_CPP_NO_STANDARD_LAYOUT_TYPES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_FORWARD_DECLARED_ENUMS +// +// Defined as 1 if the compiler doesn't support C++11 forward declared enums. Otherwise undefined. + +#if !defined(OVR_CPP_NO_FORWARD_DECLARED_ENUMS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1700)) /* VS2012+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 405))) /* EDG 4.5+ */ + #define OVR_CPP_NO_FORWARD_DECLARED_ENUMS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_STRONGLY_TYPED_ENUMS +// +// Defined as 1 if the compiler doesn't support C++11 strongly typed enums. Otherwise undefined. + +#if !defined(OVR_CPP_NO_STRONGLY_TYPED_ENUMS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_strong_enums)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1700)) /* VS2012+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 400))) /* EDG 4.0+ */ + #define OVR_CPP_NO_STRONGLY_TYPED_ENUMS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_TRAILING_RETURN_TYPES +// +// Defined as 1 if the compiler doesn't support C++11 trailing return types. Otherwise undefined. +// http://en.wikipedia.org/wiki/C%2B%2B11#Alternative_function_syntax + +#if !defined(OVR_CPP_NO_TRAILING_RETURN_TYPES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_trailing_return)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + #define OVR_CPP_NO_TRAILING_RETURN_TYPES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_TEMPLATE_ALIASES +// +// Defined as 1 if the compiler doesn't support C++11 template aliases. Otherwise undefined. + +#if !defined(OVR_CPP_NO_TEMPLATE_ALIASES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_alias_templates)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 402))) /* EDG 4.2+ */ + #define OVR_CPP_NO_TEMPLATE_ALIASES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_INITIALIZER_LISTS +// +// Defined as 1 if the compiler doesn't support C++11 initializer lists. Otherwise undefined. +// This refers to the compiler support for this and not the Standard Library support for std::initializer_list, +// as a new compiler with an old standard library (e.g. Apple clang with libstdc++) may not support std::initializer_list. + +#if !defined(OVR_CPP_NO_INITIALIZER_LISTS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_generalized_initializers)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 405))) /* EDG 4.5+ */ + #define OVR_CPP_NO_INITIALIZER_LISTS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_NORETURN +// +// Defined as 1 if the compiler doesn't support the C++11 noreturn attribute. Otherwise undefined. +// http://en.cppreference.com/w/cpp/language/attributes +// +#if !defined(OVR_CPP_NO_NORETURN) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 408)) /* GCC 4.8+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1500)) /* VS2008+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 402))) /* EDG 4.2+ */ + // Supported with VC++ only via __declspec(noreturn) (see OVR_NORETURN). + #define OVR_CPP_NO_NORETURN 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_NONSTATIC_MEMBER_INITIALIZERS +// +// Defined as 1 if the compiler doesn't support C++11 in-class non-static member initializers. Otherwise undefined. +// http://en.cppreference.com/w/cpp/language/data_members + +#if !defined(OVR_CPP_NO_NONSTATIC_MEMBER_INITIALIZERS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 406))) /* EDG 4.6+ */ + #define OVR_CPP_NO_NONSTATIC_MEMBER_INITIALIZERS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_DOUBLE_TEMPLATE_BRACKETS +// +// Defined as 1 if the compiler supports nested template declarations with >>, +// as supported by C++11. Otherwise undefined. + +#if !defined(OVR_CPP_NO_DOUBLE_TEMPLATE_ANGLE_BRACKETS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 400)) /* Apple clang 4.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 403)) /* GCC 4.3+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + #define OVR_CPP_NO_DOUBLE_TEMPLATE_BRACKETS 1 + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_INHERITING_CONSTRUCTORS +// +// Defined as 1 if the compiler supports C++11 inheriting constructors. Otherwise undefined. +// Example usage: +// struct A { explicit A(int x){} }; +// struct B : public A { using A::A; }; // As if B redeclared A::A(int). + +#if !defined(OVR_CPP_NO_INHERITING_CONSTRUCTORS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_inheriting_constructors)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 408)) /* GCC 4.8+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1900)) /* VS2014+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + #define OVR_CPP_NO_INHERITING_CONSTRUCTORS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_DELEGATING_CONSTRUCTORS +// +// Defined as 1 if the compiler supports C++11 delegating constructors. Otherwise undefined. + +#if !defined(OVR_CPP_NO_DELEGATING_CONSTRUCTORS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 300)) /* clang 3.0+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 407))) /* EDG 4.7+ */ + #define OVR_CPP_NO_DELEGATING_CONSTRUCTORS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS +// +// Defined as 1 if the compiler supports C++11 function template default arguments. Otherwise undefined. + +#if !defined(OVR_CPP_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 403)) /* GCC 4.3+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 403))) /* EDG 4.3+ */ + #define OVR_CPP_NO_FUNCTION_TEMPLATE_DEFAULT_ARGS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_UNRESTRICTED_UNIONS +// +// Defined as 1 if the compiler supports C++11 unrestricted unions. Otherwise undefined. + +#if !defined(OVR_CPP_NO_UNRESTRICTED_UNIONS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 406)) /* GCC 4.6+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 406))) /* EDG 4.6+ */ + // Not supported by VC++ as of VS2013. + #define OVR_CPP_NO_UNRESTRICTED_UNIONS 1 + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_EXTENDED_SIZEOF +// +// Defined as 1 if the compiler supports C++11 class sizeof extensions (e.g. sizeof SomeClass::someMember). +// Otherwise undefined. + +#if !defined(OVR_CPP_NO_EXTENDED_SIZEOF) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1900)) /* VS2014+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 405))) /* EDG 4.5+ */ + #define OVR_CPP_NO_EXTENDED_SIZEOF 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_INLINE_NAMESPACES +// +// Defined as 1 if the compiler supports C++11 inlined namespaces. Otherwise undefined. +// http://en.cppreference.com/w/cpp/language/namespace#Inline_namespaces + +#if !defined(OVR_CPP_NO_INLINE_NAMESPACES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 400)) /* Apple clang 4.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 405))) /* EDG 4.5+ */ + // Not supported by VC++ as of VS2013. + #define OVR_CPP_NO_INLINE_NAMESPACES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS +// +// Defined as 1 if the compiler supports C++11 explicit conversion operators. Otherwise undefined. +// http://en.cppreference.com/w/cpp/language/explicit + +#if !defined(OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_explicit_conversions)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 404))) /* EDG 4.4+ */ + #define OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS +// +// Defined as 1 if the compiler supports C++11 local class template parameters. Otherwise undefined. +// Example: +// void Test() { +// struct LocalClass{ }; +// SomeTemplateClass<LocalClass> t; // Allowed only in C++11 +// } + +#if !defined(OVR_CPP_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_local_type_template_args)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 402))) /* EDG 4.2+ */ + #define OVR_CPP_NO_LOCAL_CLASS_TEMPLATE_PARAMETERS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_NEW_CHARACTER_TYPES +// +// Defined as 1 if the compiler natively supports C++11 char16_t and char32_t. Otherwise undefined. +// VC++ through at least VS2013 defines char16_t as unsigned short in its standard library, +// but it is not a native type or unique type, nor can you for a string literal with it. + +#if !defined(OVR_CPP_NO_NEW_CHARACTER_TYPES) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_unicode_literals)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 407))) /* EDG 4.7+ */ + // Not supported by VC++ as of VS2013. + #define OVR_CPP_NO_NEW_CHARACTER_TYPES 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_UNICODE_CHAR_NAME_LITERALS +// +// Defined as 1 if the compiler supports C++11 \u and \U character literals for +// native char16_t and char32_t types. +// +#if !defined(OVR_CPP_NO_UNICODE_CHAR_NAME_LITERALS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + // Not supported by VC++ as of VS2013. VC++'s existing \U and \u are non-conforming. + #define OVR_CPP_NO_UNICODE_CHAR_NAME_LITERALS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_USER_DEFINED_LITERALS +// +// Defined as 1 if the compiler supports C++11 user-defined literals. Otherwise undefined. + +#if !defined(OVR_CPP_NO_USER_DEFINED_LITERALS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 301)) /* clang 3.1+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 401)) /* Apple clang 4.1+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + // Not supported by VC++ as of VS2013. + #define OVR_CPP_NO_USER_DEFINED_LITERALS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_UNICODE_STRING_LITERALS +// +// Defined as 1 if the compiler supports C++11 Unicode string literals. Otherwise undefined. +// http://en.wikipedia.org/wiki/C%2B%2B11#New_string_literals + +#if !defined(OVR_CPP_NO_UNICODE_STRING_LITERALS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_unicode_literals)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 407))) /* EDG 4.7+ */ + // Not supported by VC++ as of VS2013. + #define OVR_CPP_NO_UNICODE_STRING_LITERALS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_RAW_STRING_LITERALS +// +// Defined as 1 if the compiler supports C++11 raw literals. Otherwise undefined. +// http://en.wikipedia.org/wiki/C%2B%2B11#New_string_literals + +#if !defined(OVR_CPP_NO_RAW_STRING_LITERALS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_raw_string_literals)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 405)) /* GCC 4.5+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 407))) /* EDG 4.7+ */ + // Not supported by VC++ as of VS2013. + #define OVR_CPP_NO_RAW_STRING_LITERALS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_UNIFIED_INITIALIZATION_SYNTAX +// +// Defined as 1 if the compiler supports C++11 unified initialization. +// http://en.wikipedia.org/wiki/C%2B%2B11#Uniform_initialization + +#if !defined(OVR_CPP_NO_UNIFIED_INITIALIZATION_SYNTAX) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_generalized_initializers)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 404)) /* GCC 4.4+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1800)) /* VS2013+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 406))) /* EDG 4.6+ */ + #define OVR_CPP_NO_UNIFIED_INITIALIZATION_SYNTAX 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_EXTENDED_FRIEND_DECLARATIONS +// +// Defined as 1 if the compiler supports C++11 extended friends. + +#if !defined(OVR_CPP_NO_EXTENDED_FRIEND_DECLARATIONS) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && !defined(__APPLE__) && (__clang__ >= 209)) /* clang 2.9+ */ && \ + !(defined(__clang__) && defined(__APPLE__) && (__clang__ >= 400)) /* Apple clang 4.0+ */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 407)) /* GCC 4.7+ */ && \ + !(defined(_MSC_VER) && (_MSC_VER >= 1600)) /* VS2010+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 401))) /* EDG 4.1+ */ + #define OVR_CPP_NO_EXTENDED_FRIEND_DECLARATIONS 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_CPP_NO_THREAD_LOCAL +// +// Defined as 1 if the compiler supports C++11 thread_local. Else undefined. Does not +// indicate if the compiler supports C thread-local compiler extensions such as __thread +// and declspec(thread). Use OVR_THREAD_LOCAL if you want to declare a thread-local +// variable that supports C++11 thread_local when available but the C extension when +// it's available. The primary difference between C++11 thread_local and C extensions is +// that C++11 thread_local supports non-PODs and calls their constructors and destructors. +// +// Note that thread_local requires both compiler and linker support, and so it's possible +// that the compiler may support thread_local but the linker does not. + +#if !defined(OVR_CPP_NO_THREAD_LOCAL) + #if !defined(OVR_CPP11_ENABLED) || \ + (!(defined(__clang__) && OVR_CC_HAS_FEATURE(cxx_thread_local)) /* clang */ && \ + !(defined(__GNUC__) && (OVR_CC_VERSION >= 408)) /* GCC 4.8+ */ && \ + !(defined(__EDG_VERSION__) && (__EDG_VERSION__ >= 408))) /* EDG 4.8+ */ + #define OVR_CPP_NO_THREAD_LOCAL 1 + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_ALIGNAS / OVR_ALIGNOF +// +// OVR_ALIGNAS(n) // Specifies a size_t power of two alignment for a type or instance. +// OVR_ALIGNOF(type) // Returns the size_t alignment of a type or instance. +// +// Example usage: +// OVR_ALIGNAS(8) char c = 'c'; // Specifies that the instance c be aligned to an 8 byte boundary. +// typedef OVR_ALIGNAS(8) char C; // Specifies that the type C be aligned to an 8 byte boundary. +// struct OVR_ALIGNAS(64) S{ char array[16]; }; // Specfies that the struct S have a natural alignment of 64. +// OVR_ALIGNAS(32) S s; // Specifies that the instance s of struct S be aligned to an 32 byte boundary. +// OVR_ALIGNAS(32) struct T{ char array[16]; } t; // Specfies that the instance t of struct T have a natural alignment of 32. +// struct OVR_ALIGNAS(T) U{}; // Specifes that U be aligned the same as T. Supported only by C++11 compilers (see OVR_CPP_NO_ALIGNAS). +// +// size_t a = OVR_ALIGNOF(double); // Returns the natural alignment of the double type. +// size_t a = OVR_ALIGNOF(S); // Returns the natural alignment of the struct S type. +// +// Note: If C++11 alignas is supported, then alignas/OVR_ALIGNAS may take a const expression in addition to a constant. +// Note: The C11 Standard species the _Alignas keyword and alignas as a macro for it in <stdalign.h> + +#if !defined(OVR_ALIGNAS) + #if defined(OVR_CC_GNU) && !defined(OVR_CPP_NO_ALIGNAS) // If C++11 alignas is supported... + #define OVR_ALIGNAS(n) alignas(n) + #elif defined(__clang__) && !defined(OVR_CPP_NO_ALIGNAS) + #define OVR_ALIGNAS(n) alignas(n) + #elif defined(OVR_CC_GNU) || defined(__clang__) + #define OVR_ALIGNAS(n) __attribute__((aligned(n))) + #elif defined(OVR_CC_MSVC) || defined(OVR_CC_INTEL) + #define OVR_ALIGNAS(n) __declspec(align(n)) // For Microsoft the alignment must be a literal integer. + #elif defined(OVR_CC_ARM) + #define OVR_ALIGNAS(n) __align(n) + #else + #error Need to define OVR_ALIGNAS + #endif +#endif + +#if !defined(OVR_ALIGNOF) + #if defined(OVR_CC_GNU) && !defined(OVR_CPP_NO_ALIGNOF) // If C++11 alignof is supported... + #define OVR_ALIGNOF(type) alignof(type) + #elif defined(__clang__) && !defined(OVR_CPP_NO_ALIGNOF) + #define OVR_ALIGNOF(type) alignof(type) + #elif defined(OVR_CC_GNU) || defined(__clang__) + #define OVR_ALIGNOF(type) ((size_t)__alignof__(type)) + #elif defined(OVR_CC_MSVC) || defined(OVR_CC_INTEL) + #define OVR_ALIGNOF(type) ((size_t)__alignof(type)) + #elif defined(OVR_CC_ARM) + #define OVR_ALIGNOF(type) ((size_t)__ALIGNOF__(type)) + #else + #error Need to define OVR_ALIGNOF + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_ASSUME / OVR_ANALYSIS_ASSUME +// +// This is a portable wrapper for VC++'s __assume and __analysis_assume. +// __analysis_assume is typically used to quell VC++ static analysis warnings. +// +// Example usage: +// void Test(char c){ +// switch(c){ +// case 'a': +// case 'b': +// case 'c': +// case 'd': +// break; +// default: +// OVR_ASSUME(0); // Unreachable code. +// } +// } +// +// size_t Test(char* str){ +// OVR_ANALYSIS_ASSUME(str != nullptr); +// return strlen(str); +// } + +#if !defined(OVR_ASSUME) + #if defined(OVR_CC_MSVC) + #define OVR_ASSUME(x) __assume(x) + #define OVR_ANALYSIS_ASSUME(x) __analysis_assume(!!(x)) + #else + #define OVR_ASSUME(x) + #define OVR_ANALYSIS_ASSUME(x) + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_RESTRICT +// +// Wraps the C99 restrict keyword in a portable way. +// C++11 and C++14 don't have restrict but this functionality is supported by +// all C++ compilers. +// +// Example usage: +// void* memcpy(void* OVR_RESTRICT s1, const void* OVR_RESTRICT s2, size_t n); + +#if !defined(OVR_RESTRICT) + #define OVR_RESTRICT __restrict // Currently supported by all compilers of significance to us. +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_NOEXCEPT / OVR_NOEXCEPT_IF(predicate) / OVR_NOEXCEPT_EXPR(expression) +// +// Implements a portable wrapper for C++11 noexcept. +// http://en.cppreference.com/w/cpp/language/noexcept +// +// Example usage: +// void Test() OVR_NOEXCEPT {} // This function doesn't throw. +// +// template <typename T> +// void DoNothing() OVR_NOEXCEPT_IF(OVR_NOEXCEPT_EXPR(T())) // Throws an if and only if T::T(int) throws. +// { T t(3); } +// +#if !defined(OVR_NOEXCEPT) + #if defined(OVR_CPP_NOEXCEPT) + #define OVR_NOEXCEPT + #define OVR_NOEXCEPT_IF(predicate) + #define OVR_NOEXCEPT_EXPR(expression) false + #else + #define OVR_NOEXCEPT noexcept + #define OVR_NOEXCEPT_IF(predicate) noexcept((predicate)) + #define OVR_NOEXCEPT_EXPR(expression) noexcept((expression)) + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_FINAL +// +// Wraps the C++11 final keyword in a portable way. +// http://en.cppreference.com/w/cpp/language/final +// +// Example usage: +// struct Test { virtual int GetValue() OVR_FINAL; }; + +#if !defined(OVR_FINAL) + #if defined(OVR_CC_MSVC) && (OVR_CC_VERSION < 1700) // VC++ 2012 and earlier + #define OVR_FINAL sealed + #elif defined(OVR_CPP_INHERITANCE_FINAL) + #define OVR_FINAL + #else + #define OVR_FINAL final + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_OVERRIDE +// +// Wraps the C++11 override keyword in a portable way. +// http://en.cppreference.com/w/cpp/language/override +// +// Example usage: +// struct Parent { virtual void Func(int); }; +// struct Child : public Parent { void Func(int) OVR_OVERRIDE; }; + +#if !defined(OVR_CPP11_ENABLED) +#define OVR_OVERRIDE +#elif !defined(OVR_OVERRIDE) + #if defined(OVR_CPP_OVERRIDE) + #define OVR_OVERRIDE + #else + #if (defined(_MSC_VER) && (_MSC_VER <= 1600)) + #pragma warning(disable : 4481) + #endif + #define OVR_OVERRIDE override + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_FINAL_OVERRIDE +// +// Wraps the C++11 final+override keywords (a common combination) in a portable way. +// +// Example usage: +// struct Parent { virtual void Func(); }; +// struct Child : public Parent { virtual void Func() OVR_FINAL_OVERRIDE; }; + +#if !defined(OVR_FINAL_OVERRIDE) + #define OVR_FINAL_OVERRIDE OVR_FINAL OVR_OVERRIDE +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_EXTERN_TEMPLATE +// +// Portable wrapper for C++11 extern template. This tells the compiler to not instantiate +// the template in the current translation unit, which can significantly speed up +// compilation and avoid problems due to two translation units compiling code with +// different settings. +// +// Example usage: +// OVR_EXTERN_TEMPLATE(class basic_string<char>); // Nothing to do for non-C++11 compilers. + +#if !defined(OVR_EXTERN_TEMPLATE) + #if defined(OVR_CPP_EXTERN_TEMPLATE) + #define OVR_EXTERN_TEMPLATE(decl) + #else + #define OVR_EXTERN_TEMPLATE(decl) extern template decl + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_CONSTEXPR / OVR_CONSTEXPR_OR_CONST +// +// Portable wrapper for C++11 constexpr. Doesn't include C++14 relaxed constexpr, +// for which a different wrapper name is reserved. +// +// Example usage: +// OVR_CONSTEXPR int Test() { return 15; } // This can be optimized better by a C++11 compiler that supports constexpr. +// OVR_CONSTEXPR_OR_CONST float x = 3.14159f; // This can be optimized better by a C++11 compiler, but if not then at least make it const. + +#if !defined(OVR_CONSTEXPR) + #if defined(OVR_CPP_NO_CONSTEXPR) + #define OVR_CONSTEXPR + #else + #define OVR_CONSTEXPR constexpr + #endif +#endif + +#if !defined(OVR_CONSTEXPR_OR_CONST) + #if defined(OVR_CPP_NO_CONSTEXPR) + #define OVR_CONSTEXPR_OR_CONST const + #else + #define OVR_CONSTEXPR_OR_CONST constexpr + #endif +#endif + + + +// ----------------------------------------------------------------------------------- +// ***** OVR_FUNCTION_DELETE / OVR_FUNCTION_DEFAULT +// +// Wraps the C++11 delete and default keywords in a way that allows for cleaner code +// while making for a better version of uncallable or default functions. +// +// Example usage: +// struct Test{ +// Test() OVR_FUNCTION_DEFAULT; // Non-C++11 compilers will require a separate definition for Test(). +// private: // Users should put OVR_FUNCTION_DELETE usage in a private +// void Uncallable() OVR_FUNCTION_DELETE; // area for compatibility with pre-C++11 compilers. +// }; + +#if defined(OVR_CPP_NO_DELETED_FUNCTIONS) + #define OVR_FUNCTION_DELETE +#else + #define OVR_FUNCTION_DELETE = delete +#endif + +#if defined(OVR_CPP_NO_DEFAULTED_FUNCTIONS) + #define OVR_FUNCTION_DEFAULT +#else + #define OVR_FUNCTION_DEFAULT = default +#endif + + + +// ----------------------------------------------------------------------------------- +// ***** OVR_NON_COPYABLE +// +// Allows you to specify a class as being neither copy-constructible nor assignable, +// which is a commonly needed pattern in C++ programming. Classes with this declaration +// are required to be default constructible (as are most classes). For pre-C++11 +// compilers this macro declares a private section for the class, which will be +// inherited by whatever code is directly below the macro invocation by default. +// +// Example usage: +// struct Test { +// Test(); +// ... +// OVR_NON_COPYABLE(Test) +// }; + +#if !defined(OVR_NON_COPYABLE) + #if defined(OVR_CPP_NO_DELETED_FUNCTIONS) + #define OVR_NON_COPYABLE(Type) \ + private: \ + Type(const Type&); \ + void operator=(const Type&); + #else + #define OVR_NON_COPYABLE(Type) \ + Type(const Type&) = delete; \ + void operator=(const Type&) = delete; + #endif +#endif + + + +// ----------------------------------------------------------------------------------- +// ***** OVR_BUILD_DEBUG +// +// Defines OVR_BUILD_DEBUG when the compiler default debug preprocessor is set. +// +// If you want to control the behavior of these flags, then explicitly define +// either -DOVR_BUILD_RELEASE or -DOVR_BUILD_DEBUG in the compiler arguments. + +#if !defined(OVR_BUILD_DEBUG) && !defined(OVR_BUILD_RELEASE) + #if defined(OVR_CC_MSVC) + #if defined(_DEBUG) + #define OVR_BUILD_DEBUG + #endif + #else + #if defined(DEBUG) + #define OVR_BUILD_DEBUG + #endif + #endif +#endif + + + +#endif // header include guard diff --git a/LibOVRKernel/Src/Kernel/OVR_ContainerAllocator.h b/LibOVRKernel/Src/Kernel/OVR_ContainerAllocator.h new file mode 100644 index 0000000..30cf3cc --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_ContainerAllocator.h @@ -0,0 +1,281 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_ContainerAllocator.h +Content : Template allocators and constructors for containers. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_ContainerAllocator_h +#define OVR_ContainerAllocator_h + +#include "OVR_Allocator.h" +#include <string.h> + + +namespace OVR { + + +//----------------------------------------------------------------------------------- +// ***** Container Allocator + +// ContainerAllocator serves as a template argument for allocations done by +// containers, such as Array and Hash; replacing it could allow allocator +// substitution in containers. + +class ContainerAllocatorBase +{ +public: + static void* Alloc(size_t size) + { return OVR_ALLOC(size); } + + static void* Realloc(void* p, size_t newSize) + { return OVR_REALLOC(p, newSize); } + + static void Free(void *p) + { OVR_FREE(p); } +}; + + + +//----------------------------------------------------------------------------------- +// ***** Constructors, Destructors, Copiers + +// Plain Old Data - movable, no special constructors/destructor. +template<class T> +class ConstructorPOD +{ +public: + static void Construct(void *) + {} + + static void Construct(void *p, const T& source) + { + *(T*)p = source; + } + + // Same as above, but allows for a different type of constructor. + template <class S> + static void ConstructAlt(void *p, const S& source) + { + *(T*)p = source; + } + + static void ConstructArray(void*, size_t) + {} + + static void ConstructArray(void* p, size_t count, const T& source) + { + uint8_t *pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + *(T*)pdata = source; + } + + static void ConstructArray(void* p, size_t count, const T* psource) + { + memcpy(p, psource, sizeof(T) * count); + } + + static void Destruct(T*) + {} + + static void DestructArray(T*, size_t) + {} + + static void CopyArrayForward(T* dst, const T* src, size_t count) + { + memmove(dst, src, count * sizeof(T)); + } + + static void CopyArrayBackward(T* dst, const T* src, size_t count) + { + memmove(dst, src, count * sizeof(T)); + } + + static bool IsMovable() + { return true; } +}; + + +//----------------------------------------------------------------------------------- +// ***** ConstructorMov +// +// Correct C++ construction and destruction for movable objects +template<class T> +class ConstructorMov +{ +public: + static void Construct(void* p) + { + OVR::Construct<T>(p); + } + + static void Construct(void* p, const T& source) + { + OVR::Construct<T>(p, source); + } + + // Same as above, but allows for a different type of constructor. + template <class S> + static void ConstructAlt(void* p, const S& source) + { + OVR::ConstructAlt<T,S>(p, source); + } + + static void ConstructArray(void* p, size_t count) + { + uint8_t* pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + Construct(pdata); + } + + static void ConstructArray(void* p, size_t count, const T& source) + { + uint8_t* pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + Construct(pdata, source); + } + + static void ConstructArray(void* p, size_t count, const T* psource) + { + uint8_t* pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + Construct(pdata, *psource++); + } + + static void Destruct(T* p) + { + p->~T(); + OVR_UNUSED(p); // Suppress silly MSVC warning + } + + static void DestructArray(T* p, size_t count) + { + p = p + count - 1; + for (size_t i=0; i<count; ++i, --p) + p->~T(); + } + + static void CopyArrayForward(T* dst, const T* src, size_t count) + { + memmove(dst, src, count * sizeof(T)); + } + + static void CopyArrayBackward(T* dst, const T* src, size_t count) + { + memmove(dst, src, count * sizeof(T)); + } + + static bool IsMovable() + { return true; } +}; + + +//----------------------------------------------------------------------------------- +// ***** ConstructorCPP +// +// Correct C++ construction and destruction for movable objects +template<class T> +class ConstructorCPP +{ +public: + static void Construct(void* p) + { + OVR::Construct<T>(p); + } + + static void Construct(void* p, const T& source) + { + OVR::Construct<T>(p, source); + } + + // Same as above, but allows for a different type of constructor. + template <class S> + static void ConstructAlt(void* p, const S& source) + { + OVR::ConstructAlt<T,S>(p, source); + } + + static void ConstructArray(void* p, size_t count) + { + uint8_t* pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + Construct(pdata); + } + + static void ConstructArray(void* p, size_t count, const T& source) + { + uint8_t* pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + Construct(pdata, source); + } + + static void ConstructArray(void* p, size_t count, const T* psource) + { + uint8_t* pdata = (uint8_t*)p; + for (size_t i=0; i< count; ++i, pdata += sizeof(T)) + Construct(pdata, *psource++); + } + + static void Destruct(T* p) + { + p->~T(); + OVR_UNUSED(p); // Suppress silly MSVC warning + } + + static void DestructArray(T* p, size_t count) + { + p += count - 1; + for (size_t i=0; i<count; ++i, --p) + p->~T(); + } + + static void CopyArrayForward(T* dst, const T* src, size_t count) + { + for(size_t i = 0; i < count; ++i) + dst[i] = src[i]; + } + + static void CopyArrayBackward(T* dst, const T* src, size_t count) + { + for(size_t i = count; i; --i) + dst[i-1] = src[i-1]; + } + + static bool IsMovable() + { return false; } +}; + + +//----------------------------------------------------------------------------------- +// ***** Container Allocator with movement policy +// +// Simple wraps as specialized allocators +template<class T> struct ContainerAllocator_POD : ContainerAllocatorBase, ConstructorPOD<T> {}; +template<class T> struct ContainerAllocator : ContainerAllocatorBase, ConstructorMov<T> {}; +template<class T> struct ContainerAllocator_CPP : ContainerAllocatorBase, ConstructorCPP<T> {}; + + +} // OVR + + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp b/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp new file mode 100644 index 0000000..ea39fb0 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_DebugHelp.cpp @@ -0,0 +1,4101 @@ +/************************************************************************************ + +Filename : ExceptionHandler.cpp +Content : Platform-independent exception handling interface +Created : October 6, 2014 + +Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +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. + +************************************************************************************/ + +#include "OVR_DebugHelp.h" +#include "OVR_Types.h" +#include "OVR_UTF8Util.h" +#include "OVR_Atomic.h" +#include "OVR_SysFile.h" +#include "Util/Util_SystemGUI.h" + +#include <stdlib.h> +#include <time.h> + +#if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64) + #pragma warning(push, 0) + #include "OVR_Win32_IncludeWindows.h" + #include <ShlObj.h> + #include <WinNT.h> + #include <DbgHelp.h> + #include <WinVer.h> + #include <share.h> + #include <Psapi.h> + #include <TlHelp32.h> + #include <comutil.h> + #include <Wbemcli.h> + #include <Wbemidl.h> + #include <ObjBase.h> + #include <process.h> + #pragma warning(pop) + + #pragma comment(lib, "Psapi.lib") // To consider: It may be a problem to statically link to these libraries if the application at runtime intends to dynamically + #pragma comment(lib, "ole32.lib") // link to a different version of the same library, and we are statically linked into that application instead of being a DLL. + #pragma comment(lib, "shell32.lib") + #pragma comment(lib, "Version.lib") + + // NtQueryInformation and THREAD_BASIC_INFORMATION are undocumented but frequently needed for digging into thread information. + typedef LONG (WINAPI *NtQueryInformationThreadFunc)(HANDLE, int, PVOID, ULONG, PULONG); + + struct THREAD_BASIC_INFORMATION + { + LONG ExitStatus; + PVOID TebBaseAddress; + PVOID UniqueProcessId; + PVOID UniqueThreadId; + PVOID Priority; + PVOID BasePriority; + }; + + #ifndef UNW_FLAG_NHANDLER // Older Windows SDKs don't support this. + #define UNW_FLAG_NHANDLER 0 + #endif + +#elif defined(OVR_OS_MAC) + #include <unistd.h> + #include <sys/sysctl.h> + #include <sys/utsname.h> + #include <sys/types.h> + #include <sys/mman.h> + #include <stdlib.h> + #include <stdio.h> + #include <pthread.h> + #include <mach/mach.h> + #include <mach/mach_error.h> + #include <mach/thread_status.h> + #include <mach/exception.h> + #include <mach/task.h> + #include <mach/thread_act.h> + #include <mach-o/dyld.h> + #include <mach-o/dyld_images.h> + #include <libproc.h> + #include <libgen.h> + #include <execinfo.h> + #include <cxxabi.h> + #include "OVR_mach_exc_OSX.h" + + #if defined(__LP64__) + typedef struct mach_header_64 MachHeader; + typedef struct segment_command_64 SegmentCommand; + typedef struct section_64 Section; + #define kLCSegment LC_SEGMENT_64 + #else + typedef struct mach_header MachHeader; + typedef struct segment_command SegmentCommand; + typedef struct section Section; + #define kLCSegment LC_SEGMENT + #endif + + extern "C" const struct dyld_all_image_infos* _dyld_get_all_image_infos(); // From libdyld.dylib + +#elif defined(OVR_OS_UNIX) + #include <unistd.h> + #include "sys/stat.h" +#if defined(OVR_OS_ANDROID) + #include <linux/sysctl.h> +#else + #include <sys/sysctl.h> +#endif + #include <sys/utsname.h> + #include <sys/types.h> + #include <sys/ptrace.h> + #include <sys/wait.h> + #include <sys/mman.h> + #include <stdlib.h> + #include <stdio.h> + #include <pthread.h> + #include <libgen.h> +#if !defined(OVR_OS_ANDROID) + #include <execinfo.h> +#endif + #include <cxxabi.h> + //#include <libunwind.h> // Can't use this until we can ensure that we have an installed version of it. +#endif + +#if !defined(MIN) + #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) + #define MAX(X,Y) ((X) > (Y) ? (X) : (Y)) +#endif + + +OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized +OVR_DISABLE_MSVC_WARNING(4996) // This function or variable may be unsafe + + + + +#if defined(OVR_OS_APPLE) + static OVR::ExceptionHandler* sExceptionHandler = nullptr; + const uint32_t sMachCancelMessageType = 0x0ca9ce11; // This is a made-up value of our own choice. + + extern "C" + { + kern_return_t catch_mach_exception_raise_OVR(mach_port_t /*exceptionPort*/, mach_port_t /*threadSysId*/, + mach_port_t /*machTask*/, exception_type_t /*machExceptionType*/, + mach_exception_data_t /*machExceptionData*/, mach_msg_type_number_t /*machExceptionDataCount*/) + { + return KERN_FAILURE; + } + + kern_return_t catch_mach_exception_raise_state_OVR(mach_port_t /*exceptionPort*/, exception_type_t /*exceptionType*/, + const mach_exception_data_t /*machExceptionData*/, mach_msg_type_number_t /*machExceptionDataCount*/, + int* /*pMachExceptionFlavor*/, const thread_state_t /*threadStatePrev*/, mach_msg_type_number_t /*threaStatePrevCount*/, + thread_state_t /*threadStateNew*/, mach_msg_type_number_t* /*pThreadStateNewCount*/) + { + return KERN_FAILURE; + } + + kern_return_t catch_mach_exception_raise_state_identity_OVR(mach_port_t exceptionPort, mach_port_t threadSysId, mach_port_t machTask, + exception_type_t exceptionType, mach_exception_data_type_t* pMachExceptionData, + mach_msg_type_number_t machExceptionDataCount, int* pMachExceptionFlavor, + thread_state_t threadStatePrev, mach_msg_type_number_t threadStatePrevCount, + thread_state_t threadStateNew, mach_msg_type_number_t* pThreadStateNewCount) + { + return sExceptionHandler->HandleMachException(exceptionPort, threadSysId, machTask, exceptionType, pMachExceptionData, + machExceptionDataCount, pMachExceptionFlavor, threadStatePrev, threadStatePrevCount, + threadStateNew, pThreadStateNewCount); + } + + void* MachHandlerThreadFunctionStatic(void* pExceptionHandlerVoid) + { + return static_cast<OVR::ExceptionHandler*>(pExceptionHandlerVoid)->MachHandlerThreadFunction(); + } + + } // extern "C" +#endif + + +namespace OVR { + + +void GetInstructionPointer(void*& pInstruction) +{ + #if defined(OVR_CC_MSVC) + pInstruction = _ReturnAddress(); + #else // GCC, clang + pInstruction = __builtin_return_address(0); + #endif +} + + +// addressStrCapacity should be at least 2+16+1 = 19 characters. +static size_t SprintfAddress(char* addressStr, size_t addressStrCapacity, const void* pAddress) +{ + #if defined(OVR_CC_MSVC) + #if (OVR_PTR_SIZE >= 8) + return OVR_snprintf(addressStr, addressStrCapacity, "0x%016I64x", pAddress); // e.g. 0x0123456789abcdef + #else + return OVR_snprintf(addressStr, addressStrCapacity, "0x%08x", pAddress); // e.g. 0x89abcdef + #endif + #else + #if (OVR_PTR_SIZE >= 8) + return OVR_snprintf(addressStr, addressStrCapacity, "%016llx", pAddress); // e.g. 0x0123456789abcdef + #else + return OVR_snprintf(addressStr, addressStrCapacity, "%08x", pAddress); // e.g. 0x89abcdef + #endif + #endif +} + + +// threadHandleStrCapacity should be at least 2+16+1 = 19 characters. +static size_t SprintfThreadHandle(char* threadHandleStr, size_t threadHandleStrCapacity, const ThreadHandle& threadHandle) +{ + return SprintfAddress(threadHandleStr, threadHandleStrCapacity, threadHandle); +} + + +// threadSysIdStrCapacity should be at least 20+4+16+2 = 42 characters. +static size_t SprintfThreadSysId(char* threadSysIdStr, size_t threadSysIdStrCapacity, const ThreadSysId& threadSysId) +{ + #if defined(OVR_CC_MSVC) // Somebody could conceivably use VC++ with a different standard library that supports %ll. And VS2012+ also support %ll. + return OVR_snprintf(threadSysIdStr, threadSysIdStrCapacity, "%I64u (0x%I64x)", (uint64_t)threadSysId, (uint64_t)threadSysId); // e.g. 5642 (0x160a) + #else + return OVR_snprintf(threadSysIdStr, threadSysIdStrCapacity, "%llu (0x%llx)", (uint64_t)threadSysId, (uint64_t)threadSysId); + #endif +} + + + + + +void GetThreadStackBounds(void*& pStackBase, void*& pStackLimit, ThreadHandle threadHandle) +{ + #if defined(OVR_OS_WIN64) || defined(OVR_OS_WIN32) + ThreadSysId threadSysIdCurrent = (ThreadSysId)GetCurrentThreadId(); + ThreadSysId threadSysId; + NT_TIB* pTIB = nullptr; + + if(threadHandle == OVR_THREADHANDLE_INVALID) + threadSysId = threadSysIdCurrent; + else + threadSysId = ConvertThreadHandleToThreadSysId(threadHandle); + + if(threadSysId == threadSysIdCurrent) + { + #if (OVR_PTR_SIZE == 4) + // Need to use __asm__("movl %%fs:0x18, %0" : "=r" (pTIB) : : ); under gcc/clang. + __asm { + mov eax, fs:[18h] + mov pTIB, eax + } + #else + pTIB = (NT_TIB*)NtCurrentTeb(); + #endif + } + else + { + #if (OVR_PTR_SIZE == 4) + // It turns out we don't need to suspend the thread when getting SegFs/SegGS, as that's + // constant per thread and doesn't require the thread to be suspended. + //SuspendThread((HANDLE)threadHandle); + CONTEXT context; + memset(&context, 0, sizeof(context)); + context.ContextFlags = CONTEXT_SEGMENTS; + GetThreadContext((HANDLE)threadHandle, &context); // Requires THREAD_QUERY_INFORMATION privileges. + + LDT_ENTRY ldtEntry; + if(GetThreadSelectorEntry(threadHandle, context.SegFs, &ldtEntry)) // Requires THREAD_QUERY_INFORMATION + pTIB = (NT_TIB*)((ldtEntry.HighWord.Bits.BaseHi << 24 ) | (ldtEntry.HighWord.Bits.BaseMid << 16) | ldtEntry.BaseLow); + + //ResumeThread((HANDLE)threadHandle); + #else + // We cannot use GetThreadSelectorEntry or Wow64GetThreadSelectorEntry on Win64. + // We need to read the SegGs qword at offset 0x30. We can't use pTIB = (NT_TIB*)__readgsqword(0x30) because that reads only the current setGs offset. + // mov rax, qword ptr gs:[30h] + // mov qword ptr [pTIB],rax + // In the meantime we rely on the NtQueryInformationThread function. + + static NtQueryInformationThreadFunc spNtQueryInformationThread = nullptr; + + if(!spNtQueryInformationThread) + { + HMODULE hNTDLL = GetModuleHandleA("ntdll.dll"); + spNtQueryInformationThread = (NtQueryInformationThreadFunc)(uintptr_t)GetProcAddress(hNTDLL, "NtQueryInformationThread"); + } + + if(spNtQueryInformationThread) + { + THREAD_BASIC_INFORMATION tbi; + + memset(&tbi, 0, sizeof(tbi)); + LONG result = spNtQueryInformationThread(threadHandle, 0, &tbi, sizeof(tbi), nullptr); // Requires THREAD_QUERY_INFORMATION privileges + if(result == 0) + pTIB = (NT_TIB*)tbi.TebBaseAddress; + } + #endif + } + + if(pTIB) + { + pStackBase = (void*)pTIB->StackBase; + pStackLimit = (void*)pTIB->StackLimit; + } + else + { + pStackBase = nullptr; + pStackLimit = nullptr; + } + + #elif defined(OVR_OS_APPLE) + if(!threadHandle) + threadHandle = pthread_self(); + + pStackBase = pthread_get_stackaddr_np((pthread_t)threadHandle); + size_t stackSize = pthread_get_stacksize_np((pthread_t)threadHandle); + pStackLimit = (void*)((size_t)pStackBase - stackSize); + + #elif defined(OVR_OS_UNIX) + pStackBase = nullptr; + pStackLimit = nullptr; + + pthread_attr_t threadAttr; + pthread_attr_init(&threadAttr); + + #if defined(OVR_OS_LINUX) + int result = pthread_getattr_np((pthread_t)threadHandle, &threadAttr); + #else + int result = pthread_attr_get_np((pthread_t)threadHandle, &threadAttr); + #endif + + if(result == 0) + { + size_t stackSize = 0; + result = pthread_attr_getstack(&threadAttr, &pStackLimit, &stackSize); + + if(result == 0) + pStackBase = (void*)((uintptr_t)pStackLimit + stackSize); // We assume the stack grows downward. + } + + #endif +} + + +bool OVRIsDebuggerPresent() +{ + #if defined(OVR_OS_MS) + return ::IsDebuggerPresent() != 0; + + #elif defined(OVR_OS_APPLE) + int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() }; + struct kinfo_proc info; + size_t size = sizeof(info); + + info.kp_proc.p_flag = 0; + sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0); + + return ((info.kp_proc.p_flag & P_TRACED) != 0); + + #elif defined(PT_TRACE_ME) && !defined(OVR_OS_ANDROID) + return (ptrace(PT_TRACE_ME, 0, 1, 0) < 0); + + #elif (defined(OVR_OS_LINUX) || defined(OVR_OS_BSD)) && !defined(OVR_OS_ANDROID) + // This works better than the PT_TRACE_ME approach, but causes the debugger to get + // confused when executed under a debugger. + // It also presents this problem: + // http://pubs.opengroup.org/onlinepubs/009695399/functions/fork.html + // When the application calls fork() from a signal handler and any of the + // fork handlers registered by pthread_atfork() calls a function that is + // not asynch-signal-safe, the behavior is undefined. + // We may need to provide two pathways within this function, one of which + // doesn't fork and instead uses PT_TRACE_ME. + int pid = fork(); + int status; + bool present = false; + + if (pid == -1) // If fork failed... + { + // perror("fork"); + } + else if (pid == 0) // If we are the child process... + { + int ppid = getppid(); + + #if defined(OVR_OS_LINUX) + if (ptrace(PTRACE_ATTACH, ppid, nullptr, nullptr) == 0) + #else + if (ptrace(PT_ATTACH, ppid, nullptr, nullptr) == 0) + #endif + { + waitpid(ppid, nullptr, 0); + + #if defined(OVR_OS_LINUX) + ptrace(PTRACE_CONT, getppid(), nullptr, nullptr); + ptrace(PTRACE_DETACH, getppid(), nullptr, nullptr); + #else + ptrace(PT_CONTINUE, getppid(), nullptr, nullptr); + ptrace(PT_DETACH, getppid(), nullptr, nullptr); + #endif + } + else + { + // ptrace failed so the debugger is present. + present = true; + } + + exit(present ? 1 : 0); // The WEXITSTATUS call below will read this exit value. + } + else // Else we are the original process. + { + waitpid(pid, &status, 0); + present = WEXITSTATUS(status) ? true : false; // Read the exit value from the child's call to exit. + } + + return present; + + #else + return false; + #endif +} + + +// Exits the process with the given exit code. +void ExitProcess(intptr_t processReturnValue) +{ + exit((int)processReturnValue); +} + + +// Note that we can't just return sizeof(void*) == 8, as we may have the case of a +// 32 bit app running on a 64 bit operating system. +static bool Is64BitOS() +{ + #if (OVR_PTR_SIZE >= 8) + return true; + + #elif defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64) + BOOL is64BitOS = FALSE; + bool IsWow64ProcessPresent = (GetProcAddress(GetModuleHandleW(L"kernel32.dll"), "IsWow64Process") != nullptr); + return (IsWow64ProcessPresent && IsWow64Process(GetCurrentProcess(), &is64BitOS) && is64BitOS); + + #elif defined(OVR_OS_MAC) || defined(OVR_OS_UNIX) + utsname utsName; + memset(&utsName, 0, sizeof(utsName)); + return (uname(&utsName) == 0) && (strcmp(utsName.machine, "x86_64") == 0); + + #else + return false; + #endif +} + + +// The output will always be 0-terminated. +// Returns the required strlen of the output. +// Returns (size_t)-1 on failure. +size_t SpawnShellCommand(const char* shellCommand, char* output, size_t outputCapacity) +{ + #if defined(OVR_OS_UNIX) || defined(OVR_OS_APPLE) + FILE* pFile = popen(shellCommand, "r"); + + if(pFile) + { + size_t requiredLength = 0; + char buffer[256]; + + while(fgets(buffer, sizeof(buffer), pFile)) // fgets 0-terminates the buffer. + { + size_t length = OVR_strlen(buffer); + requiredLength += length; + + if(outputCapacity) + { + OVR_strlcpy(output, buffer, outputCapacity); + length = MIN(outputCapacity, length); + } + + output += length; + outputCapacity -= length; + } + + pclose(pFile); + return requiredLength; + } + #else + // To do. Properly solving this on Windows requires a bit of code. + OVR_UNUSED(shellCommand); + OVR_UNUSED(output); + OVR_UNUSED(outputCapacity); + #endif + + return (size_t)-1; +} + +// Retrieves the name of the given thread. +// To do: Move this to OVR_Threads.h +bool GetThreadName(OVR::ThreadHandle threadHandle, char* threadName, size_t threadNameCapacity) +{ + #if (defined(OVR_OS_APPLE) || defined(OVR_OS_LINUX)) && !defined(OVR_OS_ANDROID) + int result = pthread_getname_np((pthread_t)threadHandle, threadName, threadNameCapacity); + if(result == 0) + return true; + #else + // This is not currently possible on Windows, as only the debugger stores the thread name. We could potentially use a vectored + // exception handler to catch all thread name exceptions (0x406d1388) and record them in a static list at runtime. To detect + // thread exit we could use WMI Win32_ThreadStopTrace. Maintain a list of thread names between these two events. + OVR_UNUSED(threadHandle); + OVR_UNUSED(threadNameCapacity); + #endif + + if(threadNameCapacity) + threadName[0] = 0; + + return false; +} + + +OVR::ThreadSysId ConvertThreadHandleToThreadSysId(OVR::ThreadHandle threadHandle) +{ + #if defined(OVR_OS_WIN64) + return (OVR::ThreadSysId)::GetThreadId(threadHandle); // Requires THREAD_QUERY_INFORMATION privileges. + + #elif defined(OVR_OS_WIN32) + typedef DWORD (WINAPI *GetThreadIdFunc)(HANDLE); + + static volatile bool sInitialized = false; + static GetThreadIdFunc spGetThreadIdFunc = nullptr; + static NtQueryInformationThreadFunc spNtQueryInformationThread = nullptr; + + if(!sInitialized) + { + HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); + if(hKernel32) + spGetThreadIdFunc = (GetThreadIdFunc)(uintptr_t)GetProcAddress(hKernel32, "GetThreadId"); + + if(!spGetThreadIdFunc) + { + HMODULE hNTDLL = GetModuleHandleA("ntdll.dll"); + + if(hNTDLL) + spNtQueryInformationThread = (NtQueryInformationThreadFunc)(uintptr_t)GetProcAddress(hNTDLL, "NtQueryInformationThread"); + } + + sInitialized = true; + } + + if(spGetThreadIdFunc) + return (OVR::ThreadSysId)spGetThreadIdFunc(threadHandle); + + if(spNtQueryInformationThread) + { + THREAD_BASIC_INFORMATION tbi; + + if(spNtQueryInformationThread(threadHandle, 0, &tbi, sizeof(tbi), nullptr) == 0) + return (OVR::ThreadSysId)tbi.UniqueThreadId; + } + + return OVR_THREADSYSID_INVALID; + + #elif defined(OVR_OS_APPLE) + mach_port_t threadSysId = pthread_mach_thread_np((pthread_t)threadHandle); // OS 10.4 and later. + return (ThreadSysId)threadSysId; + + #elif defined(OVR_OS_LINUX) + + // I believe we can usually (though not portably) intepret the pthread_t as a pointer to a struct whose first member is a lwp id. + OVR_UNUSED(threadHandle); + return OVR_THREADSYSID_INVALID; + + #else + OVR_UNUSED(threadHandle); + return OVR_THREADSYSID_INVALID; + #endif +} + + +OVR::ThreadHandle ConvertThreadSysIdToThreadHandle(OVR::ThreadSysId threadSysId) +{ + #if defined(OVR_OS_MS) + // We currently request the given rights because that's what users of this function typically need it for. Ideally there would + // be a way to specify the requested rights in order to avoid the problem if we need only a subset of them but can't get it. + // The solution we use below to try opening with successively reduced rights will work for our uses here but isn't a good general solution to this. + OVR::ThreadHandle threadHandle = ::OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, TRUE, (DWORD)threadSysId); + + if(threadHandle == OVR_THREADHANDLE_INVALID) + { + threadHandle = ::OpenThread(THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, TRUE, (DWORD)threadSysId); + + if(threadHandle == OVR_THREADHANDLE_INVALID) + threadHandle = ::OpenThread(THREAD_QUERY_INFORMATION, TRUE, (DWORD)threadSysId); + } + + return threadHandle; + #elif defined(OVR_OS_MAC) + return (ThreadHandle)pthread_from_mach_thread_np((mach_port_t)threadSysId); + #else + return (ThreadHandle)threadSysId; + #endif +} + + +void FreeThreadHandle(OVR::ThreadHandle threadHandle) +{ + #if defined(OVR_OS_MS) + if(threadHandle != OVR_THREADHANDLE_INVALID) + ::CloseHandle(threadHandle); + #else + OVR_UNUSED(threadHandle); + #endif +} + + +OVR::ThreadSysId GetCurrentThreadSysId() +{ + #if defined(OVR_OS_MS) + return ::GetCurrentThreadId(); + #elif defined(OVR_OS_APPLE) + return (ThreadSysId)mach_thread_self(); + #else + return (ThreadSysId)pthread_self(); + #endif +} + + + +static void GetCurrentProcessFilePath(char* appPath, size_t appPathCapacity) +{ + appPath[0] = 0; + + #if defined(OVR_OS_MS) + wchar_t pathW[OVR_MAX_PATH]; + GetModuleFileNameW(0, pathW, (DWORD)OVR_ARRAY_COUNT(pathW)); + + size_t requiredUTF8Length = (size_t)OVR::UTF8Util::GetEncodeStringSize(pathW); // Returns required strlen. + + if(requiredUTF8Length < appPathCapacity) + { + OVR::UTF8Util::EncodeString(appPath, pathW, -1); + } + else + { + appPath[0] = 0; + } + + #elif defined(OVR_OS_APPLE) + struct BunderFolder + { + // Returns true if pStr ends with pFind, case insensitively. + // To do: Move OVR_striend to OVRKernel/Std.h + static bool OVR_striend(const char* pStr, const char* pFind, size_t strLength = (size_t)-1, size_t findLength = (size_t)-1) + { + if(strLength == (size_t)-1) + strLength = OVR_strlen(pStr); + if(findLength == (size_t)-1) + findLength = OVR_strlen(pFind); + if(strLength >= findLength) + return (OVR_stricmp(pStr + strLength - findLength, pFind) == 0); + return false; + } + + static bool IsBundleFolder(const char* filePath) + { + // https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/AboutBundles/AboutBundles.html#//apple_ref/doc/uid/10000123i-CH100-SW1 + static const char* extensionArray[] = { ".app", ".bundle", ".framework", ".plugin", ".kext" }; + + for(size_t i = 0; i < OVR_ARRAY_COUNT(extensionArray); i++) + { + if(OVR_striend(filePath, extensionArray[i])) + return true; + } + + return false; + } + }; + + char appPathTemp[PATH_MAX]; + uint32_t appPathTempCapacity32 = PATH_MAX; + size_t requiredStrlen = appPathCapacity; + + if(_NSGetExecutablePath(appPathTemp, &appPathTempCapacity32) == 0) + { + char appPathTempReal[PATH_MAX]; + + if(realpath(appPathTemp, appPathTempReal)) // If the path is a symbolic link, this converts it to the real path. + { + // To consider: Enable reading the internal bundle executable path. An application on Mac may in + // fact be within a file bundle, which is an private file system within a file. With Objective C + // we could use: [[NSWorkspace sharedWorkspace] isFilePackageAtPath:fullPath]; + bool shouldReadTheBunderPath = false; + + if(shouldReadTheBunderPath) + { + // We recursively call dirname() until we find .app/.bundle/.plugin as a directory name. + OVR_strlcpy(appPathTemp, appPathTempReal, OVR_ARRAY_COUNT(appPathTemp)); + bool found = BunderFolder::IsBundleFolder(appPathTemp); + + while(!found && OVR_strcmp(appPathTemp, ".") && OVR_strcmp(appPathTemp, "/")) + { + OVR_strlcpy(appPathTemp, dirname(appPathTemp), OVR_ARRAY_COUNT(appPathTemp)); + found = BunderFolder::IsBundleFolder(appPathTemp); + } + + if(found) // If somewhere above we found a parent bundle container... + requiredStrlen = OVR_strlcpy(appPath, appPathTemp, appPathCapacity); + else + requiredStrlen = OVR_strlcpy(appPath, appPathTempReal, appPathCapacity); + } + else + { + requiredStrlen = OVR_strlcpy(appPath, appPathTempReal, appPathCapacity); + } + } + } + + if(requiredStrlen >= appPathCapacity) + appPath[0] = '\0'; + + #elif defined(OVR_OS_LINUX) + ssize_t length = readlink("/proc/self/exe", appPath, appPathCapacity); + + if((length != -1) && ((size_t)length < (appPathCapacity - 1))) + { + appPath[length] = '\0'; + } + #endif +} + + +static const char* GetFileNameFromPath(const char* filePath) +{ + const char* lastPathSeparator = strrchr(filePath, '/'); + + #if defined(OVR_OS_MS) + // Microsoft APIs are inconsistent with respect to allowing / as a path separator. + const char* candidate = strrchr(filePath, '\\'); + + if(candidate > lastPathSeparator) + { + lastPathSeparator = candidate; + } + #endif + + if(lastPathSeparator) + return lastPathSeparator + 1; + + return filePath; +} + + + +static void FormatDateTime(char* buffer, size_t bufferCapacity, time_t timeValue, bool getDate, bool getTime, bool localDateTime, bool fileNameSafeCharacters = false) +{ + char temp[128]; + const tm* pTime = localDateTime ? localtime(&timeValue) : gmtime(&timeValue); + + if(bufferCapacity) + buffer[0] = 0; + + if(getDate) + { + const char* format = fileNameSafeCharacters ? "%Y-%m-%d" : "%Y/%m/%d"; + strftime(temp, OVR_ARRAY_COUNT(temp), format, pTime); + OVR::OVR_strlcpy(buffer, temp, bufferCapacity); + } + + if(getTime) + { + const char* format = fileNameSafeCharacters ? " %H.%M.%S" : " %H:%M:%S"; + strftime(temp, OVR_ARRAY_COUNT(temp), (getDate ? format : format + 1), pTime); + OVR::OVR_strlcat(buffer, temp, bufferCapacity); + } +} + + +static void GetOSVersionName(char* versionName, size_t versionNameCapacity) +{ + #if defined(OVR_OS_MS) + const char* name = "unknown"; + + OSVERSIONINFOEXW vi; + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(vi); + + if(GetVersionExW((LPOSVERSIONINFOW)&vi)) + { + if(vi.dwMajorVersion >= 7) + { + // Unknown recent version. + } + if(vi.dwMajorVersion >= 6) + { + if(vi.dwMinorVersion >= 4) + name = "Windows 10"; + else if(vi.dwMinorVersion >= 3) + { + if(vi.wProductType == VER_NT_WORKSTATION) + name = "Windows 8.1"; + else + name = "Windows Server 2012 R2"; + } + else if(vi.dwMinorVersion >= 2) + { + if(vi.wProductType == VER_NT_WORKSTATION) + name = "Windows 8"; + else + name = "Windows Server 2012"; + } + else if(vi.dwMinorVersion >= 1) + { + if(vi.wProductType == VER_NT_WORKSTATION) + name = "Windows 7"; + else + name = "Windows Server 2008 R2"; + } + else + { + if(vi.wProductType == VER_NT_WORKSTATION) + name = "Windows Vista"; + else + name = "Windows Server 2008"; + } + } + else if(vi.dwMajorVersion >= 5) + { + if(vi.dwMinorVersion == 0) + name = "Windows 2000"; + else if(vi.dwMinorVersion == 1) + name = "Windows XP"; + else // vi.dwMinorVersion == 2 + { + if(GetSystemMetrics(SM_SERVERR2) != 0) + name = "Windows Server 2003 R2"; + else if(vi.wSuiteMask & VER_SUITE_WH_SERVER) + name = "Windows Home Server"; + if(GetSystemMetrics(SM_SERVERR2) == 0) + name = "Windows Server 2003"; + else + name = "Windows XP Professional x64 Edition"; + } + } + else + name = "Windows 98 or earlier"; + } + + OVR_strlcpy(versionName, name, versionNameCapacity); + + #elif defined(OVR_OS_UNIX) || defined(OVR_OS_APPLE) + utsname utsName; + memset(&utsName, 0, sizeof(utsName)); + + if(uname(&utsName) == 0) + OVR_snprintf(versionName, versionNameCapacity, "%s %s %s %s", utsName.sysname, utsName.release, utsName.version, utsName.machine); + else + OVR_snprintf(versionName, versionNameCapacity, "Unix"); + #endif +} + + + + +void CreateException(CreateExceptionType exceptionType) +{ + char buffer[1024] = {}; + + switch(exceptionType) + { + case kCETAccessViolation: + { + int* pNullPtr = reinterpret_cast<int*>((rand() / 2) / RAND_MAX); + pNullPtr[0] = 0; // This line should generate an exception. + sprintf(buffer, "%p", pNullPtr); + break; + } + + case kCETDivideByZero: + { + int smallValue = 1; + int largeValue = (1000 * exceptionType); + int divByZero = (smallValue / largeValue); // This line should generate a div/0 exception. + sprintf(buffer, "%d", divByZero); + break; + } + + case kCETIllegalInstruction: + { + #if defined(OVR_CPU_X86) || (defined(OVR_CPU_X86_64) && !defined(OVR_CC_MSVC)) // (if x86) or (if x64 and any computer but VC++)... + #if defined(OVR_CC_MSVC) + __asm ud2 + #else // e.g. GCC + asm volatile("ud2"); + #endif + + #elif defined(OVR_CPU_X86_64) && (defined(OVR_OS_MS) && defined(PAGE_EXECUTE_READWRITE)) + // VC++ for x64 doesn't support inline asm. + void* pVoid = _AddressOfReturnAddress(); + void** ppVoid = reinterpret_cast<void**>(pVoid); + void* pReturnAddress = *ppVoid; + DWORD dwProtectPrev = 0; + + if(VirtualProtect(pReturnAddress, 2, PAGE_EXECUTE_READWRITE, &dwProtectPrev)) // If we can set the memory to be executable... + { + // Modify the code we return to. + uint8_t asm_ud2[] = { 0x0f, 0x0b }; + memcpy(pReturnAddress, asm_ud2, sizeof(asm_ud2)); + VirtualProtect(pReturnAddress, 2, dwProtectPrev, &dwProtectPrev); + } + else + { + // To do: Fix this. + } + + #else + // To do: Fix this. + #endif + + break; + } + + case kCETStackCorruption: + { + size_t size = (sizeof(buffer) * 16) - (rand() % 16); + char* pOutsizeStack = buffer - ((sizeof(buffer) * 16) + (rand() % 16)); + + memset(buffer, 0, size); + memset(pOutsizeStack, 0, size); // This line should generate an exception, or an exception will be generated upon return from this function. + break; + } + + case kCETStackOverflow: + { + CreateException(exceptionType); // Call ourselves recursively. This line should generate a div/0 exception. + sprintf(buffer, "%d", exceptionType); + break; + } + + case kCETAlignment: + { + // Not all platforms generate alignment exceptions. Some internally handle it. + void* pAligned = malloc(16); + char* pMisaligned = (char*)pAligned + 1; + uint64_t* pMisaligned64 = reinterpret_cast<uint64_t*>(pMisaligned); + + *pMisaligned64 = 0; // This line should generate an exception. + free(pAligned); + break; + } + + case kCETFPU: + // Platforms usually have FPU exceptions disabled. In order to test FPU exceptions we will need to at least + // temporarily disable them before executing code here to generate such exceptions. + // To do. + break; + + case kCETTrap: + // To do. This is hardware-specific. + break; + } +} + + +//----------------------------------------------------------------------------- +// SymbolLookup + +#if defined(OVR_OS_MS) + #if defined(OVR_CC_MSVC) + // The Lock below is one that we want to keep around as long as possible, as there may be application code that + // needs to do symbol lookups during process teardown after main has returned. The init_seg(lib) statement + // below makes it so that this module's globals are initialized right after the C standard library has initialized, + // and are destroyed right before the C standard library is destroyed (after after all other app globals are destroyed). + #pragma warning(disable: 4073) // warning C4073: initializers put in library initialization area. + #pragma warning(disable: 4075) // warning C4075: initializers put in unrecognized initialization area. + #pragma init_seg(lib) + #endif + + typedef BOOL (WINAPI * StackWalk64Type)(DWORD MachineType, HANDLE hProcess, HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine, PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress); + typedef PVOID (WINAPI * SymFunctionTableAccess64Type)(HANDLE hProcess, DWORD64 dwAddr); + typedef DWORD64 (WINAPI * SymGetModuleBase64Type)(HANDLE hProcess, DWORD64 dwAddr); + typedef DWORD (WINAPI * SymSetOptionsType)(DWORD SymOptions); + typedef BOOL (WINAPI * SymInitializeWType)(HANDLE hProcess, PCWSTR UserSearchPath, BOOL fInvadeProcess); + typedef BOOL (WINAPI * SymCleanupType)(HANDLE hProcess); + typedef DWORD64 (WINAPI * SymLoadModule64Type)(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll); + typedef BOOL (WINAPI * SymFromAddrType)(HANDLE hProcess, DWORD64 Address, PDWORD64 Displacement, PSYMBOL_INFO Symbol); + typedef BOOL (WINAPI * SymGetLineFromAddr64Type)(HANDLE hProcess, DWORD64 qwAddr, PDWORD pdwDisplacement, PIMAGEHLP_LINE64 Line64); + + static StackWalk64Type pStackWalk64 = nullptr; + static SymFunctionTableAccess64Type pSymFunctionTableAccess64 = nullptr; + static SymGetModuleBase64Type pSymGetModuleBase64 = nullptr; + static SymSetOptionsType pSymSetOptions = nullptr; + static SymInitializeWType pSymInitializeW = nullptr; + static SymCleanupType pSymCleanup = nullptr; + static SymLoadModule64Type pSymLoadModule64 = nullptr; + static SymFromAddrType pSymFromAddr = nullptr; + static SymGetLineFromAddr64Type pSymGetLineFromAddr64 = nullptr; + static int32_t sSymUsageCount = 0; + static HMODULE sDbgHelp = nullptr; + static OVR::Lock sDbgHelpLock; + + bool SymbolLookup::Initialize() + { + OVR::Lock::Locker autoLock(&sDbgHelpLock); + + if (++sSymUsageCount > 1) + { + OVR_ASSERT(pSymInitializeW != nullptr); // If it was already initialized then the pointers should be valid. + return true; + } + + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms679294%28v=vs.85%29.aspx + sDbgHelp = LoadLibraryW(L"DbgHelp.dll"); // It's best if the application supplies a recent version of this. + + if (sDbgHelp) + { + pStackWalk64 = (StackWalk64Type)(uintptr_t)::GetProcAddress(sDbgHelp, "StackWalk64"); + pSymFunctionTableAccess64 = (SymFunctionTableAccess64Type)(uintptr_t)::GetProcAddress(sDbgHelp, "SymFunctionTableAccess64"); + pSymGetModuleBase64 = (SymGetModuleBase64Type)(uintptr_t)::GetProcAddress(sDbgHelp, "SymGetModuleBase64"); + pSymSetOptions = (SymSetOptionsType)(uintptr_t)::GetProcAddress(sDbgHelp, "SymSetOptions"); + pSymInitializeW = (SymInitializeWType)(uintptr_t)::GetProcAddress(sDbgHelp, "SymInitializeW"); + pSymCleanup = (SymCleanupType)(uintptr_t)::GetProcAddress(sDbgHelp, "SymCleanup"); + pSymLoadModule64 = (SymLoadModule64Type)(uintptr_t)::GetProcAddress(sDbgHelp, "SymLoadModule64"); + pSymFromAddr = (SymFromAddrType)(uintptr_t)::GetProcAddress(sDbgHelp, "SymFromAddr"); + pSymGetLineFromAddr64 = (SymGetLineFromAddr64Type)(uintptr_t)::GetProcAddress(sDbgHelp, "SymGetLineFromAddr64"); + + // To consider: Use a manually created search path: + // wchar_t searchPathW[4096]; // Semicolon-separated strings. + // The current working directory of the application. + // The directory of the application itself (GetModuleFileName). + // The _NT_SYMBOL_PATH environment variable. + // The _NT_ALTERNATE_SYMBOL_PATH environment variable. + + if (pSymInitializeW) + { + if (pSymInitializeW(GetCurrentProcess(), nullptr /*searchPathW*/, FALSE)) + { + if (pSymSetOptions) + { + pSymSetOptions(SYMOPT_UNDNAME | SYMOPT_DEFERRED_LOADS); + } + + return true; + } + } + } + + return false; + } + + bool SymbolLookup::IsInitialized() + { + // Note that it's possible that another thread could change the state of this right after the return. + OVR::Lock::Locker autoLock(&sDbgHelpLock); + return (sSymUsageCount != 0); + } + + void SymbolLookup::Shutdown() + { + OVR::Lock::Locker autoLock(&sDbgHelpLock); + + if (sSymUsageCount > 0 && + --sSymUsageCount <= 0) + { + pSymCleanup(GetCurrentProcess()); + + pStackWalk64 = nullptr; + pSymFunctionTableAccess64 = nullptr; + pSymGetModuleBase64 = nullptr; + pSymSetOptions = nullptr; + pSymInitializeW = nullptr; + pSymCleanup = nullptr; + pSymLoadModule64 = nullptr; + pSymFromAddr = nullptr; + pSymGetLineFromAddr64 = nullptr; + + FreeLibrary(sDbgHelp); + sDbgHelp = nullptr; + } + } +#else + bool SymbolLookup::Initialize() + { + return true; + } + + bool SymbolLookup::IsInitialized() + { + return true; + } + + void SymbolLookup::Shutdown() + { + } +#endif + +SymbolLookup::SymbolLookup() : + AllowMemoryAllocation(true), + ModuleListUpdated(false), + ModuleInfoArray(), + ModuleInfoArraySize(0) +{ +} + +SymbolLookup::~SymbolLookup() +{ +} + +void SymbolLookup::AddSourceCodeDirectory(const char* pDirectory) +{ + OVR_UNUSED(pDirectory); +} + +void SymbolLookup::EnableMemoryAllocation(bool enabled) +{ + AllowMemoryAllocation = enabled; +} + + +bool SymbolLookup::Refresh() +{ + ModuleListUpdated = false; + return RefreshModuleList(); +} + + +OVR_DISABLE_MSVC_WARNING(4740) // flow in or out of inline asm code suppresses global optimization +OVR_DISABLE_MSVC_WARNING(4748) // /GS can not protect parameters and local variables from local buffer overrun because optimizations are disabled in function + + +size_t SymbolLookup::GetBacktrace(void* addressArray[], size_t addressArrayCapacity, size_t skipCount, void* platformThreadContext, OVR::ThreadSysId threadSysIdHelp) +{ + #if defined(OVR_OS_WIN64) + OVR_UNUSED(threadSysIdHelp); + + // The DbgHelp library must be loaded already. + OVR_ASSERT(sSymUsageCount > 0); + + if(platformThreadContext == nullptr) + return RtlCaptureStackBackTrace((DWORD)skipCount, (ULONG)addressArrayCapacity, addressArray, nullptr); + + // We need to get the call stack of another thread. + size_t frameIndex = 0; + CONTEXT context; + PRUNTIME_FUNCTION pRuntimeFunction; + ULONG64 imageBase = 0; + ULONG64 imageBasePrev = 0; + + memcpy(&context, (CONTEXT*)platformThreadContext, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_CONTROL; + + if(context.Rip && (frameIndex < addressArrayCapacity)) + addressArray[frameIndex++] = (void*)(uintptr_t)context.Rip; + + while(context.Rip && (frameIndex < addressArrayCapacity)) + { + imageBasePrev = imageBase; + pRuntimeFunction = (PRUNTIME_FUNCTION)RtlLookupFunctionEntry(context.Rip, &imageBase, nullptr); + + if(pRuntimeFunction) + { + VOID* handlerData = nullptr; + ULONG64 establisherFramePointers[2] = { 0, 0 }; + RtlVirtualUnwind(UNW_FLAG_NHANDLER, imageBase, context.Rip, pRuntimeFunction, &context, &handlerData, establisherFramePointers, nullptr); + } + else + { + context.Rip = (ULONG64)(*(PULONG64)context.Rsp); + context.Rsp += 8; + } + + if(context.Rip && (frameIndex < addressArrayCapacity)) + { + if(skipCount) + --skipCount; + else + addressArray[frameIndex++] = (void*)(uintptr_t)context.Rip; + } + } + + return frameIndex; + + #elif defined(OVR_OS_WIN32) + OVR_UNUSED(threadSysIdHelp); + + OVR::Lock::Locker autoLock(&sDbgHelpLock); + size_t frameIndex = 0; + + if(pStackWalk64) + { + CONTEXT context; + + if(platformThreadContext) + { + memcpy(&context, platformThreadContext, sizeof(context)); + context.ContextFlags = CONTEXT_CONTROL; + } + else + { + memset(&context, 0, sizeof(context)); + context.ContextFlags = CONTEXT_CONTROL; + + __asm { + mov context.Ebp, EBP + mov context.Esp, ESP + call GetEIP + GetEIP: + pop context.Eip + } + } + + STACKFRAME64 sf; + memset(&sf, 0, sizeof(sf)); + sf.AddrPC.Offset = context.Eip; + sf.AddrPC.Mode = AddrModeFlat; + sf.AddrStack.Offset = context.Esp; + sf.AddrStack.Mode = AddrModeFlat; + sf.AddrFrame.Offset = context.Ebp; + sf.AddrFrame.Mode = AddrModeFlat; + + const HANDLE hCurrentProcess = ::GetCurrentProcess(); + const HANDLE hCurrentThread = ::GetCurrentThread(); + + if(!platformThreadContext) // If we are reading the current thread's call stack then we ignore this current function. + skipCount++; + + while(frameIndex < addressArrayCapacity) + { + if(!pStackWalk64(IMAGE_FILE_MACHINE_I386, hCurrentProcess, hCurrentThread, &sf, &context, nullptr, pSymFunctionTableAccess64, pSymGetModuleBase64, nullptr)) + break; + + if(sf.AddrFrame.Offset == 0) + break; + + if(skipCount) + --skipCount; + else + addressArray[frameIndex++] = ((void*)(uintptr_t)sf.AddrPC.Offset); + } + } + + return frameIndex; + + #elif defined(OVR_OS_APPLE) + struct StackFrame + { + StackFrame* pParentStackFrame; + void* pReturnPC; + }; + + void* pInstruction; + StackFrame* pStackFrame; + size_t frameIndex = 0; + + if(platformThreadContext) + { + #if defined(OVR_CPU_ARM) + arm_thread_state_t* pThreadState = (arm_thread_state_t*)platformThreadContext; + pStackFrame = (StackFrame*)pThreadState->__fp; + pInstruction = (void*) pThreadState->__pc; + #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0x1) == 0) + #elif defined(OVR_CPU_X86_64) + x86_thread_state_t* pThreadState = (x86_thread_state_t*)platformThreadContext; + pInstruction = (void*) pThreadState->uts.ts64.__rip; + pStackFrame = (StackFrame*)pThreadState->uts.ts64.__rbp; + #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0xf) == 0) + #elif defined(OVR_CPU_X86) + x86_thread_state_t* pThreadState = (x86_thread_state_t*)platformThreadContext; + pInstruction = (void*) pThreadState->uts.ts32.__eip; + pStackFrame = (StackFrame*)pThreadState->uts.ts32.__ebp; + #define FrameIsAligned(pStackFrame) ((((uintptr_t)pStackFrame) & 0xf) == 8) + #endif + + if(frameIndex < addressArrayCapacity) + addressArray[frameIndex++] = pInstruction; + } + else // Else get the current values... + { + pStackFrame = (StackFrame*)__builtin_frame_address(0); + GetInstructionPointer(pInstruction); + } + + pthread_t threadSelf = pthread_self(); + void* pCurrentStackBase = pthread_get_stackaddr_np(threadSelf); + void* pCurrentStackLimit = (void*)((uintptr_t)pCurrentStackBase - pthread_get_stacksize_np(threadSelf)); + bool threadIsCurrent = (platformThreadContext == nullptr) || (((void*)pStackFrame > pCurrentStackLimit) && ((void*)pStackFrame <= pCurrentStackBase)); + StackFrame* pStackBase; + StackFrame* pStackLimit; + + if(threadIsCurrent) + { + pStackBase = (StackFrame*)pCurrentStackBase; + pStackLimit = (StackFrame*)pCurrentStackLimit; + } + else if(threadSysIdHelp) + { + pthread_t threadHandle = pthread_from_mach_thread_np((mach_port_t)threadSysIdHelp); + pStackBase = (StackFrame*)pthread_get_stackaddr_np(threadHandle); + pStackLimit = (StackFrame*)((uintptr_t)pStackBase - pthread_get_stacksize_np(threadHandle)); + } + else + { // We guess what the limits are. + pStackBase = pStackFrame + ((384 * 1024) / sizeof(StackFrame)); + pStackLimit = pStackFrame - ((384 * 1024) / sizeof(StackFrame)); + } + + if((frameIndex < addressArrayCapacity) && pStackFrame && FrameIsAligned(pStackFrame)) + { + addressArray[frameIndex++] = pStackFrame->pReturnPC; + + while(pStackFrame && pStackFrame->pReturnPC && (frameIndex < addressArrayCapacity)) + { + pStackFrame = pStackFrame->pParentStackFrame; + + if(pStackFrame && FrameIsAligned(pStackFrame) && pStackFrame->pReturnPC && (pStackFrame > pStackLimit) && (pStackFrame < pStackBase)) + { + if(skipCount) + --skipCount; + else + addressArray[frameIndex++] = pStackFrame->pReturnPC; + } + else + break; + } + } + + return frameIndex; + + #elif defined(OVR_OS_LINUX) && (defined( __LIBUNWIND__) || defined(LIBUNWIND_AVAIL)) + // Libunwind-based solution. Requires installation of libunwind package. + // Libunwind isn't always safe for threads that are in signal handlers. + // An approach to get the callstack of another thread is to use signal injection into the target thread. + + OVR_UNUSED(platformThreadContext); + OVR_UNUSED(threadSysIdHelp); + + size_t frameIndex = 0; + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, sp; + + unw_getcontext(&uc); // This gets the current thread's context. We could alternatively initialize another thread's context with it. + unw_init_local(&cursor, &uc); + + while((unw_step(&cursor) > 0) && (frameIndex < addressArrayCapacity)) + { + // We can get the function name here too on some platforms with unw_get_proc_info() and unw_get_proc_name(). + + if(skipCount) + --skipCount; + else + { + unw_get_reg(&cursor, UNW_REG_IP, &ip); + addressArray[frameIndex++] = (void*)ip; + } + } + + return frameIndex; + #else + OVR_UNUSED(addressArray); + OVR_UNUSED(addressArrayCapacity); + OVR_UNUSED(skipCount); + OVR_UNUSED(platformThreadContext); + OVR_UNUSED(threadSysIdHelp); + + return 0; + #endif +} + + +size_t SymbolLookup::GetBacktraceFromThreadHandle(void* addressArray[], size_t addressArrayCapacity, size_t skipCount, OVR::ThreadHandle threadHandle) +{ + #if defined(OVR_OS_MS) + size_t count = 0; + DWORD threadSysId = (DWORD)ConvertThreadHandleToThreadSysId(threadHandle); + + // Compare to 0, compare to the self 'pseudohandle' and compare to the self id. + if((threadHandle == OVR_THREADHANDLE_INVALID) || (threadHandle == ::GetCurrentThread()) || (threadSysId == ::GetCurrentThreadId())) // If threadSysId refers to the current thread... + return GetBacktrace(addressArray, addressArrayCapacity, skipCount, nullptr); + + // We are working with another thread. We need to suspend it and get its CONTEXT. + // Suspending other threads is risky, as they may be in some state that cannot be safely blocked. + BOOL result = false; + DWORD suspendResult = ::SuspendThread(threadHandle); // Requires that the handle have THREAD_SUSPEND_RESUME rights. + + if(suspendResult != (DWORD)-1) // Returns previous suspend count, or -1 if failed. + { + CONTEXT context; + context.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; // Requires that the handle have THREAD_GET_CONTEXT rights. + result = ::GetThreadContext(threadHandle, &context); + count = GetBacktrace(addressArray, addressArrayCapacity, skipCount, &context); + suspendResult = ::ResumeThread(threadHandle); + OVR_ASSERT_AND_UNUSED(suspendResult != (DWORD)-1, suspendResult); + } + + return count; + + #elif defined(OVR_OS_APPLE) + mach_port_t threadSysID = pthread_mach_thread_np((pthread_t)threadHandle); // Convert pthread_t to mach thread id. + return GetBacktraceFromThreadSysId(addressArray, addressArrayCapacity, skipCount, (OVR::ThreadSysId)threadSysID); + + #elif defined(OVR_OS_LINUX) + // To do. + OVR_UNUSED(addressArray); + OVR_UNUSED(addressArrayCapacity); + OVR_UNUSED(skipCount); + OVR_UNUSED(threadHandle); + return 0; + #endif +} + + +size_t SymbolLookup::GetBacktraceFromThreadSysId(void* addressArray[], size_t addressArrayCapacity, size_t skipCount, OVR::ThreadSysId threadSysId) +{ + #if defined(OVR_OS_MS) + OVR::ThreadHandle threadHandle = ConvertThreadSysIdToThreadHandle(threadSysId); + if(threadHandle) + { + size_t count = GetBacktraceFromThreadHandle(addressArray, addressArrayCapacity, skipCount, threadHandle); + FreeThreadHandle(threadHandle); + return count; + } + return 0; + + #elif defined(OVR_OS_APPLE) + mach_port_t threadCurrent = pthread_mach_thread_np(pthread_self()); + mach_port_t thread = (mach_port_t)threadSysId; + + if(thread == threadCurrent) + { + return GetBacktrace(addressArray, addressArrayCapacity, skipCount, nullptr); + } + else + { + kern_return_t result = thread_suspend(thread); // Do we need to do this if it's an thread who exception is being handled? + size_t count = 0; + + if(result == KERN_SUCCESS) + { + #if defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + x86_thread_state_t threadState; + #elif defined(OVR_CPU_ARM) + arm_thread_state_t threadState; + #endif + mach_msg_type_number_t stateCount = MACHINE_THREAD_STATE_COUNT; + + result = thread_get_state(thread, MACHINE_THREAD_STATE, (natural_t*)(uintptr_t)&threadState, &stateCount); + + if(result == KERN_SUCCESS) + count = GetBacktrace(addressArray, addressArrayCapacity, skipCount, &threadState, threadSysId); + + thread_resume(thread); + + return count; + } + } + + return 0; + + #elif defined(OVR_OS_LINUX) + // To do. + OVR_UNUSED(addressArray); + OVR_UNUSED(addressArrayCapacity); + OVR_UNUSED(skipCount); + OVR_UNUSED(threadSysId); + return 0; + #endif +} + + +// We need to return the required moduleInfoArrayCapacity. +size_t SymbolLookup::GetModuleInfoArray(ModuleInfo* pModuleInfoArray, size_t moduleInfoArrayCapacity) +{ + #if defined(OVR_OS_MS) + size_t moduleCountRequired = 0; // The count we would copy to pModuleInfoArray if moduleInfoArrayCapacity was enough. + size_t moduleCount = 0; // The count we actually copy to pModuleInfoArray. Will be <= moduleInfoArrayCapacity. + HANDLE hProcess = GetCurrentProcess(); + HMODULE hModuleArray[200]; + DWORD cbNeeded = 0; + MODULEINFO mi; + + if(EnumProcessModules(hProcess, hModuleArray, sizeof(hModuleArray), &cbNeeded)) + { + moduleCountRequired = ((cbNeeded / sizeof(HMODULE)) < OVR_ARRAY_COUNT(hModuleArray)) ? (cbNeeded / sizeof(HMODULE)) : OVR_ARRAY_COUNT(hModuleArray); + moduleCount = MIN(moduleCountRequired, OVR_ARRAY_COUNT(hModuleArray)); + moduleCount = MIN(moduleCount, moduleInfoArrayCapacity); + + for(size_t i = 0; i < moduleCount; i++) + { + ModuleInfo& moduleInfo = pModuleInfoArray[i]; + + memset(&mi, 0, sizeof(mi)); + BOOL result = GetModuleInformation(hProcess, hModuleArray[i], &mi, sizeof(mi)); + + if(result) + { + wchar_t pathW[OVR_MAX_PATH]; + char pathA[OVR_MAX_PATH * 3]; // *3 to handle UTF8 multibyte encoding. + + moduleInfo.handle = hModuleArray[i]; + moduleInfo.baseAddress = (uintptr_t)mi.lpBaseOfDll; + moduleInfo.size = mi.SizeOfImage; + + GetModuleFileNameW(hModuleArray[i], pathW, OVR_ARRAY_COUNT(pathW)); + OVR::UTF8Util::EncodeString(pathA, pathW, -1); // Problem: DecodeString provides no way to specify the destination capacity. + OVR::OVR_strlcpy(moduleInfo.filePath, pathA, OVR_ARRAY_COUNT(moduleInfo.filePath)); + + const char* fileName = GetFileNameFromPath(pathA); + OVR::OVR_strlcpy(moduleInfo.name, fileName, OVR_ARRAY_COUNT(moduleInfo.name)); + } + else + { + moduleInfo.handle = 0; + moduleInfo.baseAddress = 0; + moduleInfo.size = 0; + moduleInfo.filePath[0] = 0; + moduleInfo.name[0] = 0; + } + } + } + + return moduleCountRequired; + + #elif defined(OVR_OS_MAC) + size_t moduleCountRequired = 0; + size_t moduleCount = 0; + + struct MacModuleInfo // This struct exists solely so we can have a local function within this function.. + { + static void AddMacModuleInfo(ModuleInfo* pModuleInfoArrayL, size_t& moduleCountRequiredL, size_t& moduleCountL, size_t moduleInfoArrayCapacityL, + const char* pTypeFilterL, const char* pModulePath, uintptr_t currentSegmentPos, const MachHeader* pMachHeader, uint64_t offset) + { + for(size_t i = 0; i < pMachHeader->ncmds; i++) + { + const SegmentCommand* pSegmentCommand = reinterpret_cast<const SegmentCommand*>(currentSegmentPos); + + if(pSegmentCommand->cmd == kLCSegment) + { + const size_t segnameSize = (sizeof(pSegmentCommand->segname) + 1); // +1 so we can have a trailing '\0'. + char segname[segnameSize]; + + memcpy(segname, pSegmentCommand->segname, sizeof(pSegmentCommand->segname)); + segname[segnameSize - 1] = '\0'; + + if(!pTypeFilterL || OVR_strncmp(segname, pTypeFilterL, sizeof(segname))) + { + moduleCountRequiredL++; + + if(moduleCountL < moduleInfoArrayCapacityL) + { + ModuleInfo& info = pModuleInfoArrayL[moduleCountL++]; + + info.baseAddress = (uint64_t)(pSegmentCommand->vmaddr + offset); + info.handle = reinterpret_cast<ModuleHandle>((uintptr_t)info.baseAddress); + info.size = (uint64_t)pSegmentCommand->vmsize; + OVR_strlcpy(info.filePath, pModulePath, OVR_ARRAY_COUNT(info.filePath)); + OVR_strlcpy(info.name, GetFileNameFromPath(pModulePath), OVR_ARRAY_COUNT(info.name)); + + info.permissions[0] = (pSegmentCommand->initprot & VM_PROT_READ) ? 'r' : '-'; + info.permissions[1] = (pSegmentCommand->initprot & VM_PROT_WRITE) ? 'w' : '-'; + info.permissions[2] = (pSegmentCommand->initprot & VM_PROT_EXECUTE) ? 'x' : '-'; + info.permissions[3] = '/'; + info.permissions[4] = (pSegmentCommand->maxprot & VM_PROT_READ) ? 'r' : '-'; + info.permissions[5] = (pSegmentCommand->maxprot & VM_PROT_WRITE) ? 'w' : '-'; + info.permissions[6] = (pSegmentCommand->maxprot & VM_PROT_EXECUTE) ? 'x' : '-'; + info.permissions[7] = '\0'; + + OVR_strlcpy(info.type, pSegmentCommand->segname, OVR_ARRAY_COUNT(info.type)); + } + } + } + + currentSegmentPos += pSegmentCommand->cmdsize; + } + } + }; + + // Iterate dyld_all_image_infos->infoArray + const struct dyld_all_image_infos* pAllImageInfos = _dyld_get_all_image_infos(); + + for(uint32_t i = 0; i < pAllImageInfos->infoArrayCount; i++) + { + const char* pModulePath = pAllImageInfos->infoArray[i].imageFilePath; + + if(pModulePath && *pModulePath) + { + uintptr_t currentSegmentPos = (uintptr_t)pAllImageInfos->infoArray[i].imageLoadAddress; + const MachHeader* pMachHeader = reinterpret_cast<const MachHeader*>(currentSegmentPos); + uint64_t offset = (uint64_t)_dyld_get_image_vmaddr_slide(i); + + currentSegmentPos += sizeof(*pMachHeader); + + MacModuleInfo::AddMacModuleInfo(pModuleInfoArray, moduleCountRequired, moduleCount, moduleInfoArrayCapacity, + nullptr /*"__TEXT"*/, pModulePath, currentSegmentPos, pMachHeader, offset); + } + } + + // In addition to iterating dyld_all_image_infos->infoArray we need to also iterate /usr/lib/dyld entries. + const MachHeader* pMachHeader = (const MachHeader*)pAllImageInfos->dyldImageLoadAddress; + uintptr_t currentSegmentPos = (uintptr_t)pMachHeader + sizeof(*pMachHeader); + char modulePath[OVR_MAX_PATH] = ""; + pid_t pid = getpid(); + int filenameLen = proc_regionfilename((int)pid, currentSegmentPos, modulePath, (uint32_t)sizeof(modulePath)); + + if(filenameLen > 0) + MacModuleInfo::AddMacModuleInfo(pModuleInfoArray, moduleCountRequired, moduleCount, moduleInfoArrayCapacity, + "__TEXT", modulePath, currentSegmentPos, pMachHeader, 0); + + return moduleCountRequired; + + #elif defined(OVR_OS_LINUX) + // One approach is to read /proc/self/maps, which is supported by Linux (though not BSD). + // Linux glibc dladdr() can tell us what module an arbitrary function address comes from, but can't tell us the list of modules. + OVR_UNUSED(pModuleInfoArray); + OVR_UNUSED(moduleInfoArrayCapacity); + return 0; + + #else + OVR_UNUSED(pModuleInfoArray); + OVR_UNUSED(moduleInfoArrayCapacity); + return 0; + #endif +} + + +size_t SymbolLookup::GetThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCapacity) +{ + size_t countRequired = 0; + size_t count = 0; + + #if defined(OVR_OS_MS) + // Print a list of threads. + DWORD currentProcessId = GetCurrentProcessId(); + HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, currentProcessId); // ICreateToolhelp32Snapshot actually ignores currentProcessId. + + if(hThreadSnap != INVALID_HANDLE_VALUE) + { + THREADENTRY32 te32; + te32.dwSize = sizeof(THREADENTRY32); + + if(Thread32First(hThreadSnap, &te32)) + { + do + { + if(te32.th32OwnerProcessID == currentProcessId) + { + HANDLE hThread = ConvertThreadSysIdToThreadHandle(te32.th32ThreadID); + + if(hThread) + { + ++countRequired; + + if((threadHandleArray || threadSysIdArray) && (count < threadArrayCapacity)) + { + if(threadHandleArray) + threadHandleArray[count] = hThread; // The caller must call CloseHandle on this thread, or call DoneThreadList on the returned array. + if(threadSysIdArray) + threadSysIdArray[count] = ConvertThreadHandleToThreadSysId(hThread); + ++count; + } + + if(!threadHandleArray) // If we aren't giving this back to the user... + FreeThreadHandle(hThread); + } + } + } while(Thread32Next(hThreadSnap, &te32)); + } + + CloseHandle(hThreadSnap); + } + + #elif defined(OVR_OS_APPLE) + mach_port_t taskSelf = mach_task_self(); + thread_act_port_array_t threadArray; + mach_msg_type_number_t threadCount; + + kern_return_t result = task_threads(taskSelf, &threadArray, &threadCount); + + if(result == KERN_SUCCESS) + { + for(mach_msg_type_number_t i = 0; i < threadCount; i++) + { + ++countRequired; + + if((threadHandleArray || threadSysIdArray) && (count < threadArrayCapacity)) + { + if(threadHandleArray) + threadHandleArray[count] = pthread_from_mach_thread_np(threadArray[i]); + if(threadSysIdArray) + threadSysIdArray[count] = threadArray[i]; + ++count; + } + } + + vm_deallocate(taskSelf, (vm_address_t)threadArray, threadCount * sizeof(thread_act_t)); + } + + #elif defined(OVR_OS_LINUX) + // To do. + OVR_UNUSED(count); + OVR_UNUSED(threadHandleArray); + OVR_UNUSED(threadSysIdArray); + OVR_UNUSED(threadArrayCapacity); + #endif + + return countRequired; +} + + +void SymbolLookup::DoneThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCount) +{ + #if defined(OVR_OS_MS) + for(size_t i = 0; i != threadArrayCount; ++i) + { + if(threadHandleArray[i]) + { + CloseHandle(threadHandleArray[i]); + threadHandleArray[i] = OVR_THREADHANDLE_INVALID; + } + } + + OVR_UNUSED(threadSysIdArray); + #else + OVR_UNUSED(threadHandleArray); + OVR_UNUSED(threadSysIdArray); + OVR_UNUSED(threadArrayCount); + #endif +} + + +// Writes a given thread's callstack wity symbols to the given output. +// It may not be safe to call this from an exception handler, as sOutput allocates memory. +bool SymbolLookup::ReportThreadCallstack(OVR::String& sOutput, size_t skipCount, ThreadSysId threadSysId) +{ + sOutput.Clear(); + + if(!threadSysId) + threadSysId = GetCurrentThreadSysId(); + + void* addressArray[64]; + size_t addressCount = GetBacktraceFromThreadSysId(addressArray, OVR_ARRAY_COUNT(addressArray), skipCount, threadSysId); + + // Print the header + char headerBuffer[256]; + char threadName[32]; + char threadHandleStr[24]; + char threadSysIdStr[48]; + char stackBaseStr[24]; + char stackLimitStr[24]; + void* pStackBase; + void* pStackLimit; + //void* pStackCurrent; // Current stack pointer. To do: support reporting this. + ThreadHandle threadHandle = ConvertThreadSysIdToThreadHandle(threadSysId); + OVR::GetThreadStackBounds(pStackBase, pStackLimit, threadHandle); + + Thread::GetThreadName(threadName, OVR_ARRAY_COUNT(threadName), threadName); + SprintfThreadHandle(threadHandleStr, OVR_ARRAY_COUNT(threadHandleStr), threadHandle); + SprintfThreadSysId(threadSysIdStr, OVR_ARRAY_COUNT(threadSysIdStr), threadSysId); + SprintfAddress(stackBaseStr, OVR_ARRAY_COUNT(stackBaseStr), pStackBase); + SprintfAddress(stackLimitStr, OVR_ARRAY_COUNT(stackLimitStr), pStackLimit); + + if(threadName[0]) + OVR_snprintf(headerBuffer, OVR_ARRAY_COUNT(headerBuffer), "Thread \"%s\" handle: %s, id: %s, stack base: %s, stack limit: %s\n", threadName, threadHandleStr, threadSysIdStr, stackBaseStr, stackLimitStr); + else + OVR_snprintf(headerBuffer, OVR_ARRAY_COUNT(headerBuffer), "Thread handle: %s, id: %s, stack base: %s, stack limit: %s\n", threadHandleStr, threadSysIdStr, stackBaseStr, stackLimitStr); + + sOutput += headerBuffer; + + // Print the backtrace info + char backtraceBuffer[1024]; // Sometimes function symbol names are very long. + SymbolInfo symbolInfo; + const char* pModuleName; + + if(addressCount == 0) + { + sOutput += "<Unable to read backtrace>\n"; + } + else + { + for(size_t i = 0; i < addressCount; ++i) + { + LookupSymbol((uint64_t)addressArray[i], symbolInfo); + + if(symbolInfo.pModuleInfo && symbolInfo.pModuleInfo->name[0]) + pModuleName = symbolInfo.pModuleInfo->name; + else + pModuleName = "(unknown module)"; + + char addressStr[24]; + SprintfAddress(addressStr, OVR_ARRAY_COUNT(addressStr), addressArray[i]); + + if(symbolInfo.filePath[0]) + OVR_snprintf(backtraceBuffer, OVR_ARRAY_COUNT(backtraceBuffer), "%-2u %-24s %s %s+%d %s:%d\n", (unsigned)i, pModuleName, addressStr, symbolInfo.function, symbolInfo.functionOffset, symbolInfo.filePath, symbolInfo.fileLineNumber); + else + OVR_snprintf(backtraceBuffer, OVR_ARRAY_COUNT(backtraceBuffer), "%-2u %-24s %s %s+%d\n", (unsigned)i, pModuleName, addressStr, symbolInfo.function, symbolInfo.functionOffset); + + sOutput += backtraceBuffer; + } + } + + FreeThreadHandle(threadHandle); + + return (addressCount > 0); +} + + +// Writes all thread's callstacks with symbols to the given output. +// It may not be safe to call this from an exception handler, as sOutput allocates memory. +bool SymbolLookup::ReportThreadCallstacks(OVR::String& sOutput, size_t skipCount) +{ + sOutput.Clear(); + + ThreadSysId threadSysIdArray[64]; + size_t threadSysIdCount = GetThreadList(nullptr, threadSysIdArray, OVR_ARRAY_COUNT(threadSysIdArray)); + + if (threadSysIdCount > OVR_ARRAY_COUNT(threadSysIdArray)) + threadSysIdCount = OVR_ARRAY_COUNT(threadSysIdArray); + + for (size_t i = 0; i < threadSysIdCount; i++) + { + String sTemp; + ReportThreadCallstack(sTemp, skipCount, threadSysIdArray[i]); + if(i > 0) + sOutput += "\n"; + sOutput += sTemp; + } + + return (threadSysIdCount > 0); +} + +bool SymbolLookup::ReportModuleInformation(OVR::String& sOutput) +{ + sOutput.Clear(); + + RefreshModuleList(); + + char backtraceBuffer[1024]; + + for (size_t i = 0; i < ModuleInfoArraySize; ++i) + { + OVR_snprintf(backtraceBuffer, OVR_ARRAY_COUNT(backtraceBuffer), "Base: 0x%llx Size: 0x%llx Name: '%s' Path: '%s'\n", + ModuleInfoArray[i].baseAddress, ModuleInfoArray[i].size, ModuleInfoArray[i].name, ModuleInfoArray[i].filePath); + sOutput += backtraceBuffer; + } + + return true; +} + +bool SymbolLookup::RefreshModuleList() +{ + if(!ModuleListUpdated) + { + #if defined(OVR_OS_MS) + OVR::Lock::Locker autoLock(&sDbgHelpLock); + + // We can't rely on SymRefreshModuleList because it's present in DbgHelp 6.5, + // which doesn't distribute with Windows 7. + + // Currently we support only refreshing the list once ever. With a little effort we could revise this code to + // support re-refreshing the list at runtime to account for the possibility that modules have recently been + // added or removed. + if(pSymLoadModule64) + { + const size_t requiredCount = GetModuleInfoArray(ModuleInfoArray, OVR_ARRAY_COUNT(ModuleInfoArray)); + ModuleInfoArraySize = MIN(requiredCount, OVR_ARRAY_COUNT(ModuleInfoArray)); + + HANDLE hProcess = GetCurrentProcess(); + + for(size_t i = 0; i < ModuleInfoArraySize; i++) + pSymLoadModule64(hProcess, nullptr, ModuleInfoArray[i].filePath, nullptr, ModuleInfoArray[i].baseAddress, (DWORD)ModuleInfoArray[i].size); + + ModuleListUpdated = true; + } + #else + const size_t requiredCount = GetModuleInfoArray(ModuleInfoArray, OVR_ARRAY_COUNT(ModuleInfoArray)); + ModuleInfoArraySize = MIN(requiredCount, OVR_ARRAY_COUNT(ModuleInfoArray)); + ModuleListUpdated = true; + #endif + } + + return true; +} + + +bool SymbolLookup::LookupSymbol(uint64_t address, SymbolInfo& symbolInfo) +{ + return LookupSymbols(&address, &symbolInfo, 1); +} + + +bool SymbolLookup::LookupSymbols(uint64_t* addressArray, SymbolInfo* pSymbolInfoArray, size_t arraySize) +{ + bool success = false; + + if(!ModuleListUpdated) + { + RefreshModuleList(); + } + + #if defined(OVR_OS_MS) + OVR::Lock::Locker autoLock(&sDbgHelpLock); + + union SYMBOL_INFO_UNION + { + SYMBOL_INFO msSymbolInfo; + char suffixPadding[sizeof(SYMBOL_INFO) + 1024]; + }; + + for(size_t i = 0; i < arraySize; i++) + { + uint64_t& address = addressArray[i]; + SymbolInfo& symbolInfo = pSymbolInfoArray[i]; + + // Copy the address and ModuleInfo + symbolInfo.address = addressArray[i]; + symbolInfo.pModuleInfo = GetModuleInfoForAddress(address); // We could also use siu.msSymbolInfo.ModBase to get the module slightly faster. + + // Get the function/offset. + SYMBOL_INFO_UNION siu; + memset(&siu, 0, sizeof(siu)); + siu.msSymbolInfo.SizeOfStruct = sizeof(siu.msSymbolInfo); + siu.msSymbolInfo.MaxNameLen = sizeof(siu.suffixPadding) - sizeof(SYMBOL_INFO) + 1; // +1 because SYMBOL_INFO itself has Name[1]. + + HANDLE hProcess = GetCurrentProcess(); + DWORD64 displacement64 = 0; + bool bResult = (pSymFromAddr != nullptr) && (pSymFromAddr(hProcess, address, &displacement64, &siu.msSymbolInfo) != FALSE); + + if(bResult) + { + success = true; + symbolInfo.size = siu.msSymbolInfo.Size; + OVR_strlcpy(symbolInfo.function, siu.msSymbolInfo.Name, OVR_ARRAY_COUNT(symbolInfo.function)); + symbolInfo.functionOffset = (int32_t)displacement64; + } + else + { + symbolInfo.size = kMISizeInvalid; + symbolInfo.function[0] = 0; + symbolInfo.functionOffset = kMIFunctionOffsetInvalid; + } + + // Get the file/line + IMAGEHLP_LINE64 iLine64; + DWORD displacement = 0; + memset(&iLine64, 0, sizeof(iLine64)); + iLine64.SizeOfStruct = sizeof(iLine64); + + bResult = (pSymGetLineFromAddr64 != nullptr) && (pSymGetLineFromAddr64(hProcess, address, &displacement, &iLine64) != FALSE); + + if(bResult) + { + success = true; + OVR_strlcpy(symbolInfo.filePath, iLine64.FileName, OVR_ARRAY_COUNT(symbolInfo.filePath)); + symbolInfo.fileLineNumber = (int32_t)iLine64.LineNumber; + } + else + { + symbolInfo.filePath[0] = 0; + symbolInfo.fileLineNumber = kMILineNumberInvalid; + } + + // To do: get the source code when possible. We need to use the user-registered directory paths and the symbolInfo.filePath + // and find the given file in the tree(s), then open the file and find the symbolInfo.fileLineNumber line (and surrounding lines). + // symbolInfo.sourceCode[1024] + symbolInfo.sourceCode[0] = '\0'; + } + + #elif defined(OVR_OS_APPLE) + // Apple has an internal CoreSymbolication library which could help with this. + // Third party implementations of the CoreSymbolication header are available and could be used + // to get file/line info better than other means. It used Objective C, so we'll need a .m or .mm file. + + memset(pSymbolInfoArray, 0, arraySize * sizeof(SymbolInfo)); + + for(size_t i = 0; i < arraySize; i++) + { + pSymbolInfoArray[i].address = addressArray[i]; + pSymbolInfoArray[i].pModuleInfo = GetModuleInfoForAddress(addressArray[i]); + } + + // Problem: backtrace_symbols allocates memory from malloc. If you got into a SIGSEGV due to + // malloc arena corruption (quite common) you will likely fault in backtrace_symbols. + // To do: Use allowMemoryAllocation here. + + #if (OVR_PTR_SIZE == 4) + // backtrace_symbols takes a void* array, but we have a uint64_t array. So for 32 bit we + // need to convert the 64 bit array to 32 bit temporarily for the backtrace_symbols call. + void* ptr32Array[256]; // To do: Remove this limit. + for(size_t i = 0, iEnd = MIN(arraySize, OVR_ARRAY_COUNT(ptr32Array)); i < iEnd; i++) + ptr32Array[i] = reinterpret_cast<void*>(addressArray[i]); + char** symbolArray = backtrace_symbols(reinterpret_cast<void**>(ptr32Array), (int)arraySize); + #else + char** symbolArray = backtrace_symbols(reinterpret_cast<void**>(addressArray), (int)arraySize); + #endif + + if(symbolArray) + { + success = true; + + for(size_t i = 0; i < arraySize; i++) + { + // Generates a string like this: "0 OculusWorldDemo 0x000000010000cfd5 _ZN18OculusWorldDemoApp9OnStartupEiPPKc + 213" + static_assert(OVR_ARRAY_COUNT(pSymbolInfoArray[i].function) == 128, "Need to change the string format size below"); + + sscanf(symbolArray[i], "%*d %*s %*x %128s + %d", pSymbolInfoArray[i].function, &pSymbolInfoArray[i].functionOffset); + + if(AllowMemoryAllocation) + { + int status = 0; + char* strDemangled = abi::__cxa_demangle(pSymbolInfoArray[i].function, nullptr, nullptr, &status); + + if(strDemangled) + { + OVR_strlcpy(pSymbolInfoArray[i].function, strDemangled, OVR_ARRAY_COUNT(pSymbolInfoArray[i].function)); + free(strDemangled); + } + } + } + + free(symbolArray); + } + + // To consider: use CoreSybolication to get file/line info instead. atos is a bit slow and cumbersome. + // https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/atos.1.html + // atos -p <pid> <addr> <addr> ... + // atos -o <binary image path> -l <load-address> <addr> <addr> ... + // Generates output like this: "OVR::CreateException(OVR::CreateExceptionType) (in OculusWorldDemo) (ExceptionHandler.cpp:598)" + for(size_t i = 0; i < arraySize; i++) + { + struct stat statStruct; + + if(pSymbolInfoArray[i].pModuleInfo && pSymbolInfoArray[i].pModuleInfo->filePath[0] && (stat(pSymbolInfoArray[i].pModuleInfo->filePath, &statStruct) == 0)) + { + char command[PATH_MAX * 2]; // Problem: We can't unilaterally use pSymbolInfoArray[0] for all addresses. We need to match addresses to the corresponding modules. + OVR_snprintf(command, OVR_ARRAY_COUNT(command), "atos -o %s -l 0x%llx 0x%llx", + pSymbolInfoArray[i].pModuleInfo->filePath, (int64_t)pSymbolInfoArray[i].pModuleInfo->baseAddress, (int64_t)pSymbolInfoArray[i].address); + + char output[512]; + if(SpawnShellCommand(command, output, OVR_ARRAY_COUNT(output)) != (size_t)-1) + { + char* pLastOpenParen = strrchr(output, '('); + char* pColon = strrchr(output, ':'); + + if(pLastOpenParen && (pColon > pLastOpenParen)) + { + *pColon = '\0'; + OVR_strlcpy(pSymbolInfoArray[i].filePath, pLastOpenParen + 1, OVR_ARRAY_COUNT(pSymbolInfoArray[i].filePath)); + } + } + } + } + + #elif defined(OVR_OS_LINUX) + // We can use libunwind's unw_get_proc_name to try to get function name info. It can work regardless of relocation. + // Use backtrace_symbols and addr2line. Need to watch out for module load-time relocation. + // Ned to pass the -rdynamic flag to the linker. It will cause the linker to out in the link + // tables the name of all the none static functions in your code, not just the exported ones. + OVR_UNUSED(addressArray); + OVR_UNUSED(pSymbolInfoArray); + OVR_UNUSED(arraySize); + #endif + + return success; +} + + +const ModuleInfo* SymbolLookup::GetModuleInfoForAddress(uint64_t address) +{ + // This is a linear seach. To consider: it would be significantly faster to search by + // address if we ordered it by base address and did a binary search. + for(size_t i = 0; i < ModuleInfoArraySize; ++i) + { + const ModuleInfo& mi = ModuleInfoArray[i]; + + if((mi.baseAddress <= address) && (address < (mi.baseAddress + mi.size))) + return &mi; + } + + return nullptr; +} + + + + +ExceptionInfo::ExceptionInfo() + : time() + , timeVal(0) + , backtrace() + , backtraceCount(0) + , threadHandle(OVR_THREADHANDLE_INVALID) + , threadSysId(OVR_THREADSYSID_INVALID) + , threadName() + , pExceptionInstructionAddress(nullptr) + , pExceptionMemoryAddress(nullptr) + , cpuContext() + , exceptionDescription() + , symbolInfo() + #if defined(OVR_OS_MS) + , exceptionRecord() + #elif defined(OVR_OS_APPLE) + , exceptionType(0) + , cpuExceptionId(0) + , cpuExceptionIdError(0) + , machExceptionData() + , machExceptionDataCount(0) + #endif +{ +} + + + +ExceptionHandler::ExceptionHandler() + : enabled(false) + , pauseCount(0) + , reportPrivacyEnabled(true) + , exceptionResponse(kERHandle) + , exceptionListener(nullptr) + , exceptionListenerUserValue(0) + , appDescription() + , codeBasePathArray() + , reportFilePath() + , miniDumpFlags(0) + , miniDumpFilePath() + , file(nullptr) + , scratchBuffer() + , exceptionOccurred(false) + , handlingBusy(0) + , reportFilePathActual() + , minidumpFilePathActual() + , terminateReturnValue(0) + , exceptionInfo() + #if defined(OVR_OS_MS) + , vectoredHandle(nullptr) + , previousFilter(nullptr) + , pExceptionPointers(nullptr) + #elif defined(OVR_OS_MAC) + , machHandlerInitialized(false) + , machExceptionPort(0) + , machExceptionPortsSaved() + , machThreadShouldContinue(false) + , machThreadExecuting(false) + , machThread((pthread_t)OVR_THREADHANDLE_INVALID) + #endif +{ + SetExceptionPaths("default", "default"); +} + +void ExceptionHandler::SetPathsFromNames(const char* organizationName, const char* ApplicationName, const char* exceptionFormat, const char* minidumpFormat) +{ + char exceptionPath[OVR_MAX_PATH]; + char miniDumpPath[OVR_MAX_PATH]; + GetCrashDumpDirectory(exceptionPath, OVR_MAX_PATH); + OVR_strlcat(exceptionPath, organizationName, OVR_MAX_PATH); + + //make the organization folder if necessary + #ifdef OVR_OS_MS + WCHAR wpath[128]; + OVR::UTF8Util::DecodeString(wpath, exceptionPath); + CreateDirectoryW(wpath,NULL); + #else + mkdir(exceptionPath,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + #endif + + #ifdef OVR_OS_MS + const char* separator = "\\"; + #else + const char* separator = "/"; + #endif + OVR_strlcat(exceptionPath, separator, OVR_MAX_PATH); + OVR_strlcat(exceptionPath, ApplicationName, OVR_MAX_PATH); + #ifdef OVR_OS_MS + OVR::UTF8Util::DecodeString(wpath, exceptionPath); + CreateDirectoryW(wpath, NULL); + #else + mkdir(exceptionPath,S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + #endif + OVR_strlcat(exceptionPath, separator, OVR_MAX_PATH); + OVR_strcpy(miniDumpPath, OVR_MAX_PATH, exceptionPath); + + OVR::OVR_strlcat(exceptionPath, exceptionFormat, OVR_MAX_PATH); + OVR::OVR_strlcat(miniDumpPath, minidumpFormat, OVR_MAX_PATH); + + SetExceptionPaths(exceptionPath, miniDumpPath); +} + +ExceptionHandler::~ExceptionHandler() +{ + if(enabled) + { + Enable(false); + } +} + +size_t ExceptionHandler::GetCrashDumpDirectory(char* directoryPath, size_t directoryPathCapacity) +{ + #if defined(OVR_OS_MS) + wchar_t pathW[OVR_MAX_PATH + 1]; // +1 because we append a path separator. + HRESULT hr = SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_CREATE, nullptr, SHGFP_TYPE_CURRENT, pathW); + + if (SUCCEEDED(hr)) + { + intptr_t requiredUTF8Length = OVR::UTF8Util::GetEncodeStringSize(pathW); // Returns required strlen. + if (requiredUTF8Length < OVR_MAX_PATH) // We need space for a trailing path separator. + { + OVR::UTF8Util::EncodeString(directoryPath, pathW, -1); + OVR::OVR_strlcat(directoryPath, "\\", directoryPathCapacity); + } + + return (requiredUTF8Length + 1); + } + + #elif defined(OVR_OS_MAC) + // This is the same location that Apple puts its OS-generated .crash files. + const char* home = getenv("HOME"); + size_t requiredStrlen = OVR::OVR_snprintf(directoryPath, directoryPathCapacity, "%s/Library/Logs/DiagnosticReports/", home ? home : "/Users/Shared/Logs/DiagnosticReports/"); + // To do: create the directory if it doesn't already exist. + return requiredStrlen; + + #elif defined(OVR_OS_UNIX) + const char* home = getenv("HOME"); + size_t requiredStrlen = OVR::OVR_snprintf(directoryPath, directoryPathCapacity, "%s/Library/", home ? home : "/Users/Shared/"); + // To do: create the directory if it doesn't already exist. + return requiredStrlen; + #endif + + return 0; +} + + +#if defined(OVR_OS_MS) + +static ExceptionHandler* sExceptionHandler = nullptr; + + unsigned WINAPI ExceptionHandler::ExceptionHandlerThreadExec(void * callingHandler) + { + ExceptionHandler* caller = reinterpret_cast<ExceptionHandler*>(callingHandler); + if (caller->miniDumpFilePath[0]) + caller->WriteMiniDump(); + + if (caller->reportFilePath[0]) + caller->WriteReport(); + + if (caller->exceptionListener) + caller->exceptionListener->HandleException(caller->exceptionListenerUserValue, caller, &caller->exceptionInfo, caller->reportFilePathActual); + return 1; + } + + LONG WINAPI Win32ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers) + { + if(sExceptionHandler) + return (LONG)sExceptionHandler->ExceptionFilter(pExceptionPointers); + return EXCEPTION_CONTINUE_SEARCH; + } + + LONG ExceptionHandler::ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers) + { + if(pauseCount) + return EXCEPTION_CONTINUE_SEARCH; + + // Exception codes < 0x80000000 are not true exceptions but rather are debugger notifications. They include DBG_TERMINATE_THREAD, + // DBG_TERMINATE_PROCESS, DBG_CONTROL_BREAK, DBG_COMMAND_EXCEPTION, DBG_CONTROL_C, DBG_PRINTEXCEPTION_C, DBG_RIPEXCEPTION, + // and 0x406d1388 (thread named, http://blogs.msdn.com/b/stevejs/archive/2005/12/19/505815.aspx). + + if(pExceptionPointers->ExceptionRecord->ExceptionCode < 0x80000000) + return EXCEPTION_CONTINUE_SEARCH; + + // VC++ C++ exceptions use code 0xe06d7363 ('Emsc') + // http://support.microsoft.com/kb/185294 + // http://blogs.msdn.com/b/oldnewthing/archive/2010/07/30/10044061.aspx + if(pExceptionPointers->ExceptionRecord->ExceptionCode == 0xe06d7363) + return EXCEPTION_CONTINUE_SEARCH; + + if(handlingBusy.CompareAndSet_Acquire(0, 1)) // If we can successfully change it from 0 to 1. + { + exceptionOccurred = true; + + SymbolLookup::Initialize(); + + this->pExceptionPointers = pExceptionPointers; + + // Disable the handler while we do this processing. + ULONG result = RemoveVectoredExceptionHandler(vectoredHandle); + OVR_ASSERT_AND_UNUSED(result != 0, result); + + // Time + exceptionInfo.timeVal = time(nullptr); + exceptionInfo.time = *gmtime(&exceptionInfo.timeVal); + + // Thread id + // This is the thread id of the current thread and not the exception thread. + if(!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &exceptionInfo.threadHandle, 0, true, DUPLICATE_SAME_ACCESS)) + exceptionInfo.threadHandle = 0; + exceptionInfo.threadSysId = ConvertThreadHandleToThreadSysId(exceptionInfo.threadHandle); + + OVR::GetThreadName(exceptionInfo.threadHandle, exceptionInfo.threadName, OVR_ARRAY_COUNT(exceptionInfo.threadName)); + + // Backtraces + exceptionInfo.backtraceCount = symbolLookup.GetBacktrace(exceptionInfo.backtrace, OVR_ARRAY_COUNT(exceptionInfo.backtrace)); + + // Context + exceptionInfo.cpuContext = *pExceptionPointers->ContextRecord; + exceptionInfo.exceptionRecord = *pExceptionPointers->ExceptionRecord; + exceptionInfo.pExceptionInstructionAddress = exceptionInfo.exceptionRecord.ExceptionAddress; + if((exceptionInfo.exceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) || (exceptionInfo.exceptionRecord.ExceptionCode == EXCEPTION_IN_PAGE_ERROR)) + exceptionInfo.pExceptionMemoryAddress = (void*)exceptionInfo.exceptionRecord.ExceptionInformation[1]; // ExceptionInformation[0] indicates if it was a read (0), write (1), or data execution attempt (8). + else + exceptionInfo.pExceptionMemoryAddress = pExceptionPointers->ExceptionRecord->ExceptionAddress; + + WriteExceptionDescription(); + + if (pExceptionPointers->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW){ + unsigned int IdValue; + + void* ThreadHandle = (HANDLE)_beginthreadex(0, (unsigned)128 * 1024, + ExceptionHandlerThreadExec, this, 0, (unsigned*)&IdValue); + WaitForSingleObject(ThreadHandle, INFINITE); + CloseHandle(ThreadHandle); + + } + else + { + if (miniDumpFilePath[0]) + WriteMiniDump(); + + if (reportFilePath[0]) + WriteReport(); + + if (exceptionListener) + exceptionListener->HandleException(exceptionListenerUserValue, this, &exceptionInfo, reportFilePathActual); + } + if(exceptionInfo.threadHandle) + { + CloseHandle(exceptionInfo.threadHandle); + exceptionInfo.threadHandle = 0; + } + + SymbolLookup::Shutdown(); + + // Restore the handler that we temporarily disabled above. + vectoredHandle = AddVectoredExceptionHandler(1, Win32ExceptionFilter); + + handlingBusy.Store_Release(0); + } + + if(exceptionResponse == ExceptionHandler::kERContinue) + return EXCEPTION_CONTINUE_EXECUTION; + else if(exceptionResponse == ExceptionHandler::kERHandle) + return EXCEPTION_EXECUTE_HANDLER; + else if(exceptionResponse == ExceptionHandler::kERTerminate) + { + TerminateProcess(GetCurrentProcess(), (UINT)terminateReturnValue); + return terminateReturnValue; + } + else if(exceptionResponse == ExceptionHandler::kERThrow) + return EXCEPTION_CONTINUE_SEARCH; + + // kERDefault + return EXCEPTION_EXECUTE_HANDLER; + } + +#endif // defined(OVR_OS_MS) + + +#if defined(OVR_OS_APPLE) + // http://www.opensource.apple.com/source/xnu/xnu-2050.22.13/ + // http://www.opensource.apple.com/source/xnu/xnu-2050.22.13/osfmk/man/ + // http://www.opensource.apple.com/source/Libc/Libc-825.26/ + // https://mikeash.com/pyblog/friday-qa-2013-01-11-mach-exception-handlers.html + + void* ExceptionHandler::MachHandlerThreadFunction() + { + __Request__mach_exception_raise_state_identity_t msg; + __Reply__mach_exception_raise_state_identity_t reply; + mach_msg_return_t result; + + machThreadExecuting = true; + pthread_setname_np("ExceptionHandler"); + + while(machThreadShouldContinue) + { + mach_msg_option_t options = MACH_RCV_MSG | MACH_RCV_LARGE; + natural_t timeout = 0; // Would be better to support a non-zero time. + + if(timeout) + options |= MACH_RCV_TIMEOUT; + + result = mach_msg(&msg.Head, options, 0, sizeof(msg), machExceptionPort, timeout, MACH_PORT_NULL); + + if(msg.Head.msgh_id != sMachCancelMessageType) + { + if(result == MACH_MSG_SUCCESS) + { + if(mach_exc_server_OVR(&msg.Head, &reply.Head) == 0) //This will call our HandleMachException function. + result = ~MACH_MSG_SUCCESS; + } + + // Send the reply + if(result == MACH_MSG_SUCCESS) + { + result = mach_msg(&reply.Head, MACH_SEND_MSG, reply.Head.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + if(result != MACH_MSG_SUCCESS) + { + // Failure. + } + } + } + } + + machThreadExecuting = false; + + return nullptr; + } + + + kern_return_t ExceptionHandler::HandleMachException(mach_port_t /*machPort*/, mach_port_t threadSysId, mach_port_t machTask, + exception_type_t machExceptionType, mach_exception_data_type_t* pMachExceptionData, + mach_msg_type_number_t exceptionDataCount, int* /*pMachExceptionFlavor*/, thread_state_t threadStatePrev, + mach_msg_type_number_t /*threadStatePrevCount*/, thread_state_t /*threadStateNew*/, + mach_msg_type_number_t* /*pThreadStateNewCount*/) + { + // We don't want to handle exceptions for other processes. + if(machTask != mach_task_self()) + return ForwardMachException(threadSysId, machTask, machExceptionType, pMachExceptionData, exceptionDataCount); + + if(handlingBusy.CompareAndSet_Acquire(0, 1)) // If we can successfully change it from 0 to 1. + { + exceptionOccurred = true; + + // Disable the handler while we do this processing. + // To do. + + // Time + exceptionInfo.timeVal = time(nullptr); + exceptionInfo.time = *gmtime(&exceptionInfo.timeVal); + + // Thread id + exceptionInfo.threadHandle = pthread_from_mach_thread_np(threadSysId); + exceptionInfo.threadSysId = threadSysId; + pthread_getname_np((pthread_t)exceptionInfo.threadHandle, exceptionInfo.threadName, sizeof(exceptionInfo.threadName)); + + // Backtraces + exceptionInfo.backtraceCount = symbolLookup.GetBacktraceFromThreadSysId(exceptionInfo.backtrace, OVR_ARRAY_COUNT(exceptionInfo.backtrace), 0, threadSysId); + + // Context + #if defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + // We can read x86_THREAD_STATE directly fromk threadStatePrev. + exceptionInfo.cpuContext.threadState = *reinterpret_cast<x86_thread_state_t*>(threadStatePrev); + + mach_msg_type_number_t stateCount = x86_FLOAT_STATE_COUNT; + thread_get_state(threadSysId, x86_FLOAT_STATE, (natural_t*)&exceptionInfo.cpuContext.floatState, &stateCount); + + stateCount = x86_DEBUG_STATE_COUNT; + thread_get_state(threadSysId, x86_DEBUG_STATE, (natural_t*)&exceptionInfo.cpuContext.debugState, &stateCount); + + stateCount = x86_AVX_STATE_COUNT; + thread_get_state(threadSysId, x86_AVX_STATE, (natural_t*)&exceptionInfo.cpuContext.avxState, &stateCount); + + stateCount = x86_EXCEPTION_STATE_COUNT; + thread_get_state(threadSysId, x86_EXCEPTION_STATE, (natural_t*)&exceptionInfo.cpuContext.exceptionState, &stateCount); + + #if defined(OVR_CPU_X86) + exceptionInfo.pExceptionInstructionAddress = (void*)exceptionInfo.cpuContext.threadState.uts.ts32.__eip; + exceptionInfo.pExceptionMemoryAddress = (void*)exceptionInfo.cpuContext.exceptionState.ues.es32.__faultvaddr; + exceptionInfo.cpuExceptionId = exceptionInfo.cpuContext.exceptionState.ues.es32.__trapno; + exceptionInfo.cpuExceptionIdError = exceptionInfo.cpuContext.exceptionState.ues.es32.__err; + #else + exceptionInfo.pExceptionInstructionAddress = (void*)exceptionInfo.cpuContext.threadState.uts.ts64.__rip; + exceptionInfo.pExceptionMemoryAddress = (void*)exceptionInfo.cpuContext.exceptionState.ues.es64.__faultvaddr; + exceptionInfo.cpuExceptionId = exceptionInfo.cpuContext.exceptionState.ues.es64.__trapno; + exceptionInfo.cpuExceptionIdError = exceptionInfo.cpuContext.exceptionState.ues.es64.__err; + #endif + #endif + + exceptionInfo.exceptionType = machExceptionType; + + exceptionInfo.machExceptionDataCount = MIN(exceptionDataCount, OVR_ARRAY_COUNT(exceptionInfo.machExceptionData)); + for(int i = 0; i < exceptionInfo.machExceptionDataCount; i++) + exceptionInfo.machExceptionData[i] = pMachExceptionData[i]; + + WriteExceptionDescription(); + + if(reportFilePath[0]) + WriteReport(); + + if(miniDumpFilePath[0]) + WriteMiniDump(); + + if(exceptionListener) + exceptionListener->HandleException(exceptionListenerUserValue, this, &exceptionInfo, reportFilePathActual); + + // Re-restore the handler. + // To do. + + handlingBusy.Store_Release(0); + } + + kern_return_t result = KERN_FAILURE; // By default pass on the exception to another handler after we are done here. + + if(exceptionResponse == ExceptionHandler::kERContinue) + result = KERN_SUCCESS; // This will trigger a re-execution of the function. + else if(exceptionResponse == ExceptionHandler::kERTerminate) + ::exit(terminateReturnValue); + else if(exceptionResponse == ExceptionHandler::kERThrow) + ForwardMachException(threadSysId, machTask, machExceptionType, pMachExceptionData, exceptionDataCount); + else if(exceptionResponse == ExceptionHandler::kERDefault) + ::exit(terminateReturnValue); + + // kERHandle + return result; + } + + + bool ExceptionHandler::InitMachExceptionHandler() + { + if(!machHandlerInitialized) + { + mach_port_t machTaskSelf = mach_task_self(); + kern_return_t result = MACH_MSG_SUCCESS; + exception_mask_t mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_CRASH; + + if(machExceptionPort == MACH_PORT_NULL) + { + result = mach_port_allocate(machTaskSelf, MACH_PORT_RIGHT_RECEIVE, &machExceptionPort); + + if(result == MACH_MSG_SUCCESS) + { + result = mach_port_insert_right(machTaskSelf, machExceptionPort, machExceptionPort, MACH_MSG_TYPE_MAKE_SEND); + + if(result == MACH_MSG_SUCCESS) + result = task_get_exception_ports(machTaskSelf, mask, machExceptionPortsSaved.masks, &machExceptionPortsSaved.count, + machExceptionPortsSaved.ports, machExceptionPortsSaved.behaviors, machExceptionPortsSaved.flavors); + } + } + + if(result == MACH_MSG_SUCCESS) + { + result = task_set_exception_ports(machTaskSelf, mask, machExceptionPort, EXCEPTION_STATE_IDENTITY | MACH_EXCEPTION_CODES, MACHINE_THREAD_STATE); + + if(result == MACH_MSG_SUCCESS) + { + machThreadShouldContinue = true; + + pthread_attr_t attr; + pthread_attr_init(&attr); + + result = pthread_create(&machThread, &attr, MachHandlerThreadFunctionStatic, (void*)this); + pthread_attr_destroy(&attr); + + machHandlerInitialized = (result == 0); + } + } + + if(!machHandlerInitialized) + ShutdownMachExceptionHandler(); + } + + return machHandlerInitialized; + } + + + void ExceptionHandler::ShutdownMachExceptionHandler() + { + if(machThreadExecuting) + { + machThreadShouldContinue = false; // Tell it to stop. + + // Cancel the current exception handler thread (which is probably blocking in a call to mach_msg) by sending it a cencel message. + struct CancelMessage + { + mach_msg_header_t msgHeader; + }; + + CancelMessage msg; + memset(&msg.msgHeader, 0, sizeof(CancelMessage)); + msg.msgHeader.msgh_id = sMachCancelMessageType; + msg.msgHeader.msgh_size = sizeof(CancelMessage); + msg.msgHeader.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_MAKE_SEND); + msg.msgHeader.msgh_remote_port = machExceptionPort; + msg.msgHeader.msgh_local_port = MACH_PORT_NULL; + + mach_msg_return_t result = mach_msg(&msg.msgHeader, MACH_SEND_MSG, msg.msgHeader.msgh_size, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + + if(result == MACH_MSG_SUCCESS) + { + const time_t secondsLater = time(NULL) + 4; + + while(machThreadExecuting && (time(NULL) < secondsLater)) + { + timespec ts = { 0, 1000000000 }; + nanosleep(&ts, nullptr); + } + } + + void* joinResult = nullptr; + pthread_join(machThread, &joinResult); + machThread = 0; + } + + if(machExceptionPort != MACH_PORT_NULL) + { + // Restore the previous ports + kern_return_t result = KERN_SUCCESS; + mach_port_t machTaskSelf = mach_task_self(); + + for(unsigned i = 0; (i < machExceptionPortsSaved.count) && (result == KERN_SUCCESS); i++) + { + result = task_set_exception_ports(machTaskSelf, machExceptionPortsSaved.masks[i], machExceptionPortsSaved.ports[i], + machExceptionPortsSaved.behaviors[i], machExceptionPortsSaved.flavors[i]); + } + + mach_port_deallocate(machTaskSelf, machExceptionPort); + machExceptionPort = MACH_PORT_NULL; + } + + machHandlerInitialized = false; + } + + + kern_return_t ExceptionHandler::ForwardMachException(mach_port_t thread, mach_port_t task, exception_type_t exceptionType, + mach_exception_data_t pMachExceptionData, mach_msg_type_number_t exceptionDataCount) + { + kern_return_t result = KERN_FAILURE; + mach_msg_type_number_t i; + + for(i = 0; i < machExceptionPortsSaved.count; i++) + { + if(machExceptionPortsSaved.masks[i] & (1 << exceptionType)) + break; + } + + if(i < machExceptionPortsSaved.count) + { + mach_port_t port = machExceptionPortsSaved.ports[i]; + exception_behavior_t behavior = machExceptionPortsSaved.behaviors[i]; + thread_state_flavor_t flavor = machExceptionPortsSaved.flavors[i]; + mach_msg_type_number_t threadStateCount = THREAD_STATE_MAX; + thread_state_data_t threadState; + + if(behavior != EXCEPTION_DEFAULT) + thread_get_state(thread, flavor, threadState, &threadStateCount); + + switch(behavior) + { + case EXCEPTION_DEFAULT: + result = mach_exception_raise_OVR(port, thread, task, exceptionType, pMachExceptionData, exceptionDataCount); + break; + + case EXCEPTION_STATE: + result = mach_exception_raise_state_OVR(port, exceptionType, pMachExceptionData, exceptionDataCount, + &flavor, threadState, threadStateCount, threadState, &threadStateCount); + break; + + case EXCEPTION_STATE_IDENTITY: + result = mach_exception_raise_state_identity_OVR(port, thread, task, exceptionType, pMachExceptionData, + exceptionDataCount, &flavor, threadState, threadStateCount, threadState, &threadStateCount); + break; + + default: + result = KERN_FAILURE; + break; + } + + if(behavior != EXCEPTION_DEFAULT) + result = thread_set_state(thread, flavor, threadState, threadStateCount); + } + + return result; + } + + +#endif // OVR_OS_APPLE + + +bool ExceptionHandler::Enable(bool enable) +{ + #if defined(OVR_OS_MS) + if(enable && !enabled) + { + OVR_ASSERT(vectoredHandle == nullptr); + vectoredHandle = AddVectoredExceptionHandler(1, Win32ExceptionFilter); // Windows call. + enabled = (vectoredHandle != nullptr); + OVR_ASSERT(enabled); + sExceptionHandler = this; + return enabled; + } + else if(!enable && enabled) + { + if(sExceptionHandler == this) + sExceptionHandler = nullptr; + OVR_ASSERT(vectoredHandle != nullptr); + ULONG result = RemoveVectoredExceptionHandler(vectoredHandle); // Windows call. + OVR_ASSERT_AND_UNUSED(result != 0, result); + vectoredHandle = nullptr; + enabled = false; + return true; + } + + #elif defined(OVR_OS_APPLE) + + if(enable && !enabled) + { + enabled = InitMachExceptionHandler(); + OVR_ASSERT(enabled); + sExceptionHandler = this; + return enabled; + } + else if(!enable && enabled) + { + if(sExceptionHandler == this) + sExceptionHandler = nullptr; + ShutdownMachExceptionHandler(); + enabled = false; + return true; + } + #else + OVR_UNUSED(enable); + #endif + + return true; +} + +int ExceptionHandler::PauseHandling(bool pause) +{ + if(pause) + return ++pauseCount; + + OVR_ASSERT(pauseCount > 0); + return --pauseCount; +} + +void ExceptionHandler::EnableReportPrivacy(bool enable) +{ + reportPrivacyEnabled = enable; +} + +void ExceptionHandler::WriteExceptionDescription() +{ + #if defined(OVR_OS_MS) + // There is some extra information available for AV exception. + if(exceptionInfo.exceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION) + { + const char* error = (exceptionInfo.exceptionRecord.ExceptionInformation[0] == 0) ? "reading" : + ((exceptionInfo.exceptionRecord.ExceptionInformation[0] == 1) ? "writing" : "executing"); + + char addressStr[24]; + SprintfAddress(addressStr, OVR_ARRAY_COUNT(addressStr), exceptionInfo.pExceptionMemoryAddress); + OVR::OVR_snprintf(exceptionInfo.exceptionDescription, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription), "ACCESS_VIOLATION %s address %s", error, addressStr); + } + else + { + exceptionInfo.exceptionDescription[0] = 0; + + // Process "standard" exceptions, other than 'access violation' + #define FORMAT_EXCEPTION(x) \ + case EXCEPTION_##x: \ + OVR::OVR_strlcpy(exceptionInfo.exceptionDescription, #x, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription)); \ + break; + + switch(exceptionInfo.exceptionRecord.ExceptionCode) + { + //FORMAT_EXCEPTION(ACCESS_VIOLATION) Already handled above. + FORMAT_EXCEPTION(DATATYPE_MISALIGNMENT) + FORMAT_EXCEPTION(BREAKPOINT) + FORMAT_EXCEPTION(SINGLE_STEP) + FORMAT_EXCEPTION(ARRAY_BOUNDS_EXCEEDED) + FORMAT_EXCEPTION(FLT_DENORMAL_OPERAND) + FORMAT_EXCEPTION(FLT_DIVIDE_BY_ZERO) + FORMAT_EXCEPTION(FLT_INEXACT_RESULT) + FORMAT_EXCEPTION(FLT_INVALID_OPERATION) + FORMAT_EXCEPTION(FLT_OVERFLOW) + FORMAT_EXCEPTION(FLT_STACK_CHECK) + FORMAT_EXCEPTION(FLT_UNDERFLOW) + FORMAT_EXCEPTION(INT_DIVIDE_BY_ZERO) + FORMAT_EXCEPTION(INT_OVERFLOW) + FORMAT_EXCEPTION(PRIV_INSTRUCTION) + FORMAT_EXCEPTION(IN_PAGE_ERROR) + FORMAT_EXCEPTION(ILLEGAL_INSTRUCTION) + FORMAT_EXCEPTION(NONCONTINUABLE_EXCEPTION) + FORMAT_EXCEPTION(STACK_OVERFLOW) + FORMAT_EXCEPTION(INVALID_DISPOSITION) + FORMAT_EXCEPTION(GUARD_PAGE) + FORMAT_EXCEPTION(INVALID_HANDLE) + #if defined(EXCEPTION_POSSIBLE_DEADLOCK) && defined(STATUS_POSSIBLE_DEADLOCK) // This type seems to be non-existant in practice. + FORMAT_EXCEPTION(POSSIBLE_DEADLOCK) + #endif + } + + // If not one of the "known" exceptions, try to get the string from NTDLL.DLL's message table. + if(exceptionInfo.exceptionDescription[0] == 0) + { + char addressStr[24]; + SprintfAddress(addressStr, OVR_ARRAY_COUNT(addressStr), exceptionInfo.pExceptionMemoryAddress); + + char buffer[384]; + DWORD capacity = OVR_ARRAY_COUNT(buffer); + + const size_t length = (size_t)FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE, + GetModuleHandleW(L"NTDLL.DLL"), exceptionInfo.exceptionRecord.ExceptionCode, 0, buffer, capacity, nullptr); + if(length) + OVR::OVR_snprintf(exceptionInfo.exceptionDescription, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription), + "%s at instruction %s", buffer, addressStr); + + // If everything else failed just show the hex code. + if(exceptionInfo.exceptionDescription[0] == 0) + OVR::OVR_snprintf(exceptionInfo.exceptionDescription, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription), + "Unknown exception 0x%08x at instruction %s", exceptionInfo.exceptionRecord.ExceptionCode, addressStr); + } + } + + #elif defined(OVR_OS_APPLE) + struct MachExceptionInfo + { + static const char* GetCPUExceptionIdString(uint32_t cpuExceptionId) + { + const char* id; + + #if defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + switch (cpuExceptionId) + { + case 0: id = "integer div/0"; break; + case 1: id = "breakpoint fault"; break; + case 2: id = "non-maskable interrupt"; break; + case 3: id = "int 3"; break; + case 4: id = "overflow"; break; + case 5: id = "bounds check failure"; break; + case 6: id = "invalid instruction"; break; + case 7: id = "coprocessor unavailable"; break; + case 8: id = "exception within exception"; break; + case 9: id = "coprocessor segment overrun"; break; + case 10: id = "invalid task switch"; break; + case 11: id = "segment not present"; break; + case 12: id = "stack exception"; break; + case 13: id = "general protection fault"; break; + case 14: id = "page fault"; break; + case 16: id = "coprocessor error"; break; + default: id = "<unknown>"; break; + } + #else + // To do: Support ARM or others. + #endif + + return id; + } + + static const char* GetMachExceptionTypeString(uint64_t exceptionCause) + { + switch (exceptionCause) + { + case EXC_ARITHMETIC: return "EXC_ARITHMETIC"; + case EXC_BAD_ACCESS: return "EXC_BAD_ACCESS"; + case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION"; + case EXC_BREAKPOINT: return "EXC_BREAKPOINT"; + case EXC_CRASH: return "EXC_CRASH"; + case EXC_EMULATION: return "EXC_EMULATION"; + case EXC_MACH_SYSCALL: return "EXC_MACH_SYSCALL"; + case EXC_RPC_ALERT: return "EXC_RPC_ALERT"; + case EXC_SOFTWARE: return "EXC_SOFTWARE"; + case EXC_SYSCALL: return "EXC_SYSCALL"; + }; + + return "EXC_<unknown>"; + } + + static const char* GetMachExceptionIdString(uint64_t machExceptionId, uint64_t code0) + { + const char* id = "<unknown>"; + + #if defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + switch (machExceptionId) + { + case EXC_ARITHMETIC: + switch (code0) + { + case EXC_I386_BOUND: id = "EXC_I386_BOUND"; break; + case EXC_I386_DIV: id = "EXC_I386_DIV"; break; + case EXC_I386_EMERR: id = "EXC_I386_EMERR"; break; + case EXC_I386_EXTERR: id = "EXC_I386_EXTERR"; break; + case EXC_I386_EXTOVR: id = "EXC_I386_EXTOVR"; break; + case EXC_I386_INTO: id = "EXC_I386_INTO"; break; + case EXC_I386_NOEXT: id = "EXC_I386_NOEXT"; break; + case EXC_I386_SSEEXTERR: id = "EXC_I386_SSEEXTERR"; break; + } + break; + + case EXC_BAD_INSTRUCTION: + if(code0 == EXC_I386_INVOP) + id = "EXC_I386_INVOP"; + break; + + case EXC_BREAKPOINT: + if(code0 == EXC_I386_BPT) + id = "EXC_I386_BPT"; + else if(code0 == EXC_I386_SGL) + id = "EXC_I386_SGL"; + break; + }; + #else + // To do. + #endif + + return id; + } + }; + + OVR::OVR_snprintf(exceptionInfo.exceptionDescription, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription), + "Mach exception type: %llu (%s)\n", exceptionInfo.exceptionType, MachExceptionInfo::GetMachExceptionTypeString(exceptionInfo.exceptionType)); + + OVR::OVR_snprintf(scratchBuffer, OVR_ARRAY_COUNT(scratchBuffer), "CPU exception info: exception id: %u (%s), exception id error: %u, fault memory address: %p\n", + exceptionInfo.cpuExceptionId, MachExceptionInfo::GetCPUExceptionIdString(exceptionInfo.cpuExceptionId), exceptionInfo.cpuExceptionIdError, exceptionInfo.pExceptionMemoryAddress); + OVR::OVR_strlcat(exceptionInfo.exceptionDescription, scratchBuffer, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription)); + + + OVR::OVR_snprintf(scratchBuffer, OVR_ARRAY_COUNT(scratchBuffer), "Mach exception info: exception id: %llu (%s), 0x%llx (%llu)\n", (uint64_t)exceptionInfo.machExceptionData[0], + MachExceptionInfo::GetMachExceptionIdString(exceptionInfo.exceptionType, exceptionInfo.machExceptionData[0]), + (uint64_t)exceptionInfo.machExceptionData[1], (uint64_t)exceptionInfo.machExceptionData[1]); + OVR::OVR_strlcat(exceptionInfo.exceptionDescription, scratchBuffer, OVR_ARRAY_COUNT(exceptionInfo.exceptionDescription)); + #else + // To do. + exceptionInfo.exceptionDescription[0] = 0; + #endif +} + + +void ExceptionHandler::WriteReportLine(const char* pLine) +{ + fwrite(pLine, strlen(pLine), 1, file); +} + + +void ExceptionHandler::WriteReportLineF(const char* format, ...) +{ + va_list args; + va_start(args, format); + int length = OVR_vsnprintf(scratchBuffer, OVR_ARRAY_COUNT(scratchBuffer), format, args); + if(length >= (int)OVR_ARRAY_COUNT(scratchBuffer)) // If we didn't have enough space... + length = (OVR_ARRAY_COUNT(scratchBuffer) - 1); // ... use what we have. + va_end(args); + + fwrite(scratchBuffer, length, 1, file); +} + + +// Thread <name> <handle> <id> +// 0 <module> <address> <function> <file>:<line> +// 1 <module> <address> <function> <file>:<line> +// . . . +// +void ExceptionHandler::WriteThreadCallstack(ThreadHandle threadHandle, ThreadSysId threadSysId, const char* additionalInfo) +{ + // We intentionally do not directly use the SymbolInfo::ReportThreadCallstack function because that function allocates memory, + // which we cannot do due to possibly being within an exception handler. + + // Print the header + char threadName[32]; + char threadHandleStr[32]; + char threadSysIdStr[32]; + char stackBaseStr[24]; + char stackLimitStr[24]; + char stackCurrentStr[24]; + void* pStackBase; + void* pStackLimit; + bool isExceptionThread = (threadSysId == exceptionInfo.threadSysId); + + #if defined(OVR_OS_MS) && (OVR_PTR_SIZE == 8) + void* pStackCurrent = (threadSysId == exceptionInfo.threadSysId) ? (void*)exceptionInfo.cpuContext.Rsp : nullptr; // We would need to suspend the thread, get its context, resume it, then read the rsp register. It turns out we are already doing that suspend/resume below in the backtrace call. + #elif defined(OVR_OS_MS) + void* pStackCurrent = (threadSysId == exceptionInfo.threadSysId) ? (void*)exceptionInfo.cpuContext.Esp : nullptr; + #elif defined(OVR_OS_MAC) && (OVR_PTR_SIZE == 8) + void* pStackCurrent = (threadSysId == exceptionInfo.threadSysId) ? (void*)exceptionInfo.cpuContext.threadState.uts.ts64.__rsp : nullptr; + #elif defined(OVR_OS_MAC) + void* pStackCurrent = (threadSysId == exceptionInfo.threadSysId) ? (void*)exceptionInfo.cpuContext.threadState.uts.ts32.__esp : nullptr; + #elif defined(OVR_OS_LINUX) + void* pStackCurrent = nullptr; // To do. + #endif + + OVR::GetThreadStackBounds(pStackBase, pStackLimit, threadHandle); + + OVR::Thread::GetThreadName(threadName, OVR_ARRAY_COUNT(threadName), threadName); + SprintfThreadHandle(threadHandleStr, OVR_ARRAY_COUNT(threadHandleStr), threadHandle); + SprintfThreadSysId(threadSysIdStr, OVR_ARRAY_COUNT(threadSysIdStr), threadSysId); + SprintfAddress(stackBaseStr, OVR_ARRAY_COUNT(stackBaseStr), pStackBase); + SprintfAddress(stackLimitStr, OVR_ARRAY_COUNT(stackLimitStr), pStackLimit); + SprintfAddress(stackCurrentStr, OVR_ARRAY_COUNT(stackCurrentStr), pStackCurrent); + + if(threadName[0]) + WriteReportLineF("Thread \"%s\" handle: %s, id: %s, stack base: %s, stack limit: %s, stack current: %s, %s\n", threadName, threadHandleStr, threadSysIdStr, stackBaseStr, stackLimitStr, stackCurrentStr, additionalInfo ? additionalInfo : ""); + else + WriteReportLineF("Thread handle: %s, id: %s, stack base: %s, stack limit: %s, stack current: %s, %s\n", threadHandleStr, threadSysIdStr, stackBaseStr, stackLimitStr, stackCurrentStr, additionalInfo ? additionalInfo : ""); + + // Print the backtrace info + void* addressArray[64]; + size_t addressCount = symbolLookup.GetBacktraceFromThreadSysId(addressArray, OVR_ARRAY_COUNT(addressArray), 0, threadSysId); + SymbolInfo symbolInfo; + const char* pModuleName; + size_t backtraceSkipCount = 0; + + if(isExceptionThread) + { + // If this thread is the exception thread, skip some frames. + #if defined(OVR_OS_MS) + size_t i, iEnd = MIN(16, addressCount); + + for(i = 0; i < iEnd; i++) + { + symbolLookup.LookupSymbol((uint64_t)addressArray[i], symbolInfo); + if(strstr(symbolInfo.function, "UserExceptionDispatcher") != nullptr) + break; + } + + if(i < iEnd) // If found... + backtraceSkipCount = i; + else if(addressCount >= 9) // Else default to 9, which is coincidentally what works. + backtraceSkipCount = 9; + else + backtraceSkipCount = 0; + + addressArray[backtraceSkipCount] = exceptionInfo.pExceptionInstructionAddress; + #endif + } + + if(addressCount == 0) + { + WriteReportLine("<Unable to read backtrace>\n\n"); + } + else + { + for(size_t i = backtraceSkipCount; i < addressCount; ++i) + { + symbolLookup.LookupSymbol((uint64_t)addressArray[i], symbolInfo); + + if(symbolInfo.pModuleInfo && symbolInfo.pModuleInfo->name[0]) + pModuleName = symbolInfo.pModuleInfo->name; + else + pModuleName = "(unknown module)"; + + char addressStr[24]; + SprintfAddress(addressStr, OVR_ARRAY_COUNT(addressStr), addressArray[i]); + + if(symbolInfo.filePath[0]) + WriteReportLineF("%-2u %-24s %s %s+%d %s:%d\n%s", (unsigned)i, pModuleName, addressStr, + symbolInfo.function, symbolInfo.functionOffset, symbolInfo.filePath, + symbolInfo.fileLineNumber, (i + 1) == addressCount ? "\n" : ""); + else + WriteReportLineF("%-2u %-24s %s %s+%d\n%s", (unsigned)i, pModuleName, addressStr, + symbolInfo.function, symbolInfo.functionOffset, (i + 1) == addressCount ? "\n" : ""); // If this is the last line, append another \n. + } + } +} + + +void ExceptionHandler::WriteReport() +{ + // It's important that we don't allocate any memory here if we can help it. + using namespace OVR; + + if(strstr(reportFilePath, "%s")) // If the user-specified file path includes a date/time component... + { + char dateTimeBuffer[64]; + FormatDateTime(dateTimeBuffer, OVR_ARRAY_COUNT(dateTimeBuffer), exceptionInfo.timeVal, true, true, false, true); + OVR_snprintf(reportFilePathActual, OVR_ARRAY_COUNT(reportFilePathActual), reportFilePath, dateTimeBuffer); + } + else + { + OVR_strlcpy(reportFilePathActual, reportFilePath, OVR_ARRAY_COUNT(reportFilePathActual)); + } + + file = fopen(reportFilePathActual, "w"); + OVR_ASSERT(file != nullptr); + if(!file) + return; + + SymbolLookup::Initialize(); + + { + // Exception information + WriteReportLine("Exception Info\n"); + + WriteReportLineF("Exception report file: %s\n", reportFilePathActual); + + #if defined(OVR_OS_MS) + if(miniDumpFilePath[0]) + WriteReportLineF("Exception minidump file: %s\n", minidumpFilePathActual); + #endif + + char dateTimeBuffer[64]; + FormatDateTime(dateTimeBuffer, OVR_ARRAY_COUNT(dateTimeBuffer), exceptionInfo.timeVal, true, true, false, false); + WriteReportLineF("Time (GMT): %s\n", dateTimeBuffer); + + FormatDateTime(dateTimeBuffer, OVR_ARRAY_COUNT(scratchBuffer), exceptionInfo.timeVal, true, true, true, false); + WriteReportLineF("Time (local): %s\n", dateTimeBuffer); + WriteReportLineF("Thread name: %s\n", exceptionInfo.threadName[0] ? exceptionInfo.threadName : "(not available)"); // It's never possible on Windows to get thread names, as they are stored in the debugger at runtime. + + SprintfThreadHandle(scratchBuffer, OVR_ARRAY_COUNT(scratchBuffer), exceptionInfo.threadHandle); + OVR_strlcat(scratchBuffer, "\n", OVR_ARRAY_COUNT(scratchBuffer)); + WriteReportLine("Thread handle: "); + WriteReportLine(scratchBuffer); + + SprintfThreadSysId(scratchBuffer, OVR_ARRAY_COUNT(scratchBuffer), exceptionInfo.threadSysId); + OVR_strlcat(scratchBuffer, "\n", OVR_ARRAY_COUNT(scratchBuffer)); + WriteReportLine("Thread sys id: "); + WriteReportLine(scratchBuffer); + + char addressStr[24]; + SprintfAddress(addressStr, OVR_ARRAY_COUNT(addressStr), exceptionInfo.pExceptionInstructionAddress); + WriteReportLineF("Exception instruction address: %s (see callstack below)\n", addressStr); + WriteReportLineF("Exception description: %s\n", exceptionInfo.exceptionDescription); + + if (symbolLookup.LookupSymbol((uint64_t)exceptionInfo.pExceptionInstructionAddress, exceptionInfo.symbolInfo)) + { + if(exceptionInfo.symbolInfo.filePath[0]) + WriteReportLineF("Exception location: %s (%d)\n", exceptionInfo.symbolInfo.filePath, exceptionInfo.symbolInfo.fileLineNumber); + else + WriteReportLineF("Exception location: %s (%d)\n", exceptionInfo.symbolInfo.function, exceptionInfo.symbolInfo.functionOffset); + } + + // To consider: print exceptionInfo.cpuContext registers + } + + #if 0 // Disabled while we move this to the Util module or some other location. + /* + // OVR information + WriteReportLine("\nOVR Info\n"); + WriteReportLineF("OVR time: %f\n", ovr_GetTimeInSeconds()); + WriteReportLineF("OVR version: %s\n", ovr_GetVersionString()); + + // OVR util information + // The following would be useful to use if they didn't allocate memory, which we can't do. + // To do: see if we can have versions of the functions below which don't allocate memory + // or allocate it safely (e.g. use an alternative heap). + // String OVR::GetDisplayDriverVersion(); + // String OVR::GetCameraDriverVersion(); + + // OVR HMD information + WriteReportLine("\nOVR HMD Info\n"); + + // XXX rewrite this to use EnumerateHMDStateList() with a callback... + const OVR::List<OVR::CAPI::HMDState>& hmdStateList = OVR::CAPI::HMDState::GetHMDStateList(); + const OVR::CAPI::HMDState* pHMDState = hmdStateList.GetFirst(); + + if(hmdStateList.IsNull(pHMDState)) + { + WriteReportLine("No HMDs found.\n"); + } + + while(!hmdStateList.IsNull(pHMDState)) + { + if(pHMDState->pProfile) + { + const char* user = pHMDState->pProfile->GetValue(OVR_KEY_USER); + + if(user) + WriteReportLineF("Profile user: %s\n", reportPrivacyEnabled ? "<disabled by report privacy settings>" : user); + else + WriteReportLine("Null profile user\n"); + + float NeckEyeDistance[2]; + float EyeToNoseDistance[2]; + float MaxEyeToPlateDist[2]; + pHMDState->pProfile->GetFloatValues(OVR_KEY_NECK_TO_EYE_DISTANCE, NeckEyeDistance, 2); + pHMDState->pProfile->GetFloatValues(OVR_KEY_EYE_TO_NOSE_DISTANCE, EyeToNoseDistance, 2); + pHMDState->pProfile->GetFloatValues(OVR_KEY_MAX_EYE_TO_PLATE_DISTANCE, MaxEyeToPlateDist, 2); + + WriteReportLineF("Player height: %f, eye height: %f, IPD: %f, Neck eye distance: %f,%f, eye relief dial: %d, eye to nose distance: %f,%f, max eye to plate distance: %f,%f, custom eye render: %s\n", + pHMDState->pProfile->GetFloatValue(OVR_KEY_PLAYER_HEIGHT, 0.f), + pHMDState->pProfile->GetFloatValue(OVR_KEY_EYE_HEIGHT, 0.f), + pHMDState->pProfile->GetFloatValue(OVR_KEY_IPD, 0.f), + NeckEyeDistance[0], NeckEyeDistance[1], + pHMDState->pProfile->GetIntValue(OVR_KEY_EYE_RELIEF_DIAL, 0), + EyeToNoseDistance[0], EyeToNoseDistance[1], + MaxEyeToPlateDist[0], MaxEyeToPlateDist[1], + pHMDState->pProfile->GetBoolValue(OVR_KEY_CUSTOM_EYE_RENDER, false) ? "yes" : "no"); + + // Not currently used: + // OVR_KEY_NAME + // OVR_KEY_GENDER + // OVR_KEY_EYE_CUP + // OVR_KEY_CAMERA_POSITION + } + else + { + WriteReportLine("Null HMD profile\n"); + } + + if(pHMDState->pHmdDesc) // This should usually be true. + { + WriteReportLineF("HMD %d: Type: %u ProductName: %s, Manufacturer: %s VendorId: %d, ProductId: %d, SerialNumber: %s, FirmwareMajor: %d, FirmwareMinor: %d, Resolution: %dx%d, DisplayDeviceName: %s, DisplayId: %d\n", + 0, (unsigned)pHMDState->pHmdDesc->Type, pHMDState->pHmdDesc->ProductName, pHMDState->pHmdDesc->Manufacturer, pHMDState->pHmdDesc->VendorId, + pHMDState->pHmdDesc->ProductId, pHMDState->pHmdDesc->SerialNumber, pHMDState->pHmdDesc->FirmwareMajor, pHMDState->pHmdDesc->FirmwareMinor, + pHMDState->pHmdDesc->Resolution.w, pHMDState->pHmdDesc->Resolution.h, pHMDState->pHmdDesc->DisplayDeviceName, pHMDState->pHmdDesc->DisplayId); + + // HSW display state + ovrHSWDisplayState hswDS; + ovrHmd_GetHSWDisplayState(pHMDState->pHmdDesc, &hswDS); + WriteReportLineF("HSW displayed for hmd: %s\n", hswDS.Displayed ? "yes" : "no"); + } + + char threadIdStr[24]; + SprintfAddress(threadIdStr, OVR_ARRAY_COUNT(threadIdStr), pHMDState->BeginFrameThreadId); + + WriteReportLineF("Hmd Caps: %x, Hmd Service Caps: %x, Latency test active: %s, Last frame time: %f, Last get frame time: %f, Rendering configred: %s, Begin frame called: %s, Begin frame thread id: %s\n", + pHMDState->EnabledHmdCaps, pHMDState->EnabledServiceHmdCaps, pHMDState->LatencyTestActive ? "yes" : "no", pHMDState->LastFrameTimeSeconds, pHMDState->LastGetFrameTimeSeconds, pHMDState->RenderingConfigured ? "yes" : "no", + pHMDState->BeginFrameCalled ? "yes" : "no", threadIdStr); + + if(pHMDState->pLastError) + { + WriteReportLineF("OVR last error for hmd: %s\n", pHMDState->pLastError); + } + + pHMDState = hmdStateList.GetNext(pHMDState); + } + */ + #endif // #if 0 + + #if defined(OVR_OS_WIN32) + { + WriteReportLine("\nApp Info\n"); + + // Print the app path. + char appPath[OVR_MAX_PATH]; + GetCurrentProcessFilePath(appPath, OVR_ARRAY_COUNT(appPath)); + WriteReportLineF("Process path: %s\n", appPath); + + #if (OVR_PTR_SIZE == 4) + WriteReportLine("App format: 32 bit\n"); + #else + WriteReportLine("App format: 64 bit\n"); + #endif + + // Print the app version + wchar_t pathW[OVR_MAX_PATH] = {}; + GetModuleFileNameW(0, pathW, (DWORD)OVR_ARRAY_COUNT(pathW)); + DWORD dwUnused; + DWORD dwSize = GetFileVersionInfoSizeW(pathW, &dwUnused); + scratchBuffer[0] = 0; + + if(dwSize > 0) + { + void* const pVersionData = SafeMMapAlloc(dwSize); + + if(pVersionData) + { + if(GetFileVersionInfoW(pathW, 0, dwSize, pVersionData)) + { + VS_FIXEDFILEINFO* pFFI; + UINT size; + + if(VerQueryValueA(pVersionData, "\\", (void**)&pFFI, &size)) + { + WriteReportLineF("App version: %u.%u.%u.%u\n", + HIWORD(pFFI->dwFileVersionMS), LOWORD(pFFI->dwFileVersionMS), + HIWORD(pFFI->dwFileVersionLS), LOWORD(pFFI->dwFileVersionLS)); + } + } + + SafeMMapFree(pVersionData, dwSize); + } + } + + if(!scratchBuffer[0]) // If version info couldn't be found or read... + WriteReportLine("App version info not present\n"); + } + + { + WriteReportLine("\nSystem Info\n"); + + OSVERSIONINFOEXW vi; + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(vi); + GetVersionExW((LPOSVERSIONINFOW)&vi); // Cast to the older type. + + char osVersionName[256]; + GetOSVersionName(osVersionName, OVR_ARRAY_COUNT(osVersionName)); + WriteReportLineF("OS name: %s, version: %u.%u build %u, %s, platform id: %u, service pack: %ls\n", + osVersionName, vi.dwMajorVersion, vi.dwMinorVersion, vi.dwBuildNumber, Is64BitOS() ? "64 bit" : "32 bit", + vi.dwPlatformId, vi.szCSDVersion[0] ? vi.szCSDVersion : L"<none>"); + + WriteReportLineF("Debugger present: %s\n", OVRIsDebuggerPresent() ? "yes" : "no"); + + // System info + SYSTEM_INFO systemInfo; + GetNativeSystemInfo(&systemInfo); + + WriteReportLineF("Processor count: %u\n", systemInfo.dwNumberOfProcessors); + + // Windows Vista and later: + // BOOL WINAPI GetLogicalProcessorInformation(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION Buffer, PDWORD ReturnLength); + + if(systemInfo.wProcessorArchitecture == 0) + WriteReportLineF("Processor type: x86\n"); + else if(systemInfo.wProcessorArchitecture == 9) + WriteReportLineF("Processor type: x86-64\n"); + else if(systemInfo.wProcessorArchitecture == 10) + WriteReportLineF("Processor type: x86 on x86-64\n"); + + WriteReportLineF("Processor level: %u\n", systemInfo.wProcessorLevel); + WriteReportLineF("Processor revision: %u\n", systemInfo.wProcessorRevision); + + // Memory information + MEMORYSTATUSEX memoryStatusEx; + memset(&memoryStatusEx, 0, sizeof(memoryStatusEx)); + memoryStatusEx.dwLength = sizeof(memoryStatusEx); + GlobalMemoryStatusEx(&memoryStatusEx); + + WriteReportLineF("Memory load: %d%%\n", memoryStatusEx.dwMemoryLoad); + WriteReportLineF("Total physical memory: %I64d MiB\n", memoryStatusEx.ullTotalPhys / (1024 * 1024)); // Or are Mebibytes equal to (1024 * 1000) + WriteReportLineF("Available physical memory: %I64d MiB\n", memoryStatusEx.ullAvailPhys / (1024 * 1024)); + WriteReportLineF("Total page file memory: %I64d MiB\n", memoryStatusEx.ullTotalPageFile / (1024 * 1024)); + WriteReportLineF("Available page file memory: %I64d MiB\n", memoryStatusEx.ullAvailPageFile / (1024 * 1024)); + WriteReportLineF("Total virtual memory: %I64d MiB\n", memoryStatusEx.ullTotalVirtual / (1024 * 1024)); + WriteReportLineF("Free virtual memory: %I64d MiB\n", memoryStatusEx.ullAvailVirtual / (1024 * 1024)); + + DISPLAY_DEVICEW dd; + memset(&dd, 0, sizeof(DISPLAY_DEVICE)); + dd.cb = sizeof(DISPLAY_DEVICE); + + for(int i = 0; EnumDisplayDevicesW(nullptr, (DWORD)i, &dd, EDD_GET_DEVICE_INTERFACE_NAME); ++i) + { + WriteReportLineF("Display Device %d name: %ls, context: %ls, primary: %s, mirroring: %s\n", + i, dd.DeviceName, dd.DeviceString, (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) ? "yes" : "no", (dd.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ? "yes" : "no"); + } + } + + // Print video card information + // http://msdn.microsoft.com/en-us/library/aa394512%28v=vs.85%29.aspx + { + IWbemLocator* pIWbemLocator = nullptr; + BSTR bstrServer = nullptr; + IWbemServices* pIWbemServices = nullptr; + BSTR bstrWQL = nullptr; + BSTR bstrPath = nullptr; + IEnumWbemClassObject* pEnum = nullptr; + + CoInitializeEx(nullptr, COINIT_MULTITHREADED); + + HRESULT hr = CoCreateInstance(__uuidof(WbemLocator), nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWbemLocator), (LPVOID*)&pIWbemLocator); + if(FAILED(hr)) + goto End; + + bstrServer = SysAllocString(L"\\\\.\\root\\cimv2"); + hr = pIWbemLocator->ConnectServer(bstrServer, nullptr, nullptr, 0L, 0L, nullptr, nullptr, &pIWbemServices); + if(FAILED(hr)) + goto End; + + hr = CoSetProxyBlanket(pIWbemServices, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, nullptr, RPC_C_AUTHN_LEVEL_CALL, + RPC_C_IMP_LEVEL_IMPERSONATE, nullptr, EOAC_DEFAULT); + if(FAILED(hr)) + goto End; + + bstrWQL = SysAllocString(L"WQL"); + bstrPath = SysAllocString(L"select * from Win32_VideoController"); + hr = pIWbemServices->ExecQuery(bstrWQL, bstrPath, WBEM_FLAG_FORWARD_ONLY, nullptr, &pEnum); + if(FAILED(hr)) + goto End; + + ULONG uReturned; + IWbemClassObject* pObj = nullptr; + hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &uReturned); + if(FAILED(hr)) + goto End; + + WriteReportLine("\nDisplay adapter list\n"); + + for(unsigned i = 0; SUCCEEDED(hr) && uReturned; i++) + { + char sString[256]; + VARIANT var; + + if(i > 0) + WriteReportLine("\n"); + + WriteReportLineF("Info for display adapter %u\n", i); + + hr = pObj->Get(L"Name", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter Name: %s\n", sString); + } + + hr = pObj->Get(L"AdapterRAM", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WriteReportLineF("Display Adapter RAM: %u %s\n", + ((uint32_t)var.lVal > (1024*1024*1024) ? (uint32_t)var.lVal/(1024*1024*1024) : (uint32_t)var.lVal/(1024*1024)), ((uint32_t)var.lVal > (1024*1024*1024) ? "GiB" : "MiB")); + } + + hr = pObj->Get(L"DeviceID", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter DeviceID: %s\n", sString); + } + + hr = pObj->Get(L"DriverVersion", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter DriverVersion: %s\n", sString); + } + + hr = pObj->Get(L"DriverDate", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + // http://technet.microsoft.com/en-us/library/ee156576.aspx + wchar_t year[5] = { var.bstrVal[0], var.bstrVal[1], var.bstrVal[2], var.bstrVal[3], 0 }; + wchar_t month[3] = { var.bstrVal[4], var.bstrVal[5], 0 }; + wchar_t monthDay[3] = { var.bstrVal[6], var.bstrVal[7], 0 }; + + WriteReportLineF("Display Adapter DriverDate (US format): %ls/%ls/%ls\n", month, monthDay, year); + } + + // VideoProcessor + hr = pObj->Get(L"VideoProcessor", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter VideoProcessor %s\n", sString); + } + + hr = pObj->Get(L"VideoModeDescription", 0, &var, nullptr, nullptr); + if(SUCCEEDED(hr)) + { + WideCharToMultiByte(CP_ACP, 0, var.bstrVal, -1, sString, sizeof(sString), nullptr, nullptr); + WriteReportLineF("Display Adapter VideoModeDescription: %s\n", sString); + } + + pObj->Release(); + + hr = pEnum->Next(WBEM_INFINITE, 1, &pObj, &uReturned); + } + + End: + if(pEnum) + pEnum->Release(); + if(bstrPath) + SysFreeString(bstrPath); + if(bstrWQL) + SysFreeString(bstrWQL); + if(pIWbemServices) + pIWbemServices->Release(); + if(bstrServer) + SysFreeString(bstrServer); + if(pIWbemLocator) + pIWbemLocator->Release(); + + CoUninitialize(); + } + + { + // Print a list of threads. + DWORD currentProcessId = GetCurrentProcessId(); + HANDLE hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, currentProcessId); // ICreateToolhelp32Snapshot actually ignores currentProcessId. + + if(hThreadSnap != INVALID_HANDLE_VALUE) + { + THREADENTRY32 te32; + te32.dwSize = sizeof(THREADENTRY32); + + if(Thread32First(hThreadSnap, &te32)) + { + WriteReportLine("\nThread list\n"); + + do { + if(te32.th32OwnerProcessID == currentProcessId) + { + HANDLE hThread = ConvertThreadSysIdToThreadHandle(te32.th32ThreadID); + + if(hThread) + { + char buffer[96]; // Can't use scratchBuffer, because it's used by WriteThreadCallstack. + OVR_snprintf(buffer, OVR_ARRAY_COUNT(buffer), "base priority: %ld, delta priority: %ld", te32.tpBasePri, te32.tpDeltaPri); + + bool threadIsExceptionThread = (te32.th32ThreadID == (DWORD)exceptionInfo.threadSysId); + if(threadIsExceptionThread) + OVR_strlcat(buffer, ", exception thread", OVR_ARRAY_COUNT(buffer)); + + WriteThreadCallstack(hThread, (OVR::ThreadSysId)te32.th32ThreadID, buffer); + FreeThreadHandle(hThread); + } + } + } while(Thread32Next(hThreadSnap, &te32)); + } + + CloseHandle(hThreadSnap); + } + } + + { + // Print a list of the current modules within this process. + // DbgHelp.dll also provides a EnumerateLoadedModules64 function. + // To do: Convert the code below to use the GetModuleInfoArray function which we now have. + HMODULE hModule = LoadLibraryW(L"psapi.dll"); + + if(hModule) + { + typedef BOOL (WINAPI * ENUMPROCESSMODULES) (HANDLE hProcess, HMODULE* phModule, DWORD cb, LPDWORD lpcbNeeded); + typedef DWORD (WINAPI * GETMODULEBASENAME) (HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize); + typedef DWORD (WINAPI * GETMODULEFILENAMEEX) (HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize); + typedef BOOL (WINAPI * GETMODULEINFORMATION)(HANDLE hProcess, HMODULE hModule, MODULEINFO* pmi, DWORD nSize); + + ENUMPROCESSMODULES pEnumProcessModules = (ENUMPROCESSMODULES) (uintptr_t)GetProcAddress(hModule, "EnumProcessModules"); + GETMODULEBASENAME pGetModuleBaseName = (GETMODULEBASENAME) (uintptr_t)GetProcAddress(hModule, "GetModuleBaseNameW"); + GETMODULEFILENAMEEX pGetModuleFileNameEx = (GETMODULEFILENAMEEX) (uintptr_t)GetProcAddress(hModule, "GetModuleFileNameExW"); + GETMODULEINFORMATION pGetModuleInformation = (GETMODULEINFORMATION)(uintptr_t)GetProcAddress(hModule, "GetModuleInformation"); + + HANDLE hProcess = GetCurrentProcess(); + HMODULE hModuleArray[200]; + DWORD cbNeeded; + + if(pEnumProcessModules(hProcess, hModuleArray, sizeof(hModuleArray), &cbNeeded)) + { + size_t actualModuleCount = (cbNeeded / sizeof(HMODULE)); + + if(actualModuleCount > OVR_ARRAY_COUNT(hModuleArray)) //If hModuleArray's capacity was not enough... + actualModuleCount = OVR_ARRAY_COUNT(hModuleArray); + + // Print a header + WriteReportLine("\nModule list\n"); + + #if (OVR_PTR_SIZE == 4) + WriteReportLine("Base Size Entrypoint Name Path\n"); + #else + WriteReportLine("Base Size Entrypoint Name Path\n"); + #endif + + // And go through the list one by one + for(size_t i = 0; i < actualModuleCount; i++) + { + MODULEINFO mi; + size_t length; + + if(!pGetModuleInformation(hProcess, hModuleArray[i], &mi, sizeof(mi))) + { + mi.EntryPoint = nullptr; + mi.lpBaseOfDll = nullptr; + mi.SizeOfImage = 0; + } + + // Write the base name. + wchar_t name[OVR_MAX_PATH + 3]; + name[0] = '"'; + if(pGetModuleBaseName(hProcess, hModuleArray[i], name + 1, OVR_MAX_PATH)) + length = wcslen(name); + else + { + wcscpy(name + 1, L"(unknown)"); + length = 10; + } + + name[length] = '"'; + name[length + 1] = '\0'; + + // Write the path + wchar_t path[OVR_MAX_PATH + 3]; + path[0] = '"'; + if(pGetModuleFileNameEx(hProcess, hModuleArray[i], path + 1, OVR_MAX_PATH)) + length = wcslen(path); + else + { + wcscpy(path + 1, L"(unknown)"); + length = 10; + } + path[length] = '"'; + path[length + 1] = '\0'; + + #if (OVR_PTR_SIZE == 4) + WriteReportLineF("0x%08x, 0x%08x 0x%08x %-24ls %ls\n", (uint32_t)mi.lpBaseOfDll, (uint32_t)mi.SizeOfImage, (uint32_t)mi.EntryPoint, name, path); + #else + WriteReportLineF("0x%016I64x 0x%016I64x 0x%016I64x %-24ls %ls\n", (uint64_t)mi.lpBaseOfDll, (uint64_t)mi.SizeOfImage, (uint64_t)mi.EntryPoint, name, path); + #endif + } + } + } + } + + { + // Print a list of processes. + // DbgHelp.dll provides a SymEnumProcesses function, but it's available with DbgHelp.dll v6.2 which doesn't ship with Windows until Windows 8. + WriteReportLine("\nProcess list\n"); + + if(reportPrivacyEnabled) + WriteReportLine("Disabled by report privacy settings\n"); + else + { + HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + + if(hProcessSnapshot != INVALID_HANDLE_VALUE) + { + PROCESSENTRY32W pe32; + memset(&pe32, 0, sizeof(pe32)); + pe32.dwSize = sizeof(pe32); + + if(Process32FirstW(hProcessSnapshot, &pe32)) + { + WriteReportLine("Process Id File\n"); + + do { + // Try to get the full path to the process, as pe32.szExeFile holds only the process file name. + // This will typically fail with a privilege error unless this process has debug privileges: http://support.microsoft.com/kb/131065/en-us + wchar_t filePathW[OVR_MAX_PATH]; + const wchar_t* pFilePathW = pe32.szExeFile; + HANDLE hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pe32.th32ProcessID); // With Windows Vista+ we can use PROCESS_QUERY_LIMITED_INFORMATION. + if(hProcess) + { + if(GetProcessImageFileNameW(hProcess, filePathW, (DWORD)OVR_ARRAY_COUNT(filePathW))) + pFilePathW = filePathW; + } + + WriteReportLineF("0x%08x %ls\n", pe32.th32ProcessID, pFilePathW); + } while(Process32NextW(hProcessSnapshot, &pe32)); + } + + CloseHandle(hProcessSnapshot); + } + else + { + WriteReportLine("Unable to read process list\n"); + } + } + } + + #elif defined(OVR_OS_APPLE) + + WriteReportLine("\nApp Info\n"); + + // App path + const pid_t processId = getpid(); + WriteReportLineF("Process id: ", "%lld (0x%llx)\n", (int64_t)processId, (int64_t)processId); + + char appPath[PATH_MAX]; + GetCurrentProcessFilePath(appPath, OVR_ARRAY_COUNT(appPath)); + WriteReportLineF("Process path: %s\n", appPath); + + #if (OVR_PTR_SIZE == 4) + WriteReportLine("App format: 32 bit\n"); + #else + WriteReportLine("App format: 64 bit\n"); + #endif + + // App version + // To do. + + // System Info + WriteReportLine("\nSystem Info\n"); + + char osVersionName[256]; + GetOSVersionName(osVersionName, OVR_ARRAY_COUNT(osVersionName)); + WriteReportLineF("OS name: %s, %s\n", osVersionName, Is64BitOS() ? "64 bit" : "32 bit"); + + int name[2]; + int intValue; + size_t length; + char tempBuffer[256]; + + name[0] = CTL_KERN; + name[1] = KERN_OSTYPE; + length = sizeof(tempBuffer); + tempBuffer[0] = 0; + if(sysctl(name, 2, tempBuffer, &length, nullptr, 0) == 0) + { + WriteReportLineF("KERN_OSTYPE: %s\n", tempBuffer); + } + + name[0] = CTL_KERN; + name[1] = KERN_OSREV; + length = sizeof(intValue); + intValue = 0; + if(sysctl(name, 2, &intValue, &length, nullptr, 0) == 0) + { + WriteReportLineF("KERN_OSREV: %d\n", intValue); + } + + name[0] = CTL_KERN; + name[1] = KERN_OSRELEASE; + length = sizeof(tempBuffer); + tempBuffer[0] = 0; + if(sysctl(name, 2, tempBuffer, &length, nullptr, 0) == 0) + WriteReportLineF("KERN_OSRELEASE: %s\n", tempBuffer); + + name[0] = CTL_HW; + name[1] = HW_MACHINE; + length = sizeof(tempBuffer); + tempBuffer[0] = 0; + if(sysctl(name, 2, tempBuffer, &length, nullptr, 0) == 0) + WriteReportLineF("HW_MACHINE: %s\n", tempBuffer); + + name[0] = CTL_HW; + name[1] = HW_MODEL; + length = sizeof(tempBuffer); + tempBuffer[0] = 0; + if(sysctl(name, 2, tempBuffer, &length, nullptr, 0) == 0) + WriteReportLineF("sHW_MODEL: %s\n", tempBuffer); + + name[0] = CTL_HW; + name[1] = HW_NCPU; + length = sizeof(intValue); + intValue = 0; + if(sysctl(name, 2, &intValue, &length, nullptr, 0) == 0) + WriteReportLineF("HW_NCPU: %d\n", intValue); + + length = sizeof(tempBuffer); + tempBuffer[0] = 0; + if(sysctlbyname("machdep.cpu.brand_string", &tempBuffer, &length, nullptr, 0) == 0) + WriteReportLineF("machdep.cpu.brand_string: %s\n", tempBuffer); + + length = sizeof(tempBuffer); + tempBuffer[0] = 0; + if(sysctlbyname("hw.acpi.thermal.tz0.temperature", &tempBuffer, &length, nullptr, 0) == 0) + WriteReportLineF("hw.acpi.thermal.tz0.temperature: %s\n", tempBuffer); + + host_basic_info_data_t hostinfo; + mach_msg_type_number_t count = HOST_BASIC_INFO_COUNT; + kern_return_t kr = host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)&hostinfo, &count); + + if(kr == KERN_SUCCESS) + { + const uint64_t memoryMib = (uint64_t)hostinfo.max_mem / (1024 * 1024); + WriteReportLineF("System memory: %lld Mib (%.1f Gib)\n", memoryMib, (double)memoryMib / 1024); + } + + // Video card info + // To do. + + // Thread list + mach_port_t taskSelf = mach_task_self(); + thread_act_port_array_t threadArray; + mach_msg_type_number_t threadCount; + + kern_return_t result = task_threads(taskSelf, &threadArray, &threadCount); + + if(result == KERN_SUCCESS) + { + WriteReportLine("\nThread list\n"); + + for(mach_msg_type_number_t i = 0; i < threadCount; i++) + { + union TBIUnion{ + natural_t words[THREAD_INFO_MAX]; + thread_basic_info tbi; + }; + + TBIUnion tbiUnion; + mach_port_t thread = threadArray[i]; + pthread_t pthread = pthread_from_mach_thread_np(thread); // We assume the thread was created through pthreads. + + char threadState[32] = "unknown"; + mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX; + result = thread_info(thread, THREAD_BASIC_INFO, (thread_info_t)&tbiUnion, &threadInfoCount); + + if(result == KERN_SUCCESS) + { + const char* state; + + switch (tbiUnion.tbi.run_state) + { + case TH_STATE_HALTED: state = "halted"; break; + case TH_STATE_RUNNING: state = "running"; break; + case TH_STATE_STOPPED: state = "stopped"; break; + case TH_STATE_UNINTERRUPTIBLE: state = "uninterruptible"; break; + case TH_STATE_WAITING: state = "waiting"; break; + default: state = "<unknown>"; break; + } + + OVR_snprintf(threadState, OVR_ARRAY_COUNT(threadState), "%s", state); + if(tbiUnion.tbi.flags & TH_FLAGS_IDLE) + OVR_strlcat(threadState, ", idle", sizeof(threadState)); + if(tbiUnion.tbi.flags & TH_FLAGS_SWAPPED) + OVR_strlcat(threadState, ", swapped", sizeof(threadState)); + } + + thread_identifier_info threadIdentifierInfo; + memset(&threadIdentifierInfo, 0, sizeof(threadIdentifierInfo)); + + mach_msg_type_number_t threadIdentifierInfoCount = THREAD_IDENTIFIER_INFO_COUNT; + thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&threadIdentifierInfo, &threadIdentifierInfoCount); + + proc_threadinfo procThreadInfo; + memset(&procThreadInfo, 0, sizeof(procThreadInfo)); + result = proc_pidinfo(processId, PROC_PIDTHREADINFO, threadIdentifierInfo.thread_handle, &procThreadInfo, sizeof(procThreadInfo)); + OVR_UNUSED(result); + + char buffer[256]; // Can't use scratchBuffer, because it's used by WriteThreadCallstack. + OVR_snprintf(buffer, OVR_ARRAY_COUNT(buffer), "state: %s, suspend count: %d, kernel priority: %d", threadState, (int)tbiUnion.tbi.suspend_count, (int)procThreadInfo.pth_curpri); + + bool threadIsExceptionThread = (thread == exceptionInfo.threadSysId); + if(threadIsExceptionThread) + OVR_strlcat(buffer, ", exception thread", OVR_ARRAY_COUNT(buffer)); + + WriteThreadCallstack(pthread, thread, buffer); + } + + vm_deallocate(taskSelf, (vm_address_t)threadArray, threadCount * sizeof(thread_act_t)); + } + + + WriteReportLine("\nModule list\n"); + + const size_t mifCapacity = 256; + const size_t mifAllocSize = mifCapacity * sizeof(ModuleInfo); + ModuleInfo* moduleInfoArray = (ModuleInfo*)SafeMMapAlloc(mifAllocSize); + + if(moduleInfoArray) + { + #if (OVR_PTR_SIZE == 4) + WriteReportLine("Base Size Name Path\n"); + #else + WriteReportLine("Base Size Name Path\n"); + #endif + + size_t moduleCount = symbolLookup.GetModuleInfoArray(moduleInfoArray, mifCapacity); + if(moduleCount > mifCapacity) + moduleCount = mifCapacity; + + for(size_t i = 0; i < moduleCount; i++) + { + const ModuleInfo& mi = moduleInfoArray[i]; + + #if (OVR_PTR_SIZE == 4) + WriteReportLineF("0x%08x, 0x%08x %-24s %s\n", (uint32_t)mi.baseAddress, (uint32_t)mi.size, mi.name, mi.filePath); + #else + WriteReportLineF("0x%016llx 0x%016llx %-24s %s\n", (uint64_t)mi.baseAddress, (uint64_t)mi.size, mi.name, mi.filePath); + #endif + } + + SafeMMapFree(moduleInfoArray, mifAllocSize); + } + + + WriteReportLine("\nProcess list\n"); + + if(reportPrivacyEnabled) + WriteReportLine("Disabled by report privacy settings\n"); + else + { + WriteReportLine("Process Id File\n"); + + pid_t pidArray[1024]; + int processCount = proc_listpids(PROC_ALL_PIDS, 0, pidArray, sizeof(pidArray)); // Important that we use sizeof not OVR_ARRAY_COUNT. + char processFilePath[PATH_MAX]; + + for(int i = 0; i < processCount; i++) + { + if(proc_pidpath(pidArray[i], processFilePath, sizeof(processFilePath)) > 0) + WriteReportLineF("%-10d %s\n", pidArray[i], processFilePath); + } + + if(!processCount) + WriteReportLine("Unable to read process list\n"); + } + + #elif defined(OVR_OS_UNIX) + Is64BitOS(); + GetCurrentProcessFilePath(nullptr, 0); + GetFileNameFromPath(nullptr); + GetOSVersionName(nullptr, 0); + + #endif // OVR_OS_MS + + SymbolLookup::Shutdown(); + + fclose(file); + file = nullptr; +} + + +void ExceptionHandler::WriteMiniDump() +{ + if(strstr(miniDumpFilePath, "%s")) // If the user-specified file path includes a date/time component... + { + char dateTimeBuffer[64]; + FormatDateTime(dateTimeBuffer, OVR_ARRAY_COUNT(dateTimeBuffer), exceptionInfo.timeVal, true, true, false, true); + OVR_snprintf(minidumpFilePathActual, OVR_ARRAY_COUNT(minidumpFilePathActual), miniDumpFilePath, dateTimeBuffer); + } + else + { + OVR_strlcpy(minidumpFilePathActual, miniDumpFilePath, OVR_ARRAY_COUNT(minidumpFilePathActual)); + } + + #if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64) + typedef BOOL (WINAPI * MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE dumpType, CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam); + HMODULE hModuleDbgHelp = LoadLibraryW(L"DbgHelp.dll"); + + MINIDUMPWRITEDUMP pMiniDumpWriteDump = hModuleDbgHelp ? (MINIDUMPWRITEDUMP)(void*)GetProcAddress(hModuleDbgHelp, "MiniDumpWriteDump") : nullptr; + + if(pMiniDumpWriteDump) + { + wchar_t miniDumpFilePathW[OVR_MAX_PATH]; + OVR::UTF8Util::DecodeString(miniDumpFilePathW, minidumpFilePathActual, -1); // Problem: DecodeString provides no way to specify the destination capacity. + + HANDLE hFile = CreateFileW(miniDumpFilePathW, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH, 0); + + if(hFile != INVALID_HANDLE_VALUE) + { + MINIDUMP_EXCEPTION_INFORMATION minidumpExceptionInfo = { ::GetCurrentThreadId(), pExceptionPointers, TRUE }; + + BOOL result = pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, + (MINIDUMP_TYPE)miniDumpFlags, &minidumpExceptionInfo, + (CONST PMINIDUMP_USER_STREAM_INFORMATION)nullptr, (CONST PMINIDUMP_CALLBACK_INFORMATION)nullptr); + + OVR_ASSERT_AND_UNUSED(result, result); + CloseHandle(hFile); + hFile = 0; + } + else + { + OVR_ASSERT(pMiniDumpWriteDump); // OVR_FAIL_F(("ExceptionHandler::WriteMiniDump: Failed to create minidump file at %s", minidumpFilePathActual)); + } + } + + FreeLibrary(hModuleDbgHelp); + #else + // Some platforms support various forms or exception reports and core dumps which are automatically generated upon us + // returning from our own exception handling. We might want to put something here if we are using a custom version of + // this, such as Google Breakpad. + #endif +} + + +void ExceptionHandler::SetExceptionListener(ExceptionListener* pExceptionListener, uintptr_t userValue) +{ + exceptionListener = pExceptionListener; + exceptionListenerUserValue = userValue; +} + + +void ExceptionHandler::SetAppDescription(const char* pAppDescription) +{ + appDescription = pAppDescription; +} + + +void ExceptionHandler::SetExceptionPaths(const char* exceptionReportPath, const char* exceptionMiniDumpFilePath) +{ + char tempPath[OVR_MAX_PATH]; + + if(exceptionReportPath) + { + if(OVR_stricmp(exceptionReportPath, "default") == 0) + { + GetCrashDumpDirectory(tempPath, OVR_ARRAY_COUNT(tempPath)); + OVR::OVR_strlcat(tempPath, "Exception Report (%s).txt", OVR_ARRAY_COUNT(tempPath)); + exceptionReportPath = tempPath; + } + + OVR_strlcpy(reportFilePath, exceptionReportPath, OVR_ARRAY_COUNT(reportFilePath)); + } + else + { + reportFilePath[0] = '\0'; + } + + if(exceptionMiniDumpFilePath) + { + if(OVR_stricmp(exceptionMiniDumpFilePath, "default") == 0) + { + GetCrashDumpDirectory(tempPath, OVR_ARRAY_COUNT(tempPath)); + OVR::OVR_strlcat(tempPath, "Exception Minidump (%s).mdmp", OVR_ARRAY_COUNT(tempPath)); + exceptionMiniDumpFilePath = tempPath; + } + + OVR_strlcpy(miniDumpFilePath, exceptionMiniDumpFilePath, OVR_ARRAY_COUNT(miniDumpFilePath)); + } + else + { + miniDumpFilePath[0] = '\0'; + } +} + + +void ExceptionHandler::SetCodeBaseDirectoryPaths(const char* codeBaseDirectoryPathArray[], size_t codeBaseDirectoryPathCount) +{ + for(size_t i = 0, iCount = OVR::Alg::Min<size_t>(codeBaseDirectoryPathCount, OVR_ARRAY_COUNT(codeBasePathArray)); i != iCount; ++i) + { + codeBasePathArray[i] = codeBaseDirectoryPathArray[i]; + } +} + +const char* ExceptionHandler::GetExceptionUIText(const char* exceptionReportPath) +{ + char* uiText = nullptr; + OVR::SysFile file(exceptionReportPath, SysFile::Open_Read, SysFile::Mode_ReadWrite); + + if(file.IsValid()) + { + size_t length = (size_t)file.GetLength(); + uiText = (char*)OVR::SafeMMapAlloc(length + 1); + + if(uiText) + { + file.Read((uint8_t*)uiText, (int)length); + uiText[length] = '\0'; + file.Close(); + + // Currently on Mac our message box implementation is unable to display arbitrarily large amounts of text. + // So we reduce its size to a more summary version before presenting. + #if defined(OVR_OS_MAC) + struct Find { static char* PreviousChar(char* p, char c){ while(*p != c) p--; return p; } }; // Assumes the given c is present prior to p. + + // Print that the full report is at <file path> + // Exception Info section + // Exception thread callstack. + char empty[] = ""; + char* pExceptionInfoBegin = strstr(uiText, "Exception Info") ? strstr(uiText, "Exception Info") : empty; + char* pExceptionInfoEnd = (pExceptionInfoBegin == empty) ? (empty + 1) : strstr(uiText, "\n\n"); + char* pExceptionThreadArea = strstr(uiText, ", exception thread"); + char* pExceptionThreadBegin = pExceptionThreadArea ? Find::PreviousChar(pExceptionThreadArea, '\n') + 1 : empty; + char* pExceptionThreadEnd = (pExceptionThreadBegin == empty) ? (empty + 1) : strstr(pExceptionThreadArea, "\n\n"); + + if(!pExceptionInfoEnd) + pExceptionInfoEnd = pExceptionInfoBegin; + *pExceptionInfoEnd = '\0'; + + if(!pExceptionThreadEnd) + pExceptionThreadEnd = pExceptionThreadBegin; + *pExceptionThreadEnd = '\0'; + + size_t uiTextBriefLength = OVR_snprintf(nullptr, 0, "Full report:%s\n\nSummary report:\n%s\n\n%s", exceptionReportPath, pExceptionInfoBegin, pExceptionThreadBegin); + char* uiTextBrief = (char*)OVR::SafeMMapAlloc(uiTextBriefLength + 1); + + if(uiTextBrief) + { + OVR_snprintf(uiTextBrief, uiTextBriefLength + 1, "Full report:%s\n\nSummary report:\n%s\n\n%s", exceptionReportPath, pExceptionInfoBegin, pExceptionThreadBegin); + OVR::SafeMMapFree(uiText, length); + uiText = uiTextBrief; + } + #endif + } + } + + return uiText; +} + +void ExceptionHandler::FreeExceptionUIText(const char* messageBoxText) +{ + OVR::SafeMMapFree(messageBoxText, OVR_strlen(messageBoxText)); +} + +void ExceptionHandler::ReportDeadlock(const char* threadName, + const char* organizationName, + const char* applicationName) +{ + ExceptionHandler handler; + + if (!organizationName || !organizationName[0] || + !applicationName || !applicationName[0]) + { + char tempPath[OVR_MAX_PATH]; + GetCrashDumpDirectory(tempPath, OVR_ARRAY_COUNT(tempPath)); + OVR_strlcat(tempPath, "Deadlock Report (%s).txt", OVR_ARRAY_COUNT(tempPath)); + handler.SetExceptionPaths(tempPath); + } + else + { + handler.SetPathsFromNames(organizationName, applicationName, "Deadlock Report (%s).txt"); + } + + OVR_snprintf(handler.exceptionInfo.exceptionDescription, + sizeof(handler.exceptionInfo.exceptionDescription), + "Deadlock in thread '%s'", threadName ? threadName : "(null)"); + + handler.exceptionInfo.timeVal = time(nullptr); + handler.exceptionInfo.time = *gmtime(&handler.exceptionInfo.timeVal); + handler.WriteReport(); +} + + +//----------------------------------------------------------------------------- +// GUI Exception Listener + +GUIExceptionListener::GUIExceptionListener() : + Handler() +{ +} + +int GUIExceptionListener::HandleException(uintptr_t userValue, + ExceptionHandler* pExceptionHandler, + ExceptionInfo* pExceptionInfo, + const char* reportFilePath) +{ + OVR_UNUSED3(userValue, pExceptionHandler, pExceptionInfo); + + // If debugger is not present, + if (!OVRIsDebuggerPresent()) + { + const char* uiText = ExceptionHandler::GetExceptionUIText(reportFilePath); + if (uiText) + { + OVR::Util::DisplayMessageBox("Exception occurred", uiText); + ExceptionHandler::FreeExceptionUIText(uiText); + } + } + return 0; +} + + +} // namespace OVR + + +OVR_RESTORE_MSVC_WARNING() diff --git a/LibOVRKernel/Src/Kernel/OVR_DebugHelp.h b/LibOVRKernel/Src/Kernel/OVR_DebugHelp.h new file mode 100644 index 0000000..be104d7 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_DebugHelp.h @@ -0,0 +1,510 @@ +/************************************************************************************ + +Filename : OVR_DebugHelp.h +Content : Platform-independent exception handling interface +Created : October 6, 2014 + +Copyright : Copyright 2014 Oculus VR, LLC. All Rights reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +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_ExceptionHandler_h +#define OVR_ExceptionHandler_h + +#include "OVR_Types.h" +#include "OVR_String.h" +#include "OVR_Threads.h" +#include "OVR_Atomic.h" +#include "OVR_Nullptr.h" +#include "OVR_System.h" + +#include <stdio.h> +#include <time.h> + +#if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64) + #include "OVR_Win32_IncludeWindows.h" +#elif defined(OVR_OS_APPLE) + #include <pthread.h> + #include <mach/thread_status.h> + #include <mach/mach_types.h> + + extern "C" void* MachHandlerThreadFunctionStatic(void*); + extern "C" int catch_mach_exception_raise_state_identity_OVR(mach_port_t, mach_port_t, mach_port_t, exception_type_t, mach_exception_data_type_t*, + mach_msg_type_number_t, int*, thread_state_t, mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*); +#elif defined(OVR_OS_LINUX) + #include <pthread.h> +#endif + + +OVR_DISABLE_MSVC_WARNING(4351) // new behavior: elements of array will be default initialized + +namespace OVR { + + // Thread identifiers + //typedef void* ThreadHandle; // Already defined by OVR Threads. Same as Windows thread handle, Unix pthread_t. + //typedef void* ThreadId; // Already defined by OVR Threads. Used by Windows as DWORD thread id, by Unix as pthread_t. + typedef uintptr_t ThreadSysId; // System thread identifier. Used by Windows the same as ThreadId (DWORD), thread_act_t on Mac/BSD, lwp id on Linux. + + // Thread constants + // To do: Move to OVR Threads + #define OVR_THREADHANDLE_INVALID ((ThreadHandle*)nullptr) + #define OVR_THREADID_INVALID ((ThreadId*)nullptr) + #define OVR_THREADSYSID_INVALID ((uintptr_t)0) + + OVR::ThreadSysId ConvertThreadHandleToThreadSysId(OVR::ThreadHandle threadHandle); + OVR::ThreadHandle ConvertThreadSysIdToThreadHandle(OVR::ThreadSysId threadSysId); // The returned handle must be freed with FreeThreadHandle. + void FreeThreadHandle(OVR::ThreadHandle threadHandle); // Frees the handle returned by ConvertThreadSysIdToThreadHandle. + OVR::ThreadSysId GetCurrentThreadSysId(); + + // CPUContext + #if defined(OVR_OS_MS) + typedef CONTEXT CPUContext; + #elif defined(OVR_OS_MAC) + struct CPUContext + { + x86_thread_state_t threadState; // This works for both x86 and x64. + x86_float_state_t floatState; + x86_debug_state_t debugState; + x86_avx_state_t avxState; + x86_exception_state exceptionState; + + CPUContext() { memset(this, 0, sizeof(CPUContext)); } + }; + #elif defined(OVR_OS_LINUX) + typedef int CPUContext; // To do. + #endif + + + // Tells if the current process appears to be running under a debugger. Does not attempt to + // detect the case of stealth debuggers (malware-related for example). + bool OVRIsDebuggerPresent(); + + // Exits the process with the given exit code. + #if !defined(OVR_NORETURN) + #if defined(OVR_CC_MSVC) + #define OVR_NORETURN __declspec(noreturn) + #else + #define OVR_NORETURN __attribute__((noreturn)) + #endif + #endif + OVR_NORETURN void ExitProcess(intptr_t processReturnValue); + + // Returns the instruction pointer of the caller for the position right after the call. + OVR_NO_INLINE void GetInstructionPointer(void*& pInstruction); + + // Returns the stack base and limit addresses for the given thread, or for the current thread if the threadHandle is default. + // The stack limit is a value less than the stack base on most platforms, as stacks usually grow downward. + // Some platforms (e.g. Microsoft) have dynamically resizing stacks, in which case the stack limit reflects the current limit. + void GetThreadStackBounds(void*& pStackBase, void*& pStackLimit, ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID); + + + // OVR_MAX_PATH + // Max file path length (for most uses). + // To do: move this to OVR_File. + #if !defined(OVR_MAX_PATH) + #if defined(OVR_OS_MS) // http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx + #define OVR_MAX_PATH 260 // Windows can use paths longer than this in some cases (network paths, UNC paths). + #else + #define OVR_MAX_PATH 1024 // This isn't a strict limit on all Unix-based platforms. + #endif + #endif + + + // ModuleHandle + #if defined(OVR_OS_MS) + typedef void* ModuleHandle; // from LoadLibrary() + #elif defined(OVR_OS_APPLE) || defined(OVR_OS_UNIX) + typedef void* ModuleHandle; // from dlopen() + #endif + + #define OVR_MODULEHANDLE_INVALID ((ModuleHandle*)nullptr) + + // Module info constants + static const ModuleHandle kMIHandleInvalid = OVR_MODULEHANDLE_INVALID; + static const uint64_t kMIAddressInvalid = 0xffffffffffffffffull; + static const uint64_t kMISizeInvalid = 0xffffffffffffffffull; + static const int32_t kMILineNumberInvalid = -1; + static const int32_t kMIFunctionOffsetInvalid = -1; + static const uint64_t kMIBaseAddressInvalid = 0xffffffffffffffffull; + static const uint64_t kMIBaseAddressUnspecified = 0xffffffffffffffffull; + + struct ModuleInfo + { + ModuleHandle handle; + uint64_t baseAddress; // The actual runtime base address of the module. May be different from the base address specified in the debug symbol file. + uint64_t size; + char filePath[OVR_MAX_PATH]; + char name[32]; + char type[8]; // Unix-specific. e.g. __TEXT + char permissions[8]; // Unix specific. e.g. "drwxr-xr-x" + + ModuleInfo() : handle(kMIHandleInvalid), baseAddress(kMIBaseAddressInvalid), size(0), filePath(), name(){} + }; + + + // Refers to symbol info for an instruction address. + // Info includes function name, source code file/line, and source code itself. + struct SymbolInfo + { + uint64_t address; + uint64_t size; + const ModuleInfo* pModuleInfo; + char filePath[OVR_MAX_PATH]; + int32_t fileLineNumber; + char function[128]; // This is a fixed size because we need to use it during application exceptions. + int32_t functionOffset; + char sourceCode[1024]; // This is a string representing the code itself and not a file path to the code. + + SymbolInfo() : address(kMIAddressInvalid), size(kMISizeInvalid), pModuleInfo(nullptr), filePath(), + fileLineNumber(kMILineNumberInvalid), function(), functionOffset(kMIFunctionOffsetInvalid), sourceCode() {} + }; + + + // Implements support for reading thread lists, module lists, backtraces, and backtrace symbols. + class SymbolLookup + { + public: + SymbolLookup(); + ~SymbolLookup(); + + static bool Initialize(); + static bool IsInitialized(); + static void Shutdown(); + + void AddSourceCodeDirectory(const char* pDirectory); + + // Should be disabled when within an exception handler. + void EnableMemoryAllocation(bool enabled); + + // Refresh our view of the symbols and modules present within the current process. + bool Refresh(); + + // Retrieves the backtrace (call stack) of the given thread. There may be some per-platform restrictions on this. + // Returns the number written, which will be <= addressArrayCapacity. + // This may not work on some platforms unless stack frames are enabled. + // For Microsoft platforms the platformThreadContext is CONTEXT*. + // For Apple platforms the platformThreadContext is x86_thread_state_t* or arm_thread_state_t*. + // If threadSysIdHelp is non-zero, it may be used by the implementation to help produce a better backtrace. + size_t GetBacktrace(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, void* platformThreadContext = nullptr, OVR::ThreadSysId threadSysIdHelp = OVR_THREADSYSID_INVALID); + + // Retrieves the backtrace for the given ThreadHandle. + // Returns the number written, which will be <= addressArrayCapacity. + size_t GetBacktraceFromThreadHandle(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadHandle threadHandle = OVR_THREADHANDLE_INVALID); + + // Retrieves the backtrace for the given ThreadSysId. + // Returns the number written, which will be <= addressArrayCapacity. + size_t GetBacktraceFromThreadSysId(void* addressArray[], size_t addressArrayCapacity, size_t skipCount = 0, OVR::ThreadSysId threadSysId = OVR_THREADSYSID_INVALID); + + // Gets a list of the modules (e.g. DLLs) present in the current process. + // Writes as many ModuleInfos as possible to pModuleInfoArray. + // Returns the required count of ModuleInfos, which will be > moduleInfoArrayCapacity if the capacity needs to be larger. + size_t GetModuleInfoArray(ModuleInfo* pModuleInfoArray, size_t moduleInfoArrayCapacity); + + // Retrieves a list of the current threads. Unless the process is paused the list is volatile. + // Returns the required capacity, which may be larger than threadArrayCapacity. + // Either array can be NULL to specify that it's not written to. + // For Windows the caller needs to CloseHandle the returned ThreadHandles. This can be done by calling DoneThreadList. + size_t GetThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCapacity); + + // Frees any references to thread handles or ids returned by GetThreadList; + void DoneThreadList(ThreadHandle* threadHandleArray, ThreadSysId* threadSysIdArray, size_t threadArrayCount); + + // Writes a given thread's callstack with symbols to the given output. + // It may not be safe to call this from an exception handler, as sOutput allocates memory. + bool ReportThreadCallstack(OVR::String& sOutput, size_t skipCount = 0, ThreadSysId threadSysId = OVR_THREADSYSID_INVALID); + + // Writes all thread's callstacks with symbols to the given output. + // It may not be safe to call this from an exception handler, as sOutput allocates memory. + bool ReportThreadCallstacks(OVR::String& sOutput, size_t skipCount = 0); + + // Writes all loaded modules to the given output string. + // It may not be safe to call this from an exception handler, as sOutput allocates memory. + bool ReportModuleInformation(OVR::String& sOutput); + + // Retrieves symbol info for the given address. + bool LookupSymbol(uint64_t address, SymbolInfo& symbolInfo); + bool LookupSymbols(uint64_t* addressArray, SymbolInfo* pSymbolInfoArray, size_t arraySize); + + const ModuleInfo* GetModuleInfoForAddress(uint64_t address); // The returned ModuleInfo points to an internal structure. + + protected: + bool RefreshModuleList(); + + protected: + bool AllowMemoryAllocation; // True by default. If true then we allow allocating memory (and as a result provide less information). This is useful for when in an exception handler. + bool ModuleListUpdated; + ModuleInfo ModuleInfoArray[256]; // Cached list of modules we use. This is a fixed size because we need to use it during application exceptions. + size_t ModuleInfoArraySize; + }; + + + + // ExceptionInfo + // We need to be careful to avoid data types that can allocate memory while we are + // handling an exception, as the memory system may be corrupted at that point in time. + struct ExceptionInfo + { + tm time; // GM time. + time_t timeVal; // GM time_t (seconds since 1970). + void* backtrace[64]; + size_t backtraceCount; + ThreadHandle threadHandle; // + ThreadSysId threadSysId; // + char threadName[32]; // Cannot be an allocating String object. + void* pExceptionInstructionAddress; + void* pExceptionMemoryAddress; + CPUContext cpuContext; + char exceptionDescription[1024]; // Cannot be an allocating String object. + SymbolInfo symbolInfo; // SymbolInfo for the exception location. + + #if defined(OVR_OS_MS) + EXCEPTION_RECORD exceptionRecord; // This is a Windows SDK struct. + #elif defined(OVR_OS_APPLE) + uint64_t exceptionType; // e.g. EXC_BAD_INSTRUCTION, EXC_BAD_ACCESS, etc. + uint32_t cpuExceptionId; // The x86/x64 CPU trap id. + uint32_t cpuExceptionIdError; // The x86/x64 CPU trap id extra info. + int64_t machExceptionData[4]; // Kernel exception code info. + int machExceptionDataCount; // Count of valid entries. + #endif + + ExceptionInfo(); + }; + + // Implments support for asynchronous exception handling and basic exception report generation. + // If you are implementing exception handling for a commercial application and want auto-uploading + // functionality you may want to consider using something like Google Breakpad. This exception handler + // is for in-application debug/diagnostic services, though it can write a report that has similar + // information to Breakpad or OS-provided reports such as Apple .crash files. + // + // Example usage: + // ExceptionHandler exceptionHandler; + // + // int main(int, char**) + // { + // exceptionHandler.Enable(true); + // exceptionHandler.SetExceptionListener(pSomeListener, 0); // Optional listener hook. + // } + // + class ExceptionHandler + { + public: + ExceptionHandler(); + ~ExceptionHandler(); + + // Enables or disables handling by installing or uninstalling an exception handler. + // If you merely want to temporarily pause handling then it may be better to cause PauseHandling, + // as that's a lighter weight solution. + bool Enable(bool enable); + + // Pauses handling. Exceptions will be caught but immediately passed on to the next handler + // without taking any action. Pauses are additive and calls to Pause(true) must be eventually + // matched to Pause(false). This function can be called from multiple threads simultaneously. + // Returns the new pause count. + int PauseHandling(bool pause); + + // Some report info can be considered private information of the user, such as the current process list, + // computer name, IP address or other identifying info, etc. We should not report this information for + // external users unless they agree to this. + void EnableReportPrivacy(bool enable); + + struct ExceptionListener + { + virtual ~ExceptionListener(){} + virtual int HandleException(uintptr_t userValue, ExceptionHandler* pExceptionHandler, ExceptionInfo* pExceptionInfo, const char* reportFilePath) = 0; + }; + + void SetExceptionListener(ExceptionListener* pExceptionListener, uintptr_t userValue); + + // What we do after handling the exception. + enum ExceptionResponse + { + kERContinue, // Continue execution. Will result in the exception being re-generated unless the application has fixed the cause. Similar to Windows EXCEPTION_CONTINUE_EXECUTION. + kERHandle, // Causes the OS to handle the exception as it normally would. Similar to Windows EXCEPTION_EXECUTE_HANDLER. + kERTerminate, // Exit the application. + kERThrow, // Re-throw the exception. Other handlers may catch it. Similar to Windows EXCEPTION_CONTINUE_SEARCH. + kERDefault // Usually set to kERTerminate. + }; + + void SetExceptionResponse(ExceptionResponse er) + { exceptionResponse = er; } + + // Allws you to add an arbitrary description of the current application, which will be added to exception reports. + void SetAppDescription(const char* appDescription); + + // If the report path has a "%s" in its name, then assume the path is a sprintf format and write it + // with the %s specified as a date/time string. + // The report path can be "default" to signify that you want to use the default user location. + // Passing NULL for exceptionReportPath or exceptionMinidumpPath causes those files to not be written. + // By default both the exceptionReportPath and exceptionMinidumpPath are NULL. + // Example usage: + // handler.SetExceptionPaths("/Users/Current/Exceptions/Exception %s.txt"); + void SetExceptionPaths(const char* exceptionReportPath, const char* exceptionMinidumpPath = nullptr); + + // Calls SetExceptionPaths in the appropriate convention for each operating system + // Windows: %AppData%\Organization\Application + // Mac: ~/Library/Logs/DiagnosticReports/Organization/Application" + // Linux: ~/Library/Organization/Application + // exceptionFormat and minidumpFormat define the file names in the format above + // with the %s specified as a date/time string. + void SetPathsFromNames(const char* organizationName, const char* ApplicationName, const char* exceptionFormat = "Exception Report (%s).txt", const char* minidumpFormat = "Exception Minidump (%s).mdmp"); + + // Allows you to specify base directories for code paths, which can be used to associate exception addresses to lines + // of code as opposed to just file names and line numbers, or function names plus binary offsets. + void SetCodeBaseDirectoryPaths(const char* codeBaseDirectoryPathArray[], size_t codeBaseDirectoryPathCount); + + // Writes lines into the current report. + void WriteReportLine(const char* pLine); + void WriteReportLineF(const char* format, ...); + + // Retrieves a directory path which ends with a path separator. + // Returns the required strlen of the path. + // Guarantees the presence of the directory upon returning true. + static size_t GetCrashDumpDirectory(char* directoryPath, size_t directoryPathCapacity); + + // Given an exception report at a given file path, returns a string suitable for displaying in a message + // box or similar user interface during the handling of an exception. The returned string must be passed + // to FreeMessageBoxText when complete. + static const char* GetExceptionUIText(const char* exceptionReportPath); + static void FreeExceptionUIText(const char* messageBoxText); + + // Writes a deadlock report similar to an exception report. Since there is no allocation risk, an exception handler is created for this log. + static void ReportDeadlock(const char* threadName, const char* organizationName = nullptr, const char* applicationName = nullptr); + + protected: + void WriteExceptionDescription(); + void WriteReport(); + void WriteThreadCallstack(ThreadHandle threadHandle, ThreadSysId threadSysId, const char* additionalInfo); + void WriteMiniDump(); + // Runtime constants + bool enabled; + OVR::AtomicInt<int> pauseCount; // 0 means unpaused. 1+ means paused. + bool reportPrivacyEnabled; // Defaults to true. + ExceptionResponse exceptionResponse; // Defaults to kERHandle + ExceptionListener* exceptionListener; + uintptr_t exceptionListenerUserValue; + String appDescription; + String codeBasePathArray[6]; // 6 is arbitrary. + char reportFilePath[OVR_MAX_PATH];// May be an encoded path, in that it has "%s" in it or is named "default". See reporFiletPathActual for the runtime actual report path. + int miniDumpFlags; + char miniDumpFilePath[OVR_MAX_PATH]; + FILE* file; // Can/should we use OVR Files for this? + char scratchBuffer[4096]; + + // Runtime variables + bool exceptionOccurred; + OVR::AtomicInt<uint32_t> handlingBusy; + char reportFilePathActual[OVR_MAX_PATH]; + char minidumpFilePathActual[OVR_MAX_PATH]; + int terminateReturnValue; + ExceptionInfo exceptionInfo; + SymbolLookup symbolLookup; + + #if defined(OVR_OS_MS) + void* vectoredHandle; + LPTOP_LEVEL_EXCEPTION_FILTER previousFilter; + LPEXCEPTION_POINTERS pExceptionPointers; + + friend LONG WINAPI Win32ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers); + LONG ExceptionFilter(LPEXCEPTION_POINTERS pExceptionPointers); + + //handles exception in a new thread, used for stack overflow + static unsigned WINAPI ExceptionHandlerThreadExec(void * callingHandler); + #elif defined(OVR_OS_APPLE) + struct SavedExceptionPorts + { + SavedExceptionPorts() : count(0) { memset(this, 0, sizeof(SavedExceptionPorts)); } + + mach_msg_type_number_t count; + exception_mask_t masks[6]; + exception_handler_t ports[6]; + exception_behavior_t behaviors[6]; + thread_state_flavor_t flavors[6]; + }; + + friend void* ::MachHandlerThreadFunctionStatic(void*); + friend int ::catch_mach_exception_raise_state_identity_OVR(mach_port_t, mach_port_t, mach_port_t, exception_type_t, + mach_exception_data_type_t*, mach_msg_type_number_t, int*, thread_state_t, + mach_msg_type_number_t, thread_state_t, mach_msg_type_number_t*); + + bool InitMachExceptionHandler(); + void ShutdownMachExceptionHandler(); + void* MachHandlerThreadFunction(); + kern_return_t HandleMachException(mach_port_t port, mach_port_t thread, mach_port_t task, exception_type_t exceptionType, + mach_exception_data_type_t* pExceptionDetail, mach_msg_type_number_t exceptionDetailCount, + int* pFlavor, thread_state_t pOldState, mach_msg_type_number_t oldStateCount, thread_state_t pNewState, + mach_msg_type_number_t* pNewStateCount); + kern_return_t ForwardMachException(mach_port_t thread, mach_port_t task, exception_type_t exceptionType, + mach_exception_data_t pExceptionDetail, mach_msg_type_number_t exceptionDetailCount); + + bool machHandlerInitialized; + mach_port_t machExceptionPort; + SavedExceptionPorts machExceptionPortsSaved; + volatile bool machThreadShouldContinue; + volatile bool machThreadExecuting; + pthread_t machThread; + + #elif defined(OVR_OS_LINUX) + // To do. + #endif + }; + + + // Identifies basic exception types for the CreateException function. + enum CreateExceptionType + { + kCETAccessViolation, // Read or write to inaccessable memory. + kCETAlignment, // Misaligned read or write. + kCETDivideByZero, // Integer divide by zero. + kCETFPU, // Floating point / VPU exception. + kCETIllegalInstruction, // Illegal opcode. + kCETStackCorruption, // Stack frame was corrupted. + kCETStackOverflow, // Stack ran out of space, often due to infinite recursion. + kCETTrap // System/OS trap (system call). + }; + + + // Creates an exception of the given type, primarily for testing. + void CreateException(CreateExceptionType exceptionType); + + + //----------------------------------------------------------------------------- + // GUI Exception Listener + // + // When this exception handler is called, it will verify that the application + // is not being debugged at that instant. If not, then it will present a GUI + // to the user containing error information. + // Initially the exception listener is not silenced. + class GUIExceptionListener : public ExceptionHandler::ExceptionListener + { + public: + GUIExceptionListener(); + + virtual int HandleException(uintptr_t userValue, + ExceptionHandler* pExceptionHandler, + ExceptionInfo* pExceptionInfo, + const char* reportFilePath) OVR_OVERRIDE; + + protected: + ExceptionHandler Handler; + }; + + +} // namespace OVR + + +OVR_RESTORE_MSVC_WARNING() + + +#endif // Header include guard diff --git a/LibOVRKernel/Src/Kernel/OVR_Delegates.h b/LibOVRKernel/Src/Kernel/OVR_Delegates.h new file mode 100644 index 0000000..88948b4 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Delegates.h @@ -0,0 +1,541 @@ +/************************************************************************************ + +Filename : OVR_Delegates.h +Content : C++ Delegates +Created : June 15, 2014 +Authors : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +/* + Based on The Impossibly Fast C++ Delegates by Sergey Ryazanov from + http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx (2005) +*/ + +/* + Usage: + + Declare a delegate with a void (int) signature, also known as a + function that returns void and has one parameter that is an int: + typedef Delegate1<void, int> MyDelegate; + MyDelegate d; + + Point the delegate to a member function: + d.SetMember<A, &A::TestFunctionA>(&a); + d = MyDelegate::FromMember<A, &A::TestFunctionA>(&a); + + Point the delegate to a const member function: + d.SetConstMember<C, &C::TestFunctionA>(&c); + d = MyDelegate::FromConstMember<C, &C::TestFunctionA>(&c); + + Point the delegate to a free function: + d.SetFree<&FreeFunctionX>(); + d = MyDelegate::FromFree<&FreeFunctionX>(); + + Invoke the function via the delegate (works for all 3 cases): + d(1000); + + By default the delegates are uninitialized. + To clear an array of delegates quickly just zero the memory. + + This implementation is nicer than FastDelegates in my opinion + because it is simple and easy to read. It is a little slower + for virtual functions, but the size of the delegate is small, + and it will only get better as compilers improve. +*/ + +#ifndef OVR_Delegates_h +#define OVR_Delegates_h + +#include "OVR_Types.h" + +namespace OVR { + + +template <class ret_type> +class Delegate0 +{ + typedef ret_type (*StubPointer)(void *); + typedef Delegate0<ret_type> this_type; + + void *_object; + StubPointer _stub; + + OVR_FORCE_INLINE Delegate0(void *object, StubPointer stub) + { + _object = object; + _stub = stub; + } + + // Stubs + + template <ret_type (*F)()> + static OVR_FORCE_INLINE ret_type FreeStub(void * /*object*/) + { + return (F)(); + } + + template <class T, ret_type (T::*F)()> + static OVR_FORCE_INLINE ret_type MemberStub(void *object) + { + T *p = static_cast<T*>(object); + return (p->*F)(); + } + + template <class T, ret_type (T::*F)() const> + static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object) + { + T *p = static_cast<T*>(object); + return (p->*F)(); + } + +public: + OVR_FORCE_INLINE Delegate0() : _object(0), _stub(0){} + + // Function invocation + + OVR_FORCE_INLINE ret_type operator()() const + { + return (*_stub)(_object); + } + + // Use stub pointer as a validity flag and equality checker + + OVR_FORCE_INLINE bool operator==(const this_type &rhs) const + { + return _object == rhs._object && _stub == rhs._stub; + } + + OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const + { + return _object != rhs._object || _stub != rhs._stub; + } + + OVR_FORCE_INLINE bool IsValid() const + { + return _stub != 0; + } + + OVR_FORCE_INLINE bool operator!() const + { + return _stub == 0; + } + + OVR_FORCE_INLINE void Invalidate() + { + _stub = 0; + } + + // Delegate creation from a function + + template <ret_type (*F)()> + static OVR_FORCE_INLINE this_type FromFree() + { + return this_type(0, &FreeStub<F>); + } + + template <class T, ret_type (T::*F)()> + static OVR_FORCE_INLINE this_type FromMember(T *object) + { + return this_type(object, &MemberStub<T, F>); + } + + template <class T, ret_type (T::*F)() const> + static OVR_FORCE_INLINE this_type FromConstMember(T const *object) + { + return this_type(const_cast<T*>( object ), &ConstMemberStub<T, F>); + } + + // In-place assignment to a different function + + template <ret_type (*F)()> + OVR_FORCE_INLINE void SetFree() + { + *this = FromFree<F>(); + } + + template <class T, ret_type (T::*F)()> + OVR_FORCE_INLINE void SetMember(T *object) + { + *this = FromMember<T, F>(object); + } + + template <class T, ret_type (T::*F)() const> + OVR_FORCE_INLINE void SetConstMember(T const *object) + { + *this = FromConstMember<T, F>(object); + } +}; + + +template <class ret_type, class arg1_type> +class Delegate1 +{ + typedef ret_type (*StubPointer)(void *, arg1_type); + typedef Delegate1<ret_type, arg1_type> this_type; + + void *_object; + StubPointer _stub; + + OVR_FORCE_INLINE Delegate1(void *object, StubPointer stub) + { + _object = object; + _stub = stub; + } + + // Stubs + + template <ret_type (*F)(arg1_type)> + static OVR_FORCE_INLINE ret_type FreeStub(void * /*object*/, arg1_type a1) + { + return (F)(a1); + } + + template <class T, ret_type (T::*F)(arg1_type)> + static OVR_FORCE_INLINE ret_type MemberStub(void *object, arg1_type a1) + { + T *p = static_cast<T*>(object); + return (p->*F)(a1); + } + + template <class T, ret_type (T::*F)(arg1_type) const> + static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object, arg1_type a1) + { + T *p = static_cast<T*>(object); + return (p->*F)(a1); + } + +public: + OVR_FORCE_INLINE Delegate1() : _object(0), _stub(0){} + + // Function invocation + + OVR_FORCE_INLINE ret_type operator()(arg1_type a1) const + { + return (*_stub)(_object, a1); + } + + // Use stub pointer as a validity flag and equality checker + + OVR_FORCE_INLINE bool operator==(const this_type &rhs) const + { + return _object == rhs._object && _stub == rhs._stub; + } + + OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const + { + return _object != rhs._object || _stub != rhs._stub; + } + + OVR_FORCE_INLINE bool IsValid() const + { + return _stub != 0; + } + + OVR_FORCE_INLINE bool operator!() const + { + return _stub == 0; + } + + OVR_FORCE_INLINE void Invalidate() + { + _stub = 0; + } + + // Delegate creation from a function + + template <ret_type (*F)(arg1_type)> + static OVR_FORCE_INLINE this_type FromFree() + { + return this_type(0, &FreeStub<F>); + } + + template <class T, ret_type (T::*F)(arg1_type)> + static OVR_FORCE_INLINE this_type FromMember(T *object) + { + return this_type(object, &MemberStub<T, F>); + } + + template <class T, ret_type (T::*F)(arg1_type) const> + static OVR_FORCE_INLINE this_type FromConstMember(T const *object) + { + return this_type(const_cast<T*>( object ), &ConstMemberStub<T, F>); + } + + // In-place assignment to a different function + + template <ret_type (*F)(arg1_type)> + OVR_FORCE_INLINE void SetFree() + { + *this = FromFree<F>(); + } + + template <class T, ret_type (T::*F)(arg1_type)> + OVR_FORCE_INLINE void SetMember(T *object) + { + *this = FromMember<T, F>(object); + } + + template <class T, ret_type (T::*F)(arg1_type) const> + OVR_FORCE_INLINE void SetConstMember(T const *object) + { + *this = FromConstMember<T, F>(object); + } +}; + + +template <class ret_type, class arg1_type, class arg2_type> +class Delegate2 +{ + typedef ret_type (*StubPointer)(void *, arg1_type, arg2_type); + typedef Delegate2<ret_type, arg1_type, arg2_type> this_type; + + void *_object; + StubPointer _stub; + + OVR_FORCE_INLINE Delegate2(void *object, StubPointer stub) + { + _object = object; + _stub = stub; + } + + // Stubs + + template <ret_type (*F)(arg1_type, arg2_type)> + static OVR_FORCE_INLINE ret_type FreeStub(void * /*object*/, arg1_type a1, arg2_type a2) + { + return (F)(a1, a2); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type)> + static OVR_FORCE_INLINE ret_type MemberStub(void *object, arg1_type a1, arg2_type a2) + { + T *p = static_cast<T*>(object); + return (p->*F)(a1, a2); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type) const> + static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object, arg1_type a1, arg2_type a2) + { + T *p = static_cast<T*>(object); + return (p->*F)(a1, a2); + } + +public: + OVR_FORCE_INLINE Delegate2() : _object(0), _stub(0){} + + // Function invocation + + OVR_FORCE_INLINE ret_type operator()(arg1_type a1, arg2_type a2) const + { + return (*_stub)(_object, a1, a2); + } + + // Use stub pointer as a validity flag and equality checker + + OVR_FORCE_INLINE bool operator==(const this_type &rhs) const + { + return _object == rhs._object && _stub == rhs._stub; + } + + OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const + { + return _object != rhs._object || _stub != rhs._stub; + } + + OVR_FORCE_INLINE bool IsValid() const + { + return _stub != 0; + } + + OVR_FORCE_INLINE bool operator!() const + { + return _stub == 0; + } + + OVR_FORCE_INLINE void Invalidate() + { + _stub = 0; + } + + // Delegate creation from a function + + template <ret_type (*F)(arg1_type, arg2_type)> + static OVR_FORCE_INLINE this_type FromFree() + { + return this_type(0, &FreeStub<F>); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type)> + static OVR_FORCE_INLINE this_type FromMember(T *object) + { + return this_type(object, &MemberStub<T, F>); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type) const> + static OVR_FORCE_INLINE this_type FromConstMember(T const *object) + { + return this_type(const_cast<T*>( object ), &ConstMemberStub<T, F>); + } + + // In-place assignment to a different function + + template <ret_type (*F)(arg1_type, arg2_type)> + OVR_FORCE_INLINE void SetFree() + { + *this = FromFree<F>(); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type)> + OVR_FORCE_INLINE void SetMember(T *object) + { + *this = FromMember<T, F>(object); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type) const> + OVR_FORCE_INLINE void SetConstMember(T const *object) + { + *this = FromConstMember<T, F>(object); + } +}; + + +template <class ret_type, class arg1_type, class arg2_type, class arg3_type> +class Delegate3 +{ + typedef ret_type (*StubPointer)(void *, arg1_type, arg2_type, arg3_type); + typedef Delegate3<ret_type, arg1_type, arg2_type, arg3_type> this_type; + + void *_object; + StubPointer _stub; + + OVR_FORCE_INLINE Delegate3(void *object, StubPointer stub) + { + _object = object; + _stub = stub; + } + + // Stubs + + template <ret_type (*F)(arg1_type, arg2_type, arg3_type)> + static OVR_FORCE_INLINE ret_type FreeStub(void * /*object*/, arg1_type a1, arg2_type a2, arg3_type a3) + { + return (F)(a1, a2, a3); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type)> + static OVR_FORCE_INLINE ret_type MemberStub(void *object, arg1_type a1, arg2_type a2, arg3_type a3) + { + T *p = static_cast<T*>(object); + return (p->*F)(a1, a2, a3); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type) const> + static OVR_FORCE_INLINE ret_type ConstMemberStub(void *object, arg1_type a1, arg2_type a2, arg3_type a3) + { + T *p = static_cast<T*>(object); + return (p->*F)(a1, a2, a3); + } + +public: + OVR_FORCE_INLINE Delegate3() : _object(0), _stub(0){} + + // Function invocation + + OVR_FORCE_INLINE ret_type operator()(arg1_type a1, arg2_type a2, arg3_type a3) const + { + return (*_stub)(_object, a1, a2, a3); + } + + // Use stub pointer as a validity flag and equality checker + + OVR_FORCE_INLINE bool operator==(const this_type &rhs) const + { + return _object == rhs._object && _stub == rhs._stub; + } + + OVR_FORCE_INLINE bool operator!=(const this_type &rhs) const + { + return _object != rhs._object || _stub != rhs._stub; + } + + OVR_FORCE_INLINE bool IsValid() const + { + return _stub != 0; + } + + OVR_FORCE_INLINE bool operator!() const + { + return _stub == 0; + } + + OVR_FORCE_INLINE void Invalidate() + { + _stub = 0; + } + + // Delegate creation from a function + + template <ret_type (*F)(arg1_type, arg2_type, arg3_type)> + static OVR_FORCE_INLINE this_type FromFree() + { + return this_type(0, &FreeStub<F>); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type)> + static OVR_FORCE_INLINE this_type FromMember(T *object) + { + return this_type(object, &MemberStub<T, F>); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type) const> + static OVR_FORCE_INLINE this_type FromConstMember(T const *object) + { + return this_type(const_cast<T*>( object ), &ConstMemberStub<T, F>); + } + + // In-place assignment to a different function + + template <ret_type (*F)(arg1_type, arg2_type, arg3_type)> + OVR_FORCE_INLINE void SetFree() + { + *this = FromFree<F>(); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type)> + OVR_FORCE_INLINE void SetMember(T *object) + { + *this = FromMember<T, F>(object); + } + + template <class T, ret_type (T::*F)(arg1_type, arg2_type, arg3_type) const> + OVR_FORCE_INLINE void SetConstMember(T const *object) + { + *this = FromConstMember<T, F>(object); + } +}; + +// Add more here if needed, but keep in mind that a short, simple interface +// is rewarded by making the delegates faster... + + +} // namespace OVR + +#endif // OVR_Delegates_h diff --git a/LibOVRKernel/Src/Kernel/OVR_Deque.h b/LibOVRKernel/Src/Kernel/OVR_Deque.h new file mode 100644 index 0000000..951ed84 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Deque.h @@ -0,0 +1,316 @@ +/************************************************************************************ + +Filename : OVR_Deque.h +Content : Deque container +Created : Nov. 15, 2013 +Authors : Dov Katz + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Deque_h +#define OVR_Deque_h + +#include "OVR_ContainerAllocator.h" + +namespace OVR{ + +template <class Elem, class Allocator = ContainerAllocator<Elem> > +class Deque +{ +public: + enum + { + DefaultCapacity = 500 + }; + + Deque(int capacity = DefaultCapacity); + virtual ~Deque(void); + + virtual void PushBack (const Elem &Item); // Adds Item to the end + virtual void PushFront (const Elem &Item); // Adds Item to the beginning + virtual Elem PopBack (void); // Removes Item from the end + virtual Elem PopFront (void); // Removes Item from the beginning + virtual const Elem& PeekBack (int count = 0) const; // Returns count-th Item from the end + virtual const Elem& PeekFront (int count = 0) const; // Returns count-th Item from the beginning + + virtual inline size_t GetSize (void) const; // Returns Number of Elements + OVR_FORCE_INLINE int GetSizeI (void) const + { + return (int)GetSize(); + } + virtual inline size_t GetCapacity(void) const; // Returns the maximum possible number of elements + virtual void Clear (void); // Remove all elements + virtual inline bool IsEmpty () const; + virtual inline bool IsFull () const; + +protected: + Elem *Data; // The actual Data array + const int Capacity; // Deque capacity + int Beginning; // Index of the first element + int End; // Index of the next after last element + + // Instead of calculating the number of elements, using this variable + // is much more convenient. + int ElemCount; + +private: + OVR_NON_COPYABLE(Deque); +}; + +template <class Elem, class Allocator = ContainerAllocator<Elem> > +class InPlaceMutableDeque : public Deque<Elem, Allocator> +{ + typedef Deque<Elem, Allocator> BaseType; + +public: + InPlaceMutableDeque( int capacity = BaseType::DefaultCapacity ) : BaseType( capacity ) {} + virtual ~InPlaceMutableDeque() {}; + + using BaseType::PeekBack; + using BaseType::PeekFront; + virtual Elem& PeekBack (int count = 0); // Returns count-th Item from the end + virtual Elem& PeekFront (int count = 0); // Returns count-th Item from the beginning +}; + +// Same as Deque, but allows to write more elements than maximum capacity +// Old elements are lost as they are overwritten with the new ones +template <class Elem, class Allocator = ContainerAllocator<Elem> > +class CircularBuffer : public InPlaceMutableDeque<Elem, Allocator> +{ + typedef InPlaceMutableDeque<Elem, Allocator> BaseType; + +public: + CircularBuffer(int MaxSize = BaseType::DefaultCapacity) : BaseType(MaxSize) { }; + virtual ~CircularBuffer(){} + + // The following methods are inline as a workaround for a VS bug causing erroneous C4505 warnings + // See: http://stackoverflow.com/questions/3051992/compiler-warning-at-c-template-base-class + inline virtual void PushBack (const Elem &Item); // Adds Item to the end, overwriting the oldest element at the beginning if necessary + inline virtual void PushFront (const Elem &Item); // Adds Item to the beginning, overwriting the oldest element at the end if necessary +}; + +//---------------------------------------------------------------------------------- + +// Deque Constructor function +template <class Elem, class Allocator> +Deque<Elem, Allocator>::Deque(int capacity) : +Capacity( capacity ), Beginning(0), End(0), ElemCount(0) +{ + Data = (Elem*) Allocator::Alloc(Capacity * sizeof(Elem)); +} + +// Deque Destructor function +template <class Elem, class Allocator> +Deque<Elem, Allocator>::~Deque(void) +{ + Clear(); + Allocator::Free(Data); +} + +template <class Elem, class Allocator> +void Deque<Elem, Allocator>::Clear() +{ + if (!IsEmpty()) + { + if (Beginning < End) + { + // no wrap-around + Allocator::DestructArray(Data + Beginning, End - Beginning); + } + else + { + // wrap-around + Allocator::DestructArray(Data + Beginning, Capacity - Beginning); + Allocator::DestructArray(Data, End); + } + } + + Beginning = 0; + End = 0; + ElemCount = 0; +} + +// Push functions +template <class Elem, class Allocator> +void Deque<Elem, Allocator>::PushBack(const Elem &Item) +{ + // Error Check: Make sure we aren't + // exceeding our maximum storage space + OVR_ASSERT( ElemCount < Capacity ); + + Allocator::Construct(Data + End, Item); + ++End; + ++ElemCount; + + // Check for wrap-around + if (End >= Capacity) + End -= Capacity; +} + +template <class Elem, class Allocator> +void Deque<Elem, Allocator>::PushFront(const Elem &Item) +{ + // Error Check: Make sure we aren't + // exceeding our maximum storage space + OVR_ASSERT( ElemCount < Capacity ); + + --Beginning; + // Check for wrap-around + if (Beginning < 0) + Beginning += Capacity; + + Allocator::Construct(Data + Beginning, Item); + ++ElemCount; +} + +// Pop functions +template <class Elem, class Allocator> +Elem Deque<Elem, Allocator>::PopFront(void) +{ + // Error Check: Make sure we aren't reading from an empty Deque + OVR_ASSERT( ElemCount > 0 ); + + Elem ReturnValue = Data[ Beginning ]; + Allocator::Destruct(Data + Beginning); + + ++Beginning; + --ElemCount; + + // Check for wrap-around + if (Beginning >= Capacity) + Beginning -= Capacity; + + return ReturnValue; +} + +template <class Elem, class Allocator> +Elem Deque<Elem, Allocator>::PopBack(void) +{ + // Error Check: Make sure we aren't reading from an empty Deque + OVR_ASSERT( ElemCount > 0 ); + + --End; + --ElemCount; + + // Check for wrap-around + if (End < 0) + End += Capacity; + + Elem ReturnValue = Data[ End ]; + Allocator::Destruct(Data + End); + + return ReturnValue; +} + +// Peek functions +template <class Elem, class Allocator> +const Elem& Deque<Elem, Allocator>::PeekFront(int count) const +{ + // Error Check: Make sure we aren't reading from an empty Deque + OVR_ASSERT( ElemCount > count ); + + int idx = Beginning + count; + if (idx >= Capacity) + idx -= Capacity; + return Data[ idx ]; +} + +template <class Elem, class Allocator> +const Elem& Deque<Elem, Allocator>::PeekBack(int count) const +{ + // Error Check: Make sure we aren't reading from an empty Deque + OVR_ASSERT( ElemCount > count ); + + int idx = End - count - 1; + if (idx < 0) + idx += Capacity; + return Data[ idx ]; +} + +// Mutable Peek functions +template <class Elem, class Allocator> +Elem& InPlaceMutableDeque<Elem, Allocator>::PeekFront(int count) +{ + // Error Check: Make sure we aren't reading from an empty Deque + OVR_ASSERT( BaseType::ElemCount > count ); + + int idx = BaseType::Beginning + count; + if (idx >= BaseType::Capacity) + idx -= BaseType::Capacity; + return BaseType::Data[ idx ]; +} + +template <class Elem, class Allocator> +Elem& InPlaceMutableDeque<Elem, Allocator>::PeekBack(int count) +{ + // Error Check: Make sure we aren't reading from an empty Deque + OVR_ASSERT( BaseType::ElemCount > count ); + + int idx = BaseType::End - count - 1; + if (idx < 0) + idx += BaseType::Capacity; + return BaseType::Data[ idx ]; +} + +template <class Elem, class Allocator> +inline size_t Deque<Elem, Allocator>::GetCapacity(void) const +{ + return Capacity; +} + +template <class Elem, class Allocator> +inline size_t Deque<Elem, Allocator>::GetSize(void) const +{ + return ElemCount; +} + +template <class Elem, class Allocator> +inline bool Deque<Elem, Allocator>::IsEmpty(void) const +{ + return ElemCount == 0; +} + +template <class Elem, class Allocator> +inline bool Deque<Elem, Allocator>::IsFull(void) const +{ + return ElemCount == Capacity; +} + +// ******* CircularBuffer<Elem> ******* +// Push functions +template <class Elem, class Allocator> +void CircularBuffer<Elem, Allocator>::PushBack(const Elem &Item) +{ + if (this->IsFull()) + this->PopFront(); + BaseType::PushBack(Item); +} + +template <class Elem, class Allocator> +void CircularBuffer<Elem, Allocator>::PushFront(const Elem &Item) +{ + if (this->IsFull()) + this->PopBack(); + BaseType::PushFront(Item); +} + +}; + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_File.cpp b/LibOVRKernel/Src/Kernel/OVR_File.cpp new file mode 100644 index 0000000..c431928 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_File.cpp @@ -0,0 +1,585 @@ +/************************************************************************** + +Filename : OVR_File.cpp +Content : File wrapper class implementation (Win32) + +Created : April 5, 1999 +Authors : Michael Antonov + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +**************************************************************************/ + +#define GFILE_CXX + +// Standard C library (Captain Obvious guarantees!) +#include <stdio.h> + +#include "OVR_File.h" + +namespace OVR { + +// Buffered file adds buffering to an existing file +// FILEBUFFER_SIZE defines the size of internal buffer, while +// FILEBUFFER_TOLERANCE controls the amount of data we'll effectively try to buffer +#define FILEBUFFER_SIZE (8192-8) +#define FILEBUFFER_TOLERANCE 4096 + +// ** Constructor/Destructor + +// Hidden constructor +// Not supposed to be used +BufferedFile::BufferedFile() : DelegatedFile(0) +{ + pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE); + BufferMode = NoBuffer; + FilePos = 0; + Pos = 0; + DataSize = 0; +} + +// Takes another file as source +BufferedFile::BufferedFile(File *pfile) : DelegatedFile(pfile) +{ + pBuffer = (uint8_t*)OVR_ALLOC(FILEBUFFER_SIZE); + BufferMode = NoBuffer; + FilePos = pfile->LTell(); + Pos = 0; + DataSize = 0; +} + + +// Destructor +BufferedFile::~BufferedFile() +{ + // Flush in case there's data + if (pFile) + FlushBuffer(); + // Get rid of buffer + if (pBuffer) + OVR_FREE(pBuffer); +} + +/* +bool BufferedFile::VCopy(const Object &source) +{ + if (!DelegatedFile::VCopy(source)) + return 0; + + // Data members + BufferedFile *psource = (BufferedFile*)&source; + + // Buffer & the mode it's in + pBuffer = psource->pBuffer; + BufferMode = psource->BufferMode; + Pos = psource->Pos; + DataSize = psource->DataSize; + return 1; +} +*/ + +// Initializes buffering to a certain mode +bool BufferedFile::SetBufferMode(BufferModeType mode) +{ + if (!pBuffer) + return false; + if (mode == BufferMode) + return true; + + FlushBuffer(); + + // Can't set write mode if we can't write + if ((mode==WriteBuffer) && (!pFile || !pFile->IsWritable()) ) + return 0; + + // And SetMode + BufferMode = mode; + Pos = 0; + DataSize = 0; + return 1; +} + +// Flushes buffer +void BufferedFile::FlushBuffer() +{ + switch(BufferMode) + { + case WriteBuffer: + // Write data in buffer + FilePos += pFile->Write(pBuffer,Pos); + Pos = 0; + break; + + case ReadBuffer: + // Seek back & reset buffer data + if ((DataSize-Pos)>0) + FilePos = pFile->LSeek(-(int)(DataSize-Pos), Seek_Cur); + DataSize = 0; + Pos = 0; + break; + default: + // not handled! + break; + } +} + +// Reloads data for ReadBuffer +void BufferedFile::LoadBuffer() +{ + if (BufferMode == ReadBuffer) + { + // We should only reload once all of pre-loaded buffer is consumed. + OVR_ASSERT(Pos == DataSize); + + // WARNING: Right now LoadBuffer() assumes the buffer's empty + int sz = pFile->Read(pBuffer,FILEBUFFER_SIZE); + DataSize = sz<0 ? 0 : (unsigned)sz; + Pos = 0; + FilePos += DataSize; + } +} + + +// ** Overridden functions + +// We override all the functions that can possibly +// require buffer mode switch, flush, or extra calculations + +// Tell() requires buffer adjustment +int BufferedFile::Tell() +{ + if (BufferMode == ReadBuffer) + return int (FilePos - DataSize + Pos); + + int pos = pFile->Tell(); + // Adjust position based on buffer mode & data + if (pos!=-1) + { + OVR_ASSERT(BufferMode != ReadBuffer); + if (BufferMode == WriteBuffer) + pos += Pos; + } + return pos; +} + +int64_t BufferedFile::LTell() +{ + if (BufferMode == ReadBuffer) + return FilePos - DataSize + Pos; + + int64_t pos = pFile->LTell(); + if (pos!=-1) + { + OVR_ASSERT(BufferMode != ReadBuffer); + if (BufferMode == WriteBuffer) + pos += Pos; + } + return pos; +} + +int BufferedFile::GetLength() +{ + int len = pFile->GetLength(); + // If writing through buffer, file length may actually be bigger + if ((len!=-1) && (BufferMode==WriteBuffer)) + { + int currPos = pFile->Tell() + Pos; + if (currPos>len) + len = currPos; + } + return len; +} +int64_t BufferedFile::LGetLength() +{ + int64_t len = pFile->LGetLength(); + // If writing through buffer, file length may actually be bigger + if ((len!=-1) && (BufferMode==WriteBuffer)) + { + int64_t currPos = pFile->LTell() + Pos; + if (currPos>len) + len = currPos; + } + return len; +} + +/* +bool BufferedFile::Stat(FileStats *pfs) +{ + // Have to fix up length is stat + if (pFile->Stat(pfs)) + { + if (BufferMode==WriteBuffer) + { + int64_t currPos = pFile->LTell() + Pos; + if (currPos > pfs->Size) + { + pfs->Size = currPos; + // ?? + pfs->Blocks = (pfs->Size+511) >> 9; + } + } + return 1; + } + return 0; +} +*/ + +int BufferedFile::Write(const uint8_t *psourceBuffer, int numBytes) +{ + if ( (BufferMode==WriteBuffer) || SetBufferMode(WriteBuffer)) + { + // If not data space in buffer, flush + if ((FILEBUFFER_SIZE-(int)Pos)<numBytes) + { + FlushBuffer(); + // If bigger then tolerance, just write directly + if (numBytes>FILEBUFFER_TOLERANCE) + { + int sz = pFile->Write(psourceBuffer,numBytes); + if (sz > 0) + FilePos += sz; + return sz; + } + } + + // Enough space in buffer.. so copy to it + memcpy(pBuffer+Pos, psourceBuffer, numBytes); + Pos += numBytes; + return numBytes; + } + int sz = pFile->Write(psourceBuffer,numBytes); + if (sz > 0) + FilePos += sz; + return sz; +} + +int BufferedFile::Read(uint8_t *pdestBuffer, int numBytes) +{ + if ( (BufferMode==ReadBuffer) || SetBufferMode(ReadBuffer)) + { + // Data in buffer... copy it + if ((int)(DataSize-Pos) >= numBytes) + { + memcpy(pdestBuffer, pBuffer+Pos, numBytes); + Pos += numBytes; + return numBytes; + } + + // Not enough data in buffer, copy buffer + int readBytes = DataSize-Pos; + memcpy(pdestBuffer, pBuffer+Pos, readBytes); + numBytes -= readBytes; + pdestBuffer += readBytes; + Pos = DataSize; + + // Don't reload buffer if more then tolerance + // (No major advantage, and we don't want to write a loop) + if (numBytes>FILEBUFFER_TOLERANCE) + { + numBytes = pFile->Read(pdestBuffer,numBytes); + if (numBytes > 0) + { + FilePos += numBytes; + Pos = DataSize = 0; + } + return readBytes + ((numBytes==-1) ? 0 : numBytes); + } + + // Reload the buffer + // WARNING: Right now LoadBuffer() assumes the buffer's empty + LoadBuffer(); + if ((int)(DataSize-Pos) < numBytes) + numBytes = (int)DataSize-Pos; + + memcpy(pdestBuffer, pBuffer+Pos, numBytes); + Pos += numBytes; + return numBytes + readBytes; + + /* + // Alternative Read implementation. The one above is probably better + // due to FILEBUFFER_TOLERANCE. + int total = 0; + + do { + int bufferBytes = (int)(DataSize-Pos); + int copyBytes = (bufferBytes > numBytes) ? numBytes : bufferBytes; + + memcpy(pdestBuffer, pBuffer+Pos, copyBytes); + numBytes -= copyBytes; + pdestBuffer += copyBytes; + Pos += copyBytes; + total += copyBytes; + + if (numBytes == 0) + break; + LoadBuffer(); + + } while (DataSize > 0); + + return total; + */ + } + int sz = pFile->Read(pdestBuffer,numBytes); + if (sz > 0) + FilePos += sz; + return sz; +} + + +int BufferedFile::SkipBytes(int numBytes) +{ + int skippedBytes = 0; + + // Special case for skipping a little data in read buffer + if (BufferMode==ReadBuffer) + { + skippedBytes = (((int)DataSize-(int)Pos) >= numBytes) ? numBytes : (DataSize-Pos); + Pos += skippedBytes; + numBytes -= skippedBytes; + } + + if (numBytes) + { + numBytes = pFile->SkipBytes(numBytes); + // Make sure we return the actual number skipped, or error + if (numBytes!=-1) + { + skippedBytes += numBytes; + FilePos += numBytes; + Pos = DataSize = 0; + } + else if (skippedBytes <= 0) + skippedBytes = -1; + } + return skippedBytes; +} + +int BufferedFile::BytesAvailable() +{ + int available = pFile->BytesAvailable(); + // Adjust available size based on buffers + switch(BufferMode) + { + case ReadBuffer: + available += DataSize-Pos; + break; + case WriteBuffer: + available -= Pos; + if (available<0) + available= 0; + break; + default: + break; + } + return available; +} + +bool BufferedFile::Flush() +{ + FlushBuffer(); + return pFile->Flush(); +} + +// Seeking could be optimized better.. +int BufferedFile::Seek(int offset, int origin) +{ + if (BufferMode == ReadBuffer) + { + if (origin == Seek_Cur) + { + // Seek can fall either before or after Pos in the buffer, + // but it must be within bounds. + if (((unsigned(offset) + Pos)) <= DataSize) + { + Pos += offset; + return int (FilePos - DataSize + Pos); + } + + // Lightweight buffer "Flush". We do this to avoid an extra seek + // back operation which would take place if we called FlushBuffer directly. + origin = Seek_Set; + OVR_ASSERT(((FilePos - DataSize + Pos) + (uint64_t)offset) < ~(uint64_t)0); + offset = (int)(FilePos - DataSize + Pos) + offset; + Pos = DataSize = 0; + } + else if (origin == Seek_Set) + { + if (((unsigned)offset - (FilePos-DataSize)) <= DataSize) + { + OVR_ASSERT((FilePos-DataSize) < ~(uint64_t)0); + Pos = (unsigned)offset - (unsigned)(FilePos-DataSize); + return offset; + } + Pos = DataSize = 0; + } + else + { + FlushBuffer(); + } + } + else + { + FlushBuffer(); + } + + /* + // Old Seek Logic + if (origin == Seek_Cur && offset + Pos < DataSize) + { + //OVR_ASSERT((FilePos - DataSize) >= (FilePos - DataSize + Pos + offset)); + Pos += offset; + OVR_ASSERT(int (Pos) >= 0); + return int (FilePos - DataSize + Pos); + } + else if (origin == Seek_Set && unsigned(offset) >= FilePos - DataSize && unsigned(offset) < FilePos) + { + Pos = unsigned(offset - FilePos + DataSize); + OVR_ASSERT(int (Pos) >= 0); + return int (FilePos - DataSize + Pos); + } + + FlushBuffer(); + */ + + + FilePos = pFile->Seek(offset,origin); + return int (FilePos); +} + +int64_t BufferedFile::LSeek(int64_t offset, int origin) +{ + if (BufferMode == ReadBuffer) + { + if (origin == Seek_Cur) + { + // Seek can fall either before or after Pos in the buffer, + // but it must be within bounds. + if (((unsigned(offset) + Pos)) <= DataSize) + { + Pos += (unsigned)offset; + return int64_t(FilePos - DataSize + Pos); + } + + // Lightweight buffer "Flush". We do this to avoid an extra seek + // back operation which would take place if we called FlushBuffer directly. + origin = Seek_Set; + offset = (int64_t)(FilePos - DataSize + Pos) + offset; + Pos = DataSize = 0; + } + else if (origin == Seek_Set) + { + if (((uint64_t)offset - (FilePos-DataSize)) <= DataSize) + { + Pos = (unsigned)((uint64_t)offset - (FilePos-DataSize)); + return offset; + } + Pos = DataSize = 0; + } + else + { + FlushBuffer(); + } + } + else + { + FlushBuffer(); + } + +/* + OVR_ASSERT(BufferMode != NoBuffer); + + if (origin == Seek_Cur && offset + Pos < DataSize) + { + Pos += int (offset); + return FilePos - DataSize + Pos; + } + else if (origin == Seek_Set && offset >= int64_t(FilePos - DataSize) && offset < int64_t(FilePos)) + { + Pos = unsigned(offset - FilePos + DataSize); + return FilePos - DataSize + Pos; + } + + FlushBuffer(); + */ + + FilePos = pFile->LSeek(offset,origin); + return FilePos; +} + +int BufferedFile::CopyFromStream(File *pstream, int byteSize) +{ + // We can't rely on overridden Write() + // because delegation doesn't override virtual pointers + // So, just re-implement + uint8_t* buff = new uint8_t[0x4000]; + int count = 0; + int szRequest, szRead, szWritten; + + while(byteSize) + { + szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize; + + szRead = pstream->Read(buff,szRequest); + szWritten = 0; + if (szRead > 0) + szWritten = Write(buff,szRead); + + count +=szWritten; + byteSize-=szWritten; + if (szWritten < szRequest) + break; + } + + delete[] buff; + + return count; +} + +// Closing files +bool BufferedFile::Close() +{ + switch(BufferMode) + { + case WriteBuffer: + FlushBuffer(); + break; + case ReadBuffer: + // No need to seek back on close + BufferMode = NoBuffer; + break; + default: + break; + } + return pFile->Close(); +} + + +// ***** Global path helpers + +// Find trailing short filename in a path. +const char* OVR_CDECL GetShortFilename(const char* purl) +{ + size_t len = OVR_strlen(purl); + for (size_t i=len; i>0; i--) + if (purl[i]=='\\' || purl[i]=='/') + return purl+i+1; + return purl; +} + +} // OVR + diff --git a/LibOVRKernel/Src/Kernel/OVR_File.h b/LibOVRKernel/Src/Kernel/OVR_File.h new file mode 100644 index 0000000..d9d3b0f --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_File.h @@ -0,0 +1,530 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_File.h +Content : Header for all internal file management - functions and structures + to be inherited by OS specific subclasses. +Created : September 19, 2012 +Notes : + +Notes : errno may not be preserved across use of BaseFile member functions + : Directories cannot be deleted while files opened from them are in use + (For the GetFullName function) + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_File_h +#define OVR_File_h + +#include "OVR_RefCount.h" +#include "OVR_Std.h" +#include "OVR_Alg.h" + +#include <stdio.h> +#include "OVR_String.h" + +namespace OVR { + +// ***** Declared classes +class FileConstants; +class File; +class DelegatedFile; +class BufferedFile; + + +// ***** Flags for File & Directory accesses + +class FileConstants +{ +public: + + // *** File open flags + enum OpenFlags + { + Open_Read = 1, + Open_Write = 2, + Open_ReadWrite = 3, + + // Opens file and truncates it to zero length + // - file must have write permission + // - when used with Create, it opens an existing + // file and empties it or creates a new file + Open_Truncate = 4, + + // Creates and opens new file + // - does not erase contents if file already + // exists unless combined with Truncate + Open_Create = 8, + + // Returns an error value if the file already exists + Open_CreateOnly = 24, + + // Open file with buffering + Open_Buffered = 32 + }; + + // *** File Mode flags + enum Modes + { + Mode_Read = 0444, + Mode_Write = 0222, + Mode_Execute = 0111, + + Mode_ReadWrite = 0666 + }; + + // *** Seek operations + enum SeekOps + { + Seek_Set = 0, + Seek_Cur = 1, + Seek_End = 2 + }; + + // *** Errors + enum Errors + { + Error_FileNotFound = 0x1001, + Error_Access = 0x1002, + Error_IOError = 0x1003, + Error_DiskFull = 0x1004 + }; +}; + + +//----------------------------------------------------------------------------------- +// ***** File Class + +// The pure virtual base random-access file +// This is a base class to all files + +class File : public RefCountBase<File>, public FileConstants +{ +public: + File() { } + // ** Location Information + + // Returns a file name path relative to the 'reference' directory + // This is often a path that was used to create a file + // (this is not a global path, global path can be obtained with help of directory) + virtual const char* GetFilePath() = 0; + + + // ** File Information + + // Return 1 if file's usable (open) + virtual bool IsValid() = 0; + // Return 1 if file's writable, otherwise 0 + virtual bool IsWritable() = 0; + + // Return position + virtual int Tell() = 0; + virtual int64_t LTell() = 0; + + // File size + virtual int GetLength() = 0; + virtual int64_t LGetLength() = 0; + + // Returns file stats + // 0 for failure + //virtual bool Stat(FileStats *pfs) = 0; + + // Return errno-based error code + // Useful if any other function failed + virtual int GetErrorCode() = 0; + + + // ** Stream implementation & I/O + + // Blocking write, will write in the given number of bytes to the stream + // Returns : -1 for error + // Otherwise number of bytes read + virtual int Write(const uint8_t *pbufer, int numBytes) = 0; + // Blocking read, will read in the given number of bytes or less from the stream + // Returns : -1 for error + // Otherwise number of bytes read, + // if 0 or < numBytes, no more bytes available; end of file or the other side of stream is closed + virtual int Read(uint8_t *pbufer, int numBytes) = 0; + + // Skips (ignores) a given # of bytes + // Same return values as Read + virtual int SkipBytes(int numBytes) = 0; + + // Returns the number of bytes available to read from a stream without blocking + // For a file, this should generally be number of bytes to the end + virtual int BytesAvailable() = 0; + + // Causes any implementation's buffered data to be delivered to destination + // Return 0 for error + virtual bool Flush() = 0; + + + // Need to provide a more optimized implementation that doe snot necessarily involve a lot of seeking + inline bool IsEOF() { return !BytesAvailable(); } + + + // Seeking + // Returns new position, -1 for error + virtual int Seek(int offset, int origin=Seek_Set) = 0; + virtual int64_t LSeek(int64_t offset, int origin=Seek_Set) = 0; + // Seek simplification + int SeekToBegin() {return Seek(0); } + int SeekToEnd() {return Seek(0,Seek_End); } + int Skip(int numBytes) {return Seek(numBytes,Seek_Cur); } + + + // Appends other file data from a stream + // Return -1 for error, else # of bytes written + virtual int CopyFromStream(File *pstream, int byteSize) = 0; + + // Closes the file + // After close, file cannot be accessed + virtual bool Close() = 0; + + + // ***** Inlines for convenient primitive type serialization + + // Read/Write helpers +private: + uint64_t PRead64() { uint64_t v = 0; Read((uint8_t*)&v, 8); return v; } + uint32_t PRead32() { uint32_t v = 0; Read((uint8_t*)&v, 4); return v; } + uint16_t PRead16() { uint16_t v = 0; Read((uint8_t*)&v, 2); return v; } + uint8_t PRead8() { uint8_t v = 0; Read((uint8_t*)&v, 1); return v; } + void PWrite64(uint64_t v) { Write((uint8_t*)&v, 8); } + void PWrite32(uint32_t v) { Write((uint8_t*)&v, 4); } + void PWrite16(uint16_t v) { Write((uint8_t*)&v, 2); } + void PWrite8(uint8_t v) { Write((uint8_t*)&v, 1); } + +public: + + // Writing primitive types - Little Endian + inline void WriteUByte(uint8_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteSByte(int8_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteUInt8(uint8_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteSInt8(int8_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteUInt16(uint16_t v) { PWrite16((uint16_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteSInt16(int16_t v) { PWrite16((uint16_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteUInt32(uint32_t v) { PWrite32((uint32_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteSInt32(int32_t v) { PWrite32((uint32_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteUInt64(uint64_t v) { PWrite64((uint64_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteSInt64(int64_t v) { PWrite64((uint64_t)Alg::ByteUtil::SystemToLE(v)); } + inline void WriteFloat(float v) { v = Alg::ByteUtil::SystemToLE(v); Write((uint8_t*)&v, 4); } + inline void WriteDouble(double v) { v = Alg::ByteUtil::SystemToLE(v); Write((uint8_t*)&v, 8); } + // Writing primitive types - Big Endian + inline void WriteUByteBE(uint8_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteSByteBE(int8_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteUInt8BE(uint16_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteSInt8BE(int16_t v) { PWrite8((uint8_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteUInt16BE(uint16_t v) { PWrite16((uint16_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteSInt16BE(uint16_t v) { PWrite16((uint16_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteUInt32BE(uint32_t v) { PWrite32((uint32_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteSInt32BE(uint32_t v) { PWrite32((uint32_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteUInt64BE(uint64_t v) { PWrite64((uint64_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteSInt64BE(uint64_t v) { PWrite64((uint64_t)Alg::ByteUtil::SystemToBE(v)); } + inline void WriteFloatBE(float v) { v = Alg::ByteUtil::SystemToBE(v); Write((uint8_t*)&v, 4); } + inline void WriteDoubleBE(double v) { v = Alg::ByteUtil::SystemToBE(v); Write((uint8_t*)&v, 8); } + + // Reading primitive types - Little Endian + inline uint8_t ReadUByte() { return (uint8_t)Alg::ByteUtil::LEToSystem(PRead8()); } + inline int8_t ReadSByte() { return (int8_t)Alg::ByteUtil::LEToSystem(PRead8()); } + inline uint8_t ReadUInt8() { return (uint8_t)Alg::ByteUtil::LEToSystem(PRead8()); } + inline int8_t ReadSInt8() { return (int8_t)Alg::ByteUtil::LEToSystem(PRead8()); } + inline uint16_t ReadUInt16() { return (uint16_t)Alg::ByteUtil::LEToSystem(PRead16()); } + inline int16_t ReadSInt16() { return (int16_t)Alg::ByteUtil::LEToSystem(PRead16()); } + inline uint32_t ReadUInt32() { return (uint32_t)Alg::ByteUtil::LEToSystem(PRead32()); } + inline int32_t ReadSInt32() { return (int32_t)Alg::ByteUtil::LEToSystem(PRead32()); } + inline uint64_t ReadUInt64() { return (uint64_t)Alg::ByteUtil::LEToSystem(PRead64()); } + inline int64_t ReadSInt64() { return (int64_t)Alg::ByteUtil::LEToSystem(PRead64()); } + inline float ReadFloat() { float v = 0.0f; Read((uint8_t*)&v, 4); return Alg::ByteUtil::LEToSystem(v); } + inline double ReadDouble() { double v = 0.0; Read((uint8_t*)&v, 8); return Alg::ByteUtil::LEToSystem(v); } + // Reading primitive types - Big Endian + inline uint8_t ReadUByteBE() { return (uint8_t)Alg::ByteUtil::BEToSystem(PRead8()); } + inline int8_t ReadSByteBE() { return (int8_t)Alg::ByteUtil::BEToSystem(PRead8()); } + inline uint8_t ReadUInt8BE() { return (uint8_t)Alg::ByteUtil::BEToSystem(PRead8()); } + inline int8_t ReadSInt8BE() { return (int8_t)Alg::ByteUtil::BEToSystem(PRead8()); } + inline uint16_t ReadUInt16BE() { return (uint16_t)Alg::ByteUtil::BEToSystem(PRead16()); } + inline int16_t ReadSInt16BE() { return (int16_t)Alg::ByteUtil::BEToSystem(PRead16()); } + inline uint32_t ReadUInt32BE() { return (uint32_t)Alg::ByteUtil::BEToSystem(PRead32()); } + inline int32_t ReadSInt32BE() { return (int32_t)Alg::ByteUtil::BEToSystem(PRead32()); } + inline uint64_t ReadUInt64BE() { return (uint64_t)Alg::ByteUtil::BEToSystem(PRead64()); } + inline int64_t ReadSInt64BE() { return (int64_t)Alg::ByteUtil::BEToSystem(PRead64()); } + inline float ReadFloatBE() { float v = 0.0f; Read((uint8_t*)&v, 4); return Alg::ByteUtil::BEToSystem(v); } + inline double ReadDoubleBE() { double v = 0.0; Read((uint8_t*)&v, 8); return Alg::ByteUtil::BEToSystem(v); } +}; + + +// *** Delegated File + +class DelegatedFile : public File +{ +protected: + // Delegating file pointer + Ptr<File> pFile; + + // Hidden default constructor + DelegatedFile() : pFile(0) { } + DelegatedFile(const DelegatedFile &source) : File() { OVR_UNUSED(source); } +public: + // Constructors + DelegatedFile(File *pfile) : pFile(pfile) { } + + // ** Location Information + virtual const char* GetFilePath() { return pFile->GetFilePath(); } + + // ** File Information + virtual bool IsValid() { return pFile && pFile->IsValid(); } + virtual bool IsWritable() { return pFile->IsWritable(); } +// virtual bool IsRecoverable() { return pFile->IsRecoverable(); } + + virtual int Tell() { return pFile->Tell(); } + virtual int64_t LTell() { return pFile->LTell(); } + + virtual int GetLength() { return pFile->GetLength(); } + virtual int64_t LGetLength() { return pFile->LGetLength(); } + + //virtual bool Stat(FileStats *pfs) { return pFile->Stat(pfs); } + + virtual int GetErrorCode() { return pFile->GetErrorCode(); } + + // ** Stream implementation & I/O + virtual int Write(const uint8_t *pbuffer, int numBytes) { return pFile->Write(pbuffer,numBytes); } + virtual int Read(uint8_t *pbuffer, int numBytes) { return pFile->Read(pbuffer,numBytes); } + + virtual int SkipBytes(int numBytes) { return pFile->SkipBytes(numBytes); } + + virtual int BytesAvailable() { return pFile->BytesAvailable(); } + + virtual bool Flush() { return pFile->Flush(); } + + // Seeking + virtual int Seek(int offset, int origin=Seek_Set) { return pFile->Seek(offset,origin); } + virtual int64_t LSeek(int64_t offset, int origin=Seek_Set) { return pFile->LSeek(offset,origin); } + + virtual int CopyFromStream(File *pstream, int byteSize) { return pFile->CopyFromStream(pstream,byteSize); } + + // Closing the file + virtual bool Close() { return pFile->Close(); } +}; + + +//----------------------------------------------------------------------------------- +// ***** Buffered File + +// This file class adds buffering to an existing file +// Buffered file never fails by itself; if there's not +// enough memory for buffer, no buffer's used + +class BufferedFile : public DelegatedFile +{ +protected: + enum BufferModeType + { + NoBuffer, + ReadBuffer, + WriteBuffer + }; + + // Buffer & the mode it's in + uint8_t* pBuffer; + BufferModeType BufferMode; + // Position in buffer + unsigned Pos; + // Data in buffer if reading + unsigned DataSize; + // Underlying file position + uint64_t FilePos; + + // Initializes buffering to a certain mode + bool SetBufferMode(BufferModeType mode); + // Flushes buffer + // WriteBuffer - write data to disk, ReadBuffer - reset buffer & fix file position + void FlushBuffer(); + // Loads data into ReadBuffer + // WARNING: Right now LoadBuffer() assumes the buffer's empty + void LoadBuffer(); + + // Hidden constructor + BufferedFile(); + BufferedFile(const BufferedFile &) : DelegatedFile(), pBuffer(NULL), BufferMode(NoBuffer), Pos(0), DataSize(0), FilePos(0) { } + +public: + + // Constructor + // - takes another file as source + BufferedFile(File *pfile); + ~BufferedFile(); + + + // ** Overridden functions + + // We override all the functions that can possibly + // require buffer mode switch, flush, or extra calculations + virtual int Tell(); + virtual int64_t LTell(); + + virtual int GetLength(); + virtual int64_t LGetLength(); + +// virtual bool Stat(GFileStats *pfs); + + virtual int Write(const uint8_t *pbufer, int numBytes); + virtual int Read(uint8_t *pbufer, int numBytes); + + virtual int SkipBytes(int numBytes); + + virtual int BytesAvailable(); + + virtual bool Flush(); + + virtual int Seek(int offset, int origin=Seek_Set); + virtual int64_t LSeek(int64_t offset, int origin=Seek_Set); + + virtual int CopyFromStream(File *pstream, int byteSize); + + virtual bool Close(); +}; + + +//----------------------------------------------------------------------------------- +// ***** Memory File + +class MemoryFile : public File +{ +public: + + const char* GetFilePath() { return FilePath.ToCStr(); } + + bool IsValid() { return Valid; } + bool IsWritable() { return false; } + + bool Flush() { return true; } + int GetErrorCode() { return 0; } + + int Tell() { return FileIndex; } + int64_t LTell() { return (int64_t) FileIndex; } + + int GetLength() { return FileSize; } + int64_t LGetLength() { return (int64_t) FileSize; } + + bool Close() + { + Valid = false; + return false; + } + + int CopyFromStream(File *pstream, int byteSize) + { OVR_UNUSED2(pstream, byteSize); + return 0; + } + + int Write(const uint8_t *pbuffer, int numBytes) + { OVR_UNUSED2(pbuffer, numBytes); + return 0; + } + + int Read(uint8_t *pbufer, int numBytes) + { + if (FileIndex + numBytes > FileSize) + { + numBytes = FileSize - FileIndex; + } + + if (numBytes > 0) + { + ::memcpy (pbufer, &FileData [FileIndex], numBytes); + + FileIndex += numBytes; + } + + return numBytes; + } + + int SkipBytes(int numBytes) + { + if (FileIndex + numBytes > FileSize) + { + numBytes = FileSize - FileIndex; + } + + FileIndex += numBytes; + + return numBytes; + } + + int BytesAvailable() + { + return (FileSize - FileIndex); + } + + int Seek(int offset, int origin = Seek_Set) + { + switch (origin) + { + case Seek_Set : FileIndex = offset; break; + case Seek_Cur : FileIndex += offset; break; + case Seek_End : FileIndex = FileSize - offset; break; + } + + return FileIndex; + } + + int64_t LSeek(int64_t offset, int origin = Seek_Set) + { + return (int64_t) Seek((int) offset, origin); + } + +public: + + MemoryFile (const String& fileName, const uint8_t *pBuffer, int buffSize) + : FilePath(fileName) + { + FileData = pBuffer; + FileSize = buffSize; + FileIndex = 0; + Valid = (!fileName.IsEmpty() && pBuffer && buffSize > 0) ? true : false; + } + + // pfileName should be encoded as UTF-8 to support international file names. + MemoryFile (const char* pfileName, const uint8_t *pBuffer, int buffSize) + : FilePath(pfileName) + { + FileData = pBuffer; + FileSize = buffSize; + FileIndex = 0; + Valid = (pfileName && pBuffer && buffSize > 0) ? true : false; + } +private: + + String FilePath; + const uint8_t *FileData; + int FileSize; + int FileIndex; + bool Valid; +}; + + +// ***** Global path helpers + +// Find trailing short filename in a path. +const char* OVR_CDECL GetShortFilename(const char* purl); + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_FileFILE.cpp b/LibOVRKernel/Src/Kernel/OVR_FileFILE.cpp new file mode 100644 index 0000000..2bb2057 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_FileFILE.cpp @@ -0,0 +1,608 @@ +/************************************************************************** + +Filename : OVR_FileFILE.cpp +Content : File wrapper class implementation (Win32) + +Created : April 5, 1999 +Authors : Michael Antonov + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +**************************************************************************/ + +#define GFILE_CXX + +#include "OVR_Types.h" +#include "OVR_Log.h" + +// Standard C library (Captain Obvious guarantees!) +#include <stdio.h> +#ifndef OVR_OS_WINCE +#include <sys/stat.h> +#endif + +#include "OVR_SysFile.h" + +#ifndef OVR_OS_WINCE +#include <errno.h> +#endif + +namespace OVR { + +// ***** File interface + +// ***** FILEFile - C streams file + +static int SFerror () +{ + if (errno == ENOENT) + return FileConstants::Error_FileNotFound; + else if (errno == EACCES || errno == EPERM) + return FileConstants::Error_Access; + else if (errno == ENOSPC) + return FileConstants::Error_DiskFull; + else + return FileConstants::Error_IOError; +}; + +#if defined(OVR_OS_WIN32) +#include "OVR_Win32_IncludeWindows.h" +// A simple helper class to disable/enable system error mode, if necessary +// Disabling happens conditionally only if a drive name is involved +class SysErrorModeDisabler +{ + BOOL Disabled; + UINT OldMode; +public: + SysErrorModeDisabler(const char* pfileName) + { + if (pfileName && (pfileName[0]!=0) && pfileName[1]==':') + { + Disabled = TRUE; + OldMode = ::SetErrorMode(SEM_FAILCRITICALERRORS); + } + else + { + Disabled = 0; + OldMode = 0; + } + } + + ~SysErrorModeDisabler() + { + if (Disabled) + ::SetErrorMode(OldMode); + } +}; +#else +class SysErrorModeDisabler +{ +public: + SysErrorModeDisabler(const char* pfileName) { OVR_UNUSED(pfileName); } +}; +#endif // OVR_OS_WIN32 + + +// This macro enables verification of I/O results after seeks against a pre-loaded +// full file buffer copy. This is generally not necessary, but can been used to debug +// memory corruptions; we've seen this fail due to EAX2/DirectSound corrupting memory +// under FMOD with XP64 (32-bit) and Realtek HA Audio driver. +//#define GFILE_VERIFY_SEEK_ERRORS + + +// This is the simplest possible file implementation, it wraps around the descriptor +// This file is delegated to by SysFile. + +class FILEFile : public File +{ +protected: + + // Allocated filename + String FileName; + + // File handle & open mode + bool Opened; + FILE* fs; + int OpenFlags; + // Error code for last request + int ErrorCode; + + int LastOp; + +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + uint8_t* pFileTestBuffer; + unsigned FileTestLength; + unsigned TestPos; // File pointer position during tests. +#endif + +public: + + FILEFile() : + FileName(), + Opened(false), + fs(NULL), + OpenFlags(0), + ErrorCode(0), + LastOp(0) + #ifdef OVR_FILE_VERIFY_SEEK_ERRORS + ,pFileTestBuffer(NULL) + ,FileTestLength(0) + ,TestPos(0) + #endif + { + } + + // Initialize file by opening it + FILEFile(const String& fileName, int flags, int Mode); + + // The 'pfileName' should be encoded as UTF-8 to support international file names. + FILEFile(const char* pfileName, int flags, int Mode); + + ~FILEFile() + { + if (Opened) + Close(); + } + + virtual const char* GetFilePath(); + + // ** File Information + virtual bool IsValid(); + virtual bool IsWritable(); + + // Return position / file size + virtual int Tell(); + virtual int64_t LTell(); + virtual int GetLength(); + virtual int64_t LGetLength(); + +// virtual bool Stat(FileStats *pfs); + virtual int GetErrorCode(); + + // ** Stream implementation & I/O + virtual int Write(const uint8_t *pbuffer, int numBytes); + virtual int Read(uint8_t *pbuffer, int numBytes); + virtual int SkipBytes(int numBytes); + virtual int BytesAvailable(); + virtual bool Flush(); + virtual int Seek(int offset, int origin); + virtual int64_t LSeek(int64_t offset, int origin); + + virtual int CopyFromStream(File *pStream, int byteSize); + virtual bool Close(); +private: + void init(); +}; + + +// Initialize file by opening it +FILEFile::FILEFile(const String& fileName, int flags, int mode) + : FileName(fileName), OpenFlags(flags) +{ + OVR_UNUSED(mode); + init(); +} + +// The 'pfileName' should be encoded as UTF-8 to support international file names. +FILEFile::FILEFile(const char* pfileName, int flags, int mode) + : FileName(pfileName), OpenFlags(flags) +{ + OVR_UNUSED(mode); + init(); +} + +void FILEFile::init() +{ + // Open mode for file's open + const char *omode = "rb"; + + if (OpenFlags & Open_Truncate) + { + if (OpenFlags & Open_Read) + omode = "w+b"; + else + omode = "wb"; + } + else if (OpenFlags & Open_Create) + { + if (OpenFlags & Open_Read) + omode = "a+b"; + else + omode = "ab"; + } + else if (OpenFlags & Open_Write) + omode = "r+b"; + +#if defined(OVR_OS_MS) + SysErrorModeDisabler disabler(FileName.ToCStr()); +#endif + +#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) + wchar_t womode[16]; + wchar_t *pwFileName = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(FileName.ToCStr())+1) * sizeof(wchar_t)); + UTF8Util::DecodeString(pwFileName, FileName.ToCStr()); + OVR_ASSERT(strlen(omode) < sizeof(womode)/sizeof(womode[0])); + UTF8Util::DecodeString(womode, omode); + _wfopen_s(&fs, pwFileName, womode); + OVR_FREE(pwFileName); +#else + fs = fopen(FileName.ToCStr(), omode); +#endif + if (fs) + rewind (fs); + Opened = (fs != NULL); + // Set error code + if (!Opened) + ErrorCode = SFerror(); + else + { + // If we are testing file seek correctness, pre-load the entire file so + // that we can do comparison tests later. +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + TestPos = 0; + fseek(fs, 0, SEEK_END); + FileTestLength = ftell(fs); + fseek(fs, 0, SEEK_SET); + pFileTestBuffer = (uint8_t*)OVR_ALLOC(FileTestLength); + if (pFileTestBuffer) + { + OVR_ASSERT(FileTestLength == (unsigned)Read(pFileTestBuffer, FileTestLength)); + Seek(0, Seek_Set); + } +#endif + + ErrorCode = 0; + } + LastOp = 0; +} + + +const char* FILEFile::GetFilePath() +{ + return FileName.ToCStr(); +} + + +// ** File Information +bool FILEFile::IsValid() +{ + return Opened; +} +bool FILEFile::IsWritable() +{ + return IsValid() && (OpenFlags&Open_Write); +} +/* +bool FILEFile::IsRecoverable() +{ + return IsValid() && ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC); +} +*/ + +// Return position / file size +int FILEFile::Tell() +{ + int pos = (int)ftell (fs); + if (pos < 0) + ErrorCode = SFerror(); + return pos; +} + +int64_t FILEFile::LTell() +{ + int64_t pos = ftell(fs); + if (pos < 0) + ErrorCode = SFerror(); + return pos; +} + +int FILEFile::GetLength() +{ + int pos = Tell(); + if (pos >= 0) + { + Seek (0, Seek_End); + int size = Tell(); + Seek (pos, Seek_Set); + return size; + } + return -1; +} +int64_t FILEFile::LGetLength() +{ + int64_t pos = LTell(); + if (pos >= 0) + { + LSeek (0, Seek_End); + int64_t size = LTell(); + LSeek (pos, Seek_Set); + return size; + } + return -1; +} + +int FILEFile::GetErrorCode() +{ + return ErrorCode; +} + +// ** Stream implementation & I/O +int FILEFile::Write(const uint8_t *pbuffer, int numBytes) +{ + if (LastOp && LastOp != Open_Write) + fflush(fs); + LastOp = Open_Write; + int written = (int) fwrite(pbuffer, 1, numBytes, fs); + if (written < numBytes) + ErrorCode = SFerror(); + +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + if (written > 0) + TestPos += written; +#endif + + return written; +} + +int FILEFile::Read(uint8_t *pbuffer, int numBytes) +{ + if (LastOp && LastOp != Open_Read) + fflush(fs); + LastOp = Open_Read; + int read = (int) fread(pbuffer, 1, numBytes, fs); + if (read < numBytes) + ErrorCode = SFerror(); + +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + if (read > 0) + { + // Read-in data must match our pre-loaded buffer data! + uint8_t* pcompareBuffer = pFileTestBuffer + TestPos; + for (int i=0; i< read; i++) + { + OVR_ASSERT(pcompareBuffer[i] == pbuffer[i]); + } + + //OVR_ASSERT(!memcmp(pFileTestBuffer + TestPos, pbuffer, read)); + TestPos += read; + OVR_ASSERT(ftell(fs) == (int)TestPos); + } +#endif + + return read; +} + +// Seeks ahead to skip bytes +int FILEFile::SkipBytes(int numBytes) +{ + int64_t pos = LTell(); + int64_t newPos = LSeek(numBytes, Seek_Cur); + + // Return -1 for major error + if ((pos==-1) || (newPos==-1)) + { + return -1; + } + //ErrorCode = ((NewPos-Pos)<numBytes) ? errno : 0; + + return int (newPos-(int)pos); +} + +// Return # of bytes till EOF +int FILEFile::BytesAvailable() +{ + int64_t pos = LTell(); + int64_t endPos = LGetLength(); + + // Return -1 for major error + if ((pos==-1) || (endPos==-1)) + { + ErrorCode = SFerror(); + return 0; + } + else + ErrorCode = 0; + + return int (endPos-(int)pos); +} + +// Flush file contents +bool FILEFile::Flush() +{ + return !fflush(fs); +} + +int FILEFile::Seek(int offset, int origin) +{ + int newOrigin = 0; + switch(origin) + { + case Seek_Set: newOrigin = SEEK_SET; break; + case Seek_Cur: newOrigin = SEEK_CUR; break; + case Seek_End: newOrigin = SEEK_END; break; + } + + if (newOrigin == SEEK_SET && offset == Tell()) + return Tell(); + + if (fseek (fs, offset, newOrigin)) + { +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + OVR_ASSERT(0); +#endif + return -1; + } + +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + // Track file position after seeks for read verification later. + switch(origin) + { + case Seek_Set: TestPos = offset; break; + case Seek_Cur: TestPos += offset; break; + case Seek_End: TestPos = FileTestLength + offset; break; + } + OVR_ASSERT((int)TestPos == Tell()); +#endif + + return (int)Tell(); +} + +int64_t FILEFile::LSeek(int64_t offset, int origin) +{ + return Seek((int)offset,origin); +} + +int FILEFile::CopyFromStream(File *pstream, int byteSize) +{ + uint8_t* buff = new uint8_t[0x4000]; + int count = 0; + int szRequest, szRead, szWritten; + + while (byteSize) + { + szRequest = (byteSize > int(sizeof(buff))) ? int(sizeof(buff)) : byteSize; + + szRead = pstream->Read(buff, szRequest); + szWritten = 0; + if (szRead > 0) + szWritten = Write(buff, szRead); + + count += szWritten; + byteSize -= szWritten; + if (szWritten < szRequest) + break; + } + + delete[] buff; + + return count; +} + + +bool FILEFile::Close() +{ +#ifdef OVR_FILE_VERIFY_SEEK_ERRORS + if (pFileTestBuffer) + { + OVR_FREE(pFileTestBuffer); + pFileTestBuffer = 0; + FileTestLength = 0; + } +#endif + + bool closeRet = !fclose(fs); + + if (!closeRet) + { + ErrorCode = SFerror(); + return 0; + } + else + { + Opened = 0; + fs = 0; + ErrorCode = 0; + } + + // Handle safe truncate + /* + if ((OpenFlags & OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC) + { + // Delete original file (if it existed) + DWORD oldAttributes = FileUtilWin32::GetFileAttributes(FileName); + if (oldAttributes!=0xFFFFFFFF) + if (!FileUtilWin32::DeleteFile(FileName)) + { + // Try to remove the readonly attribute + FileUtilWin32::SetFileAttributes(FileName, oldAttributes & (~FILE_ATTRIBUTE_READONLY) ); + // And delete the file again + if (!FileUtilWin32::DeleteFile(FileName)) + return 0; + } + + // Rename temp file to real filename + if (!FileUtilWin32::MoveFile(TempName, FileName)) + { + //ErrorCode = errno; + return 0; + } + } + */ + return 1; +} + +/* +bool FILEFile::CloseCancel() +{ + bool closeRet = (bool)::CloseHandle(fd); + + if (!closeRet) + { + //ErrorCode = errno; + return 0; + } + else + { + Opened = 0; + fd = INVALID_HANDLE_VALUE; + ErrorCode = 0; + } + + // Handle safe truncate (delete tmp file, leave original unchanged) + if ((OpenFlags&OVR_FO_SAFETRUNC) == OVR_FO_SAFETRUNC) + if (!FileUtilWin32::DeleteFile(TempName)) + { + //ErrorCode = errno; + return 0; + } + return 1; +} +*/ + +Ptr<File> FileFILEOpen(const String& path, int flags, int mode) +{ + Ptr<File> result = *new FILEFile(path, flags, mode); + return result; +} + +// Helper function: obtain file information time. +bool SysFile::GetFileStat(FileStat* pfileStat, const String& path) +{ +#if defined(OVR_OS_MS) + // 64-bit implementation on Windows. + struct __stat64 fileStat; + // Stat returns 0 for success. + wchar_t *pwpath = (wchar_t*)OVR_ALLOC((UTF8Util::GetLength(path.ToCStr())+1)*sizeof(wchar_t)); + UTF8Util::DecodeString(pwpath, path.ToCStr()); + + int ret = _wstat64(pwpath, &fileStat); + OVR_FREE(pwpath); + if (ret) return false; +#else + struct stat fileStat; + // Stat returns 0 for success. + if (stat(path, &fileStat) != 0) + return false; +#endif + pfileStat->AccessTime = fileStat.st_atime; + pfileStat->ModifyTime = fileStat.st_mtime; + pfileStat->FileSize = fileStat.st_size; + return true; +} + +} // Namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_Hash.h b/LibOVRKernel/Src/Kernel/OVR_Hash.h new file mode 100644 index 0000000..06d0add --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Hash.h @@ -0,0 +1,1306 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_Hash.h +Content : Template hash-table/set implementation +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Hash_h +#define OVR_Hash_h + +#include "OVR_ContainerAllocator.h" +#include "OVR_Alg.h" + +// 'new' operator is redefined/used in this file. +#undef new + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** Hash Table Implementation + +// HastSet and Hash. +// +// Hash table, linear probing, internal chaining. One interesting/nice thing +// about this implementation is that the table itself is a flat chunk of memory +// containing no pointers, only relative indices. If the key and value types +// of the Hash contain no pointers, then the Hash can be serialized using raw IO. +// +// Never shrinks, unless you explicitly Clear() it. Expands on +// demand, though. For best results, if you know roughly how big your +// table will be, default it to that size when you create it. +// +// Key usability feature: +// +// 1. Allows node hash values to either be cached or not. +// +// 2. Allows for alternative keys with methods such as GetAlt(). Handy +// if you need to search nodes by their components; no need to create +// temporary nodes. +// + + +// *** Hash functors: +// +// IdentityHash - use when the key is already a good hash +// HFixedSizeHash - general hash based on object's in-memory representation. + + +// Hash is just the input value; can use this for integer-indexed hash tables. +template<class C> +class IdentityHash +{ +public: + size_t operator()(const C& data) const + { return (size_t) data; } +}; + +// Computes a hash of an object's representation. +template<class C> +class FixedSizeHash +{ +public: + // Alternative: "sdbm" hash function, suggested at same web page + // above, http::/www.cs.yorku.ca/~oz/hash.html + // This is somewhat slower then Bernstein, but it works way better than the above + // hash function for hashing large numbers of 32-bit ints. + static OVR_FORCE_INLINE size_t SDBM_Hash(const void* data_in, size_t size, size_t seed = 5381) + { + const uint8_t* data = (const uint8_t*) data_in; + size_t h = seed; + while (size > 0) + { + --size; + #ifndef __clang_analyzer__ // It mistakenly thinks data is garbage. + h = (h << 16) + (h << 6) - h + (size_t)data[size]; + #endif + } + return h; + } + + size_t operator()(const C& data) const + { + const unsigned char* p = (const unsigned char*) &data; + const size_t size = sizeof(C); + + return SDBM_Hash(p, size); + } +}; + + + +// *** HashsetEntry Entry types. + +// Compact hash table Entry type that re-computes hash keys during hash traversal. +// Good to use if the hash function is cheap or the hash value is already cached in C. +template<class C, class HashF> +class HashsetEntry +{ +public: + // Internal chaining for collisions. + intptr_t NextInChain; + C Value; + + HashsetEntry() + : NextInChain(-2) { } + HashsetEntry(const HashsetEntry& e) + : NextInChain(e.NextInChain), Value(e.Value) { } + HashsetEntry(const C& key, intptr_t next) + : NextInChain(next), Value(key) { } + + bool IsEmpty() const { return NextInChain == -2; } + bool IsEndOfChain() const { return NextInChain == -1; } + + // Cached hash value access - can be optimized bu storing hash locally. + // Mask value only needs to be used if SetCachedHash is not implemented. + size_t GetCachedHash(size_t maskValue) const { return HashF()(Value) & maskValue; } + void SetCachedHash(size_t) {} + + void Clear() + { + Value.~C(); // placement delete + NextInChain = -2; + } + // Free is only used from dtor of hash; Clear is used during regular operations: + // assignment, hash reallocations, value reassignments, so on. + void Free() { Clear(); } +}; + +// Hash table Entry type that caches the Entry hash value for nodes, so that it +// does not need to be re-computed during access. +template<class C, class HashF> +class HashsetCachedEntry +{ +public: + // Internal chaining for collisions. + intptr_t NextInChain; + size_t HashValue; + C Value; + + HashsetCachedEntry() + : NextInChain(-2) { } + HashsetCachedEntry(const HashsetCachedEntry& e) + : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { } + HashsetCachedEntry(const C& key, intptr_t next) + : NextInChain(next), Value(key) { } + + bool IsEmpty() const { return NextInChain == -2; } + bool IsEndOfChain() const { return NextInChain == -1; } + + // Cached hash value access - can be optimized bu storing hash locally. + // Mask value only needs to be used if SetCachedHash is not implemented. + size_t GetCachedHash(size_t maskValue) const { OVR_UNUSED(maskValue); return HashValue; } + void SetCachedHash(size_t hashValue) { HashValue = hashValue; } + + void Clear() + { + Value.~C(); + NextInChain = -2; + } + // Free is only used from dtor of hash; Clear is used during regular operations: + // assignment, hash reallocations, value reassignments, so on. + void Free() { Clear(); } +}; + + +//----------------------------------------------------------------------------------- +// *** HashSet implementation - relies on either cached or regular entries. +// +// Use: Entry = HashsetCachedEntry<C, HashF> if hashes are expensive to +// compute and thus need caching in entries. +// Entry = HashsetEntry<C, HashF> if hashes are already externally cached. +// +template<class C, class HashF = FixedSizeHash<C>, + class AltHashF = HashF, + class Allocator = ContainerAllocator<C>, + class Entry = HashsetCachedEntry<C, HashF> > +class HashSetBase +{ + enum { HashMinSize = 8 }; + +public: + OVR_MEMORY_REDEFINE_NEW(HashSetBase) + + typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> SelfType; + + HashSetBase() : pTable(NULL) { } + HashSetBase(int sizeHint) : pTable(NULL) { SetCapacity(sizeHint); } + HashSetBase(const SelfType& src) : pTable(NULL) { Assign(src); } + + ~HashSetBase() + { + if (pTable) + { + // Delete the entries. + for (size_t i = 0, n = pTable->SizeMask; i <= n; i++) + { + Entry* e = &E(i); + if (!e->IsEmpty()) + e->Free(); + } + + Allocator::Free(pTable); + pTable = NULL; + } + } + + + void Assign(const SelfType& src) + { + Clear(); + if (src.IsEmpty() == false) + { + SetCapacity(src.GetSize()); + + for (ConstIterator it = src.Begin(); it != src.End(); ++it) + { + Add(*it); + } + } + } + + + // Remove all entries from the HashSet table. + void Clear() + { + if (pTable) + { + // Delete the entries. + for (size_t i = 0, n = pTable->SizeMask; i <= n; i++) + { + Entry* e = &E(i); + if (!e->IsEmpty()) + e->Clear(); + } + + Allocator::Free(pTable); + pTable = NULL; + } + } + + // Returns true if the HashSet is empty. + bool IsEmpty() const + { + return pTable == NULL || pTable->EntryCount == 0; + } + + + // Set a new or existing value under the key, to the value. + // Pass a different class of 'key' so that assignment reference object + // can be passed instead of the actual object. + template<class CRef> + void Set(const CRef& key) + { + size_t hashValue = HashF()(key); + intptr_t index = (intptr_t)-1; + + if (pTable != NULL) + index = findIndexCore(key, hashValue & pTable->SizeMask); + + if (index >= 0) + { + E(index).Value = key; + } + else + { + // Entry under key doesn't exist. + add(key, hashValue); + } + } + + template<class CRef> + inline void Add(const CRef& key) + { + size_t hashValue = HashF()(key); + add(key, hashValue); + } + + // Remove by alternative key. + template<class K> + void RemoveAlt(const K& key) + { + if (pTable == NULL) + return; + + size_t hashValue = AltHashF()(key); + intptr_t index = hashValue & pTable->SizeMask; + + Entry* e = &E(index); + + // If empty node or occupied by collider, we have nothing to remove. + if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != (size_t)index)) + return; + + // Save index + intptr_t naturalIndex = index; + intptr_t prevIndex = -1; + + while ((e->GetCachedHash(pTable->SizeMask) != (size_t)naturalIndex) || !(e->Value == key)) + { + // Keep looking through the chain. + prevIndex = index; + index = e->NextInChain; + if (index == -1) + return; // End of chain, item not found + e = &E(index); + } + + // Found it - our item is at index + if (naturalIndex == index) + { + // If we have a follower, move it to us + if (!e->IsEndOfChain()) + { + Entry* enext = &E(e->NextInChain); + e->Clear(); + new (e) Entry(*enext); + // Point us to the follower's cell that will be cleared + e = enext; + } + } + else + { + // We are not at natural index, so deal with the prev items next index + E(prevIndex).NextInChain = e->NextInChain; + } + + // Clear us, of the follower cell that was moved. + e->Clear(); + pTable->EntryCount --; + // Should we check the size to condense hash? ... + } + + // Remove by main key. + template<class CRef> + void Remove(const CRef& key) + { + RemoveAlt(key); + } + + // Retrieve the pointer to a value under the given key. + // - If there's no value under the key, then return NULL. + // - If there is a value, return the pointer. + template<class K> + C* Get(const K& key) + { + intptr_t index = findIndex(key); + if (index >= 0) + return &E(index).Value; + return 0; + } + + template<class K> + const C* Get(const K& key) const + { + intptr_t index = findIndex(key); + if (index >= 0) + return &E(index).Value; + return 0; + } + + // Alternative key versions of Get. Used by Hash. + template<class K> + const C* GetAlt(const K& key) const + { + intptr_t index = findIndexAlt(key); + if (index >= 0) + return &E(index).Value; + return 0; + } + + template<class K> + C* GetAlt(const K& key) + { + intptr_t index = findIndexAlt(key); + if (index >= 0) + return &E(index).Value; + return 0; + } + + template<class K> + bool GetAlt(const K& key, C* pval) const + { + intptr_t index = findIndexAlt(key); + if (index >= 0) + { + if (pval) + *pval = E(index).Value; + return true; + } + return false; + } + + + size_t GetSize() const + { + return pTable == NULL ? 0 : (size_t)pTable->EntryCount; + } + int GetSizeI() const { return (int)GetSize(); } + + + // Resize the HashSet table to fit one more Entry. Often this + // doesn't involve any action. + void CheckExpand() + { + if (pTable == NULL) + { + // Initial creation of table. Make a minimum-sized table. + setRawCapacity(HashMinSize); + } + else if (pTable->EntryCount * 5 > (pTable->SizeMask + 1) * 4) + { + // pTable is more than 5/4 ths full. Expand. + setRawCapacity((pTable->SizeMask + 1) * 2); + } + } + + // Hint the bucket count to >= n. + void Resize(size_t n) + { + // Not really sure what this means in relation to + // STLport's hash_map... they say they "increase the + // bucket count to at least n" -- but does that mean + // their real capacity after Resize(n) is more like + // n*2 (since they do linked-list chaining within + // buckets?). + SetCapacity(n); + } + + // Size the HashSet so that it can comfortably contain the given + // number of elements. If the HashSet already contains more + // elements than newSize, then this may be a no-op. + void SetCapacity(size_t newSize) + { + size_t newRawSize = (newSize * 5) / 4; + if (newRawSize <= GetSize()) + return; + setRawCapacity(newRawSize); + } + + // Disable inappropriate 'operator ->' warning on MSVC6. +#ifdef OVR_CC_MSVC +#if (OVR_CC_MSVC < 1300) +# pragma warning(disable : 4284) +#endif +#endif + + // Iterator API, like STL. + struct ConstIterator + { + const C& operator * () const + { + OVR_ASSERT(Index >= 0 && Index <= (intptr_t)pHash->pTable->SizeMask); + return pHash->E(Index).Value; + } + + const C* operator -> () const + { + OVR_ASSERT(Index >= 0 && Index <= (intptr_t)pHash->pTable->SizeMask); + return &pHash->E(Index).Value; + } + + void operator ++ () + { + // Find next non-empty Entry. + if (Index <= (intptr_t)pHash->pTable->SizeMask) + { + Index++; + while ((size_t)Index <= pHash->pTable->SizeMask && + pHash->E(Index).IsEmpty()) + { + Index++; + } + } + } + + bool operator == (const ConstIterator& it) const + { + if (IsEnd() && it.IsEnd()) + { + return true; + } + else + { + return (pHash == it.pHash) && (Index == it.Index); + } + } + + bool operator != (const ConstIterator& it) const + { + return ! (*this == it); + } + + + bool IsEnd() const + { + return (pHash == NULL) || + (pHash->pTable == NULL) || + (Index > (intptr_t)pHash->pTable->SizeMask); + } + + ConstIterator() + : pHash(NULL), Index(0) + { } + + public: + // Constructor was intentionally made public to allow create + // iterator with arbitrary index. + ConstIterator(const SelfType* h, intptr_t index) + : pHash(h), Index(index) + { } + + const SelfType* GetContainer() const + { + return pHash; + } + intptr_t GetIndex() const + { + return Index; + } + + protected: + friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>; + + const SelfType* pHash; + intptr_t Index; + }; + + friend struct ConstIterator; + + + // Non-const Iterator; Get most of it from ConstIterator. + struct Iterator : public ConstIterator + { + // Allow non-const access to entries. + C& operator*() const + { + OVR_ASSERT((ConstIterator::pHash) && ConstIterator::pHash->pTable && (ConstIterator::Index >= 0) && (ConstIterator::Index <= (intptr_t)ConstIterator::pHash->pTable->SizeMask)); + return const_cast<SelfType*>(ConstIterator::pHash)->E(ConstIterator::Index).Value; + } + + C* operator->() const + { + return &(operator*()); + } + + Iterator() + : ConstIterator(NULL, 0) + { } + + // Removes current element from Hash + void Remove() + { + RemoveAlt(operator*()); + } + + template <class K> + void RemoveAlt(const K& key) + { + SelfType* phash = const_cast<SelfType*>(ConstIterator::pHash); + //Entry* ee = &phash->E(ConstIterator::Index); + //const C& key = ee->Value; + + size_t hashValue = AltHashF()(key); + intptr_t index = hashValue & phash->pTable->SizeMask; + + Entry* e = &phash->E(index); + + // If empty node or occupied by collider, we have nothing to remove. + if (e->IsEmpty() || (e->GetCachedHash(phash->pTable->SizeMask) != (size_t)index)) + return; + + // Save index + intptr_t naturalIndex = index; + intptr_t prevIndex = -1; + + while ((e->GetCachedHash(phash->pTable->SizeMask) != (size_t)naturalIndex) || !(e->Value == key)) + { + // Keep looking through the chain. + prevIndex = index; + index = e->NextInChain; + if (index == -1) + return; // End of chain, item not found + e = &phash->E(index); + } + + if (index == (intptr_t)ConstIterator::Index) + { + // Found it - our item is at index + if (naturalIndex == index) + { + // If we have a follower, move it to us + if (!e->IsEndOfChain()) + { + Entry* enext = &phash->E(e->NextInChain); + e->Clear(); + new (e) Entry(*enext); + // Point us to the follower's cell that will be cleared + e = enext; + --ConstIterator::Index; + } + } + else + { + // We are not at natural index, so deal with the prev items next index + phash->E(prevIndex).NextInChain = e->NextInChain; + } + + // Clear us, of the follower cell that was moved. + e->Clear(); + phash->pTable->EntryCount --; + } + else + OVR_ASSERT(0); //? + } + + private: + friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>; + + Iterator(SelfType* h, intptr_t i0) + : ConstIterator(h, i0) + { } + }; + + friend struct Iterator; + + Iterator Begin() + { + if (pTable == 0) + return Iterator(NULL, 0); + + // Scan till we hit the First valid Entry. + size_t i0 = 0; + while (i0 <= pTable->SizeMask && E(i0).IsEmpty()) + { + i0++; + } + return Iterator(this, i0); + } + Iterator End() { return Iterator(NULL, 0); } + + ConstIterator Begin() const { return const_cast<SelfType*>(this)->Begin(); } + ConstIterator End() const { return const_cast<SelfType*>(this)->End(); } + + template<class K> + Iterator Find(const K& key) + { + intptr_t index = findIndex(key); + if (index >= 0) + return Iterator(this, index); + return Iterator(NULL, 0); + } + + template<class K> + Iterator FindAlt(const K& key) + { + intptr_t index = findIndexAlt(key); + if (index >= 0) + return Iterator(this, index); + return Iterator(NULL, 0); + } + + template<class K> + ConstIterator Find(const K& key) const { return const_cast<SelfType*>(this)->Find(key); } + + template<class K> + ConstIterator FindAlt(const K& key) const { return const_cast<SelfType*>(this)->FindAlt(key); } + +private: + // Find the index of the matching Entry. If no match, then return -1. + template<class K> + intptr_t findIndex(const K& key) const + { + if (pTable == NULL) + return -1; + size_t hashValue = HashF()(key) & pTable->SizeMask; + return findIndexCore(key, hashValue); + } + + template<class K> + intptr_t findIndexAlt(const K& key) const + { + if (pTable == NULL) + return -1; + size_t hashValue = AltHashF()(key) & pTable->SizeMask; + return findIndexCore(key, hashValue); + } + + // Find the index of the matching Entry. If no match, then return -1. + template<class K> + intptr_t findIndexCore(const K& key, size_t hashValue) const + { + // Table must exist. + OVR_ASSERT(pTable != 0); + // Hash key must be 'and-ed' by the caller. + OVR_ASSERT((hashValue & ~pTable->SizeMask) == 0); + + size_t index = hashValue; + const Entry* e = &E(index); + + // If empty or occupied by a collider, not found. + if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != index)) + return -1; + + while(1) + { + OVR_ASSERT(e->GetCachedHash(pTable->SizeMask) == hashValue); + + if (e->GetCachedHash(pTable->SizeMask) == hashValue && e->Value == key) + { + // Found it. + return index; + } + // Values can not be equal at this point. + // That would mean that the hash key for the same value differs. + OVR_ASSERT(!(e->Value == key)); + + // Keep looking through the chain. + index = e->NextInChain; + if (index == (size_t)-1) + break; // end of chain + + e = &E(index); + OVR_ASSERT(!e->IsEmpty()); + } + return -1; + } + + + // Add a new value to the HashSet table, under the specified key. + template<class CRef> + void add(const CRef& key, size_t hashValue) + { + CheckExpand(); + hashValue &= pTable->SizeMask; + + pTable->EntryCount++; + + intptr_t index = hashValue; + Entry* naturalEntry = &(E(index)); + + if (naturalEntry->IsEmpty()) + { + // Put the new Entry in. + new (naturalEntry) Entry(key, -1); + } + else + { + // Find a blank spot. + intptr_t blankIndex = index; + do { + blankIndex = (blankIndex + 1) & pTable->SizeMask; + } while(!E(blankIndex).IsEmpty()); + + Entry* blankEntry = &E(blankIndex); + + if (naturalEntry->GetCachedHash(pTable->SizeMask) == (size_t)index) + { + // Collision. Link into this chain. + + // Move existing list head. + new (blankEntry) Entry(*naturalEntry); // placement new, copy ctor + + // Put the new info in the natural Entry. + naturalEntry->Value = key; + naturalEntry->NextInChain = blankIndex; + } + else + { + // Existing Entry does not naturally + // belong in this slot. Existing + // Entry must be moved. + + // Find natural location of collided element (i.e. root of chain) + intptr_t collidedIndex = naturalEntry->GetCachedHash(pTable->SizeMask); + OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (intptr_t)pTable->SizeMask); + for (;;) + { + Entry* e = &E(collidedIndex); + if (e->NextInChain == index) + { + // Here's where we need to splice. + new (blankEntry) Entry(*naturalEntry); + e->NextInChain = blankIndex; + break; + } + collidedIndex = e->NextInChain; + OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (intptr_t)pTable->SizeMask); + } + + // Put the new data in the natural Entry. + naturalEntry->Value = key; + naturalEntry->NextInChain = -1; + } + } + + // Record hash value: has effect only if cached node is used. + naturalEntry->SetCachedHash(hashValue); + } + + // Index access helpers. + Entry& E(size_t index) + { + // Must have pTable and access needs to be within bounds. + OVR_ASSERT(index <= pTable->SizeMask); + return *(((Entry*) (pTable + 1)) + index); + } + const Entry& E(size_t index) const + { + OVR_ASSERT(index <= pTable->SizeMask); + return *(((Entry*) (pTable + 1)) + index); + } + + + // Resize the HashSet table to the given size (Rehash the + // contents of the current table). The arg is the number of + // HashSet table entries, not the number of elements we should + // actually contain (which will be less than this). + void setRawCapacity(size_t newSize) + { + if (newSize == 0) + { + // Special case. + Clear(); + return; + } + + // Minimum size; don't incur rehashing cost when expanding + // very small tables. Not that we perform this check before + // 'log2f' call to avoid fp exception with newSize == 1. + if (newSize < HashMinSize) + newSize = HashMinSize; + else + { + // Force newSize to be a power of two. + int bits = Alg::UpperBit(newSize-1) + 1; // Chop( Log2f((float)(newSize-1)) + 1); + OVR_ASSERT((size_t(1) << bits) >= newSize); + newSize = size_t(1) << bits; + } + + SelfType newHash; + newHash.pTable = (TableType*) + Allocator::Alloc( + sizeof(TableType) + sizeof(Entry) * newSize); + // Need to do something on alloc failure! + OVR_ASSERT(newHash.pTable); + + newHash.pTable->EntryCount = 0; + newHash.pTable->SizeMask = newSize - 1; + size_t i, n; + + // Mark all entries as empty. + for (i = 0; i < newSize; i++) + newHash.E(i).NextInChain = -2; + + // Copy stuff to newHash + if (pTable) + { + for (i = 0, n = pTable->SizeMask; i <= n; i++) + { + Entry* e = &E(i); + if (e->IsEmpty() == false) + { + // Insert old Entry into new HashSet. + newHash.Add(e->Value); + // placement delete of old element + e->Clear(); + } + } + + // Delete our old data buffer. + Allocator::Free(pTable); + } + + // Steal newHash's data. + pTable = newHash.pTable; + newHash.pTable = NULL; + } + + struct TableType + { + size_t EntryCount; + size_t SizeMask; + // Entry array follows this structure + // in memory. + }; + TableType* pTable; +}; + + + +//----------------------------------------------------------------------------------- +template<class C, class HashF = FixedSizeHash<C>, + class AltHashF = HashF, + class Allocator = ContainerAllocator<C>, + class Entry = HashsetCachedEntry<C, HashF> > +class HashSet : public HashSetBase<C, HashF, AltHashF, Allocator, Entry> +{ +public: + typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> BaseType; + typedef HashSet<C, HashF, AltHashF, Allocator, Entry> SelfType; + + HashSet() { } + HashSet(int sizeHint) : BaseType(sizeHint) { } + HashSet(const SelfType& src) : BaseType(src) { } + ~HashSet() { } + + void operator = (const SelfType& src) { BaseType::Assign(src); } + + // Set a new or existing value under the key, to the value. + // Pass a different class of 'key' so that assignment reference object + // can be passed instead of the actual object. + template<class CRef> + void Set(const CRef& key) + { + BaseType::Set(key); + } + + template<class CRef> + inline void Add(const CRef& key) + { + BaseType::Add(key); + } + + // Hint the bucket count to >= n. + void Resize(size_t n) + { + BaseType::SetCapacity(n); + } + + // Size the HashSet so that it can comfortably contain the given + // number of elements. If the HashSet already contains more + // elements than newSize, then this may be a no-op. + void SetCapacity(size_t newSize) + { + BaseType::SetCapacity(newSize); + } + +}; + +// HashSet with uncached hash code; declared for convenience. +template<class C, class HashF = FixedSizeHash<C>, + class AltHashF = HashF, + class Allocator = ContainerAllocator<C> > +class HashSetUncached : public HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> > +{ +public: + + typedef HashSetUncached<C, HashF, AltHashF, Allocator> SelfType; + typedef HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> > BaseType; + + // Delegated constructors. + HashSetUncached() { } + HashSetUncached(int sizeHint) : BaseType(sizeHint) { } + HashSetUncached(const SelfType& src) : BaseType(src) { } + ~HashSetUncached() { } + + void operator = (const SelfType& src) + { + BaseType::operator = (src); + } +}; + + +//----------------------------------------------------------------------------------- +// ***** Hash hash table implementation + +// Node for Hash - necessary so that Hash can delegate its implementation +// to HashSet. +template<class C, class U, class HashF> +struct HashNode +{ + typedef HashNode<C, U, HashF> SelfType; + typedef C FirstType; + typedef U SecondType; + + C First; + U Second; + + // NodeRef is used to allow passing of elements into HashSet + // without using a temporary object. + struct NodeRef + { + const C* pFirst; + const U* pSecond; + + NodeRef(const C& f, const U& s) : pFirst(&f), pSecond(&s) { } + NodeRef(const NodeRef& src) : pFirst(src.pFirst), pSecond(src.pSecond) { } + + // Enable computation of ghash_node_hashf. + inline size_t GetHash() const { return HashF()(*pFirst); } + // Necessary conversion to allow HashNode::operator == to work. + operator const C& () const { return *pFirst; } + }; + + // Note: No default constructor is necessary. + HashNode(const HashNode& src) : First(src.First), Second(src.Second) { } + HashNode(const NodeRef& src) : First(*src.pFirst), Second(*src.pSecond) { } + void operator = (const NodeRef& src) { First = *src.pFirst; Second = *src.pSecond; } + + template<class K> + bool operator == (const K& src) const { return (First == src); } + + template<class K> + static size_t CalcHash(const K& data) { return HashF()(data); } + inline size_t GetHash() const { return HashF()(First); } + + // Hash functors used with this node. A separate functor is used for alternative + // key lookup so that it does not need to access the '.First' element. + struct NodeHashF + { + template<class K> + size_t operator()(const K& data) const { return data.GetHash(); } + }; + struct NodeAltHashF + { + template<class K> + size_t operator()(const K& data) const { return HashNode<C,U,HashF>::CalcHash(data); } + }; +}; + + + +// **** Extra hashset_entry types to allow NodeRef construction. + +// The big difference between the below types and the ones used in hash_set is that +// these allow initializing the node with 'typename C::NodeRef& keyRef', which +// is critical to avoid temporary node allocation on stack when using placement new. + +// Compact hash table Entry type that re-computes hash keys during hash traversal. +// Good to use if the hash function is cheap or the hash value is already cached in C. +template<class C, class HashF> +class HashsetNodeEntry +{ +public: + // Internal chaining for collisions. + intptr_t NextInChain; + C Value; + + HashsetNodeEntry() + : NextInChain(-2) { } + HashsetNodeEntry(const HashsetNodeEntry& e) + : NextInChain(e.NextInChain), Value(e.Value) { } + HashsetNodeEntry(const C& key, intptr_t next) + : NextInChain(next), Value(key) { } + HashsetNodeEntry(const typename C::NodeRef& keyRef, intptr_t next) + : NextInChain(next), Value(keyRef) { } + + bool IsEmpty() const { return NextInChain == -2; } + bool IsEndOfChain() const { return NextInChain == -1; } + size_t GetCachedHash(size_t maskValue) const { return HashF()(Value) & maskValue; } + void SetCachedHash(size_t hashValue) { OVR_UNUSED(hashValue); } + + void Clear() + { + Value.~C(); // placement delete + NextInChain = -2; + } + // Free is only used from dtor of hash; Clear is used during regular operations: + // assignment, hash reallocations, value reassignments, so on. + void Free() { Clear(); } +}; + +// Hash table Entry type that caches the Entry hash value for nodes, so that it +// does not need to be re-computed during access. +template<class C, class HashF> +class HashsetCachedNodeEntry +{ +public: + // Internal chaining for collisions. + intptr_t NextInChain; + size_t HashValue; + C Value; + + HashsetCachedNodeEntry() + : NextInChain(-2) { } + HashsetCachedNodeEntry(const HashsetCachedNodeEntry& e) + : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { } + HashsetCachedNodeEntry(const C& key, intptr_t next) + : NextInChain(next), Value(key) { } + HashsetCachedNodeEntry(const typename C::NodeRef& keyRef, intptr_t next) + : NextInChain(next), Value(keyRef) { } + + bool IsEmpty() const { return NextInChain == -2; } + bool IsEndOfChain() const { return NextInChain == -1; } + size_t GetCachedHash(size_t maskValue) const { OVR_UNUSED(maskValue); return HashValue; } + void SetCachedHash(size_t hashValue) { HashValue = hashValue; } + + void Clear() + { + Value.~C(); + NextInChain = -2; + } + // Free is only used from dtor of hash; Clear is used during regular operations: + // assignment, hash reallocations, value reassignments, so on. + void Free() { Clear(); } +}; + + +//----------------------------------------------------------------------------------- +template<class C, class U, + class HashF = FixedSizeHash<C>, + class Allocator = ContainerAllocator<C>, + class HashNode = OVR::HashNode<C,U,HashF>, + class Entry = HashsetCachedNodeEntry<HashNode, typename HashNode::NodeHashF>, + class Container = HashSet<HashNode, typename HashNode::NodeHashF, + typename HashNode::NodeAltHashF, Allocator, + Entry> > +class Hash +{ +public: + OVR_MEMORY_REDEFINE_NEW(Hash) + + // Types used for hash_set. + typedef U ValueType; + typedef Hash<C, U, HashF, Allocator, HashNode, Entry, Container> SelfType; + + // Actual hash table itself, implemented as hash_set. + Container mHash; + +public: + Hash() { } + Hash(int sizeHint) : mHash(sizeHint) { } + Hash(const SelfType& src) : mHash(src.mHash) { } + ~Hash() { } + + void operator = (const SelfType& src) { mHash = src.mHash; } + + // Remove all entries from the Hash table. + inline void Clear() { mHash.Clear(); } + // Returns true if the Hash is empty. + inline bool IsEmpty() const { return mHash.IsEmpty(); } + + // Access (set). + inline void Set(const C& key, const U& value) + { + typename HashNode::NodeRef e(key, value); + mHash.Set(e); + } + inline void Add(const C& key, const U& value) + { + typename HashNode::NodeRef e(key, value); + mHash.Add(e); + } + + // Removes an element by clearing its Entry. + inline void Remove(const C& key) + { + mHash.RemoveAlt(key); + } + template<class K> + inline void RemoveAlt(const K& key) + { + mHash.RemoveAlt(key); + } + + // Retrieve the value under the given key. + // - If there's no value under the key, then return false and leave *pvalue alone. + // - If there is a value, return true, and Set *Pvalue to the Entry's value. + // - If value == NULL, return true or false according to the presence of the key. + bool Get(const C& key, U* pvalue) const + { + const HashNode* p = mHash.GetAlt(key); + if (p) + { + if (pvalue) + *pvalue = p->Second; + return true; + } + return false; + } + + template<class K> + bool GetAlt(const K& key, U* pvalue) const + { + const HashNode* p = mHash.GetAlt(key); + if (p) + { + if (pvalue) + *pvalue = p->Second; + return true; + } + return false; + } + + // Retrieve the pointer to a value under the given key. + // - If there's no value under the key, then return NULL. + // - If there is a value, return the pointer. + inline U* Get(const C& key) + { + HashNode* p = mHash.GetAlt(key); + return p ? &p->Second : 0; + } + inline const U* Get(const C& key) const + { + const HashNode* p = mHash.GetAlt(key); + return p ? &p->Second : 0; + } + + template<class K> + inline U* GetAlt(const K& key) + { + HashNode* p = mHash.GetAlt(key); + return p ? &p->Second : 0; + } + template<class K> + inline const U* GetAlt(const K& key) const + { + const HashNode* p = mHash.GetAlt(key); + return p ? &p->Second : 0; + } + + // Sizing methods - delegate to Hash. + inline size_t GetSize() const { return mHash.GetSize(); } + inline int GetSizeI() const { return (int)GetSize(); } + inline void Resize(size_t n) { mHash.Resize(n); } + inline void SetCapacity(size_t newSize) { mHash.SetCapacity(newSize); } + + // Iterator API, like STL. + typedef typename Container::ConstIterator ConstIterator; + typedef typename Container::Iterator Iterator; + + inline Iterator Begin() { return mHash.Begin(); } + inline Iterator End() { return mHash.End(); } + inline ConstIterator Begin() const { return mHash.Begin(); } + inline ConstIterator End() const { return mHash.End(); } + + Iterator Find(const C& key) { return mHash.FindAlt(key); } + ConstIterator Find(const C& key) const { return mHash.FindAlt(key); } + + template<class K> + Iterator FindAlt(const K& key) { return mHash.FindAlt(key); } + template<class K> + ConstIterator FindAlt(const K& key) const { return mHash.FindAlt(key); } +}; + + + +// Hash with uncached hash code; declared for convenience. +template<class C, class U, class HashF = FixedSizeHash<C>, class Allocator = ContainerAllocator<C> > +class HashUncached + : public Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>, + HashsetNodeEntry<HashNode<C,U,HashF>, typename HashNode<C,U,HashF>::NodeHashF> > +{ +public: + typedef HashUncached<C, U, HashF, Allocator> SelfType; + typedef Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>, + HashsetNodeEntry<HashNode<C,U,HashF>, + typename HashNode<C,U,HashF>::NodeHashF> > BaseType; + + // Delegated constructors. + HashUncached() { } + HashUncached(int sizeHint) : BaseType(sizeHint) { } + HashUncached(const SelfType& src) : BaseType(src) { } + ~HashUncached() { } + void operator = (const SelfType& src) { BaseType::operator = (src); } +}; + + + +// And identity hash in which keys serve as hash value. Can be uncached, +// since hash computation is assumed cheap. +template<class C, class U, class Allocator = ContainerAllocator<C>, class HashF = IdentityHash<C> > +class HashIdentity + : public HashUncached<C, U, HashF, Allocator> +{ +public: + typedef HashIdentity<C, U, Allocator, HashF> SelfType; + typedef HashUncached<C, U, HashF, Allocator> BaseType; + + // Delegated constructors. + HashIdentity() { } + HashIdentity(int sizeHint) : BaseType(sizeHint) { } + HashIdentity(const SelfType& src) : BaseType(src) { } + ~HashIdentity() { } + void operator = (const SelfType& src) { BaseType::operator = (src); } +}; + + +} // OVR + + +#ifdef OVR_DEFINE_NEW +#define new OVR_DEFINE_NEW +#endif + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_JSON.cpp b/LibOVRKernel/Src/Kernel/OVR_JSON.cpp new file mode 100644 index 0000000..b0ae183 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_JSON.cpp @@ -0,0 +1,1332 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_JSON.h +Content : JSON format reader and writer +Created : April 9, 2013 +Author : Brant Lewis +Notes : + The code is a derivative of the cJSON library written by Dave Gamble and subject + to the following permissive copyright. + + Copyright (c) 2009 Dave Gamble + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <stdlib.h> +#include <float.h> +#include <limits.h> +#include <ctype.h> +#include "OVR_JSON.h" +#include "OVR_SysFile.h" +#include "OVR_Log.h" + + +namespace OVR { + + +//----------------------------------------------------------------------------- +// Create a new copy of a string +static char* JSON_strdup(const char* str) +{ + size_t len = OVR_strlen(str) + 1; + char* copy = (char*)OVR_ALLOC(len); + if (!copy) + return 0; + memcpy(copy, str, len); + return copy; +} + + +//----------------------------------------------------------------------------- +// Render the number from the given item into a string. +static char* PrintInt(int valueint) +{ + char *str; + str = (char*)OVR_ALLOC(21); // 2^64+1 can be represented in 21 chars. + if (str) + { + OVR_sprintf(str, 21, "%d", valueint); + } + return str; +} + + +//----------------------------------------------------------------------------- +// Render the number from the given item into a string. +static char* PrintNumber(double d) +{ + char *str; + int valueint = (int)d; + + if ((fabs(((double)valueint)-d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) + { + return PrintInt(valueint); + } + else + { + const size_t kCapacity = 64; + + str=(char*)OVR_ALLOC(kCapacity); // This is a nice tradeoff. + if (str) + { + // The JSON Standard, section 7.8.3, specifies that decimals are always expressed with '.' and + // not some locale-specific decimal such as ',' or ' '. However, since we are using the C standard + // library below to write a floating point number, we need to make sure that it's writing a '.' + // and not something else. We can't change the locale (even temporarily) here, as it will affect + // the whole process by default. That are compiler-specific ways to change this per-thread, but + // below we implement the simple solution of simply fixing the decimal after the string was written. + + if ((fabs(floor(d)-d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) + OVR_sprintf(str, kCapacity, "%.0f", d); + else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) + OVR_sprintf(str, kCapacity, "%e", d); + else + OVR_sprintf(str, kCapacity, "%f", d); + + // Convert any found ',' or ''' char to '.'. This will happen only if the locale was set to write a ',' + // instead of a '.' for the decimal point. Decimal points are represented only by one of these + // three characters in practice. + for(char* p = str; *p; p++) + { + if((*p == ',') || (*p == '\'')) + { + *p = '.'; + break; + } + } + } + } + return str; +} + + +// Parse the input text into an un-escaped cstring, and populate item. +static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +// Helper to assign error sting and return 0. +const char* AssignError(const char** perror, const char *errorMessage) +{ + if (perror) + *perror = errorMessage; + return 0; +} + +//----------------------------------------------------------------------------- +// ***** JSON Node class + +JSON::JSON(JSONItemType itemType) : + Type(itemType), dValue(0.) +{ +} + +JSON::~JSON() +{ + JSON* child = Children.GetFirst(); + while (!Children.IsNull(child)) + { + child->RemoveNode(); + child->Release(); + child = Children.GetFirst(); + } +} + +//----------------------------------------------------------------------------- +// Parse the input text to generate a number, and populate the result into item +// Returns the text position after the parsed number +const char* JSON::parseNumber(const char *num) +{ + const char* num_start = num; + double n=0, scale=0; + int subscale = 0, + signsubscale = 1; + bool positiveSign = true; + const char decimalSeparator = '.'; // The JSON standard specifies that numbers use '.' regardless of locale. + + // Could use sscanf for this? + if (*num == '-') + { + positiveSign = false; + num++; // Has sign? + } + if (*num == '0') + { + num++; // is zero + } + + if (*num>='1' && *num<='9') + { + do + { + n = (n*10.0) + (*num++ - '0'); + } + while (*num>='0' && *num<='9'); // Number? + } + + if ((*num=='.' || *num==decimalSeparator) && num[1]>='0' && num[1]<='9') + { + num++; + do + { + n=(n*10.0)+(*num++ -'0'); + scale--; + } + while (*num>='0' && *num<='9'); // Fractional part? + } + + if (*num=='e' || *num=='E') // Exponent? + { + num++; + if (*num == '+') + { + num++; + } + else if (*num=='-') + { + signsubscale=-1; + num++; // With sign? + } + + while (*num >= '0' && *num <= '9') + { + subscale = (subscale * 10) + (*num++ - '0'); // Number? + } + } + + // Number = +/- number.fraction * 10^+/- exponent + n *= pow(10.0, (scale + subscale*signsubscale)); + + if (!positiveSign) + { + n = -n; + } + + // Assign parsed value. + Type = JSON_Number; + dValue = n; + Value.AssignString(num_start, num - num_start); + + return num; +} + +// Parses a hex string up to the specified number of digits. +// Returns the first character after the string. +const char* ParseHex(unsigned* val, unsigned digits, const char* str) +{ + *val = 0; + + for(unsigned digitCount = 0; digitCount < digits; digitCount++, str++) + { + unsigned v = *str; + + if ((v >= '0') && (v <= '9')) + v -= '0'; + else if ((v >= 'a') && (v <= 'f')) + v = 10 + v - 'a'; + else if ((v >= 'A') && (v <= 'F')) + v = 10 + v - 'A'; + else + break; + + *val = *val * 16 + v; + } + + return str; +} + +//----------------------------------------------------------------------------- +// Parses the input text into a string item and returns the text position after +// the parsed string +const char* JSON::parseString(const char* str, const char** perror) +{ + const char* ptr = str+1; + const char* p; + char* ptr2; + char* out; + int len=0; + unsigned uc, uc2; + + if (*str!='\"') + { + return AssignError(perror, "Syntax Error: Missing quote"); + } + + while (*ptr!='\"' && *ptr && ++len) + { + if (*ptr++ == '\\') ptr++; // Skip escaped quotes. + } + + // This is how long we need for the string, roughly. + out=(char*)OVR_ALLOC(len+1); + if (!out) + return 0; + + ptr = str+1; + ptr2= out; + + while (*ptr!='\"' && *ptr) + { + if (*ptr!='\\') + { + *ptr2++ = *ptr++; + } + else + { + ptr++; + switch (*ptr) + { + case 'b': *ptr2++ = '\b'; break; + case 'f': *ptr2++ = '\f'; break; + case 'n': *ptr2++ = '\n'; break; + case 'r': *ptr2++ = '\r'; break; + case 't': *ptr2++ = '\t'; break; + + // Transcode utf16 to utf8. + case 'u': + + // Get the unicode char. + p = ParseHex(&uc, 4, ptr + 1); + if (ptr != p) + ptr = p - 1; + + if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) + break; // Check for invalid. + + // UTF16 surrogate pairs. + if (uc>=0xD800 && uc<=0xDBFF) + { + if (ptr[1]!='\\' || ptr[2]!='u') + break; // Missing second-half of surrogate. + + p= ParseHex(&uc2, 4, ptr + 3); + if (ptr != p) + ptr = p - 1; + + if (uc2<0xDC00 || uc2>0xDFFF) + break; // Invalid second-half of surrogate. + + uc = 0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF)); + } + + len=4; + + if (uc<0x80) + len=1; + else if (uc<0x800) + len=2; + else if (uc<0x10000) + len=3; + + ptr2+=len; + + switch (len) + { + case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + //no break, fall through + case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + //no break + case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6; + //no break + case 1: *--ptr2 = (char)(uc | firstByteMark[len]); + //no break + } + ptr2+=len; + break; + + default: + *ptr2++ = *ptr; + break; + } + ptr++; + } + } + + *ptr2 = 0; + if (*ptr=='\"') + ptr++; + + // Make a copy of the string + Value=out; + OVR_FREE(out); + Type=JSON_String; + + return ptr; +} + +//----------------------------------------------------------------------------- +// Render the string provided to an escaped version that can be printed. +char* PrintString(const char* str) +{ + const char *ptr; + char *ptr2,*out; + int len=0; + unsigned char token; + + if (!str) + return JSON_strdup(""); + ptr=str; + + token=*ptr; + while (token && ++len)\ + { + if (strchr("\"\\\b\f\n\r\t",token)) + len++; + else if (token<32) + len+=5; + ptr++; + token=*ptr; + } + + int buff_size = len+3; + out=(char*)OVR_ALLOC(buff_size); + if (!out) + return 0; + + ptr2 = out; + ptr = str; + *ptr2++ = '\"'; + + while (*ptr) + { + if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') + *ptr2++=*ptr++; + else + { + *ptr2++='\\'; + switch (token=*ptr++) + { + case '\\': *ptr2++='\\'; break; + case '\"': *ptr2++='\"'; break; + case '\b': *ptr2++='b'; break; + case '\f': *ptr2++='f'; break; + case '\n': *ptr2++='n'; break; + case '\r': *ptr2++='r'; break; + case '\t': *ptr2++='t'; break; + default: + OVR_sprintf(ptr2, buff_size - (ptr2-out), "u%04x",token); + ptr2+=5; + break; // Escape and print. + } + } + } + *ptr2++='\"'; + *ptr2++=0; + return out; +} + +//----------------------------------------------------------------------------- +// Utility to jump whitespace and cr/lf +static const char* skip(const char* in) +{ + while (in && *in && (unsigned char)*in<=' ') + in++; + return in; +} + +//----------------------------------------------------------------------------- +// Parses the supplied buffer of JSON text and returns a JSON object tree +// The returned object must be Released after use +JSON* JSON::Parse(const char* buff, const char** perror) +{ + const char* end = 0; + JSON* json = new JSON(); + + if (!json) + { + AssignError(perror, "Error: Failed to allocate memory"); + return 0; + } + + end = json->parseValue(skip(buff), perror); + if (!end) + { + json->Release(); + return NULL; + } // parse failure. ep is set. + + return json; +} + +//----------------------------------------------------------------------------- +// This version works for buffers that are not null terminated strings. +JSON* JSON::ParseBuffer(const char *buff, int len, const char** perror) +{ + // Our JSON parser does not support length-based parsing, + // so ensure it is null-terminated. + char *termStr = new char[len + 1]; + memcpy(termStr, buff, len); + termStr[len] = '\0'; + + JSON *objJson = Parse(termStr, perror); + + delete[]termStr; + + return objJson; +} + +//----------------------------------------------------------------------------- +// Parser core - when encountering text, process appropriately. +const char* JSON::parseValue(const char* buff, const char** perror) +{ + if (perror) + *perror = 0; + + if (!buff) + return NULL; // Fail on null. + + if (!OVR_strncmp(buff, "null", 4)) + { + Type = JSON_Null; + return buff + 4; + } + if (!OVR_strncmp(buff, "false", 5)) + { + Type = JSON_Bool; + Value = "false"; + dValue = 0.; + return buff + 5; + } + if (!OVR_strncmp(buff, "true", 4)) + { + Type = JSON_Bool; + Value = "true"; + dValue = 1.; + return buff + 4; + } + if (*buff=='\"') + { + return parseString(buff, perror); + } + if (*buff=='-' || (*buff>='0' && *buff<='9')) + { + return parseNumber(buff); + } + if (*buff=='[') + { + return parseArray(buff, perror); + } + if (*buff=='{') + { + return parseObject(buff, perror); + } + + return AssignError(perror, "Syntax Error: Invalid syntax"); +} + +//----------------------------------------------------------------------------- +// Render a value to text. +char* JSON::PrintValue(int depth, bool fmt) +{ + char *out=0; + + switch (Type) + { + case JSON_Null: out = JSON_strdup("null"); break; + case JSON_Bool: + if ((int)dValue == 0) + out = JSON_strdup("false"); + else + out = JSON_strdup("true"); + break; + case JSON_Number: out = PrintNumber(dValue); break; + case JSON_String: out = PrintString(Value); break; + case JSON_Array: out = PrintArray(depth, fmt); break; + case JSON_Object: out = PrintObject(depth, fmt); break; + case JSON_None: OVR_ASSERT_LOG(false, ("Bad JSON type.")); break; + } + return out; +} + +//----------------------------------------------------------------------------- +// Build an array object from input text and returns the text position after +// the parsed array +const char* JSON::parseArray(const char* buff, const char** perror) +{ + JSON *child; + if (*buff!='[') + { + return AssignError(perror, "Syntax Error: Missing opening bracket"); + } + + Type=JSON_Array; + buff=skip(buff+1); + + if (*buff==']') + return buff+1; // empty array. + + child = new JSON(); + if (!child) + return 0; // memory fail + Children.PushBack(child); + + buff=skip(child->parseValue(skip(buff), perror)); // skip any spacing, get the buff. + if (!buff) + return 0; + + while (*buff==',') + { + JSON *new_item = new JSON(); + if (!new_item) + return AssignError(perror, "Error: Failed to allocate memory"); + + Children.PushBack(new_item); + + buff=skip(new_item->parseValue(skip(buff+1), perror)); + if (!buff) + return AssignError(perror, "Error: Failed to allocate memory"); + } + + if (*buff==']') + return buff+1; // end of array + + return AssignError(perror, "Syntax Error: Missing ending bracket"); +} + +//----------------------------------------------------------------------------- +// Render an array to text. The returned text must be freed +char* JSON::PrintArray(int depth, bool fmt) +{ + char ** entries; + char * out = 0, *ptr,*ret; + intptr_t len = 5; + + bool fail = false; + + // How many entries in the array? + int numentries = GetItemCount(); + if (!numentries) + { + out=(char*)OVR_ALLOC(3); + if (out) + OVR_strcpy(out, 3, "[]"); + return out; + } + // Allocate an array to hold the values for each + entries=(char**)OVR_ALLOC(numentries*sizeof(char*)); + if (!entries) + return 0; + memset(entries,0,numentries*sizeof(char*)); + + //// Retrieve all the results: + JSON* child = Children.GetFirst(); + for (int i=0; i<numentries; i++) + { + //JSON* child = Children[i]; + ret=child->PrintValue(depth+1, fmt); + entries[i]=ret; + if (ret) + len+=OVR_strlen(ret)+2+(fmt?1:0); + else + { + fail = true; + break; + } + child = Children.GetNext(child); + } + + // If we didn't fail, try to malloc the output string + if (!fail) + out=(char*)OVR_ALLOC(len); + // If that fails, we fail. + if (!out) + fail = true; + + // Handle failure. + if (fail) + { + for (int i=0; i<numentries; i++) + { + if (entries[i]) + OVR_FREE(entries[i]); + } + OVR_FREE(entries); + return 0; + } + + // Compose the output array. + *out='['; + ptr=out+1; + *ptr=0; + for (int i=0; i<numentries; i++) + { + OVR_strcpy(ptr, len - (ptr-out), entries[i]); + ptr+=OVR_strlen(entries[i]); + if (i!=numentries-1) + { + *ptr++=','; + if (fmt) + *ptr++=' '; + *ptr=0; + } + OVR_FREE(entries[i]); + } + OVR_FREE(entries); + *ptr++=']'; + *ptr++=0; + return out; +} + +//----------------------------------------------------------------------------- +// Build an object from the supplied text and returns the text position after +// the parsed object +const char* JSON::parseObject(const char* buff, const char** perror) +{ + if (*buff!='{') + { + return AssignError(perror, "Syntax Error: Missing opening brace"); + } + + Type=JSON_Object; + buff=skip(buff+1); + if (*buff=='}') + return buff+1; // empty array. + + JSON* child = new JSON(); + Children.PushBack(child); + + buff=skip(child->parseString(skip(buff), perror)); + if (!buff) + return 0; + child->Name = child->Value; + child->Value.Clear(); + + if (*buff!=':') + { + return AssignError(perror, "Syntax Error: Missing colon"); + } + + buff=skip(child->parseValue(skip(buff+1), perror)); // skip any spacing, get the value. + if (!buff) + return 0; + + while (*buff==',') + { + child = new JSON(); + if (!child) + return 0; // memory fail + + Children.PushBack(child); + + buff=skip(child->parseString(skip(buff+1), perror)); + if (!buff) + return 0; + + child->Name=child->Value; + child->Value.Clear(); + + if (*buff!=':') + { + return AssignError(perror, "Syntax Error: Missing colon"); + } // fail! + + // Skip any spacing, get the value. + buff=skip(child->parseValue(skip(buff+1), perror)); + if (!buff) + return 0; + } + + if (*buff=='}') + return buff+1; // end of array + + return AssignError(perror, "Syntax Error: Missing closing brace"); +} + +//----------------------------------------------------------------------------- +// Render an object to text. The returned string must be freed +char* JSON::PrintObject(int depth, bool fmt) +{ + char** entries = 0, **names = 0; + char* out = 0; + char* ptr, *ret, *str; + intptr_t len = 7, i = 0, j; + bool fail = false; + + // Count the number of entries. + int numentries = GetItemCount(); + + // Explicitly handle empty object case + if (numentries == 0) + { + out=(char*)OVR_ALLOC(fmt?depth+4:4); + if (!out) + return 0; + ptr=out; + *ptr++='{'; + + if (fmt) + { + *ptr++='\n'; + for (i=0;i<depth-1;i++) + *ptr++='\t'; + } + *ptr++='}'; + *ptr++=0; + return out; + } + // Allocate space for the names and the objects + entries=(char**)OVR_ALLOC(numentries*sizeof(char*)); + if (!entries) + return 0; + names=(char**)OVR_ALLOC(numentries*sizeof(char*)); + + if (!names) + { + OVR_FREE(entries); + return 0; + } + memset(entries,0,sizeof(char*)*numentries); + memset(names,0,sizeof(char*)*numentries); + + // Collect all the results into our arrays: + depth++; + if (fmt) + len+=depth; + + JSON* child = Children.GetFirst(); + while (!Children.IsNull(child)) + { + names[i] = str = PrintString(child->Name); + entries[i++] = ret = child->PrintValue(depth, fmt); + + if (str && ret) + { + len += OVR_strlen(ret)+OVR_strlen(str)+2+(fmt?3+depth:0); + } + else + { + fail = true; + break; + } + + child = Children.GetNext(child); + } + + // Try to allocate the output string + if (!fail) + out=(char*)OVR_ALLOC(len); + if (!out) + fail=true; + + // Handle failure + if (fail) + { + for (i=0;i<numentries;i++) + { + if (names[i]) + OVR_FREE(names[i]); + + if (entries[i]) + OVR_FREE(entries[i]);} + + OVR_FREE(names); + OVR_FREE(entries); + return 0; + } + + // Compose the output: + *out = '{'; + ptr = out+1; + if (fmt) + { +#ifdef OVR_OS_WIN32 + *ptr++ = '\r'; +#endif + *ptr++ = '\n'; + } + *ptr = 0; + + for (i=0; i<numentries; i++) + { + if (fmt) + { + for (j = 0; j < depth; j++) + { + *ptr++ = '\t'; + } + } + OVR_strcpy(ptr, len - (ptr-out), names[i]); + ptr += OVR_strlen(names[i]); + *ptr++ =':'; + + if (fmt) + { + *ptr++ = '\t'; + } + + OVR_strcpy(ptr, len - (ptr-out), entries[i]); + ptr+=OVR_strlen(entries[i]); + + if (i != numentries - 1) + { + *ptr++ = ','; + } + + if (fmt) + { +#ifdef OVR_OS_WIN32 + *ptr++ = '\r'; +#endif + *ptr++ = '\n'; + } + *ptr = 0; + + OVR_FREE(names[i]); + OVR_FREE(entries[i]); + } + + OVR_FREE(names); + OVR_FREE(entries); + + if (fmt) + { + for (i = 0; i < depth - 1; i++) + { + *ptr++ = '\t'; + } + } + *ptr++='}'; + *ptr++=0; + + return out; +} + + + +// Returns the number of child items in the object +// Counts the number of items in the object. +unsigned JSON::GetItemCount() const +{ + unsigned count = 0; + for (const JSON* p = Children.GetFirst(); !Children.IsNull(p); p = Children.GetNext(p)) + { + count++; + } + return count; +} + +JSON* JSON::GetItemByIndex(unsigned index) +{ + unsigned i = 0; + JSON* child = 0; + + if (!Children.IsEmpty()) + { + child = Children.GetFirst(); + + while (i < index) + { + if (Children.IsLast(child)) + { + child = 0; + break; + } + child = child->GetNext(); + i++; + } + } + + return child; +} + +// Returns the child item with the given name or NULL if not found +JSON* JSON::GetItemByName(const char* name) +{ + JSON* child = 0; + + if (!Children.IsEmpty()) + { + child = Children.GetFirst(); + + while (OVR_strcmp(child->Name, name) != 0) + { + if (Children.IsLast(child)) + { + child = 0; + break; + } + child = child->GetNext(); + } + } + + return child; +} + +//----------------------------------------------------------------------------- +// Adds a new item to the end of the child list +void JSON::AddItem(const char *string, JSON *item) +{ + if (item) + { + item->Name = string; + Children.PushBack(item); + } +} + +/* + +// Removes and frees the items at the given index +void JSON::DeleteItem(unsigned int index) +{ + unsigned int num_items = 0; + JSON* child = Children.GetFirst(); + while (!Children.IsNull(child) && num_items < index) + { + num_items++; + child = Children.GetNext(child); + } + + if (!Children.IsNull(child)) + + child->RemoveNode(); + child->Release(); + } +} + +// Replaces and frees the item at the give index with the new item +void JSON::ReplaceItem(unsigned int index, JSON* new_item) +{ + unsigned int num_items = 0; + JSON* child = Children.GetFirst(); + while (!Children.IsNull(child) && num_items < index) + { + num_items++; + child = Children.GetNext(child); + } + + if (!Children.IsNull(child)) + { + child->ReplaceNodeWith(new_item); + child->Release(); + } +} +*/ + +// Removes and frees the last child item +void JSON::RemoveLast() +{ + JSON* child = Children.GetLast(); + if (!Children.IsNull(child)) + { + child->RemoveNode(); + child->Release(); + } +} + +JSON* JSON::CreateBool(bool b) +{ + JSON *item = new JSON(JSON_Bool); + if (item) + { + item->dValue = b ? 1. : 0.; + item->Value = b ? "true" : "false"; + } + return item; +} + +JSON* JSON::CreateNumber(double num) +{ + JSON *item = new JSON(JSON_Number); + if (item) + { + item->dValue = num; + } + return item; +} + +JSON* JSON::CreateInt(int num) +{ + JSON *item = new JSON(JSON_Number); + if (item) + { + item->dValue = num; + } + return item; +} + +JSON* JSON::CreateString(const char *s) +{ + JSON *item = new JSON(JSON_String); + if (item && s) + { + item->Value = s; + } + return item; +} + + +//----------------------------------------------------------------------------- +// Get elements by name +double JSON::GetNumberByName(const char *name, double defValue) +{ + JSON* item = GetItemByName(name); + if (!item || item->Type != JSON_Number) + { + return defValue; + } + else + { + return item->dValue; + } +} + +int JSON::GetIntByName(const char *name, int defValue) +{ + JSON* item = GetItemByName(name); + if (!item || item->Type != JSON_Number) + { + return defValue; + } + else + { + return (int)item->dValue; + } +} + +bool JSON::GetBoolByName(const char *name, bool defValue) +{ + JSON* item = GetItemByName(name); + if (!item || item->Type != JSON_Bool) + { + return defValue; + } + else + { + return (int)item->dValue != 0; + } +} + +String JSON::GetStringByName(const char *name, const String &defValue) +{ + JSON* item = GetItemByName(name); + if (!item || item->Type != JSON_String) + { + return defValue; + } + else + { + return item->Value; + } +} + + +int JSON::GetArrayByName(const char *name, double values[], int count) +{ + JSON* array = GetItemByName(name); + if (!array || array->Type != JSON_Array) + return 0; + + int i = 0; + for (JSON* child = array->Children.GetFirst(); !array->Children.IsNull(child); child = array->Children.GetNext(child)) + { + if (i >= count) + break; + values[i++] = child->dValue; + } + + OVR_ASSERT(i <= count); + return i; +} + + +//----------------------------------------------------------------------------- +// Adds an element to an array object type +void JSON::AddArrayElement(JSON *item) +{ + if (item) + { + Children.PushBack(item); + } +} + +// Inserts an element into a valid array position +void JSON::InsertArrayElement(int index, JSON *item) +{ + if (!item) + { + return; + } + + if (index == 0) + { + Children.PushFront(item); + return; + } + + JSON* iter = Children.GetFirst(); + int i=0; + while (iter && i<index) + { + iter = Children.GetNext(iter); + i++; + } + + if (iter) + iter->InsertNodeBefore(item); + else + Children.PushBack(item); +} + +// Returns the size of an array +int JSON::GetArraySize() +{ + if (Type == JSON_Array) + { + return GetItemCount(); + } + + return 0; +} + +// Returns the number value an the give array index +double JSON::GetArrayNumber(int index) +{ + if (Type == JSON_Array) + { + JSON* number = GetItemByIndex(index); + return number ? number->dValue : 0.0; + } + + return 0; +} + +// Returns the string value at the given array index +const char* JSON::GetArrayString(int index) +{ + if (Type == JSON_Array) + { + JSON* number = GetItemByIndex(index); + return number ? number->Value : 0; + } + + return 0; +} + +JSON* JSON::Copy() +{ + JSON* copy = new JSON(Type); + copy->Name = Name; + copy->Value = Value; + copy->dValue = dValue; + + JSON* child = Children.GetFirst(); + while (!Children.IsNull(child)) + { + copy->Children.PushBack(child->Copy()); + child = Children.GetNext(child); + } + + return copy; +} + +char* JSON::PrintValue(bool fmt) +{ + return PrintValue(0, fmt); +} + +//----------------------------------------------------------------------------- +// Loads and parses the given JSON file pathname and returns a JSON object tree. +// The returned object must be Released after use. +JSON* JSON::Load(const char* path, const char** perror) +{ + SysFile f; + if (!f.Open(path, File::Open_Read, File::Mode_Read)) + { + AssignError(perror, "Failed to open file"); + return NULL; + } + + int len = f.GetLength(); + uint8_t* buff = (uint8_t*)OVR_ALLOC(len + 1); + int bytes = f.Read(buff, len); + f.Close(); + + if (bytes == 0 || bytes != len) + { + OVR_FREE(buff); + return NULL; + } + + // Ensure the result is null-terminated since Parse() expects null-terminated input. + buff[len] = '\0'; + + JSON* json = JSON::Parse((char*)buff, perror); + OVR_FREE(buff); + return json; +} + +//----------------------------------------------------------------------------- +// Serializes the JSON object and writes to the give file path +bool JSON::Save(const char* path) +{ + SysFile f; + if (!f.Open(path, File::Open_Write | File::Open_Create | File::Open_Truncate, File::Mode_Write)) + return false; + + char* text = PrintValue(0, true); + if (text) + { + intptr_t len = OVR_strlen(text); + OVR_ASSERT(len <= (intptr_t)(int)len); + + int bytes = f.Write((uint8_t*)text, (int)len); + f.Close(); + OVR_FREE(text); + return (bytes == len); + } + else + { + return false; + } +} + +//----------------------------------------------------------------------------- +// Serializes the JSON object to a String +String JSON::Stringify(bool fmt) +{ + char* text = PrintValue(0, fmt); + String copy(text); + OVR_FREE(text); + return copy; +} + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_JSON.h b/LibOVRKernel/Src/Kernel/OVR_JSON.h new file mode 100644 index 0000000..e5e715e --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_JSON.h @@ -0,0 +1,171 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_JSON.h +Content : JSON format reader and writer +Created : April 9, 2013 +Author : Brant Lewis +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_JSON_h +#define OVR_JSON_h + +#include "OVR_RefCount.h" +#include "OVR_String.h" +#include "OVR_List.h" + +namespace OVR { + +// JSONItemType describes the type of JSON item, specifying the type of +// data that can be obtained from it. +enum JSONItemType +{ + JSON_None = 0, + JSON_Null = 1, + JSON_Bool = 2, + JSON_Number = 3, + JSON_String = 4, + JSON_Array = 5, + JSON_Object = 6 +}; + +//----------------------------------------------------------------------------- +// ***** JSON + +// JSON object represents a JSON node that can be either a root of the JSON tree +// or a child item. Every node has a type that describes what is is. +// New JSON trees are typically loaded JSON::Load or created with JSON::Parse. + +class JSON : public RefCountBase<JSON>, public ListNode<JSON> +{ +protected: + List<JSON> Children; + +public: + JSONItemType Type; // Type of this JSON node. + String Name; // Name part of the {Name, Value} pair in a parent object. + String Value; + double dValue; + +public: + ~JSON(); + + // *** Creation of NEW JSON objects + + static JSON* CreateObject() { return new JSON(JSON_Object);} + static JSON* CreateNull() { return new JSON(JSON_Null); } + static JSON* CreateArray() { return new JSON(JSON_Array); } + static JSON* CreateBool(bool b); + static JSON* CreateNumber(double num); + static JSON* CreateInt(int num); + static JSON* CreateString(const char *s); + + // Creates a new JSON object from parsing string. + // Returns null pointer and fills in *perror in case of parse error. + static JSON* Parse(const char* buff, const char** perror = 0); + + // This version works for buffers that are not null terminated strings. + static JSON* ParseBuffer(const char *buff, int len, const char** perror = 0); + + // Loads and parses a JSON object from a file. + // Returns 0 and assigns perror with error message on fail. + static JSON* Load(const char* path, const char** perror = 0); + + // Saves a JSON object to a file. + bool Save(const char* path); + + // Return the String representation of a JSON object. + String Stringify(bool fmt); + + // *** Object Member Access + + // These provide access to child items of the list. + bool HasItems() const { return Children.IsEmpty(); } + // Returns first/last child item, or null if child list is empty + JSON* GetFirstItem() { return (!Children.IsEmpty()) ? Children.GetFirst() : 0; } + JSON* GetLastItem() { return (!Children.IsEmpty()) ? Children.GetLast() : 0; } + + // Counts the number of items in the object; these methods are inefficient. + unsigned GetItemCount() const; + JSON* GetItemByIndex(unsigned i); + JSON* GetItemByName(const char* name); + + // Accessors by name + double GetNumberByName(const char *name, double defValue = 0.0); + int GetIntByName(const char *name, int defValue = 0); + bool GetBoolByName(const char *name, bool defValue = false); + String GetStringByName(const char *name, const String &defValue = ""); + int GetArrayByName(const char *name, double values[], int count); + + // Returns next item in a list of children; 0 if no more items exist. + JSON* GetNextItem(JSON* item) { return Children.IsLast (item) ? nullptr : item->GetNext(); } + JSON* GetPrevItem(JSON* item) { return Children.IsFirst(item) ? nullptr : item->GetPrev(); } + + + // Child item access functions + void AddItem(const char *string, JSON* item); + void AddNullItem(const char* name) { AddItem(name, CreateNull()); } + void AddBoolItem(const char* name, bool b) { AddItem(name, CreateBool(b)); } + void AddIntItem(const char* name, int n) { AddItem(name, CreateInt(n)); } + void AddNumberItem(const char* name, double n) { AddItem(name, CreateNumber(n)); } + void AddStringItem(const char* name, const char* s) { AddItem(name, CreateString(s)); } +// void ReplaceItem(unsigned index, JSON* new_item); +// void DeleteItem(unsigned index); + void RemoveLast(); + + // *** Array Element Access + + // Add new elements to the end of array. + void AddArrayElement(JSON *item); + void InsertArrayElement(int index, JSON* item); + void AddArrayNumber(double n) { AddArrayElement(CreateNumber(n)); } + void AddArrayInt(int n) { AddArrayElement(CreateInt(n)); } + void AddArrayString(const char* s) { AddArrayElement(CreateString(s)); } + + // Accessed array elements; currently inefficient. + int GetArraySize(); + double GetArrayNumber(int index); + const char* GetArrayString(int index); + + JSON* Copy(); // Create a copy of this object + + // Return text value of JSON. Use OVR_FREE when done with return value + char* PrintValue(bool fmt); +protected: + JSON(JSONItemType itemType = JSON_Object); + + // JSON Parsing helper functions. + const char* parseValue(const char *buff, const char** perror); + const char* parseNumber(const char *num); + const char* parseArray(const char* value, const char** perror); + const char* parseObject(const char* value, const char** perror); + const char* parseString(const char* str, const char** perror); + + char* PrintValue(int depth, bool fmt); + char* PrintObject(int depth, bool fmt); + char* PrintArray(int depth, bool fmt); +}; + + +} + +#endif // OVR_JSON_h diff --git a/LibOVRKernel/Src/Kernel/OVR_KeyCodes.h b/LibOVRKernel/Src/Kernel/OVR_KeyCodes.h new file mode 100644 index 0000000..12b66a9 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_KeyCodes.h @@ -0,0 +1,255 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_KeyCodes.h +Content : Common keyboard constants +Created : September 19, 2012 + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_KeyCodes_h +#define OVR_KeyCodes_h + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** KeyCode + +// KeyCode enumeration defines platform-independent keyboard key constants. +// Note that Key_A through Key_Z are mapped to capital ascii constants. + +enum KeyCode +{ + // Key_None indicates that no key was specified. + Key_None = 0, + + // A through Z and numbers 0 through 9. + Key_A = 65, + Key_B, + Key_C, + Key_D, + Key_E, + Key_F, + Key_G, + Key_H, + Key_I, + Key_J, + Key_K, + Key_L, + Key_M, + Key_N, + Key_O, + Key_P, + Key_Q, + Key_R, + Key_S, + Key_T, + Key_U, + Key_V, + Key_W, + Key_X, + Key_Y, + Key_Z, + Key_Num0 = 48, + Key_Num1, + Key_Num2, + Key_Num3, + Key_Num4, + Key_Num5, + Key_Num6, + Key_Num7, + Key_Num8, + Key_Num9, + + // Numeric keypad. + Key_KP_0 = 0xa0, + Key_KP_1, + Key_KP_2, + Key_KP_3, + Key_KP_4, + Key_KP_5, + Key_KP_6, + Key_KP_7, + Key_KP_8, + Key_KP_9, + Key_KP_Multiply, + Key_KP_Add, + Key_KP_Enter, + Key_KP_Subtract, + Key_KP_Decimal, + Key_KP_Divide, + + // Function keys. + Key_F1 = 0xb0, + Key_F2, + Key_F3, + Key_F4, + Key_F5, + Key_F6, + Key_F7, + Key_F8, + Key_F9, + Key_F10, + Key_F11, + Key_F12, + Key_F13, + Key_F14, + Key_F15, + + // Other keys. + Key_Backspace = 8, + Key_Tab, + Key_Clear = 12, + Key_Return, + Key_Shift = 16, + Key_Control, + Key_Alt, + Key_Pause, + Key_CapsLock = 20, // Toggle + Key_Escape = 27, + Key_Space = 32, + Key_Quote = 39, + Key_PageUp = 0xc0, + Key_PageDown, + Key_End, + Key_Home, + Key_Left, + Key_Up, + Key_Right, + Key_Down, + Key_Insert, + Key_Delete, + Key_Help, + + // Synthetic mouse wheel state + Key_MouseWheelAwayFromUser, // "forwards" or "up" + Key_MouseWheelTowardUser, // "backwards" or "down" + + Key_Comma = 44, + Key_Minus, + Key_Slash = 47, + Key_Period, + Key_NumLock = 144, // Toggle + Key_ScrollLock = 145, // Toggle + + Key_Semicolon = 59, + Key_Equal = 61, + Key_Backtick = 96, // ` and tilda~ when shifted (US keyboard) + Key_BracketLeft = 91, + Key_Backslash, + Key_BracketRight, + + Key_OEM_AX = 0xE1, // 'AX' key on Japanese AX keyboard + Key_OEM_102 = 0xE2, // "<>" or "\|" on RT 102-key keyboard. + Key_ICO_HELP = 0xE3, // Help key on ICO + Key_ICO_00 = 0xE4, // 00 key on ICO + + Key_Meta, + + // Total number of keys. + Key_CodeCount +}; + + +//----------------------------------------------------------------------------------- + +class KeyModifiers +{ +public: + enum + { + Key_ShiftPressed = 0x01, + Key_CtrlPressed = 0x02, + Key_AltPressed = 0x04, + Key_MetaPressed = 0x08, + Key_CapsToggled = 0x10, + Key_NumToggled = 0x20, + Key_ScrollToggled = 0x40, + + Initialized_Bit = 0x80, + Initialized_Mask = 0xFF + }; + unsigned char States; + + KeyModifiers() : States(0) { } + KeyModifiers(unsigned char st) : States((unsigned char)(st | Initialized_Bit)) { } + + void Reset() { States = 0; } + + bool IsShiftPressed() const { return (States & Key_ShiftPressed) != 0; } + bool IsCtrlPressed() const { return (States & Key_CtrlPressed) != 0; } + bool IsAltPressed() const { return (States & Key_AltPressed) != 0; } + bool IsMetaPressed() const { return (States & Key_MetaPressed) != 0; } + bool IsCapsToggled() const { return (States & Key_CapsToggled) != 0; } + bool IsNumToggled() const { return (States & Key_NumToggled) != 0; } + bool IsScrollToggled() const{ return (States & Key_ScrollToggled) != 0; } + + void SetShiftPressed(bool v = true) { (v) ? States |= Key_ShiftPressed : States &= ~Key_ShiftPressed; } + void SetCtrlPressed(bool v = true) { (v) ? States |= Key_CtrlPressed : States &= ~Key_CtrlPressed; } + void SetAltPressed(bool v = true) { (v) ? States |= Key_AltPressed : States &= ~Key_AltPressed; } + void SetMetaPressed(bool v = true) { (v) ? States |= Key_MetaPressed : States &= ~Key_MetaPressed; } + void SetCapsToggled(bool v = true) { (v) ? States |= Key_CapsToggled : States &= ~Key_CapsToggled; } + void SetNumToggled(bool v = true) { (v) ? States |= Key_NumToggled : States &= ~Key_NumToggled; } + void SetScrollToggled(bool v = true) { (v) ? States |= Key_ScrollToggled: States &= ~Key_ScrollToggled; } + + bool IsInitialized() const { return (States & Initialized_Mask) != 0; } +}; + + +//----------------------------------------------------------------------------------- + +/* +enum PadKeyCode +{ + Pad_None, // Indicates absence of key code. + Pad_Back, + Pad_Start, + Pad_A, + Pad_B, + Pad_X, + Pad_Y, + Pad_R1, // RightShoulder; + Pad_L1, // LeftShoulder; + Pad_R2, // RightTrigger; + Pad_L2, // LeftTrigger; + Pad_Up, + Pad_Down, + Pad_Right, + Pad_Left, + Pad_Plus, + Pad_Minus, + Pad_1, + Pad_2, + Pad_H, + Pad_C, + Pad_Z, + Pad_O, + Pad_T, + Pad_S, + Pad_Select, + Pad_Home, + Pad_RT, // RightThumb; + Pad_LT // LeftThumb; +}; +*/ + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_List.h b/LibOVRKernel/Src/Kernel/OVR_List.h new file mode 100644 index 0000000..70027db --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_List.h @@ -0,0 +1,365 @@ +/************************************************************************************ + +PublicHeader: OVR +Filename : OVR_List.h +Content : Template implementation for doubly-connected linked List +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_List_h +#define OVR_List_h + +#include "OVR_Types.h" + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** ListNode +// +// Base class for the elements of the intrusive linked list. +// To store elements in the List do: +// +// class MyData : ListNode<MyData> +// { +// . . . +// }; + +template<class T> +class ListNode +{ +private: + ListNode<T>* pPrev; + ListNode<T>* pNext; + + template<class X, class B> friend class List; + +public: + T* GetPrev() const { return (T*)(pPrev); } + T* GetNext() const { return (T*)(pNext); } + + ListNode() + { + pPrev = nullptr; + pNext = nullptr; + } + + bool IsInList() + { + return (pNext != nullptr); + } + + void RemoveNode() + { + pPrev->pNext = pNext; + pNext->pPrev = pPrev; + pPrev = nullptr; + pNext = nullptr; + } + + // Removes us from the list and inserts pnew there instead. + void ReplaceNodeWith(T* pnew) + { + pPrev->pNext = pnew; + pNext->pPrev = pnew; + pnew->pPrev = pPrev; + pnew->pNext = pNext; + pPrev = nullptr; + pNext = nullptr; + } + + // Inserts the argument linked list node after us in the list. + void InsertNodeAfter(T* p) + { + p->pPrev = pNext->pPrev; // this + p->pNext = pNext; + pNext->pPrev = p; + pNext = p; + } + // Inserts the argument linked list node before us in the list. + void InsertNodeBefore(T* p) + { + p->pNext = pNext->pPrev; // this + p->pPrev = pPrev; + pPrev->pNext = p; + pPrev = p; + } + + void Alloc_MoveTo(ListNode<T>* pdest) + { + pdest->pNext = pNext; + pdest->pPrev = pPrev; + pPrev->pNext = pdest; + pNext->pPrev = pdest; + pPrev = nullptr; + pNext = nullptr; + } +}; + +//------------------------------------------------------------------------ +// ***** List +// +// Doubly linked intrusive list. +// The data type must be derived from ListNode. +// +// Adding: PushFront(), PushBack(). +// Removing: Remove() - the element must be in the list! +// Moving: BringToFront(), SendToBack() - the element must be in the list! +// +// Iterating: +// MyData* data = MyList.GetFirst(); +// while (!MyList.IsNull(data)) +// { +// . . . +// data = MyList.GetNext(data); +// } +// +// Removing: +// MyData* data = MyList.GetFirst(); +// while (!MyList.IsNull(data)) +// { +// MyData* next = MyList.GetNext(data); +// if (ToBeRemoved(data)) +// MyList.Remove(data); +// data = next; +// } +// + +// List<> represents a doubly-linked list of T, where each T must derive +// from ListNode<B>. B specifies the base class that was directly +// derived from ListNode, and is only necessary if there is an intermediate +// inheritance chain. + +template<class T, class B = T> class List +{ +public: + typedef T ValueType; + + List() + { + Root.pNext = Root.pPrev = &Root; + } + + void Clear() + { + Root.pNext = Root.pPrev = &Root; + } + + size_t GetSize() const + { + size_t n = 0; + + for(const ListNode<B>* pNode = Root.pNext; pNode != &Root; pNode = pNode->pNext) + ++n; + + return n; + } + + const ValueType* GetFirst() const { return IsEmpty() ? nullptr : (const ValueType*)Root.pNext; } + const ValueType* GetLast () const { return IsEmpty() ? nullptr : (const ValueType*)Root.pPrev; } + ValueType* GetFirst() { return IsEmpty() ? nullptr : (ValueType*)Root.pNext; } + ValueType* GetLast () { return IsEmpty() ? nullptr : (ValueType*)Root.pPrev; } + + // Determine if list is empty (i.e.) points to itself. + // Go through void* access to avoid issues with strict-aliasing optimizing out the + // access after RemoveNode(), etc. + bool IsEmpty() const { return Root.pNext == &Root; } + bool IsFirst(const ValueType* p) const { return p == Root.pNext; } + bool IsLast (const ValueType* p) const { return p == Root.pPrev; } + bool IsNull (const ListNode<B>* p) const { return p == nullptr || p == &Root; } + + inline const ValueType* GetPrev(const ValueType* p) const { return IsNull(p->pPrev) ? nullptr : (const ValueType*)p->pPrev; } + inline const ValueType* GetNext(const ValueType* p) const { return IsNull(p->pNext) ? nullptr : (const ValueType*)p->pNext; } + inline ValueType* GetPrev( ValueType* p) { return IsNull(p->pPrev) ? nullptr : (ValueType*)p->pPrev; } + inline ValueType* GetNext( ValueType* p) { return IsNull(p->pNext) ? nullptr : (ValueType*)p->pNext; } + + void PushFront(ValueType* p) + { + p->pNext = Root.pNext; + p->pPrev = &Root; + Root.pNext->pPrev = p; + Root.pNext = p; + } + + void PushBack(ValueType* p) + { + p->pPrev = Root.pPrev; + p->pNext = &Root; + Root.pPrev->pNext = p; + Root.pPrev = p; + } + + static void Remove(ValueType* p) + { + p->pPrev->pNext = p->pNext; + p->pNext->pPrev = p->pPrev; + p->pPrev = nullptr; + p->pNext = nullptr; + } + + void BringToFront(ValueType* p) + { + Remove(p); + PushFront(p); + } + + void SendToBack(ValueType* p) + { + Remove(p); + PushBack(p); + } + + // Appends the contents of the argument list to the front of this list; + // items are removed from the argument list. + void PushListToFront(List<T>& src) + { + if (!src.IsEmpty()) + { + ValueType* pfirst = src.GetFirst(); + ValueType* plast = src.GetLast(); + src.Clear(); + plast->pNext = Root.pNext; + pfirst->pPrev = &Root; + Root.pNext->pPrev = plast; + Root.pNext = pfirst; + } + } + + void PushListToBack(List<T>& src) + { + if (!src.IsEmpty()) + { + ValueType* pfirst = src.GetFirst(); + ValueType* plast = src.GetLast(); + src.Clear(); + plast->pNext = &Root; + pfirst->pPrev = Root.pPrev; + Root.pPrev->pNext = pfirst; + Root.pPrev = plast; + } + } + + // Removes all source list items after (and including) the 'pfirst' node from the + // source list and adds them to out list. + void PushFollowingListItemsToFront(List<T>& src, ValueType *pfirst) + { + if (pfirst != &src.Root) + { + ValueType *plast = src.Root.pPrev; + + // Remove list remainder from source. + pfirst->pPrev->pNext = &src.Root; + src.Root.pPrev = pfirst->pPrev; + // Add the rest of the items to list. + plast->pNext = Root.pNext; + pfirst->pPrev = &Root; + Root.pNext->pPrev = plast; + Root.pNext = pfirst; + } + } + + // Removes all source list items up to but NOT including the 'pend' node from the + // source list and adds them to out list. + void PushPrecedingListItemsToFront(List<T>& src, ValueType *ptail) + { + if (src.GetFirst() != ptail) + { + ValueType *pfirst = src.Root.pNext; + ValueType *plast = ptail->pPrev; + + // Remove list remainder from source. + ptail->pPrev = &src.Root; + src.Root.pNext = ptail; + + // Add the rest of the items to list. + plast->pNext = Root.pNext; + pfirst->pPrev = &Root; + Root.pNext->pPrev = plast; + Root.pNext = pfirst; + } + } + + + // Removes a range of source list items starting at 'pfirst' and up to, but not including 'pend', + // and adds them to out list. Note that source items MUST already be in the list. + void PushListItemsToFront(ValueType *pfirst, ValueType *pend) + { + if (pfirst != pend) + { + ValueType *plast = pend->pPrev; + + // Remove list remainder from source. + pfirst->pPrev->pNext = pend; + pend->pPrev = pfirst->pPrev; + // Add the rest of the items to list. + plast->pNext = Root.pNext; + pfirst->pPrev = &Root; + Root.pNext->pPrev = plast; + Root.pNext = pfirst; + } + } + + + void Alloc_MoveTo(List<T>* pdest) + { + if (IsEmpty()) + pdest->Clear(); + else + { + pdest->Root.pNext = Root.pNext; + pdest->Root.pPrev = Root.pPrev; + + Root.pNext->pPrev = &pdest->Root; + Root.pPrev->pNext = &pdest->Root; + } + } + + +private: + // Copying is prohibited + List(const List<T>&); + const List<T>& operator = (const List<T>&); + + ListNode<B> Root; +}; + + +//------------------------------------------------------------------------ +// ***** FreeListElements +// +// Remove all elements in the list and free them in the allocator + +template<class List, class Allocator> +void FreeListElements(List& list, Allocator& allocator) +{ + typename List::ValueType* self = list.GetFirst(); + while(!list.IsNull(self)) + { + typename List::ValueType* next = list.GetNext(self); + allocator.Free(self); + self = next; + } + list.Clear(); +} + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Lockless.cpp b/LibOVRKernel/Src/Kernel/OVR_Lockless.cpp new file mode 100644 index 0000000..6a5ec6b --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Lockless.cpp @@ -0,0 +1,225 @@ +/************************************************************************************ + +Filename : OVR_Lockless.cpp +Content : Test logic for lock-less classes +Created : December 27, 2013 +Authors : Michael Antonov + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +*************************************************************************************/ + +#include "OVR_Lockless.h" + +#ifdef OVR_LOCKLESS_TEST + +#include "OVR_Threads.h" +#include "OVR_Timer.h" +#include "OVR_Log.h" + +namespace OVR { namespace LocklessTest { + + +const int TestIterations = 10000000; + +// Use volatile dummies to force compiler to do spinning. +volatile int Dummy1; +int Unused1[32]; +volatile int Dummy2; +int Unused2[32]; +volatile int Dummy3; +int Unused3[32]; + + +// Data block out of 20 consecutive integers, should be internally consistent. +struct TestData +{ + enum { ItemCount = 20 }; + + int Data[ItemCount]; + + + void Set(int val) + { + for (int i=0; i<ItemCount; i++) + { + Data[i] = val*100 + i; + } + } + + int ReadAndCheckConsistency(int prevValue) const + { + int val = Data[0]; + + for (int i=1; i<ItemCount; i++) + { + + if (Data[i] != (val + i)) + { + // Only complain once per same-value entry + if (prevValue != val / 100) + { + LogText("LocklessTest Fail - corruption at %d inside block %d\n", + i, val/100); + // OVR_ASSERT(Data[i] == val + i); + } + break; + } + } + + return val / 100; + } +}; + + + +volatile bool FirstItemWritten = false; +LocklessUpdater<TestData, TestData> TestDataUpdater; + +// Use this lock to verify that testing algorithm is otherwise correct... +Lock TestLock; + + +//------------------------------------------------------------------------------------- + +// Consumer thread reads values from TestDataUpdater and +// ensures that each one is internally consistent. + +class Consumer : public Thread +{ + virtual int Run() + { + LogText("LocklessTest::Consumer::Run started.\n"); + + while (!FirstItemWritten) + { + // spin until producer wrote first value... + } + + TestData d; + int oldValue = 0; + int newValue; + + do + { + { + //Lock::Locker scope(&TestLock); + d = TestDataUpdater.GetState(); + } + + newValue = d.ReadAndCheckConsistency(oldValue); + + // Values should increase or stay the same! + if (newValue < oldValue) + { + LogText("LocklessTest Fail - %d after %d; delta = %d\n", + newValue, oldValue, newValue - oldValue); + // OVR_ASSERT(0); + } + + + if (oldValue != newValue) + { + oldValue = newValue; + + if (oldValue % (TestIterations/30) == 0) + { + LogText("LocklessTest::Consumer - %5.2f%% done\n", + 100.0f * (float)oldValue/(float)TestIterations); + } + } + + // Spin a while + for (int j = 0; j< 300; j++) + { + Dummy3 = j; + } + + + } while (oldValue < (TestIterations * 99 / 100)); + + LogText("LocklessTest::Consumer::Run exiting.\n"); + return 0; + } + +}; + + +//------------------------------------------------------------------------------------- + +class Producer : public Thread +{ + + virtual int Run() + { + LogText("LocklessTest::Producer::Run started.\n"); + + for (int testVal = 0; testVal < TestIterations; testVal++) + { + TestData d; + d.Set(testVal); + + { + //Lock::Locker scope(&TestLock); + TestDataUpdater.SetState(d); + } + + FirstItemWritten = true; + + // Spin a bit + for(int j = 0; j < 1000; j++) + { + Dummy2 = j; + } + + if (testVal % (TestIterations/30) == 0) + { + LogText("LocklessTest::Producer - %5.2f%% done\n", + 100.0f * (float)testVal/(float)TestIterations); + } + } + + LogText("LocklessTest::Producer::Run exiting.\n"); + return 0; + } +}; + + +} // namespace LocklessTest + + + +void StartLocklessTest() +{ + // These threads will release themselves once done + Ptr<LocklessTest::Producer> producerThread = *new LocklessTest::Producer; + Ptr<LocklessTest::Consumer> consumerThread = *new LocklessTest::Consumer; + + producerThread->Start(); + consumerThread->Start(); + + while (!producerThread->IsFinished() && consumerThread->IsFinished()) + { + Thread::MSleep(500); + } +} + + +} // namespace OVR + +#endif // OVR_LOCKLESS_TEST diff --git a/LibOVRKernel/Src/Kernel/OVR_Lockless.h b/LibOVRKernel/Src/Kernel/OVR_Lockless.h new file mode 100644 index 0000000..f9043a9 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Lockless.h @@ -0,0 +1,117 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.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, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. +// +// The SlotType can be the same as T, but should probably be a larger fixed size. +// This allows for forward compatibility when the updater is shared between processes. + +// FIXME: ExchangeAdd_Sync() should be replaced with a portable read-only primitive, +// so that the lockless pose state can be read-only on remote processes and to reduce +// false sharing between processes and improve performance. + +template<class T, class SlotType = T> +class LocklessUpdater +{ +public: + LocklessUpdater() : UpdateBegin( 0 ), UpdateEnd( 0 ) + { + OVR_COMPILER_ASSERT(sizeof(T) <= sizeof(SlotType)); + } + + 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.Load_Acquire(); + state = Slots[ end & 1 ]; + begin = UpdateBegin.Load_Acquire(); + 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.Load_Acquire(); + 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( const 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); + } + + AtomicInt<int> UpdateBegin; + AtomicInt<int> UpdateEnd; + SlotType Slots[2]; +}; + + +#ifdef OVR_LOCKLESS_TEST +void StartLocklessTest(); +#endif + + +} // namespace OVR + +#endif // OVR_Lockless_h + diff --git a/LibOVRKernel/Src/Kernel/OVR_Log.cpp b/LibOVRKernel/Src/Kernel/OVR_Log.cpp new file mode 100644 index 0000000..f39c654 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Log.cpp @@ -0,0 +1,506 @@ +/************************************************************************************ + +Filename : OVR_Log.cpp +Content : Logging support +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Log.h" +#include "OVR_Std.h" +#include <stdarg.h> +#include <stdio.h> +#include <time.h> +#include "OVR_System.h" +#include "OVR_DebugHelp.h" +#include <Util/Util_SystemGUI.h> +#include <Tracing/Tracing.h> + +#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE) +#include "OVR_Win32_IncludeWindows.h" +#elif defined(OVR_OS_ANDROID) +#include <android/log.h> +#elif defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) || defined(OVR_OS_UNIX) +#include <syslog.h> +#endif + + +//----------------------------------------------------------------------------------- +// ***** LogSubject + +static bool LogSubject_IsReady = false; + +class LogSubject : public OVR::SystemSingletonBase<LogSubject> +{ + OVR_DECLARE_SINGLETON(LogSubject); + +public: + void AddListener(OVR::CallbackListener<OVR::Log::LogHandler> *listener) + { + OVR::Lock::Locker locker(&SubjectLock); + Subject.AddListener(listener); + } + + void Call(const char* message, OVR::LogMessageType type) + { + OVR::Lock::Locker locker(&SubjectLock); + Subject.Call(message, type); + } + +protected: + virtual void OnThreadDestroy(); // Listen to thread shutdown event + + OVR::CallbackEmitter<OVR::Log::LogHandler> Subject; + + // This lock is needed because AddListener() and Call() can happen on different + // threads but CallbackEmitter is not thread-safe. + OVR::Lock SubjectLock; +}; + +LogSubject::LogSubject() +{ + LogSubject_IsReady = true; + + // Must be at end of function + PushDestroyCallbacks(); +} + +LogSubject::~LogSubject() +{ +} + +void LogSubject::OnThreadDestroy() +{ + LogSubject_IsReady = false; +} + +void LogSubject::OnSystemDestroy() +{ + delete this; +} + +OVR_DEFINE_SINGLETON(LogSubject); + + +namespace OVR { + + +// Global Log pointer. +Log* OVR_GlobalLog = nullptr; +Log::CAPICallback OVR_CAPICallback = nullptr; + + +//----------------------------------------------------------------------------------- +// ***** Log Implementation + +Log::Log(unsigned logMask) : + LoggingMask(logMask) +{ +#ifdef OVR_OS_WIN32 + hEventSource = RegisterEventSourceA(NULL, "OculusVR"); + OVR_ASSERT(hEventSource != NULL); +#endif +} + +Log::~Log() +{ +#ifdef OVR_OS_WIN32 + if (hEventSource) + { + DeregisterEventSource(hEventSource); + } +#endif + + // Clear out global log + if (this == OVR_GlobalLog) + { + // TBD: perhaps we should ASSERT if this happens before system shutdown? + OVR_GlobalLog = 0; + } +} + +void Log::SetCAPICallback(CAPICallback callback) +{ + if (!OVR::System::IsInitialized()) + { + OVR_CAPICallback = callback; + } +} + +void Log::AddLogObserver(CallbackListener<LogHandler>* listener) +{ + if (OVR::System::IsInitialized() && LogSubject_IsReady) + { + LogSubject::GetInstance()->AddListener(listener); + } +} + +static void RouteLogOutput(const char* message, LogMessageType messageType) +{ + int level = int(LogLevel_Debug); + if (Log::IsDebugMessage(messageType)) + { + TraceLogDebug(message); + } + else if (messageType == OVR::Log_Error) + { + level = int(LogLevel_Error); + TraceLogError(message); + } + else + { + level = int(LogLevel_Info); + TraceLogInfo(message); + } + + if (OVR_CAPICallback) + OVR_CAPICallback(level, message); + + LogSubject::GetInstance()->Call(message, messageType); +} + +void Log::LogMessageVargInt(LogMessageType messageType, const char* fmt, va_list argList) +{ + if (OVR::System::IsInitialized()) + { + // Invoke subject + char buffer[MaxLogBufferMessageSize]; + char* pBuffer = buffer; + char* pAllocated = NULL; + + #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list. + va_list argListSaved; + va_copy(argListSaved, argList); + #endif + + int result = FormatLog(pBuffer, MaxLogBufferMessageSize, Log_Text, fmt, argList); + + if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity... + { + // We assume C++ exceptions are disabled. + // FormatLog will handle the case that pAllocated is NULL. + pAllocated = new char [result + 1]; + // We cannot use OVR_ALLOC() for this allocation because the logging subsystem exists + // outside of the rest of LibOVR so that it can be used to log events from anywhere. + pBuffer = pAllocated; + + #if !defined(OVR_CC_MSVC) + va_end(argList); // The caller owns argList and will call va_end on it. + va_copy(argList, argListSaved); + #endif + + FormatLog(pBuffer, (size_t)result + 1, Log_Text, fmt, argList); + } + + RouteLogOutput(pBuffer, messageType); + + delete[] pAllocated; + } +} + +void Log::LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList) +{ + if ((messageType & LoggingMask) == 0) + return; +#ifndef OVR_BUILD_DEBUG + if (IsDebugMessage(messageType)) + return; +#endif + + char buffer[MaxLogBufferMessageSize]; + char* pBuffer = buffer; + char* pAllocated = NULL; + + #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list. + va_list argListSaved; + va_copy(argListSaved, argList); + #endif + + int result = FormatLog(pBuffer, MaxLogBufferMessageSize, messageType, fmt, argList); + + if(result >= MaxLogBufferMessageSize) // If there was insufficient capacity... + { + // We assume C++ exceptions are disabled. + // FormatLog will handle the case that pAllocated is NULL. + pAllocated = new char [result + 1]; + // We cannot use OVR_ALLOC() for this allocation because the logging subsystem exists + // outside of the rest of LibOVR so that it can be used to log events from anywhere. + pBuffer = pAllocated; + + #if !defined(OVR_CC_MSVC) + va_end(argList); // The caller owns argList and will call va_end on it. + va_copy(argList, argListSaved); + #endif + + FormatLog(pBuffer, (size_t)result + 1, messageType, fmt, argList); + } + + DefaultLogOutput(pBuffer, messageType, result); + delete[] pAllocated; +} + +void OVR::Log::LogMessage(LogMessageType messageType, const char* pfmt, ...) +{ + va_list argList; + va_start(argList, pfmt); + LogMessageVarg(messageType, pfmt, argList); + va_end(argList); +} + + +// Return behavior is the same as ISO C vsnprintf: returns the required strlen of buffer (which will +// be >= bufferSize if bufferSize is insufficient) or returns a negative value because the input was bad. +int Log::FormatLog(char* buffer, size_t bufferSize, LogMessageType messageType, + const char* fmt, va_list argList) +{ + OVR_ASSERT(buffer && (bufferSize >= 10)); // Need to be able to at least print "Assert: \n" to it. + if(!buffer || (bufferSize < 10)) + return -1; + + int addNewline = 1; + int prefixLength = 0; + + switch(messageType) + { + case Log_Error: OVR_strcpy(buffer, bufferSize, "Error: "); prefixLength = 7; break; + case Log_Debug: OVR_strcpy(buffer, bufferSize, "Debug: "); prefixLength = 7; break; + case Log_Assert: OVR_strcpy(buffer, bufferSize, "Assert: "); prefixLength = 8; break; + case Log_Text: buffer[0] = 0; addNewline = 0; break; + case Log_DebugText: buffer[0] = 0; addNewline = 0; break; + default: buffer[0] = 0; addNewline = 0; break; + } + + char* buffer2 = buffer + prefixLength; + size_t size2 = bufferSize - (size_t)prefixLength; + int messageLength = OVR_vsnprintf(buffer2, size2, fmt, argList); + + if (addNewline) + { + if (messageLength < 0) // If there was a format error... + { + // To consider: append <format error> to the buffer here. + buffer2[0] = '\n'; // We are guaranteed to have capacity for this. + buffer2[1] = '\0'; + } + else + { + // If the printed string used all of the capacity or required more than the capacity, + // Chop the output by one character so we can append the \n safely. + int messageEnd = (messageLength >= (int)(size2 - 1)) ? (int)(size2 - 2) : messageLength; + buffer2[messageEnd + 0] = '\n'; + buffer2[messageEnd + 1] = '\0'; + } + } + + if (messageLength >= 0) // If the format was OK... + return prefixLength + messageLength + addNewline; // Return the required strlen of buffer. + + return messageLength; // Else we cannot know what the required strlen is and return the error to the caller. +} + +void Log::DefaultLogOutput(const char* formattedText, LogMessageType messageType, int bufferSize) +{ + OVR_UNUSED2(bufferSize, formattedText); + +#if defined(OVR_OS_WIN32) + + ::OutputDebugStringA(formattedText); + fputs(formattedText, stdout); + +#elif defined(OVR_OS_MS) // Any other Microsoft OSs + + ::OutputDebugStringA(formattedText); + +#elif defined(OVR_OS_ANDROID) + // To do: use bufferSize to deal with the case that Android has a limited output length. + __android_log_write(ANDROID_LOG_INFO, "OVR", formattedText); + +#else + fputs(formattedText, stdout); + +#endif + + if (messageType == Log_Error) + { +#if defined(OVR_OS_WIN32) + if (!ReportEventA(hEventSource, EVENTLOG_ERROR_TYPE, 0, 0, NULL, 1, 0, &formattedText, NULL)) + { + OVR_ASSERT(false); + } +#elif defined(OVR_OS_MS) // Any other Microsoft OSs + // TBD +#elif defined(OVR_OS_ANDROID) + // TBD +#elif defined(OVR_OS_MAC) || defined(OVR_OS_LINUX) + syslog(LOG_ERR, "%s", formattedText); +#else + // TBD +#endif + } +} + + +//static +void Log::SetGlobalLog(Log *log) +{ + OVR_GlobalLog = log; +} +//static +Log* Log::GetGlobalLog() +{ +// No global log by default? +// if (!OVR_GlobalLog) +// OVR_GlobalLog = GetDefaultLog(); + return OVR_GlobalLog; +} + +//static +Log* Log::GetDefaultLog() +{ + // Create default log pointer statically so that it can be used + // even during startup. + static Log defaultLog; + return &defaultLog; +} + + +//----------------------------------------------------------------------------------- +// ***** Global Logging functions + +#if !defined(OVR_CC_MSVC) +// The reason for va_copy is because you can't use va_start twice on Linux +#define OVR_LOG_FUNCTION_IMPL(Name) \ + void Log##Name(const char* fmt, ...) \ + { \ + if (OVR_GlobalLog) \ + { \ + va_list argList1; \ + va_start(argList1, fmt); \ + va_list argList2; \ + va_copy(argList2, argList1); \ + OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList2); \ + va_end(argList2); \ + OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1); \ + va_end(argList1); \ + } \ + } +#else +#define OVR_LOG_FUNCTION_IMPL(Name) \ + void Log##Name(const char* fmt, ...) \ + { \ + if (OVR_GlobalLog) \ + { \ + va_list argList1; \ + va_start(argList1, fmt); \ + OVR_GlobalLog->LogMessageVargInt(Log_##Name, fmt, argList1); \ + OVR_GlobalLog->LogMessageVarg(Log_##Name, fmt, argList1); \ + va_end(argList1); \ + } \ + } +#endif // #if !defined(OVR_OS_WIN32) + +OVR_LOG_FUNCTION_IMPL(Text) +OVR_LOG_FUNCTION_IMPL(Error) + +#ifdef OVR_BUILD_DEBUG +OVR_LOG_FUNCTION_IMPL(DebugText) +OVR_LOG_FUNCTION_IMPL(Debug) +OVR_LOG_FUNCTION_IMPL(Assert) +#endif + + + +// Assertion handler support +// To consider: Move this to an OVR_Types.cpp or OVR_Assert.cpp source file. + +static OVRAssertionHandler sOVRAssertionHandler = OVR::DefaultAssertionHandler; +static intptr_t sOVRAssertionHandlerUserParameter = 0; + +OVRAssertionHandler GetAssertionHandler(intptr_t* userParameter) +{ + if(userParameter) + *userParameter = sOVRAssertionHandlerUserParameter; + return sOVRAssertionHandler; +} + +void SetAssertionHandler(OVRAssertionHandler assertionHandler, intptr_t userParameter) +{ + sOVRAssertionHandler = assertionHandler; + sOVRAssertionHandlerUserParameter = userParameter; +} + +intptr_t DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message) +{ +#if !defined(HEADLESS_APP) + if(OVRIsDebuggerPresent()) + { + OVR_DEBUG_BREAK; + } + else +#endif /* !defined(HEADLESS_APP) */ + { + OVR_UNUSED(title); + OVR_UNUSED(message); + + #if defined(OVR_BUILD_DEBUG) + if(Allocator::GetInstance()) // The code below currently depends on having a valid Allocator. + { + // Print a stack trace of all threads. + OVR::String s; + OVR::String threadListOutput; + static OVR::SymbolLookup symbolLookup; + + s = "Failure: "; + s += message; + + if(symbolLookup.Initialize() && symbolLookup.ReportThreadCallstack(threadListOutput, 4)) // This '4' is there to skip our internal handling and retrieve starting at the assertion location (our caller) only. + { + // threadListOutput has newlines that are merely \n, whereas Windows MessageBox wants \r\n newlines. So we insert \r in front of all \n. + for(size_t i = 0, iEnd = threadListOutput.GetSize(); i < iEnd; i++) + { + if(threadListOutput[i] == '\n') + { + threadListOutput.Insert("\r", i, 1); + ++i; + ++iEnd; + } + } + + s += "\r\n\r\n"; + s += threadListOutput; + } + + OVR::Util::DisplayMessageBox(title, s.ToCStr()); + } + else + { + OVR::Util::DisplayMessageBox(title, message); + } + #else + OVR::Util::DisplayMessageBox(title, message); + #endif + } + + return 0; +} + + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_Log.h b/LibOVRKernel/Src/Kernel/OVR_Log.h new file mode 100644 index 0000000..9d38457 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Log.h @@ -0,0 +1,240 @@ +/************************************************************************************ + +PublicHeader: OVR +Filename : OVR_Log.h +Content : Logging support +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Log_h +#define OVR_Log_h + +#include "OVR_Types.h" +#include "OVR_Delegates.h" +#include "OVR_Callbacks.h" +#include <stdarg.h> + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** Logging Constants + +// LogMaskConstants defined bit mask constants that describe what log messages +// should be displayed. +enum LogMaskConstants +{ + LogMask_Regular = 0x100, + LogMask_Debug = 0x200, + LogMask_None = 0, + LogMask_All = LogMask_Regular|LogMask_Debug +}; + +// LogLevel should match the CAPI ovrLogLevel enum, values are passed back to ovrLogCallback +enum LogLevel +{ + LogLevel_Debug = 0, + LogLevel_Info = 1, + LogLevel_Error = 2 +}; + +// LogMessageType describes the type of the log message, controls when it is +// displayed and what prefix/suffix is given to it. Messages are subdivided into +// regular and debug logging types. Debug logging is only generated in debug builds. +// +// Log_Text - General output text displayed without prefix or new-line. +// Used in OVR libraries for general log flow messages +// such as "Device Initialized". +// +// Log_Error - Error message output with "Error: %s\n", intended for +// application/sample-level use only, in cases where an expected +// operation failed. OVR libraries should not use this internally, +// reporting status codes instead. +// +// Log_DebugText - Message without prefix or new lines; output in Debug build only. +// +// Log_Debug - Debug-build only message, formatted with "Debug: %s\n". +// Intended to comment on incorrect API usage that doesn't lead +// to crashes but can be avoided with proper use. +// There is no Debug Error on purpose, since real errors should +// be handled by API user. +// +// Log_Assert - Debug-build only message, formatted with "Assert: %s\n". +// Intended for severe unrecoverable conditions in library +// source code. Generated though OVR_ASSERT_MSG(c, "Text"). + +enum LogMessageType +{ + // General Logging + Log_Text = LogMask_Regular | 0, + Log_Error = LogMask_Regular | 1, // "Error: %s\n". + + // Debug-only messages (not generated in release build) + Log_DebugText = LogMask_Debug | 0, + Log_Debug = LogMask_Debug | 1, // "Debug: %s\n". + Log_Assert = LogMask_Debug | 2, // "Assert: %s\n". +}; + + +// LOG_VAARG_ATTRIBUTE macro, enforces printf-style formatting for message types +#ifdef __GNUC__ +# define OVR_LOG_VAARG_ATTRIBUTE(a,b) __attribute__((format (printf, a, b))) +#else +# define OVR_LOG_VAARG_ATTRIBUTE(a,b) +#endif + +//----------------------------------------------------------------------------------- +// ***** Log + +// Log defines a base class interface that can be implemented to catch both +// debug and runtime messages. +// Debug logging can be overridden by calling Log::SetGlobalLog. + +class Log +{ + friend class System; + +#ifdef OVR_OS_WIN32 + void* hEventSource; +#endif + +public: + Log(unsigned logMask = LogMask_Debug); + virtual ~Log(); + + typedef Delegate2<void, const char*, LogMessageType> LogHandler; + + // The following is deprecated, as there is no longer a max log buffer message size. + enum { MaxLogBufferMessageSize = 4096 }; + + unsigned GetLoggingMask() const { return LoggingMask; } + void SetLoggingMask(unsigned logMask) { LoggingMask = logMask; } + + static void AddLogObserver(CallbackListener<LogHandler>* listener); + + // This is the same callback signature as in the CAPI. + typedef void (*CAPICallback)(int level, const char* message); + + // This function should be called before OVR::Initialize() + static void SetCAPICallback(CAPICallback callback); + + // Internal + // Invokes observers, then calls LogMessageVarg() + static void LogMessageVargInt(LogMessageType messageType, const char* fmt, va_list argList); + + // This virtual function receives all the messages, + // developers should override this function in order to do custom logging + virtual void LogMessageVarg(LogMessageType messageType, const char* fmt, va_list argList); + + // Call the logging function with specific message type, with no type filtering. + void LogMessage(LogMessageType messageType, + const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(3,4); + + + // Helper used by LogMessageVarg to format the log message, writing the resulting + // string into buffer. It formats text based on fmt and appends prefix/new line + // based on LogMessageType. Return behavior is the same as ISO C vsnprintf: returns the + // required strlen of buffer (which will be >= bufferSize if bufferSize is insufficient) + // or returns a negative value because the input was bad. + static int FormatLog(char* buffer, size_t bufferSize, LogMessageType messageType, + const char* fmt, va_list argList); + + // Default log output implementation used by by LogMessageVarg. + // Debug flag may be used to re-direct output on some platforms, but doesn't + // necessarily disable it in release builds; that is the job of the called. + void DefaultLogOutput(const char* textBuffer, LogMessageType messageType, int bufferSize = -1); + + // Determines if the specified message type is for debugging only. + static bool IsDebugMessage(LogMessageType messageType) + { + return (messageType & LogMask_Debug) != 0; + } + + // *** Global APIs + + // Global Log registration APIs. + // - Global log is used for OVR_DEBUG messages. Set global log to null (0) + // to disable all logging. + static void SetGlobalLog(Log *log); + static Log* GetGlobalLog(); + + // Returns default log singleton instance. + static Log* GetDefaultLog(); + + // Applies logMask to the default log and returns a pointer to it. + // By default, only Debug logging is enabled, so to avoid SDK generating console + // messages in user app (those are always disabled in release build, + // even if the flag is set). This function is useful in System constructor. + static Log* ConfigureDefaultLog(unsigned logMask = LogMask_Debug) + { + Log* log = GetDefaultLog(); + log->SetLoggingMask(logMask); + return log; + } + +private: + // Logging mask described by LogMaskConstants. + unsigned LoggingMask; +}; + + +//----------------------------------------------------------------------------------- +// ***** Global Logging Functions and Debug Macros + +// These functions will output text to global log with semantics described by +// their LogMessageType. +void LogText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); +void LogError(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); + +#ifdef OVR_BUILD_DEBUG + + // Debug build only logging. + void LogDebugText(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); + void LogDebug(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); + void LogAssert(const char* fmt, ...) OVR_LOG_VAARG_ATTRIBUTE(1,2); + + // Macro to do debug logging, printf-style. + // An extra set of set of parenthesis must be used around arguments, + // as in: OVR_DEBUG_LOG(("Value %d", 2)). + #define OVR_DEBUG_LOG(args) do { OVR::LogDebug args; } while(0) + #define OVR_DEBUG_LOG_TEXT(args) do { OVR::LogDebugText args; } while(0) + + // Conditional logging. It logs when the condition 'c' is true. + #define OVR_DEBUG_LOG_COND(c, args) do { if ((c)) { OVR::LogDebug args; } } while(0) + #define OVR_DEBUG_LOG_TEXT_COND(c, args) do { if ((c)) { OVR::LogDebugText args; } } while(0) + + // Conditional logging & asserting. It asserts/logs when the condition 'c' is NOT true. + #define OVR_ASSERT_LOG(c, args) do { if (!(c)) { OVR::LogAssert args; OVR_DEBUG_BREAK; } } while(0) + +#else + + // If not in debug build, macros do nothing. + #define OVR_DEBUG_LOG(args) ((void)0) + #define OVR_DEBUG_LOG_TEXT(args) ((void)0) + #define OVR_DEBUG_LOG_COND(c, args) ((void)0) + #define OVR_DEBUG_LOG_TEXT_COND(args) ((void)0) + #define OVR_ASSERT_LOG(c, args) ((void)0) + +#endif + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Nullptr.h b/LibOVRKernel/Src/Kernel/OVR_Nullptr.h new file mode 100644 index 0000000..a09f446 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Nullptr.h @@ -0,0 +1,150 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Nullptr.h +Content : Implements C++11 nullptr for the case that the compiler doesn't. +Created : June 19, 2014 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Nullptr_h +#define OVR_Nullptr_h + +#pragma once + +#include "OVR_Types.h" + + +//----------------------------------------------------------------------------------- +// ***** OVR_HAVE_std_nullptr_t +// +// Identifies if <cstddef.h> includes std::nullptr_t. +// +#if !defined(OVR_HAVE_std_nullptr_t) && defined(OVR_CPP11_ENABLED) + #if defined(OVR_STDLIB_LIBCPP) + #define OVR_HAVE_std_nullptr_t 1 + #elif defined(OVR_STDLIB_LIBSTDCPP) + #if (__GLIBCXX__ >= 20110325) && (__GLIBCXX__ != 20110428) && (__GLIBCXX__ != 20120702) + #define OVR_HAVE_std_nullptr_t 1 + #endif + #elif defined(_MSC_VER) && (_MSC_VER >= 1600) // VS2010+ + #define OVR_HAVE_std_nullptr_t 1 + #elif defined(__clang__) + #define OVR_HAVE_std_nullptr_t 1 + #elif defined(OVR_CPP_GNUC) && (OVR_CC_VERSION >= 406) // GCC 4.6+ + #define OVR_HAVE_std_nullptr_t 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** nullptr / std::nullptr_t +// +// Declares and defines nullptr and related types. +// +#if defined(OVR_CPP_NO_NULLPTR) + namespace std + { + class nullptr_t + { + public: + template <typename T> + operator T*() const + { return 0; } + + template <typename C, typename T> + operator T C::*() const + { return 0; } + + #if OVR_CPP_NO_EXPLICIT_CONVERSION_OPERATORS + typedef void* (nullptr_t::*bool_)() const; // 4.12,p1. We can't portably use operator bool(){ return false; } because bool + operator bool_() const // is convertable to int which breaks other required functionality. + { return false; } + #else + operator bool() const + { return false; } + #endif + + private: + void operator&() const; // 5.2.10,p9 + }; + + inline nullptr_t nullptr_get() + { + nullptr_t n = { }; + return n; + } + + #if !defined(nullptr) + #define nullptr nullptr_get() + #endif + + } // namespace std + + + // 5.9,p2 p4 + // 13.6, p13 + template <typename T> + inline bool operator==(T* pT, const std::nullptr_t) + { return pT == 0; } + + template <typename T> + inline bool operator==(const std::nullptr_t, T* pT) + { return pT == 0; } + + template <typename T, typename U> + inline bool operator==(const std::nullptr_t, T U::* pU) + { return pU == 0; } + + template <typename T, typename U> + inline bool operator==(T U::* pTU, const std::nullptr_t) + { return pTU == 0; } + + inline bool operator==(const std::nullptr_t, const std::nullptr_t) + { return true; } + + inline bool operator!=(const std::nullptr_t, const std::nullptr_t) + { return false; } + + inline bool operator<(const std::nullptr_t, const std::nullptr_t) + { return false; } + + inline bool operator<=(const std::nullptr_t, const std::nullptr_t) + { return true; } + + inline bool operator>(const std::nullptr_t, const std::nullptr_t) + { return false; } + + inline bool operator>=(const std::nullptr_t, const std::nullptr_t) + { return true; } + + using std::nullptr_t; + using std::nullptr_get; + +// Some compilers natively support C++11 nullptr but the standard library being used +// doesn't declare std::nullptr_t, in which case we provide one ourselves. +#elif !defined(OVR_HAVE_std_nullptr_t) && !defined(OVR_CPP_NO_DECLTYPE) + namespace std { typedef decltype(nullptr) nullptr_t; } +#endif + + +#endif + diff --git a/LibOVRKernel/Src/Kernel/OVR_Rand.cpp b/LibOVRKernel/Src/Kernel/OVR_Rand.cpp new file mode 100644 index 0000000..3d6f50e --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Rand.cpp @@ -0,0 +1,79 @@ +/************************************************************************** + +Filename : OVR_Rand.cpp +Content : Random number generator +Created : Aug 28, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Rand.h" +#include "OVR_Timer.h" + +namespace OVR { + + +void RandomNumberGenerator::SeedRandom() +{ + uint64_t seed = Timer::GetTicksNanos(); + + uint32_t x = (uint32_t)seed, y = (uint32_t)(seed >> 32); + + Seed(x, y); +} + +void RandomNumberGenerator::Seed(uint32_t x, uint32_t y) +{ + // Based on the mixing functions of MurmurHash3 + static const uint64_t C1 = 0xff51afd7ed558ccdULL; + static const uint64_t C2 = 0xc4ceb9fe1a85ec53ULL; + + x += y; + y += x; + + uint64_t seed_x = 0x9368e53c2f6af274ULL ^ x; + uint64_t seed_y = 0x586dcd208f7cd3fdULL ^ y; + + seed_x *= C1; + seed_x ^= seed_x >> 33; + seed_x *= C2; + seed_x ^= seed_x >> 33; + + seed_y *= C1; + seed_y ^= seed_y >> 33; + seed_y *= C2; + seed_y ^= seed_y >> 33; + + Rx = seed_x; + Ry = seed_y; + + // Inlined Next(): Discard first output + + Rx = (uint64_t)0xfffd21a7 * (uint32_t)Rx + (uint32_t)(Rx >> 32); + Ry = (uint64_t)0xfffd1361 * (uint32_t)Ry + (uint32_t)(Ry >> 32); + + // Throw away any saved RandN() state + HaveRandN = false; + + Seeded = true; +} + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_Rand.h b/LibOVRKernel/Src/Kernel/OVR_Rand.h new file mode 100644 index 0000000..14897c0 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Rand.h @@ -0,0 +1,201 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Rand.h +Content : Random number generator +Created : Aug 28, 2014 +Author : Chris Taylor + +Copyright : Copyright 2014 Oculus VR, Inc. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Rand_h +#define OVR_Rand_h + +#include "OVR_Types.h" +#include <math.h> + +namespace OVR { + + +/* + This is designed to generate up to 2^^32 numbers per seed. + + Its period is about 2^^126 and passes all BigCrush tests. + It is the fastest simple generator that passes all tests. + + It has a few advantages over the stdlib RNG, including that + all bits of the output are equally good in quality. + Furthermore, the input seeds are hashed to avoid linear + relationships between the input seeds and the low bits of + the first few outputs. +*/ +class RandomNumberGenerator +{ +protected: + uint64_t Rx; + uint64_t Ry; + double NextRandN; + bool Seeded; + bool HaveRandN; + +public: + RandomNumberGenerator() : + Seeded(false), + HaveRandN(false) + // Other members left uninitialized + { + } + + bool IsSeeded() const + { + return Seeded; + } + + // Seed with a random state + void SeedRandom(); + + // Start with a specific seed + void Seed(uint32_t x, uint32_t y); + + // Returns an unsigned uint32_t uniformly distributed in interval [0..2^32-1] + OVR_FORCE_INLINE uint32_t Next() + { + // If it is not Seeded yet, + if (!IsSeeded()) + { + SeedRandom(); + } + + // Sum of two long-period MWC generators + Rx = (uint64_t)0xfffd21a7 * (uint32_t)Rx + (uint32_t)(Rx >> 32); + Ry = (uint64_t)0xfffd1361 * (uint32_t)Ry + (uint32_t)(Ry >> 32); + return (((uint32_t)Rx << 7) | ((uint32_t)Rx >> (32 - 7))) + (uint32_t)Ry; // ROL(x, 7) + y + } + + // The following functions are inspired by the Matlab functions rand(), randi(), and randn() + + // Uniform distribution over open interval (0..2^32) + // (i.e. closed interval [1..2^32-1], not including 0) + OVR_FORCE_INLINE uint32_t NextNonZero() + { + uint32_t n; + do + { + n = Next(); + } while (n == 0); + return n; + } + + // Double uniformly distributed over open interval (0..1) + OVR_FORCE_INLINE double Rand() + { + return NextNonZero() * (1.0 / 4294967296.0); // 2^32 + } + + // Double uniformly distributed over open interval (dmin..dmax) + OVR_FORCE_INLINE double Rand(double dmin, double dmax) + { + return dmin + (dmax - dmin) * (1.0 / 4294967296.0) * NextNonZero(); // 2^32 + } + + // Integer uniformly distributed over closed interval [0..imax-1] + // (NOTE: Matalb randi(imax) returns 1..imax) + OVR_FORCE_INLINE int RandI(int imax) + { + return (int)(Next() % imax); + } + + // Integer uniformly distributed over closed interval [imin..imax-1] + // (NOTE: Matlab randi() returns imin..imax) + OVR_FORCE_INLINE int RandI(int imin, int imax) + { + return imin + (int)(Next() % (imax - imin)); + } + + // Coordinate (x,y) uniformly distributed inside unit circle. + // Returns magnitude squared of (x,y) + OVR_FORCE_INLINE double RandInUnitCircle(double& x, double& y) + { + double r2; + do + { + x = Rand(-1.0, 1.0); + y = Rand(-1.0, 1.0); + r2 = x*x + y*y; + } while (r2 >= 1.0); + return r2; + } + + // Standard normal (gaussian) distribution: mean 0.0, stdev 1.0 + double RandN() + { + if (HaveRandN) + { + HaveRandN = false; + return NextRandN; + } + else + { + double x, y; + double r2 = RandInUnitCircle(x, y); + // Box-Muller transform + double f = sqrt(-2 * log(r2) / r2); + + // Return first, save second for next call + NextRandN = y * f; + HaveRandN = true; + + return x * f; + } + } + + // Uniform coordinate (c,s) ON unit circle. + // This function computes cos(theta), sin(theta) + // of rotation uniform in (0..2*pi). + // [ c s] is a random 2D rotation matrix. + // [-s c] + // Reference: Numerical Recipes in C++, chap. 21 + OVR_FORCE_INLINE void RandOnUnitCircle(double& c, double& s) + { + double r2 = RandInUnitCircle(c, s); + double normalize = 1.0 / sqrt(r2); + c *= normalize; + s *= normalize; + } + + // Uniform coordinate (x,y,z,w) on surface of 4D hypersphere. + // This is a quaternion rotation uniformly distributed across all rotations + // Reference: Numerical Recipes in C++, chap. 21 + OVR_FORCE_INLINE void RandOnUnitSphere4(double& x, double& y, double& z, double& w) + { + double r2xy = RandInUnitCircle(x, y); + + double u, v; + double r2uv = RandInUnitCircle(u, v); + + double f = sqrt((1.0 - r2xy) / r2uv); + z = u * f; + w = v * f; + } +}; + +} // namespace OVR + +#endif // OVR_Rand_h diff --git a/LibOVRKernel/Src/Kernel/OVR_RefCount.cpp b/LibOVRKernel/Src/Kernel/OVR_RefCount.cpp new file mode 100644 index 0000000..b04ad29 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_RefCount.cpp @@ -0,0 +1,105 @@ +/************************************************************************************ + +Filename : OVR_RefCount.cpp +Content : Reference counting implementation +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_RefCount.h" +#include "OVR_Atomic.h" +#include "OVR_Log.h" + +namespace OVR { + + +// ***** Reference Count Base implementation + +RefCountImplCore::~RefCountImplCore() +{ + // RefCount can be either 1 or 0 here. + // 0 if Release() was properly called. + // 1 if the object was declared on stack or as an aggregate. + OVR_ASSERT(RefCount <= 1); +} + +#ifdef OVR_BUILD_DEBUG +void RefCountImplCore::reportInvalidDelete(void *pmem) +{ + OVR_DEBUG_LOG( + ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem)); + OVR_ASSERT(0); +} +#endif + +RefCountNTSImplCore::~RefCountNTSImplCore() +{ + // RefCount can be either 1 or 0 here. + // 0 if Release() was properly called. + // 1 if the object was declared on stack or as an aggregate. + OVR_ASSERT(RefCount <= 1); +} + +#ifdef OVR_BUILD_DEBUG +void RefCountNTSImplCore::reportInvalidDelete(void *pmem) +{ + OVR_DEBUG_LOG( + ("Invalid delete call on ref-counted object at %p. Please use Release()", pmem)); + OVR_ASSERT(0); +} +#endif + + +// *** Thread-Safe RefCountImpl + +void RefCountImpl::AddRef() +{ + AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1); +} +void RefCountImpl::Release() +{ + if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0) + delete this; +} + +// *** Thread-Safe RefCountVImpl w/virtual AddRef/Release + +void RefCountVImpl::AddRef() +{ + AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, 1); +} +void RefCountVImpl::Release() +{ + if ((AtomicOps<int>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0) + delete this; +} + +// *** NON-Thread-Safe RefCountImpl + +void RefCountNTSImpl::Release() const +{ + RefCount--; + if (RefCount == 0) + delete this; +} + + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_RefCount.h b/LibOVRKernel/Src/Kernel/OVR_RefCount.h new file mode 100644 index 0000000..68c2633 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_RefCount.h @@ -0,0 +1,512 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_RefCount.h +Content : Reference counting implementation headers +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_RefCount_h +#define OVR_RefCount_h + +#include "OVR_Types.h" +#include "OVR_Allocator.h" + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** Reference Counting + +// There are three types of reference counting base classes: +// +// RefCountBase - Provides thread-safe reference counting (Default). +// RefCountBaseNTS - Non Thread Safe version of reference counting. + + +// ***** Declared classes + +template<class C> +class RefCountBase; +template<class C> +class RefCountBaseNTS; + +class RefCountImpl; +class RefCountNTSImpl; + + +//----------------------------------------------------------------------------------- +// ***** Implementation For Reference Counting + +// RefCountImplCore holds RefCount value and defines a few utility +// functions shared by all implementations. + +class RefCountImplCore +{ +protected: + volatile int RefCount; + +public: + // RefCountImpl constructor always initializes RefCount to 1 by default. + OVR_FORCE_INLINE RefCountImplCore() : RefCount(1) { } + + // Need virtual destructor + // This: 1. Makes sure the right destructor's called. + // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() + virtual ~RefCountImplCore(); + + // Debug method only. + int GetRefCount() const { return RefCount; } + + // This logic is used to detect invalid 'delete' calls of reference counted + // objects. Direct delete calls are not allowed on them unless they come in + // internally from Release. +#ifdef OVR_BUILD_DEBUG + static void OVR_CDECL reportInvalidDelete(void *pmem); + inline static void checkInvalidDelete(RefCountImplCore *pmem) + { + if (pmem->RefCount != 0) + reportInvalidDelete(pmem); + } +#else + inline static void checkInvalidDelete(RefCountImplCore *) { } +#endif + + // Base class ref-count content should not be copied. + void operator = (const RefCountImplCore &) { } +}; + +class RefCountNTSImplCore +{ +protected: + mutable int RefCount; + +public: + // RefCountImpl constructor always initializes RefCount to 1 by default. + OVR_FORCE_INLINE RefCountNTSImplCore() : RefCount(1) { } + + // Need virtual destructor + // This: 1. Makes sure the right destructor's called. + // 2. Makes us have VTable, necessary if we are going to have format needed by InitNewMem() + virtual ~RefCountNTSImplCore(); + + // Debug method only. + int GetRefCount() const + { + return RefCount; + } + + // This logic is used to detect invalid 'delete' calls of reference counted + // objects. Direct delete calls are not allowed on them unless they come in + // internally from Release. +#ifdef OVR_BUILD_DEBUG + static void OVR_CDECL reportInvalidDelete(void *pmem); + OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *pmem) + { + if (pmem->RefCount != 0) + reportInvalidDelete(pmem); + } +#else + OVR_FORCE_INLINE static void checkInvalidDelete(RefCountNTSImplCore *) { } +#endif + + // Base class ref-count content should not be copied. + void operator = (const RefCountNTSImplCore &) { } +}; + + + +// RefCountImpl provides Thread-Safe implementation of reference counting, so +// it should be used by default in most places. + +class RefCountImpl : public RefCountImplCore +{ +public: + // Thread-Safe Ref-Count Implementation. + void AddRef(); + void Release(); +}; + +// RefCountVImpl provides Thread-Safe implementation of reference counting, plus, +// virtual AddRef and Release. + +class RefCountVImpl : virtual public RefCountImplCore +{ +public: + // Thread-Safe Ref-Count Implementation. + virtual void AddRef(); + virtual void Release(); +}; + + +// RefCountImplNTS provides Non-Thread-Safe implementation of reference counting, +// which is slightly more efficient since it doesn't use atomics. + +class RefCountNTSImpl : public RefCountNTSImplCore +{ +public: + OVR_FORCE_INLINE void AddRef() const + { + RefCount++; + } + + void Release() const; +}; + + + +// RefCountBaseStatImpl<> is a common class that adds new/delete override with Stat tracking +// to the reference counting implementation. Base must be one of the RefCountImpl classes. + +template<class Base> +class RefCountBaseStatImpl : public Base +{ +public: + RefCountBaseStatImpl() { } + + // *** Override New and Delete + + // DOM-IGNORE-BEGIN + // Undef new temporarily if it is being redefined +#ifdef OVR_DEFINE_NEW +#undef new +#endif + +#ifdef OVR_BUILD_DEBUG + // Custom check used to detect incorrect calls of 'delete' on ref-counted objects. + #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) \ + do {if (p) Base::checkInvalidDelete((class_name*)p); } while(0) +#else + #define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) +#endif + + // Redefine all new & delete operators. + OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) + +#undef OVR_REFCOUNTALLOC_CHECK_DELETE + +#ifdef OVR_DEFINE_NEW +#define new OVR_DEFINE_NEW +#endif + // OVR_BUILD_DEFINE_NEW + // DOM-IGNORE-END +}; + + +template<class Base> +class RefCountBaseStatVImpl : virtual public Base +{ +public: + RefCountBaseStatVImpl() { } + + // *** Override New and Delete + + // DOM-IGNORE-BEGIN + // Undef new temporarily if it is being redefined +#ifdef OVR_DEFINE_NEW +#undef new +#endif + +#define OVR_REFCOUNTALLOC_CHECK_DELETE(class_name, p) + + // Redefine all new & delete operators. + OVR_MEMORY_REDEFINE_NEW_IMPL(Base, OVR_REFCOUNTALLOC_CHECK_DELETE) + +#undef OVR_REFCOUNTALLOC_CHECK_DELETE + +#ifdef OVR_DEFINE_NEW +#define new OVR_DEFINE_NEW +#endif + // OVR_BUILD_DEFINE_NEW + // DOM-IGNORE-END +}; + + + +//----------------------------------------------------------------------------------- +// *** End user RefCountBase<> classes + + +// RefCountBase is a base class for classes that require thread-safe reference +// counting; it also overrides the new and delete operators to use MemoryHeap. +// +// Reference counted objects start out with RefCount value of 1. Further lifetime +// management is done through the AddRef() and Release() methods, typically +// hidden by Ptr<>. + +template<class C> +class RefCountBase : public RefCountBaseStatImpl<RefCountImpl> +{ +public: + // Constructor. + OVR_FORCE_INLINE RefCountBase() : RefCountBaseStatImpl<RefCountImpl>() { } +}; + +// RefCountBaseV is the same as RefCountBase but with virtual AddRef/Release + +template<class C> +class RefCountBaseV : virtual public RefCountBaseStatVImpl<RefCountVImpl> +{ +public: + // Constructor. + OVR_FORCE_INLINE RefCountBaseV() : RefCountBaseStatVImpl<RefCountVImpl>() { } +}; + + +// RefCountBaseNTS is a base class for classes that require Non-Thread-Safe reference +// counting; it also overrides the new and delete operators to use MemoryHeap. +// This class should only be used if all pointers to it are known to be assigned, +// destroyed and manipulated within one thread. +// +// Reference counted objects start out with RefCount value of 1. Further lifetime +// management is done through the AddRef() and Release() methods, typically +// hidden by Ptr<>. + +template<class C> +class RefCountBaseNTS : public RefCountBaseStatImpl<RefCountNTSImpl> +{ +public: + // Constructor. + OVR_FORCE_INLINE RefCountBaseNTS() : RefCountBaseStatImpl<RefCountNTSImpl>() { } +}; + + + + +//----------------------------------------------------------------------------------- +// ***** Ref-Counted template pointer +// +// Automatically AddRefs and Releases interfaces +// +// Note: Some of the member functions take C& as opposed to C* arguments: +// Ptr(C&) +// const Ptr<C>& operator= (C&) +// Ptr<C>& SetPtr(C&) +// These functions do not AddRef the assigned C& value, unlike the C* assignment +// functions. Thus the purpose of these functions is for the Ptr instance to +// assume ownership of a C reference count. Example usage: +// Ptr<Widget> w = *new Widget; // Calls the Ptr(C&) constructor. Note that the Widget constructor sets initial refcount to 1. +// + +template<class C> +class Ptr +{ +protected: + C *pObject; + +public: + + // Constructors + OVR_FORCE_INLINE Ptr() + : pObject(0) + { } + + // This constructor adopts the object's existing reference count rather than increment it. + OVR_FORCE_INLINE Ptr(C &robj) + : pObject(&robj) + { } + + OVR_FORCE_INLINE Ptr(C *pobj) + { + if (pobj) + pobj->AddRef(); + pObject = pobj; + } + + OVR_FORCE_INLINE Ptr(const Ptr<C> &src) + { + if (src.pObject) + src.pObject->AddRef(); + pObject = src.pObject; + } + + template<class R> + OVR_FORCE_INLINE Ptr(Ptr<R> &src) + { + if (src) + src->AddRef(); + pObject = src; + } + + // Destructor + OVR_FORCE_INLINE ~Ptr() + { + if (pObject) + pObject->Release(); + } + + // Compares + OVR_FORCE_INLINE bool operator == (const Ptr &other) const + { + return pObject == other.pObject; + } + + OVR_FORCE_INLINE bool operator != (const Ptr &other) const + { + return pObject != other.pObject; + } + + OVR_FORCE_INLINE bool operator == (C *pother) const + { + return pObject == pother; + } + + OVR_FORCE_INLINE bool operator != (C *pother) const + { + return pObject != pother; + } + + OVR_FORCE_INLINE bool operator < (const Ptr &other) const + { + return pObject < other.pObject; + } + + // Assignment + template<class R> + OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<R> &src) + { + // By design we don't check for src == pObject, as we don't expect that to be the case the large majority of the time. + if (src) + src->AddRef(); + if (pObject) + pObject->Release(); + pObject = src; + return *this; + } + + // Specialization + OVR_FORCE_INLINE const Ptr<C>& operator = (const Ptr<C> &src) + { + if (src) + src->AddRef(); + if (pObject) + pObject->Release(); + pObject = src; + return *this; + } + + OVR_FORCE_INLINE const Ptr<C>& operator = (C *psrc) + { + if (psrc) + psrc->AddRef(); + if (pObject) + pObject->Release(); + pObject = psrc; + return *this; + } + + // This operator adopts the object's existing reference count rather than increment it. + OVR_FORCE_INLINE const Ptr<C>& operator = (C &src) + { + if (pObject) + pObject->Release(); + pObject = &src; + return *this; + } + + // Set Assignment + template<class R> + OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<R> &src) + { + if (src) + src->AddRef(); + if (pObject) + pObject->Release(); + pObject = src; + return *this; + } + // Specialization + OVR_FORCE_INLINE Ptr<C>& SetPtr(const Ptr<C> &src) + { + if (src) + src->AddRef(); + if (pObject) + pObject->Release(); + pObject = src; + return *this; + } + + OVR_FORCE_INLINE Ptr<C>& SetPtr(C *psrc) + { + if (psrc) + psrc->AddRef(); + if (pObject) + pObject->Release(); + pObject = psrc; + return *this; + } + + // This function adopts the object's existing reference count rather than increment it. + OVR_FORCE_INLINE Ptr<C>& SetPtr(C &src) + { + if (pObject) + pObject->Release(); + pObject = &src; + return *this; + } + + // Nulls ref-counted pointer without decrement + OVR_FORCE_INLINE void NullWithoutRelease() + { + pObject = 0; + } + + // Clears the pointer to the object + OVR_FORCE_INLINE void Clear() + { + if (pObject) + pObject->Release(); + pObject = 0; + } + + // Obtain pointer reference directly, for D3D interfaces + OVR_FORCE_INLINE C*& GetRawRef() + { + return pObject; + } + + // Access Operators + OVR_FORCE_INLINE C* GetPtr() const + { + return pObject; + } + + OVR_FORCE_INLINE C& operator * () const + { + return *pObject; + } + + OVR_FORCE_INLINE C* operator -> () const + { + return pObject; + } + + // Conversion + OVR_FORCE_INLINE operator C* () const + { + return pObject; + } + +}; + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_SharedMemory.cpp b/LibOVRKernel/Src/Kernel/OVR_SharedMemory.cpp new file mode 100644 index 0000000..cb5c1e2 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_SharedMemory.cpp @@ -0,0 +1,742 @@ +/************************************************************************************ + +Filename : OVR_SharedMemory.cpp +Content : Inter-process shared memory subsystem +Created : June 1, 2014 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_SharedMemory.h" +#include "OVR_Atomic.h" +#include "OVR_Log.h" +#include "OVR_String.h" +#include "OVR_Array.h" + +#if defined(OVR_OS_WIN32) +#include <Sddl.h> // ConvertStringSecurityDescriptorToSecurityDescriptor +#endif // OVR_OS_WIN32 + +#if defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) +#include <sys/mman.h> // shm_open(), mmap() +#include <errno.h> // error results for mmap +#include <sys/stat.h> // mode constants +#include <fcntl.h> // O_ constants +#include <unistd.h> // close() +#endif // OVR_OS_LINUX + +OVR_DEFINE_SINGLETON(OVR::SharedMemoryFactory); + +namespace OVR { + + +//----------------------------------------------------------------------------- +// SharedMemoryInternalBase + +class SharedMemoryInternalBase : public NewOverrideBase +{ +public: + SharedMemoryInternalBase() + { + } + virtual ~SharedMemoryInternalBase() + { + } + + virtual void* GetFileView() = 0; +}; + + +//----------------------------------------------------------------------------- +// FakeMemoryBlock + +class FakeMemoryBlock : public RefCountBase<FakeMemoryBlock> +{ + String Name; + char* Data; + int SizeBytes; + int References; + +public: + FakeMemoryBlock(const String& name, int size) : + Name(name), + Data(NULL), + SizeBytes(size), + References(1) + { + Data = new char[SizeBytes]; + } + ~FakeMemoryBlock() + { + delete[] Data; + } + + bool IsNamed(const String& name) + { + return Name.CompareNoCase(name) == 0; + } + void* GetData() + { + return Data; + } + int GetSizeI() + { + return SizeBytes; + } + void IncrementReferences() + { + ++References; + } + bool DecrementReferences() + { + return --References <= 0; + } +}; + +class FakeMemoryInternal : public SharedMemoryInternalBase +{ +public: + void* FileView; + Ptr<FakeMemoryBlock> Block; + + FakeMemoryInternal(FakeMemoryBlock* block); + ~FakeMemoryInternal(); + + virtual void* GetFileView() OVR_OVERRIDE + { + return FileView; + } +}; + + +//----------------------------------------------------------------------------- +// FakeMemoryManager + +class FakeMemoryManager : public NewOverrideBase, public SystemSingletonBase<FakeMemoryManager> +{ + OVR_DECLARE_SINGLETON(FakeMemoryManager); + + Lock FakeLock; + Array< Ptr<FakeMemoryBlock> > FakeArray; + +public: + FakeMemoryInternal* Open(const char *name, int bytes, bool openOnly) + { + Lock::Locker locker(&FakeLock); + + const int count = FakeArray.GetSizeI(); + for (int ii = 0; ii < count; ++ii) + { + if (FakeArray[ii]->IsNamed(name)) + { + FakeArray[ii]->IncrementReferences(); + return new FakeMemoryInternal(FakeArray[ii]); + } + } + + if (openOnly) + { + return NULL; + } + + Ptr<FakeMemoryBlock> data = *new FakeMemoryBlock(name, bytes); + FakeArray.PushBack(data); + return new FakeMemoryInternal(data); + } + + void Free(FakeMemoryBlock* block) + { + Lock::Locker locker(&FakeLock); + + const int count = FakeArray.GetSizeI(); + for (int ii = 0; ii < count; ++ii) + { + if (FakeArray[ii].GetPtr() == block) + { + // If the reference count hit zero, + if (FakeArray[ii]->DecrementReferences()) + { + // Toast + FakeArray.RemoveAtUnordered(ii); + } + break; + } + } + } +}; + +FakeMemoryManager::FakeMemoryManager() +{ + PushDestroyCallbacks(); +} + +FakeMemoryManager::~FakeMemoryManager() +{ + // If this assertion trips it is because we have not cleanly released shared memory resources. + OVR_ASSERT(FakeArray.GetSizeI() == 0); +} + +void FakeMemoryManager::OnSystemDestroy() +{ + delete this; +} + +FakeMemoryInternal::FakeMemoryInternal(FakeMemoryBlock* block) : + Block(block) +{ + FileView = Block->GetData(); +} + +FakeMemoryInternal::~FakeMemoryInternal() +{ + FakeMemoryManager::GetInstance()->Free(Block); + Block.Clear(); +} + + +} // namespace OVR + +OVR_DEFINE_SINGLETON(FakeMemoryManager); + +namespace OVR { + + +static SharedMemoryInternalBase* CreateFakeSharedMemory(const SharedMemory::OpenParameters& params) +{ + return FakeMemoryManager::GetInstance()->Open(params.globalName, params.minSizeBytes, params.openMode == SharedMemory::OpenMode_OpenOnly); +} + + +//// Windows version + +#if defined(OVR_OS_WIN32) + +#pragma comment(lib, "advapi32.lib") + +// Hidden implementation class for OS-specific behavior +class SharedMemoryInternal : public SharedMemoryInternalBase +{ +public: + HANDLE FileMapping; + void* FileView; + + SharedMemoryInternal(HANDLE fileMapping, void* fileView) : + FileMapping(fileMapping), + FileView(fileView) + { + } + + ~SharedMemoryInternal() + { + // If file view is set, + if (FileView) + { + UnmapViewOfFile(FileView); + FileView = NULL; + } + + // If file mapping is set, + if (FileMapping != NULL) + { + CloseHandle(FileMapping); + FileMapping = NULL; + } + } + + virtual void* GetFileView() OVR_OVERRIDE + { + return FileView; + } +}; + +static SharedMemoryInternal* DoFileMap(HANDLE hFileMapping, const char* fileName, bool openReadOnly, int minSize) +{ + // Interpret the access mode as a map desired access code + DWORD mapDesiredAccess = openReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE; + + // Map view of the file to this process + void* pFileView = MapViewOfFile(hFileMapping, mapDesiredAccess, 0, 0, minSize); + + // If mapping could not be created, + if (!pFileView) + { + CloseHandle(hFileMapping); + + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to map view of file for %s error code = %d", fileName, GetLastError())); + OVR_UNUSED(fileName); + return NULL; + } + + // Create internal representation + SharedMemoryInternal* pimple = new SharedMemoryInternal(hFileMapping, pFileView); + + // If memory allocation fails, + if (!pimple) + { + UnmapViewOfFile(pFileView); + CloseHandle(hFileMapping); + + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Out of memory")); + return NULL; + } + + return pimple; +} + +static SharedMemoryInternal* AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly) +{ + // Interpret the access mode as a map desired access code + DWORD mapDesiredAccess = openReadOnly ? FILE_MAP_READ : FILE_MAP_WRITE; + + // Open file mapping + HANDLE hFileMapping = OpenFileMappingA(mapDesiredAccess, TRUE, fileName); + + // If file was mapped unsuccessfully, + if (NULL == hFileMapping) + { + //OVR_DEBUG_LOG(("[SharedMemory] WARNING: Unable to open file mapping for %s error code = %d (not necessarily bad)", fileName, GetLastError())); + return NULL; + } + + // Map the file + return DoFileMap(hFileMapping, fileName, openReadOnly, minSize); +} + +static SharedMemoryInternal* AttemptCreateSharedMemory(const char* fileName, int minSize, bool openReadOnly, bool allowRemoteWrite) +{ + // Prepare a SECURITY_ATTRIBUTES object + SECURITY_ATTRIBUTES security; + ZeroMemory(&security, sizeof(security)); + security.nLength = sizeof(security); + + // Security descriptor by DACL strings: + // ACE strings grant Allow(A), Object/Contains Inheritance (OICI) of: + // + Grant All (GA) to System (SY) + // + Grant All (GA) to Built-in Administrators (BA) + // + Grant Read-Only (GR) or Read-Write (GWGR) to Interactive Users (IU) - ie. games + static const char* DACLString_ReadOnly = "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GR;;;IU)"; + static const char* DACLString_ReadWrite = "D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)(A;OICI;GWGR;;;IU)"; + + // Select the remote process access mode + const char* remoteAccessString = + allowRemoteWrite ? DACLString_ReadWrite : DACLString_ReadOnly; + + // Attempt to convert access string to security attributes + // Note: This will allocate the security descriptor with LocalAlloc() and must be freed later + BOOL bConvertOkay = ConvertStringSecurityDescriptorToSecurityDescriptorA( + remoteAccessString, SDDL_REVISION_1, &security.lpSecurityDescriptor, NULL); + + // If conversion fails, + if (!bConvertOkay) + { + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to convert access string, error code = %d", GetLastError())); + return NULL; + } + + // Interpret the access mode as a page protection code + int pageProtectCode = openReadOnly ? PAGE_READONLY : PAGE_READWRITE; + + // Attempt to create a file mapping + HANDLE hFileMapping = CreateFileMappingA(INVALID_HANDLE_VALUE, // From page file + &security, // Security attributes + pageProtectCode, // Read-only? + 0, // High word for size = 0 + minSize, // Low word for size + fileName); // Name of global shared memory file + + // Free the security descriptor buffer + LocalFree(security.lpSecurityDescriptor); + + // If mapping could not be created, + if (NULL == hFileMapping) + { + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to create file mapping for %s error code = %d", fileName, GetLastError())); + return NULL; + } + +#ifndef OVR_ALLOW_CREATE_FILE_MAPPING_IF_EXISTS + // If the file mapping already exists, + if (GetLastError() == ERROR_ALREADY_EXISTS) + { + CloseHandle(hFileMapping); + + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: File mapping at %s already exists", fileName)); + return NULL; + } +#endif + + // Map the file + return DoFileMap(hFileMapping, fileName, openReadOnly, minSize); +} + +static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params) +{ + SharedMemoryInternal* retval = NULL; + + // Construct the file mapping name in a Windows-specific way + OVR::String fileMappingName = params.globalName; + const char *fileName = fileMappingName.ToCStr(); + + // Is being opened read-only? + const bool openReadOnly = (params.accessMode == SharedMemory::AccessMode_ReadOnly); + + // Try up to 3 times to reduce low-probability failures: + static const int ATTEMPTS_MAX = 3; + for (int attempts = 0; attempts < ATTEMPTS_MAX; ++attempts) + { + // If opening should be attempted first, + if (params.openMode != SharedMemory::OpenMode_CreateOnly) + { + // Attempt to open a shared memory map + retval = AttemptOpenSharedMemory(fileName, params.minSizeBytes, openReadOnly); + + // If successful, + if (retval) + { + // Done! + break; + } + } + + // If creating the shared memory is also acceptable, + if (params.openMode != SharedMemory::OpenMode_OpenOnly) + { + // Interpret create mode + const bool allowRemoteWrite = (params.remoteMode == SharedMemory::RemoteMode_ReadWrite); + + // Attempt to create a shared memory map + retval = AttemptCreateSharedMemory(fileName, params.minSizeBytes, openReadOnly, allowRemoteWrite); + + // If successful, + if (retval) + { + // Done! + break; + } + } + } // Re-attempt create/open + + // Note: On Windows the initial contents of the region are guaranteed to be zero. + return retval; +} + +#endif // OVR_OS_WIN32 + + +#if (defined(OVR_OS_LINUX) || defined(OVR_OS_MAC)) + +// Hidden implementation class for OS-specific behavior +class SharedMemoryInternal : public SharedMemoryInternalBase +{ +public: + int FileMapping; + void* FileView; + int FileSize; + + SharedMemoryInternal(int fileMapping, void* fileView, int fileSize) : + FileMapping(fileMapping), + FileView(fileView), + FileSize(fileSize) + { + } + + virtual ~SharedMemoryInternal() + { + // If file view is set, + if (FileView) + { + munmap(FileView, FileSize); + FileView = MAP_FAILED; + } + + // If file mapping is set, + if (FileMapping >= 0) + { + close(FileMapping); + FileMapping = -1; + } + } + + virtual void* GetFileView() OVR_OVERRIDE + { + return FileView; + } +}; + +static SharedMemoryInternal* DoFileMap(int hFileMapping, const char* fileName, bool openReadOnly, int minSize) +{ + // Calculate the required flags based on read/write mode + int prot = openReadOnly ? PROT_READ : (PROT_READ|PROT_WRITE); + + // Map the file view + void* pFileView = mmap(NULL, minSize, prot, MAP_SHARED, hFileMapping, 0); + + if (pFileView == MAP_FAILED) + { + close(hFileMapping); + + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to map view of file for %s error code = %d", fileName, errno)); + OVR_UNUSED(fileName); + return NULL; + } + + // Create internal representation + SharedMemoryInternal* pimple = new SharedMemoryInternal(hFileMapping, pFileView, minSize); + + // If memory allocation fails, + if (!pimple) + { + munmap(pFileView, minSize); + close(hFileMapping); + + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Out of memory")); + return NULL; + } + + return pimple; +} + +static SharedMemoryInternal* AttemptOpenSharedMemory(const char* fileName, int minSize, bool openReadOnly) +{ + // Calculate permissions and flags based on read/write mode + int flags = openReadOnly ? O_RDONLY : O_RDWR; + int perms = openReadOnly ? S_IRUSR : (S_IRUSR | S_IWUSR); + + // Attempt to open the shared memory file + int hFileMapping = shm_open(fileName, flags, perms); + + // If file was not opened successfully, + if (hFileMapping < 0) + { + OVR_DEBUG_LOG(("[SharedMemory] WARNING: Unable to open file mapping for %s error code = %d (not necessarily bad)", fileName, errno)); + return NULL; + } + + // Map the file + return DoFileMap(hFileMapping, fileName, openReadOnly, minSize); +} + +static SharedMemoryInternal* AttemptCreateSharedMemory(const char* fileName, int minSize, bool openReadOnly, bool allowRemoteWrite) +{ + // Create mode + // Note: Cannot create the shared memory file read-only because then ftruncate() will fail. + int flags = O_CREAT | O_RDWR; + +#ifndef OVR_ALLOW_CREATE_FILE_MAPPING_IF_EXISTS + // Require exclusive access when creating (seems like a good idea without trying it yet..) + if (shm_unlink(fileName) < 0) + { + OVR_DEBUG_LOG(("[SharedMemory] WARNING: Unable to unlink shared memory file %s error code = %d", fileName, errno)); + } + flags |= O_EXCL; +#endif + + // Set own read/write permissions + int perms = openReadOnly ? S_IRUSR : (S_IRUSR|S_IWUSR); + + // Allow other users to read/write the shared memory file + perms |= allowRemoteWrite ? (S_IWGRP|S_IWOTH|S_IRGRP|S_IROTH) : (S_IRGRP|S_IROTH); + + // Attempt to open the shared memory file + int hFileMapping = shm_open(fileName, flags, perms); + + // If file was not opened successfully, + if (hFileMapping < 0) + { + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to create file mapping for %s error code = %d", fileName, errno)); + return NULL; + } + + int truncRes = ftruncate(hFileMapping, minSize); + + // If file was not opened successfully, + if (truncRes < 0) + { + close(hFileMapping); + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Unable to truncate file for %s to %d error code = %d", fileName, minSize, errno)); + return NULL; + } + + // Map the file + return DoFileMap(hFileMapping, fileName, openReadOnly, minSize); +} + +static SharedMemoryInternal* CreateSharedMemory(const SharedMemory::OpenParameters& params) +{ + SharedMemoryInternal* retval = NULL; + + // Construct the file mapping name in a Linux-specific way + OVR::String fileMappingName = "/"; + fileMappingName += params.globalName; + const char *fileName = fileMappingName.ToCStr(); + + // Is being opened read-only? + const bool openReadOnly = (params.accessMode == SharedMemory::AccessMode_ReadOnly); + + // Try up to 3 times to reduce low-probability failures: + static const int ATTEMPTS_MAX = 3; + for (int attempts = 0; attempts < ATTEMPTS_MAX; ++attempts) + { + // If opening should be attempted first, + if (params.openMode != SharedMemory::OpenMode_CreateOnly) + { + // Attempt to open a shared memory map + retval = AttemptOpenSharedMemory(fileName, params.minSizeBytes, openReadOnly); + + // If successful, + if (retval) + { + // Done! + break; + } + } + + // If creating the shared memory is also acceptable, + if (params.openMode != SharedMemory::OpenMode_OpenOnly) + { + // Interpret create mode + const bool allowRemoteWrite = (params.remoteMode == SharedMemory::RemoteMode_ReadWrite); + + // Attempt to create a shared memory map + retval = AttemptCreateSharedMemory(fileName, params.minSizeBytes, openReadOnly, allowRemoteWrite); + + // If successful, + if (retval) + { + // Done! + break; + } + } + } // Re-attempt create/open + + // Note: On Windows the initial contents of the region are guaranteed to be zero. + return retval; +} + +#endif // OVR_OS_LINUX + + +//----------------------------------------------------------------------------- +// SharedMemory + +static bool FakingSharedMemory = false; + +void SharedMemory::SetFakeSharedMemory(bool enabled) +{ + FakingSharedMemory = enabled; +} + +bool SharedMemory::IsFakingSharedMemory() +{ + return FakingSharedMemory; +} + +SharedMemory::SharedMemory(int size, void* data, const String& name, SharedMemoryInternalBase* pInternal) : + Size(size), + Data(data), + Name(name), + Internal(pInternal) +{ +} + +SharedMemory::~SharedMemory() +{ + // Call close when it goes out of scope + Close(); + delete Internal; +} + +void SharedMemory::Close() +{ + if (Internal) + { + delete Internal; + Internal = NULL; + } +} + + +//----------------------------------------------------------------------------- +// SharedMemoryFactory + +Ptr<SharedMemory> SharedMemoryFactory::Open(const SharedMemory::OpenParameters& params) +{ + Ptr<SharedMemory> retval; + + // If no name specified or no size requested, + if (!params.globalName || (params.minSizeBytes <= 0)) + { + OVR_DEBUG_LOG(("[SharedMemory] FAILURE: Invalid parameters to Create()")); + return NULL; + } + +#ifdef OVR_BUILD_DEBUG + const char* OpType = "{Unknown}"; + switch (params.openMode) + { + case SharedMemory::OpenMode_CreateOnly: OpType = "Creating"; break; + case SharedMemory::OpenMode_CreateOrOpen: OpType = "Creating/Opening"; break; + case SharedMemory::OpenMode_OpenOnly: OpType = "Opening"; break; + default: OVR_ASSERT(false); break; + } + + OVR_DEBUG_LOG(("[SharedMemory] %s shared memory region: %s > %d bytes", + OpType, params.globalName, params.minSizeBytes)); +#endif + + // Attempt to create a shared memory region from the parameters + SharedMemoryInternalBase* pInternal; + if (SharedMemory::IsFakingSharedMemory()) + { + pInternal = CreateFakeSharedMemory(params); + } + else + { + pInternal = CreateSharedMemory(params); + } + + if (pInternal) + { + // Create the wrapper object + retval = *new SharedMemory(params.minSizeBytes, pInternal->GetFileView(), params.globalName, pInternal); + } + + return retval; +} + +SharedMemoryFactory::SharedMemoryFactory() +{ + OVR_DEBUG_LOG(("[SharedMemory] Creating factory")); + + PushDestroyCallbacks(); +} + +SharedMemoryFactory::~SharedMemoryFactory() +{ + OVR_DEBUG_LOG(("[SharedMemory] Destroying factory")); +} + +void SharedMemoryFactory::OnSystemDestroy() +{ + delete this; +} + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_SharedMemory.h b/LibOVRKernel/Src/Kernel/OVR_SharedMemory.h new file mode 100644 index 0000000..dd155f7 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_SharedMemory.h @@ -0,0 +1,254 @@ +/************************************************************************************ + +PublicHeader: OVR +Filename : OVR_SharedMemory.h +Content : Inter-process shared memory subsystem +Created : June 1, 2014 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_SharedMemory_h +#define OVR_SharedMemory_h + +#include "OVR_Types.h" +#include "OVR_RefCount.h" +#include "OVR_Allocator.h" +#include "OVR_System.h" +#include "OVR_String.h" + + +namespace OVR { + +class SharedMemoryInternalBase; // Opaque + + +// SharedMemory +// Note: Safe when used between 32-bit and 64-bit processes +class SharedMemory : public RefCountBase<SharedMemory> +{ + friend class SharedMemoryFactory; + + OVR_NON_COPYABLE(SharedMemory); + +public: + // Only constructed by the SharedMemory Factory + SharedMemory(int size, void* data, const String& name, SharedMemoryInternalBase* pInternal); + // Call close when it goes out of scope + ~SharedMemory(); + + // Modes for opening a new shared memory region + enum OpenMode + { + // Note: On Windows, Create* requires Administrator priviledges or running as a Service. + OpenMode_CreateOnly, // Must not already exist + OpenMode_OpenOnly, // Must already exist + OpenMode_CreateOrOpen // May exist or not + }; + + // Local access restrictions + enum AccessMode + { + AccessMode_ReadOnly, // Acquire read-only access + AccessMode_ReadWrite, // Acquire read or write access + }; + + // Remote access restrictions + enum RemoteMode + { + RemoteMode_ReadOnly, // Other processes will need to open in read-only mode + RemoteMode_ReadWrite // Other processes can open in read-write mode + }; + + // Modes for opening a new shared memory region + struct OpenParameters + { + OpenParameters() : + globalName(NULL), + minSizeBytes(0), + openMode(SharedMemory::OpenMode_CreateOrOpen), + remoteMode(SharedMemory::RemoteMode_ReadWrite), + accessMode(SharedMemory::AccessMode_ReadWrite) + { + } + + // Creation parameters + const char* globalName; // Name of the shared memory region + int minSizeBytes; // Minimum number of bytes to request + SharedMemory::OpenMode openMode; // Creating the file or opening the file? + SharedMemory::RemoteMode remoteMode; // When creating, what access should other processes get? + SharedMemory::AccessMode accessMode; // When opening/creating, what access should this process get? + }; + +public: + // Returns the size of the shared memory region + int GetSizeI() const + { + return Size; + } + + // Returns the process-local pointer to the shared memory region + // Note: This may be different on different processes + void* GetData() const + { + return Data; + } + + // Returns the name of the shared memory region + String GetName() + { + return Name; + } + +protected: + int Size; // How many shared bytes are shared at the pointer address? + void* Data; // Pointer to the shared memory region. + String Name; // Name that can be used to access this region + + // Hidden implementation class for OS-specific behavior + SharedMemoryInternalBase* Internal; + + // Close and cleanup the shared memory region + // Note: This is called on destruction + void Close(); + +public: + static void SetFakeSharedMemory(bool enabled); + static bool IsFakingSharedMemory(); +}; + + +// SharedMemoryFactory +class SharedMemoryFactory : public NewOverrideBase, public SystemSingletonBase<SharedMemoryFactory> +{ + OVR_DECLARE_SINGLETON(SharedMemoryFactory); + +public: + // Construct a SharedMemory object. + // Note: The new object is reference-counted so it should be stored with Ptr<>. Initial reference count is 1. + Ptr<SharedMemory> Open(const SharedMemory::OpenParameters&); +}; + + +// A shared object +// Its constructor will be called when creating a writer +// Its destructor will not be called +template<class SharedType> +class ISharedObject : public RefCountBase<ISharedObject<SharedType> > +{ +public: + static const int RegionSize = (int)sizeof(SharedType); + +protected: + Ptr<SharedMemory> pSharedMemory; + + bool Open(const char* name, bool readOnly) + { + // Configure open parameters based on read-only mode + SharedMemory::OpenParameters params; + + // FIXME: This is a hack. We currently need to allow clients to open this for read-write even + // though they only need read-only access. This is because in the first 0.4 release the + // LocklessUpdater class technically writes to it (increments by 0) to read from the space. + // This was quickly corrected in 0.4.1 and we are waiting for the right time to disallow write + // access when everyone upgrades to 0.4.1+. + //params.remoteMode = SharedMemory::RemoteMode_ReadOnly; + params.remoteMode = SharedMemory::RemoteMode_ReadWrite; + params.globalName = name; + params.accessMode = readOnly ? SharedMemory::AccessMode_ReadOnly : SharedMemory::AccessMode_ReadWrite; + params.minSizeBytes = RegionSize; + params.openMode = readOnly ? SharedMemory::OpenMode_OpenOnly : SharedMemory::OpenMode_CreateOrOpen; + + // Attempt to open the shared memory file + pSharedMemory = SharedMemoryFactory::GetInstance()->Open(params); + + // If it was not able to be opened, + if (pSharedMemory && pSharedMemory->GetSizeI() >= RegionSize && pSharedMemory->GetData()) + { + // If writing, + if (!readOnly) + { + // Construct the object also + Construct<SharedType>(pSharedMemory->GetData()); + } + + return true; + } + + return false; + } + + SharedType* Get() const + { + if (!pSharedMemory) + { + return NULL; + } + + void* data = pSharedMemory->GetData(); + if (!data) + { + return NULL; + } + + return reinterpret_cast<SharedType*>(data); + } + +public: + String GetName() const + { + return pSharedMemory ? pSharedMemory->GetName() : ""; + } +}; + +// Writer specialized shared object: Ctor will be called on Open() +template<class SharedType> +class SharedObjectWriter : public ISharedObject<SharedType> +{ +public: + OVR_FORCE_INLINE bool Open(const char* name) + { + return ISharedObject<SharedType>::Open(name, false); + } + OVR_FORCE_INLINE SharedType* Get() + { + return ISharedObject<SharedType>::Get(); + } +}; + +// Reader specialized shared object: Ctor will not be called +template<class SharedType> +class SharedObjectReader : public ISharedObject<SharedType> +{ +public: + OVR_FORCE_INLINE bool Open(const char* name) + { + return ISharedObject<SharedType>::Open(name, true); + } + OVR_FORCE_INLINE const SharedType* Get() const + { + return ISharedObject<SharedType>::Get(); + } +}; + + +} // namespace OVR + +#endif // OVR_SharedMemory_h diff --git a/LibOVRKernel/Src/Kernel/OVR_Std.cpp b/LibOVRKernel/Src/Kernel/OVR_Std.cpp new file mode 100644 index 0000000..fc5ad04 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Std.cpp @@ -0,0 +1,1097 @@ +/************************************************************************************ + +Filename : OVR_Std.cpp +Content : Standard C function implementation +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Std.h" +#include "OVR_Alg.h" + +// localeconv() call in OVR_strtod() +#include <locale.h> + +namespace OVR { + +// Source for functions not available on all platforms is included here. + +size_t OVR_CDECL OVR_strlcpy(char* dest, const char* src, size_t destsize) +{ + const char* s = src; + size_t n = destsize; + + if(n && --n) + { + do{ + if((*dest++ = *s++) == 0) + break; + } while(--n); + } + + if(!n) + { + if(destsize) + *dest = 0; + while(*s++) + { } + } + + return (size_t)((s - src) - 1); +} + + +size_t OVR_CDECL OVR_strlcat(char* dest, const char* src, size_t destsize) +{ + const size_t d = destsize ? OVR_strlen(dest) : 0; + const size_t s = OVR_strlen(src); + const size_t t = s + d; + + OVR_ASSERT((destsize == 0) || (d < destsize)); + + if(t < destsize) + memcpy(dest + d, src, (s + 1) * sizeof(*src)); + else + { + if(destsize) + { + memcpy(dest + d, src, ((destsize - d) - 1) * sizeof(*src)); + dest[destsize - 1] = 0; + } + } + + return t; +} + + +// Case insensitive compare implemented in platform-specific way. +int OVR_CDECL OVR_stricmp(const char* a, const char* b) +{ +#if defined(OVR_OS_MS) + #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) + return ::_stricmp(a, b); + #else + return ::stricmp(a, b); + #endif + +#else + return strcasecmp(a, b); +#endif +} + +int OVR_CDECL OVR_strnicmp(const char* a, const char* b, size_t count) +{ +#if defined(OVR_OS_MS) + #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) + return ::_strnicmp(a, b, count); + #else + return ::strnicmp(a, b, count); + #endif + +#else + return strncasecmp(a, b, count); +#endif +} + +wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, size_t destsize, const wchar_t* src) +{ +#if defined(OVR_MSVC_SAFESTRING) + wcscpy_s(dest, destsize, src); + return dest; +#elif defined(OVR_OS_MS) + OVR_UNUSED(destsize); + wcscpy(dest, src); + return dest; +#else + size_t l = OVR_wcslen(src) + 1; // incl term null + l = (l < destsize) ? l : destsize; + memcpy(dest, src, l * sizeof(wchar_t)); + return dest; +#endif +} + +wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, size_t destsize, const wchar_t* src, size_t count) +{ +#if defined(OVR_MSVC_SAFESTRING) + wcsncpy_s(dest, destsize, src, count); + return dest; +#else + size_t srclen = OVR_wcslen(src); + size_t l = Alg::Min(srclen, count); + l = (l < destsize) ? l : destsize; + memcpy(dest, src, l * sizeof(wchar_t)); + if (count > srclen) + { + size_t remLen = Alg::Min(destsize - l, (count - srclen)); + memset(&dest[l], 0, sizeof(wchar_t)*remLen); + } + else if (l < destsize) + dest[l] = 0; + return dest; +#endif +} + + +wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, size_t destsize, const wchar_t* src) +{ +#if defined(OVR_MSVC_SAFESTRING) + wcscat_s(dest, destsize, src); + return dest; +#elif defined(OVR_OS_MS) + OVR_UNUSED(destsize); + wcscat(dest, src); + return dest; +#else + size_t dstlen = OVR_wcslen(dest); // do not incl term null + size_t srclen = OVR_wcslen(src) + 1; // incl term null + size_t copylen = (dstlen + srclen < destsize) ? srclen : destsize - dstlen; + memcpy(dest + dstlen, src, copylen * sizeof(wchar_t)); + return dest; +#endif +} + +size_t OVR_CDECL OVR_wcslen(const wchar_t* str) +{ +#if defined(OVR_OS_MS) + return wcslen(str); +#else + size_t i = 0; + while(str[i] != '\0') + ++i; + return i; +#endif +} + +int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b) +{ +#if defined(OVR_OS_MS) || defined(OVR_OS_LINUX) + return wcscmp(a, b); +#else + // not supported, use custom implementation + const wchar_t *pa = a, *pb = b; + while (*pa && *pb) + { + wchar_t ca = *pa; + wchar_t cb = *pb; + if (ca < cb) + return -1; + else if (ca > cb) + return 1; + pa++; + pb++; + } + if (*pa) + return 1; + else if (*pb) + return -1; + else + return 0; +#endif +} + +int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b) +{ +#if defined(OVR_OS_MS) + #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) + return ::_wcsicmp(a, b); + #else + return ::wcsicmp(a, b); + #endif +#elif defined(OVR_OS_MAC) || defined(__CYGWIN__) || defined(OVR_OS_ANDROID) || defined(OVR_OS_IPHONE) + // not supported, use custom implementation + const wchar_t *pa = a, *pb = b; + while (*pa && *pb) + { + wchar_t ca = OVR_towlower(*pa); + wchar_t cb = OVR_towlower(*pb); + if (ca < cb) + return -1; + else if (ca > cb) + return 1; + pa++; + pb++; + } + if (*pa) + return 1; + else if (*pb) + return -1; + else + return 0; +#else + return wcscasecmp(a, b); +#endif +} + +// This function is not inline because of dependency on <locale.h> +double OVR_CDECL OVR_strtod(const char* str, char** tailptr) +{ +#if !defined(OVR_OS_ANDROID) // The Android C library doesn't have localeconv. + const char s = *localeconv()->decimal_point; + + if (s != '.') // If the C library is using a locale that is not using '.' as a decimal point, we convert the input str's '.' chars to the char that the C library expects (e.g. ',' or ' '). + { + char buffer[347 + 1]; + + OVR_strcpy(buffer, sizeof(buffer), str); + + // Ensure null-termination of string + buffer[sizeof(buffer)-1] = '\0'; + + for (char* c = buffer; *c != '\0'; ++c) + { + if (*c == '.') + { + *c = s; + break; + } + } + + char *nextPtr = NULL; + double retval = strtod(buffer, &nextPtr); + + // If a tail pointer is requested, + if (tailptr) + { + // Return a tail pointer that points to the same offset as nextPtr, in the orig string + *tailptr = !nextPtr ? NULL : (char*)str + (int)(nextPtr - buffer); + } + + return retval; + } +#endif + + return strtod(str, tailptr); +} + + +#ifndef OVR_NO_WCTYPE + +//// Use this class to generate Unicode bitsets. For example: +//// +//// UnicodeBitSet bitSet; +//// for(unsigned i = 0; i < 65536; ++i) +//// { +//// if (iswalpha(i)) +//// bitSet.Set(i); +//// } +//// bitSet.Dump(); +//// +////--------------------------------------------------------------- +//class UnicodeBitSet +//{ +//public: +// UnicodeBitSet() +// { +// memset(Offsets, 0, sizeof(Offsets)); +// memset(Bits, 0, sizeof(Bits)); +// } +// +// void Set(unsigned bit) { Bits[bit >> 8][(bit >> 4) & 15] |= 1 << (bit & 15); } +// +// void Dump() +// { +// unsigned i, j; +// unsigned offsetCount = 0; +// for(i = 0; i < 256; ++i) +// { +// if (isNull(i)) Offsets[i] = 0; +// else +// if (isFull(i)) Offsets[i] = 1; +// else Offsets[i] = uint16_t(offsetCount++ * 16 + 256); +// } +// for(i = 0; i < 16; ++i) +// { +// for(j = 0; j < 16; ++j) +// { +// printf("%5u,", Offsets[i*16+j]); +// } +// printf("\n"); +// } +// for(i = 0; i < 256; ++i) +// { +// if (Offsets[i] > 255) +// { +// for(j = 0; j < 16; j++) +// { +// printf("%5u,", Bits[i][j]); +// } +// printf("\n"); +// } +// } +// } +// +//private: +// bool isNull(unsigned n) const +// { +// const uint16_t* p = Bits[n]; +// for(unsigned i = 0; i < 16; ++i) +// if (p[i] != 0) return false; +// return true; +// } +// +// bool isFull(unsigned n) const +// { +// const uint16_t* p = Bits[n]; +// for(unsigned i = 0; i < 16; ++i) +// if (p[i] != 0xFFFF) return false; +// return true; +// } +// +// uint16_t Offsets[256]; +// uint16_t Bits[256][16]; +//}; + + +const uint16_t UnicodeAlnumBits[] = { + 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464, + 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624, + 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, + 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832, + 0, 0, 0, 1023,65534, 2047,65534, 2047, 0, 0, 0, 524,65535,65407,65535,65407, +65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0, + 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15, +65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831, + 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7, + 0, 0,65534, 2047,65534, 63, 1023,65535,65535,65535,65535,65535,65535, 8175, 8702, 8191, + 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0, +65518,65535,65535,58367, 8191,65281,65487, 0,40942,65529,65023,50117, 6559,45184,65487, 3, +34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0, +40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0, +57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0, +57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 12, +65534,65535,65535, 2047,32767, 1023, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0, + 1, 0, 1023, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0, +65535,65535,63227, 327, 1023, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127, +65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023, +65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535, +32767,32573,65535,65535,65407, 2047,65024, 3, 0, 0,65535,65535,65535,65535,65535, 31, +65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, +65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0, + 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 1023, 0, + 0, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023, +65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156, + 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0, +64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047, +65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0, +65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535, +65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095, + 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191, + 0, 1023,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0}; + +const uint16_t UnicodeAlphaBits[] = { + 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464, + 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624, + 640, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 672, 688, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 704, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, + 1, 1, 1, 1, 736, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 768, 784, 1, 800, 816, 832, + 0, 0, 0, 0,65534, 2047,65534, 2047, 0, 0, 0, 0,65535,65407,65535,65407, +65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0, + 0, 0, 0, 0, 32, 0, 0, 1024,55104,65535,65531,65535,32767,64767,65535, 15, +65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831, + 0, 0, 0,65534,65535, 639,65534,65535, 255, 0, 0, 0, 0,65535, 2047, 7, + 0, 0,65534, 2047,65534, 63, 0,65535,65535,65535,65535,65535,65535, 8175, 8702, 7168, + 0,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0, +65518,65535,65535,58367, 8191,65281, 15, 0,40942,65529,65023,50117, 6559,45184, 15, 3, +34788,65529,65023,50029, 6535,24064, 0, 31,45038,65531,65023,58349, 7103, 1, 1, 0, +40942,65529,65023,58317, 6543,45248, 3, 0,51180,54845,50968,50111, 7623, 128, 0, 0, +57326,65533,65023,50159, 7647, 96, 3, 0,57324,65533,65023,50159, 7647,16480, 3, 0, +57324,65533,65023,50175, 7631, 128, 3, 0,65516,64639,65535,12283,32895,65375, 0, 12, +65534,65535,65535, 2047,32767, 0, 0, 0, 9622,65264,60590,15359, 8223,12288, 0, 0, + 1, 0, 0, 0,65279,65535, 2047,65534, 3843,65279,65535, 8191, 0, 0, 0, 0, +65535,65535,63227, 327, 0, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 127, +65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023, +65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535, +32767,32573,65535,65535,65407, 2047, 0, 0, 0, 0,65535,65535,65535,65535,65535, 31, +65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, +65535,65535,65535,65535,65535,65535,40959, 127,65534, 2047,65535,65535,65535,65535, 2047, 0, + 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 0, 0, 0, + 0, 0,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023, +65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156, + 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0, +64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0, + 192, 0, 1022, 1792,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 2047, +65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0, +65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0, +65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535, +65535,65535,65535,16383, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095, + 0, 0, 0, 0, 0, 0, 0,65495,65535,65535,65535,65535,65535,65535,65535, 8191, + 0, 0,65534, 2047,65534, 2047,65472,65534,65535,16383,65535,32767,64764, 7420, 0, 0}; + +const uint16_t UnicodeDigitBits[] = { + 256, 0, 0, 0, 0, 0, 272, 0, 0, 288, 304, 320, 336, 352, 368, 384, + 400, 0, 0, 416, 0, 0, 0, 432, 448, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 464, + 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 524, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 1023, + 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0, + 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0, + 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65408, 0, + 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0,65472, 0, + 0, 0, 0, 0, 0, 0,65472, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 1023, 0, 0, + 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0,65024, 3, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1023, 0, + 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1023, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +const uint16_t UnicodeSpaceBits[] = { + 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 288, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +15872, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 4095, 0,33536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +const uint16_t UnicodeXDigitBits[] = { + 256, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 272, + 0, 0, 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1023, 126, 0, 126, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +// Uncomment if necessary +//const uint16_t UnicodeCntrlBits[] = { +// 256, 0, 0, 0, 0, 0, 0, 272, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 288, 0, 0, 0, 0, 0, 0, 0, +// 304, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 320, 336, +//65535,65535, 0, 0, 0, 0, 0,32768,65535,65535, 0, 0, 0, 0, 0, 0, +//32768, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//30720, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//61440, 0,31744, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,32768, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3584}; +// +//const uint16_t UnicodeGraphBits[] = { +// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464, +// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624, +// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736, +// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848, +// 0, 0,65534,65535,65535,65535,65535,32767, 0, 0,65534,65535,65535,65535,65535,65535, +//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0, +// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15, +//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831, +// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31, +// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191, +//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0, +//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3, +//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0, +//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0, +//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0, +//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28, +//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0, +//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0, +//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175, +//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023, +//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535, +//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31, +//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, +//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0, +// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0, +// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023, +//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156, +// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0, +//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//65486,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095, +//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0, +//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535, +//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095, +// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535, 8191, +//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0}; +// +//const uint16_t UnicodePrintBits[] = { +// 256, 1, 272, 288, 304, 320, 336, 352, 0, 368, 384, 400, 416, 432, 448, 464, +// 480, 496, 512, 528, 544, 1, 560, 576, 592, 0, 0, 0, 0, 0, 608, 624, +// 640, 656, 0, 672, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 688, 704, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 720, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 736, +// 1, 1, 1, 1, 752, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, +// 1, 1, 1, 1, 1, 1, 1, 768, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 784, 800, 1, 816, 832, 848, +// 512, 0,65535,65535,65535,65535,65535,32767, 0, 0,65535,65535,65535,65535,65535,65535, +//65535,65535,65532, 15, 0,65535,65535,65535,65535,65535,16383,63999, 3, 0,16415, 0, +// 0, 0, 0, 0, 32, 0, 0,17408,55232,65535,65531,65535,32767,64767,65535, 15, +//65535,65535,65535,65535,65535,65535,65535,65535,61443,65535,65535,65535, 6559,65535,65535, 831, +// 0, 0, 0,65534,65535,65151,65534,65535, 1791, 0, 0,16384, 9,65535, 2047, 31, +// 4096,34816,65534, 2047,65534, 63,16383,65535,65535,65535,65535,65535,65535, 8191, 8702, 8191, +//16383,65535, 8191,65535, 0, 0, 0, 0,65535,65535,65535, 1, 0, 0, 0, 0, +//65518,65535,65535,58367, 8191,65281,65535, 1,40942,65529,65023,50117, 6559,45184,65487, 3, +//34788,65529,65023,50029, 6535,24064,65472, 31,45038,65531,65023,58349, 7103, 1,65473, 0, +//40942,65529,65023,58317, 6543,45248,65475, 0,51180,54845,50968,50111, 7623, 128,65408, 0, +//57326,65533,65023,50159, 7647, 96,65475, 0,57324,65533,65023,50159, 7647,16480,65475, 0, +//57324,65533,65023,50175, 7631, 128,65475, 0,65516,64639,65535,12283,32895,65375, 0, 28, +//65534,65535,65535, 2047,65535, 4095, 0, 0, 9622,65264,60590,15359, 8223,13311, 0, 0, +//65521, 7, 1023,15360,65279,65535, 2047,65534, 3875,65279,65535, 8191, 0, 0, 0, 0, +//65535,65535,63227, 327,65535, 1023, 0, 0, 0, 0,65535,65535, 63,65535,65535, 2175, +//65535,65535,65535,65535,65535,33791,65535,65535,65535,65535,65287,65535,65535,65535,65535, 1023, +//65407,65535,65535,65535,15743,15743,65535,65535,15743,65535,32767,32573,32573,65407,32767,65535, +//32767,32573,65535,65535,65407, 2047,65534, 3, 0, 0,65535,65535,65535,65535,65535, 31, +//65534,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, +//65535,65535,65535,65535,65535,65535,65535, 127,65534, 8191,65535,65535,65535,65535,16383, 0, +// 0, 0, 0, 0, 0, 0, 0, 0,65535,65535,65535,65535, 511, 6128, 1023, 0, +// 2047, 1023,65535,65535,65527,65535,65535, 255,65535,65535, 1023, 0, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535, 4095,65535,65535,65535,65535,65535, 1023, +//65535,16191,65535,65535,16191,43775,65535,16383,65535,65535,65535,24543, 8156, 4047, 8191, 8156, +// 0,65535, 255,65535,16239, 0, 0,57344,24576, 0, 0, 0, 0, 0, 0, 0, +//64644,15919,48464, 1019, 0, 0,65535,65535, 15, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//65487,65523, 1022, 1793,65534,65535,65535,65535,65535, 31,65534,65535,65535,65535,65535, 4095, +//65504,65535, 8191,65534,65535,65535,65535,65535,32767, 0,65535, 255, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 63, 0, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535, 8191, 0, 0, 0, 0, 0, 0, 0, +//65535,65535,65535,65535,65535,65535,65535,65535,65535,65535, 15, 0, 0, 0, 0, 0, +//65535,65535,16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 127,41208,65023,24447,65499,65535,65535,65535,65535,65535,65535, 3, 0,65528,65535,65535, +//65535,65535,65535,65535, 0,65535,65535,65535,65535,65532,65535,65535, 255, 0, 0, 4095, +// 0, 0, 0,65535,65055,65527, 3339,65495,65535,65535,65535,65535,65535,65535,65535,40959, +//63470,36863,65535,49151,65534,12287,65534,65534,65535,16383,65535,32767,64764, 7420, 0, 0}; +// +//const uint16_t UnicodePunctBits[] = { +// 256, 0, 0, 272, 0, 288, 304, 320, 0, 336, 0, 0, 0, 352, 368, 384, +// 400, 0, 0, 416, 0, 0, 432, 448, 464, 0, 0, 0, 0, 0, 0, 0, +// 480, 0, 0, 496, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 528, 544, 560, +// 0, 0,65534,64512, 1,63488, 1,30720, 0, 0,65534,65535, 0, 128, 0, 128, +// 0, 0, 0, 0, 0, 0, 0,16384, 128, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0,64512, 0, 0, 1536, 0, 0,16384, 9, 0, 0, 24, +// 4096,34816, 0, 0, 0, 0,15360, 0, 0, 0, 0, 0, 0, 16, 0, 0, +//16383, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 48, 1, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, +// 0, 0, 0, 0,32768, 3072, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//65520, 7, 0,15360, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0,64512, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048, +// 0, 0, 0, 0, 0, 0, 510, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0,24576, 0, 0, 6144, 0, 0, 0, 0,14336, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6128, 0, 0, +// 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0,65535, 255,65535,16239, 0, 0,24576,24576, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 1536, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//65294,65523, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2048, +// 0, 0, 0,49152, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0,65535,65055,65527, 3339, 0, 0, 0, 0, 0, 0, 0, 0, 0, +//63470,35840, 1,47104, 0,10240, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +// +//const uint16_t UnicodeLowerBits[] = { +// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368, +// 384, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416, 0, 0, 0, 432, +// 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0,32768,65535,65407, +//43690,43690,43690,21930,43861,43690,43690,54442,12585,20004,11562,58961,23392,46421,43690,43565, +//43690,43690,43688, 10, 0,65535,65535,65535,65535,65535,16383, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,61440,65535,32767,43235,43690, 15, +// 0, 0, 0,65535,65535,65535,43690,43690,40962,43690,43690,43690, 4372,43690,43690, 554, +// 0, 0, 0, 0, 0, 0,65534,65535, 255, 0, 0, 0, 0, 0, 0, 0, +//43690,43690,43690,43690,43690,43690,43690,43690,43690, 4074,43690,43690,43690,43690,43690, 682, +// 255, 63, 255, 255, 63, 255, 255,16383,65535,65535,65535,20703, 4316, 207, 255, 4316, +// 0, 0, 0, 0, 0, 0, 0,32768, 0, 0, 0, 0, 0, 0, 0, 0, +//50176, 8,32768, 528, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 127, 248, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +// +//const uint16_t UnicodeUpperBits[] = { +// 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384, +// 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416, +// 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0, +//21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53973, 4526,44464,19114,21845,21974, +//21845,21845,21844, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0,21532,21845, 0, +//65535,65535,65535, 0, 0, 0,21845,21845,20481,21845,21845,21845, 2187,21845,21845, 277, +// 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0, +//21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341, +//65280,16128,65280,65280,16128,43520,65280, 0,65280,65280,65280, 7936, 7936, 3840, 7936, 7936, +//14468,15911,15696, 11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +// 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +// MA: March 19, 2010 +// Modified ToUpper and ToLower tables to match values expected by AS3 tests. +// ToLower modifications: +// 304 -> 105 +// 1024 -> 1104 * +// 1037 -> 1117 * +// UoUpper modifications: +// 255 -> 376 +// 305 -> 73 +// 383 -> 83 +// 1104 -> 1024 * +// 1117 -> 1037 * +// Entries marked with a '*' don't make complete sense based on Unicode manual, although +// they match AS3. + + +static const uint16_t UnicodeToUpperBits[] = { + 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 352, 368, + 0, 384, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416, + 0, 0, 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,65407, +43690,43690,43690,21674,43349,43690,43690,54442, 4392, 516, 8490, 8785,21056,46421,43690,43048, // MA: Modified for AS3. +43690, 170, 0, 0, 0, 2776,33545, 36, 3336, 4, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,61440,65534,32767, 0,43688, 0, + 0, 0, 0,65535,65535,65535,43690,43690, 2,43690,43690,43690, 4372,43690,35498, 554, // MA: Modified for AS3. + 0, 0, 0, 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, +43690,43690,43690,43690,43690,43690,43690,43690,43690, 42,43690,43690,43690,43690,43690, 682, + 255, 63, 255, 255, 63, 170, 255,16383, 0, 0, 0, 3, 0, 3, 35, 0, + 0, 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535, 1023, 0, + 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +static const uint16_t UnicodeToLowerBits[] = { + 256, 272, 288, 304, 320, 336, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 352, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368, 384, + 0, 400, 0, 0, 416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 432, + 0, 0, 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0,65535,32639, 0, 0, +21845,21845,21845,43605,21674,21845,21845,11093,52950,45531,53909, 4526,42128,19114,21845,21522,// MA: Modidied for AS3. +21845, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,55104,65534, 4091, 0, 0, 0,21844, 0, +65535,65535,65535, 0, 0, 0,21845,21845, 1,21845,21845,21845, 2186,21845,17749, 277, + 0, 0, 0,65534,65535, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65535,65535, 63, 0, 0, 0, +21845,21845,21845,21845,21845,21845,21845,21845,21845, 21,21845,21845,21845,21845,21845, 341, +65280,16128,65280,65280,16128,43520,65280, 0, 0, 0, 0, 3840, 3840, 3840, 7936, 3840, + 0, 0, 0, 0, 0, 0,65535, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,65472,65535, 0, 0, 0, + 0, 0,65534, 2047, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + +struct GUnicodePairType +{ + uint16_t Key, Value; +}; + +static inline bool CmpUnicodeKey(const GUnicodePairType& a, uint16_t key) +{ + return a.Key < key; +} + +static const GUnicodePairType UnicodeToUpperTable[] = { +{ 97, 65}, { 98, 66}, { 99, 67}, { 100, 68}, { 101, 69}, { 102, 70}, { 103, 71}, +{ 104, 72}, { 105, 73}, { 106, 74}, { 107, 75}, { 108, 76}, { 109, 77}, { 110, 78}, +{ 111, 79}, { 112, 80}, { 113, 81}, { 114, 82}, { 115, 83}, { 116, 84}, { 117, 85}, +{ 118, 86}, { 119, 87}, { 120, 88}, { 121, 89}, { 122, 90}, { 224, 192}, { 225, 193}, +{ 226, 194}, { 227, 195}, { 228, 196}, { 229, 197}, { 230, 198}, { 231, 199}, { 232, 200}, +{ 233, 201}, { 234, 202}, { 235, 203}, { 236, 204}, { 237, 205}, { 238, 206}, { 239, 207}, +{ 240, 208}, { 241, 209}, { 242, 210}, { 243, 211}, { 244, 212}, { 245, 213}, { 246, 214}, +{ 248, 216}, { 249, 217}, { 250, 218}, { 251, 219}, { 252, 220}, { 253, 221}, { 254, 222}, +{ 255, 376}, { 257, 256}, { 259, 258}, { 261, 260}, { 263, 262}, { 265, 264}, { 267, 266}, +{ 269, 268}, { 271, 270}, { 273, 272}, { 275, 274}, { 277, 276}, { 279, 278}, { 281, 280}, +{ 283, 282}, { 285, 284}, { 287, 286}, { 289, 288}, { 291, 290}, { 293, 292}, { 295, 294}, +{ 297, 296}, { 299, 298}, { 301, 300}, { 303, 302}, { 305, 73}, { 307, 306}, { 309, 308}, { 311, 310}, +{ 314, 313}, { 316, 315}, { 318, 317}, { 320, 319}, { 322, 321}, { 324, 323}, { 326, 325}, +{ 328, 327}, { 331, 330}, { 333, 332}, { 335, 334}, { 337, 336}, { 339, 338}, { 341, 340}, +{ 343, 342}, { 345, 344}, { 347, 346}, { 349, 348}, { 351, 350}, { 353, 352}, { 355, 354}, +{ 357, 356}, { 359, 358}, { 361, 360}, { 363, 362}, { 365, 364}, { 367, 366}, { 369, 368}, +{ 371, 370}, { 373, 372}, { 375, 374}, { 378, 377}, { 380, 379}, { 382, 381}, { 383, 83}, { 387, 386}, +{ 389, 388}, { 392, 391}, { 396, 395}, { 402, 401}, { 409, 408}, { 417, 416}, { 419, 418}, +{ 421, 420}, { 424, 423}, { 429, 428}, { 432, 431}, { 436, 435}, { 438, 437}, { 441, 440}, +{ 445, 444}, { 454, 452}, { 457, 455}, { 460, 458}, { 462, 461}, { 464, 463}, { 466, 465}, +{ 468, 467}, { 470, 469}, { 472, 471}, { 474, 473}, { 476, 475}, { 477, 398}, { 479, 478}, +{ 481, 480}, { 483, 482}, { 485, 484}, { 487, 486}, { 489, 488}, { 491, 490}, { 493, 492}, +{ 495, 494}, { 499, 497}, { 501, 500}, { 507, 506}, { 509, 508}, { 511, 510}, { 513, 512}, +{ 515, 514}, { 517, 516}, { 519, 518}, { 521, 520}, { 523, 522}, { 525, 524}, { 527, 526}, +{ 529, 528}, { 531, 530}, { 533, 532}, { 535, 534}, { 595, 385}, { 596, 390}, { 598, 393}, +{ 599, 394}, { 601, 399}, { 603, 400}, { 608, 403}, { 611, 404}, { 616, 407}, { 617, 406}, +{ 623, 412}, { 626, 413}, { 629, 415}, { 643, 425}, { 648, 430}, { 650, 433}, { 651, 434}, +{ 658, 439}, { 940, 902}, { 941, 904}, { 942, 905}, { 943, 906}, { 945, 913}, { 946, 914}, +{ 947, 915}, { 948, 916}, { 949, 917}, { 950, 918}, { 951, 919}, { 952, 920}, { 953, 921}, +{ 954, 922}, { 955, 923}, { 956, 924}, { 957, 925}, { 958, 926}, { 959, 927}, { 960, 928}, +{ 961, 929}, { 962, 931}, { 963, 931}, { 964, 932}, { 965, 933}, { 966, 934}, { 967, 935}, +{ 968, 936}, { 969, 937}, { 970, 938}, { 971, 939}, { 972, 908}, { 973, 910}, { 974, 911}, +{ 995, 994}, { 997, 996}, { 999, 998}, { 1001, 1000}, { 1003, 1002}, { 1005, 1004}, { 1007, 1006}, +{ 1072, 1040}, { 1073, 1041}, { 1074, 1042}, { 1075, 1043}, { 1076, 1044}, { 1077, 1045}, { 1078, 1046}, +{ 1079, 1047}, { 1080, 1048}, { 1081, 1049}, { 1082, 1050}, { 1083, 1051}, { 1084, 1052}, { 1085, 1053}, +{ 1086, 1054}, { 1087, 1055}, { 1088, 1056}, { 1089, 1057}, { 1090, 1058}, { 1091, 1059}, { 1092, 1060}, +{ 1093, 1061}, { 1094, 1062}, { 1095, 1063}, { 1096, 1064}, { 1097, 1065}, { 1098, 1066}, { 1099, 1067}, +{ 1100, 1068}, { 1101, 1069}, { 1102, 1070}, { 1103, 1071}, { 1104, 1024}, { 1105, 1025}, { 1106, 1026}, { 1107, 1027}, +{ 1108, 1028}, { 1109, 1029}, { 1110, 1030}, { 1111, 1031}, { 1112, 1032}, { 1113, 1033}, { 1114, 1034}, +{ 1115, 1035}, { 1116, 1036}, { 1117, 1037}, { 1118, 1038}, { 1119, 1039}, { 1121, 1120}, { 1123, 1122}, { 1125, 1124}, +{ 1127, 1126}, { 1129, 1128}, { 1131, 1130}, { 1133, 1132}, { 1135, 1134}, { 1137, 1136}, { 1139, 1138}, +{ 1141, 1140}, { 1143, 1142}, { 1145, 1144}, { 1147, 1146}, { 1149, 1148}, { 1151, 1150}, { 1153, 1152}, +{ 1169, 1168}, { 1171, 1170}, { 1173, 1172}, { 1175, 1174}, { 1177, 1176}, { 1179, 1178}, { 1181, 1180}, +{ 1183, 1182}, { 1185, 1184}, { 1187, 1186}, { 1189, 1188}, { 1191, 1190}, { 1193, 1192}, { 1195, 1194}, +{ 1197, 1196}, { 1199, 1198}, { 1201, 1200}, { 1203, 1202}, { 1205, 1204}, { 1207, 1206}, { 1209, 1208}, +{ 1211, 1210}, { 1213, 1212}, { 1215, 1214}, { 1218, 1217}, { 1220, 1219}, { 1224, 1223}, { 1228, 1227}, +{ 1233, 1232}, { 1235, 1234}, { 1237, 1236}, { 1239, 1238}, { 1241, 1240}, { 1243, 1242}, { 1245, 1244}, +{ 1247, 1246}, { 1249, 1248}, { 1251, 1250}, { 1253, 1252}, { 1255, 1254}, { 1257, 1256}, { 1259, 1258}, +{ 1263, 1262}, { 1265, 1264}, { 1267, 1266}, { 1269, 1268}, { 1273, 1272}, { 1377, 1329}, { 1378, 1330}, +{ 1379, 1331}, { 1380, 1332}, { 1381, 1333}, { 1382, 1334}, { 1383, 1335}, { 1384, 1336}, { 1385, 1337}, +{ 1386, 1338}, { 1387, 1339}, { 1388, 1340}, { 1389, 1341}, { 1390, 1342}, { 1391, 1343}, { 1392, 1344}, +{ 1393, 1345}, { 1394, 1346}, { 1395, 1347}, { 1396, 1348}, { 1397, 1349}, { 1398, 1350}, { 1399, 1351}, +{ 1400, 1352}, { 1401, 1353}, { 1402, 1354}, { 1403, 1355}, { 1404, 1356}, { 1405, 1357}, { 1406, 1358}, +{ 1407, 1359}, { 1408, 1360}, { 1409, 1361}, { 1410, 1362}, { 1411, 1363}, { 1412, 1364}, { 1413, 1365}, +{ 1414, 1366}, { 7681, 7680}, { 7683, 7682}, { 7685, 7684}, { 7687, 7686}, { 7689, 7688}, { 7691, 7690}, +{ 7693, 7692}, { 7695, 7694}, { 7697, 7696}, { 7699, 7698}, { 7701, 7700}, { 7703, 7702}, { 7705, 7704}, +{ 7707, 7706}, { 7709, 7708}, { 7711, 7710}, { 7713, 7712}, { 7715, 7714}, { 7717, 7716}, { 7719, 7718}, +{ 7721, 7720}, { 7723, 7722}, { 7725, 7724}, { 7727, 7726}, { 7729, 7728}, { 7731, 7730}, { 7733, 7732}, +{ 7735, 7734}, { 7737, 7736}, { 7739, 7738}, { 7741, 7740}, { 7743, 7742}, { 7745, 7744}, { 7747, 7746}, +{ 7749, 7748}, { 7751, 7750}, { 7753, 7752}, { 7755, 7754}, { 7757, 7756}, { 7759, 7758}, { 7761, 7760}, +{ 7763, 7762}, { 7765, 7764}, { 7767, 7766}, { 7769, 7768}, { 7771, 7770}, { 7773, 7772}, { 7775, 7774}, +{ 7777, 7776}, { 7779, 7778}, { 7781, 7780}, { 7783, 7782}, { 7785, 7784}, { 7787, 7786}, { 7789, 7788}, +{ 7791, 7790}, { 7793, 7792}, { 7795, 7794}, { 7797, 7796}, { 7799, 7798}, { 7801, 7800}, { 7803, 7802}, +{ 7805, 7804}, { 7807, 7806}, { 7809, 7808}, { 7811, 7810}, { 7813, 7812}, { 7815, 7814}, { 7817, 7816}, +{ 7819, 7818}, { 7821, 7820}, { 7823, 7822}, { 7825, 7824}, { 7827, 7826}, { 7829, 7828}, { 7841, 7840}, +{ 7843, 7842}, { 7845, 7844}, { 7847, 7846}, { 7849, 7848}, { 7851, 7850}, { 7853, 7852}, { 7855, 7854}, +{ 7857, 7856}, { 7859, 7858}, { 7861, 7860}, { 7863, 7862}, { 7865, 7864}, { 7867, 7866}, { 7869, 7868}, +{ 7871, 7870}, { 7873, 7872}, { 7875, 7874}, { 7877, 7876}, { 7879, 7878}, { 7881, 7880}, { 7883, 7882}, +{ 7885, 7884}, { 7887, 7886}, { 7889, 7888}, { 7891, 7890}, { 7893, 7892}, { 7895, 7894}, { 7897, 7896}, +{ 7899, 7898}, { 7901, 7900}, { 7903, 7902}, { 7905, 7904}, { 7907, 7906}, { 7909, 7908}, { 7911, 7910}, +{ 7913, 7912}, { 7915, 7914}, { 7917, 7916}, { 7919, 7918}, { 7921, 7920}, { 7923, 7922}, { 7925, 7924}, +{ 7927, 7926}, { 7929, 7928}, { 7936, 7944}, { 7937, 7945}, { 7938, 7946}, { 7939, 7947}, { 7940, 7948}, +{ 7941, 7949}, { 7942, 7950}, { 7943, 7951}, { 7952, 7960}, { 7953, 7961}, { 7954, 7962}, { 7955, 7963}, +{ 7956, 7964}, { 7957, 7965}, { 7968, 7976}, { 7969, 7977}, { 7970, 7978}, { 7971, 7979}, { 7972, 7980}, +{ 7973, 7981}, { 7974, 7982}, { 7975, 7983}, { 7984, 7992}, { 7985, 7993}, { 7986, 7994}, { 7987, 7995}, +{ 7988, 7996}, { 7989, 7997}, { 7990, 7998}, { 7991, 7999}, { 8000, 8008}, { 8001, 8009}, { 8002, 8010}, +{ 8003, 8011}, { 8004, 8012}, { 8005, 8013}, { 8017, 8025}, { 8019, 8027}, { 8021, 8029}, { 8023, 8031}, +{ 8032, 8040}, { 8033, 8041}, { 8034, 8042}, { 8035, 8043}, { 8036, 8044}, { 8037, 8045}, { 8038, 8046}, +{ 8039, 8047}, { 8048, 8122}, { 8049, 8123}, { 8050, 8136}, { 8051, 8137}, { 8052, 8138}, { 8053, 8139}, +{ 8054, 8154}, { 8055, 8155}, { 8056, 8184}, { 8057, 8185}, { 8058, 8170}, { 8059, 8171}, { 8060, 8186}, +{ 8061, 8187}, { 8112, 8120}, { 8113, 8121}, { 8144, 8152}, { 8145, 8153}, { 8160, 8168}, { 8161, 8169}, +{ 8165, 8172}, { 8560, 8544}, { 8561, 8545}, { 8562, 8546}, { 8563, 8547}, { 8564, 8548}, { 8565, 8549}, +{ 8566, 8550}, { 8567, 8551}, { 8568, 8552}, { 8569, 8553}, { 8570, 8554}, { 8571, 8555}, { 8572, 8556}, +{ 8573, 8557}, { 8574, 8558}, { 8575, 8559}, { 9424, 9398}, { 9425, 9399}, { 9426, 9400}, { 9427, 9401}, +{ 9428, 9402}, { 9429, 9403}, { 9430, 9404}, { 9431, 9405}, { 9432, 9406}, { 9433, 9407}, { 9434, 9408}, +{ 9435, 9409}, { 9436, 9410}, { 9437, 9411}, { 9438, 9412}, { 9439, 9413}, { 9440, 9414}, { 9441, 9415}, +{ 9442, 9416}, { 9443, 9417}, { 9444, 9418}, { 9445, 9419}, { 9446, 9420}, { 9447, 9421}, { 9448, 9422}, +{ 9449, 9423}, {65345,65313}, {65346,65314}, {65347,65315}, {65348,65316}, {65349,65317}, {65350,65318}, +{65351,65319}, {65352,65320}, {65353,65321}, {65354,65322}, {65355,65323}, {65356,65324}, {65357,65325}, +{65358,65326}, {65359,65327}, {65360,65328}, {65361,65329}, {65362,65330}, {65363,65331}, {65364,65332}, +{65365,65333}, {65366,65334}, {65367,65335}, {65368,65336}, {65369,65337}, {65370,65338}, {65535, 0}}; + +static const GUnicodePairType UnicodeToLowerTable[] = { +{ 65, 97}, { 66, 98}, { 67, 99}, { 68, 100}, { 69, 101}, { 70, 102}, { 71, 103}, +{ 72, 104}, { 73, 105}, { 74, 106}, { 75, 107}, { 76, 108}, { 77, 109}, { 78, 110}, +{ 79, 111}, { 80, 112}, { 81, 113}, { 82, 114}, { 83, 115}, { 84, 116}, { 85, 117}, +{ 86, 118}, { 87, 119}, { 88, 120}, { 89, 121}, { 90, 122}, { 192, 224}, { 193, 225}, +{ 194, 226}, { 195, 227}, { 196, 228}, { 197, 229}, { 198, 230}, { 199, 231}, { 200, 232}, +{ 201, 233}, { 202, 234}, { 203, 235}, { 204, 236}, { 205, 237}, { 206, 238}, { 207, 239}, +{ 208, 240}, { 209, 241}, { 210, 242}, { 211, 243}, { 212, 244}, { 213, 245}, { 214, 246}, +{ 216, 248}, { 217, 249}, { 218, 250}, { 219, 251}, { 220, 252}, { 221, 253}, { 222, 254}, +{ 256, 257}, { 258, 259}, { 260, 261}, { 262, 263}, { 264, 265}, { 266, 267}, { 268, 269}, +{ 270, 271}, { 272, 273}, { 274, 275}, { 276, 277}, { 278, 279}, { 280, 281}, { 282, 283}, +{ 284, 285}, { 286, 287}, { 288, 289}, { 290, 291}, { 292, 293}, { 294, 295}, { 296, 297}, +{ 298, 299}, { 300, 301}, { 302, 303}, { 304, 105}, { 306, 307}, { 308, 309}, { 310, 311}, { 313, 314}, +{ 315, 316}, { 317, 318}, { 319, 320}, { 321, 322}, { 323, 324}, { 325, 326}, { 327, 328}, +{ 330, 331}, { 332, 333}, { 334, 335}, { 336, 337}, { 338, 339}, { 340, 341}, { 342, 343}, +{ 344, 345}, { 346, 347}, { 348, 349}, { 350, 351}, { 352, 353}, { 354, 355}, { 356, 357}, +{ 358, 359}, { 360, 361}, { 362, 363}, { 364, 365}, { 366, 367}, { 368, 369}, { 370, 371}, +{ 372, 373}, { 374, 375}, { 376, 255}, { 377, 378}, { 379, 380}, { 381, 382}, { 385, 595}, +{ 386, 387}, { 388, 389}, { 390, 596}, { 391, 392}, { 393, 598}, { 394, 599}, { 395, 396}, +{ 398, 477}, { 399, 601}, { 400, 603}, { 401, 402}, { 403, 608}, { 404, 611}, { 406, 617}, +{ 407, 616}, { 408, 409}, { 412, 623}, { 413, 626}, { 415, 629}, { 416, 417}, { 418, 419}, +{ 420, 421}, { 423, 424}, { 425, 643}, { 428, 429}, { 430, 648}, { 431, 432}, { 433, 650}, +{ 434, 651}, { 435, 436}, { 437, 438}, { 439, 658}, { 440, 441}, { 444, 445}, { 452, 454}, +{ 455, 457}, { 458, 460}, { 461, 462}, { 463, 464}, { 465, 466}, { 467, 468}, { 469, 470}, +{ 471, 472}, { 473, 474}, { 475, 476}, { 478, 479}, { 480, 481}, { 482, 483}, { 484, 485}, +{ 486, 487}, { 488, 489}, { 490, 491}, { 492, 493}, { 494, 495}, { 497, 499}, { 500, 501}, +{ 506, 507}, { 508, 509}, { 510, 511}, { 512, 513}, { 514, 515}, { 516, 517}, { 518, 519}, +{ 520, 521}, { 522, 523}, { 524, 525}, { 526, 527}, { 528, 529}, { 530, 531}, { 532, 533}, +{ 534, 535}, { 902, 940}, { 904, 941}, { 905, 942}, { 906, 943}, { 908, 972}, { 910, 973}, +{ 911, 974}, { 913, 945}, { 914, 946}, { 915, 947}, { 916, 948}, { 917, 949}, { 918, 950}, +{ 919, 951}, { 920, 952}, { 921, 953}, { 922, 954}, { 923, 955}, { 924, 956}, { 925, 957}, +{ 926, 958}, { 927, 959}, { 928, 960}, { 929, 961}, { 931, 963}, { 932, 964}, { 933, 965}, +{ 934, 966}, { 935, 967}, { 936, 968}, { 937, 969}, { 938, 970}, { 939, 971}, { 994, 995}, +{ 996, 997}, { 998, 999}, { 1000, 1001}, { 1002, 1003}, { 1004, 1005}, { 1006, 1007}, { 1024, 1104}, { 1025, 1105}, +{ 1026, 1106}, { 1027, 1107}, { 1028, 1108}, { 1029, 1109}, { 1030, 1110}, { 1031, 1111}, { 1032, 1112}, +{ 1033, 1113}, { 1034, 1114}, { 1035, 1115}, { 1036, 1116}, { 1037, 1117}, { 1038, 1118}, { 1039, 1119}, { 1040, 1072}, +{ 1041, 1073}, { 1042, 1074}, { 1043, 1075}, { 1044, 1076}, { 1045, 1077}, { 1046, 1078}, { 1047, 1079}, +{ 1048, 1080}, { 1049, 1081}, { 1050, 1082}, { 1051, 1083}, { 1052, 1084}, { 1053, 1085}, { 1054, 1086}, +{ 1055, 1087}, { 1056, 1088}, { 1057, 1089}, { 1058, 1090}, { 1059, 1091}, { 1060, 1092}, { 1061, 1093}, +{ 1062, 1094}, { 1063, 1095}, { 1064, 1096}, { 1065, 1097}, { 1066, 1098}, { 1067, 1099}, { 1068, 1100}, +{ 1069, 1101}, { 1070, 1102}, { 1071, 1103}, { 1120, 1121}, { 1122, 1123}, { 1124, 1125}, { 1126, 1127}, +{ 1128, 1129}, { 1130, 1131}, { 1132, 1133}, { 1134, 1135}, { 1136, 1137}, { 1138, 1139}, { 1140, 1141}, +{ 1142, 1143}, { 1144, 1145}, { 1146, 1147}, { 1148, 1149}, { 1150, 1151}, { 1152, 1153}, { 1168, 1169}, +{ 1170, 1171}, { 1172, 1173}, { 1174, 1175}, { 1176, 1177}, { 1178, 1179}, { 1180, 1181}, { 1182, 1183}, +{ 1184, 1185}, { 1186, 1187}, { 1188, 1189}, { 1190, 1191}, { 1192, 1193}, { 1194, 1195}, { 1196, 1197}, +{ 1198, 1199}, { 1200, 1201}, { 1202, 1203}, { 1204, 1205}, { 1206, 1207}, { 1208, 1209}, { 1210, 1211}, +{ 1212, 1213}, { 1214, 1215}, { 1217, 1218}, { 1219, 1220}, { 1223, 1224}, { 1227, 1228}, { 1232, 1233}, +{ 1234, 1235}, { 1236, 1237}, { 1238, 1239}, { 1240, 1241}, { 1242, 1243}, { 1244, 1245}, { 1246, 1247}, +{ 1248, 1249}, { 1250, 1251}, { 1252, 1253}, { 1254, 1255}, { 1256, 1257}, { 1258, 1259}, { 1262, 1263}, +{ 1264, 1265}, { 1266, 1267}, { 1268, 1269}, { 1272, 1273}, { 1329, 1377}, { 1330, 1378}, { 1331, 1379}, +{ 1332, 1380}, { 1333, 1381}, { 1334, 1382}, { 1335, 1383}, { 1336, 1384}, { 1337, 1385}, { 1338, 1386}, +{ 1339, 1387}, { 1340, 1388}, { 1341, 1389}, { 1342, 1390}, { 1343, 1391}, { 1344, 1392}, { 1345, 1393}, +{ 1346, 1394}, { 1347, 1395}, { 1348, 1396}, { 1349, 1397}, { 1350, 1398}, { 1351, 1399}, { 1352, 1400}, +{ 1353, 1401}, { 1354, 1402}, { 1355, 1403}, { 1356, 1404}, { 1357, 1405}, { 1358, 1406}, { 1359, 1407}, +{ 1360, 1408}, { 1361, 1409}, { 1362, 1410}, { 1363, 1411}, { 1364, 1412}, { 1365, 1413}, { 1366, 1414}, +{ 4256, 4304}, { 4257, 4305}, { 4258, 4306}, { 4259, 4307}, { 4260, 4308}, { 4261, 4309}, { 4262, 4310}, +{ 4263, 4311}, { 4264, 4312}, { 4265, 4313}, { 4266, 4314}, { 4267, 4315}, { 4268, 4316}, { 4269, 4317}, +{ 4270, 4318}, { 4271, 4319}, { 4272, 4320}, { 4273, 4321}, { 4274, 4322}, { 4275, 4323}, { 4276, 4324}, +{ 4277, 4325}, { 4278, 4326}, { 4279, 4327}, { 4280, 4328}, { 4281, 4329}, { 4282, 4330}, { 4283, 4331}, +{ 4284, 4332}, { 4285, 4333}, { 4286, 4334}, { 4287, 4335}, { 4288, 4336}, { 4289, 4337}, { 4290, 4338}, +{ 4291, 4339}, { 4292, 4340}, { 4293, 4341}, { 7680, 7681}, { 7682, 7683}, { 7684, 7685}, { 7686, 7687}, +{ 7688, 7689}, { 7690, 7691}, { 7692, 7693}, { 7694, 7695}, { 7696, 7697}, { 7698, 7699}, { 7700, 7701}, +{ 7702, 7703}, { 7704, 7705}, { 7706, 7707}, { 7708, 7709}, { 7710, 7711}, { 7712, 7713}, { 7714, 7715}, +{ 7716, 7717}, { 7718, 7719}, { 7720, 7721}, { 7722, 7723}, { 7724, 7725}, { 7726, 7727}, { 7728, 7729}, +{ 7730, 7731}, { 7732, 7733}, { 7734, 7735}, { 7736, 7737}, { 7738, 7739}, { 7740, 7741}, { 7742, 7743}, +{ 7744, 7745}, { 7746, 7747}, { 7748, 7749}, { 7750, 7751}, { 7752, 7753}, { 7754, 7755}, { 7756, 7757}, +{ 7758, 7759}, { 7760, 7761}, { 7762, 7763}, { 7764, 7765}, { 7766, 7767}, { 7768, 7769}, { 7770, 7771}, +{ 7772, 7773}, { 7774, 7775}, { 7776, 7777}, { 7778, 7779}, { 7780, 7781}, { 7782, 7783}, { 7784, 7785}, +{ 7786, 7787}, { 7788, 7789}, { 7790, 7791}, { 7792, 7793}, { 7794, 7795}, { 7796, 7797}, { 7798, 7799}, +{ 7800, 7801}, { 7802, 7803}, { 7804, 7805}, { 7806, 7807}, { 7808, 7809}, { 7810, 7811}, { 7812, 7813}, +{ 7814, 7815}, { 7816, 7817}, { 7818, 7819}, { 7820, 7821}, { 7822, 7823}, { 7824, 7825}, { 7826, 7827}, +{ 7828, 7829}, { 7840, 7841}, { 7842, 7843}, { 7844, 7845}, { 7846, 7847}, { 7848, 7849}, { 7850, 7851}, +{ 7852, 7853}, { 7854, 7855}, { 7856, 7857}, { 7858, 7859}, { 7860, 7861}, { 7862, 7863}, { 7864, 7865}, +{ 7866, 7867}, { 7868, 7869}, { 7870, 7871}, { 7872, 7873}, { 7874, 7875}, { 7876, 7877}, { 7878, 7879}, +{ 7880, 7881}, { 7882, 7883}, { 7884, 7885}, { 7886, 7887}, { 7888, 7889}, { 7890, 7891}, { 7892, 7893}, +{ 7894, 7895}, { 7896, 7897}, { 7898, 7899}, { 7900, 7901}, { 7902, 7903}, { 7904, 7905}, { 7906, 7907}, +{ 7908, 7909}, { 7910, 7911}, { 7912, 7913}, { 7914, 7915}, { 7916, 7917}, { 7918, 7919}, { 7920, 7921}, +{ 7922, 7923}, { 7924, 7925}, { 7926, 7927}, { 7928, 7929}, { 7944, 7936}, { 7945, 7937}, { 7946, 7938}, +{ 7947, 7939}, { 7948, 7940}, { 7949, 7941}, { 7950, 7942}, { 7951, 7943}, { 7960, 7952}, { 7961, 7953}, +{ 7962, 7954}, { 7963, 7955}, { 7964, 7956}, { 7965, 7957}, { 7976, 7968}, { 7977, 7969}, { 7978, 7970}, +{ 7979, 7971}, { 7980, 7972}, { 7981, 7973}, { 7982, 7974}, { 7983, 7975}, { 7992, 7984}, { 7993, 7985}, +{ 7994, 7986}, { 7995, 7987}, { 7996, 7988}, { 7997, 7989}, { 7998, 7990}, { 7999, 7991}, { 8008, 8000}, +{ 8009, 8001}, { 8010, 8002}, { 8011, 8003}, { 8012, 8004}, { 8013, 8005}, { 8025, 8017}, { 8027, 8019}, +{ 8029, 8021}, { 8031, 8023}, { 8040, 8032}, { 8041, 8033}, { 8042, 8034}, { 8043, 8035}, { 8044, 8036}, +{ 8045, 8037}, { 8046, 8038}, { 8047, 8039}, { 8120, 8112}, { 8121, 8113}, { 8122, 8048}, { 8123, 8049}, +{ 8136, 8050}, { 8137, 8051}, { 8138, 8052}, { 8139, 8053}, { 8152, 8144}, { 8153, 8145}, { 8154, 8054}, +{ 8155, 8055}, { 8168, 8160}, { 8169, 8161}, { 8170, 8058}, { 8171, 8059}, { 8172, 8165}, { 8184, 8056}, +{ 8185, 8057}, { 8186, 8060}, { 8187, 8061}, { 8544, 8560}, { 8545, 8561}, { 8546, 8562}, { 8547, 8563}, +{ 8548, 8564}, { 8549, 8565}, { 8550, 8566}, { 8551, 8567}, { 8552, 8568}, { 8553, 8569}, { 8554, 8570}, +{ 8555, 8571}, { 8556, 8572}, { 8557, 8573}, { 8558, 8574}, { 8559, 8575}, { 9398, 9424}, { 9399, 9425}, +{ 9400, 9426}, { 9401, 9427}, { 9402, 9428}, { 9403, 9429}, { 9404, 9430}, { 9405, 9431}, { 9406, 9432}, +{ 9407, 9433}, { 9408, 9434}, { 9409, 9435}, { 9410, 9436}, { 9411, 9437}, { 9412, 9438}, { 9413, 9439}, +{ 9414, 9440}, { 9415, 9441}, { 9416, 9442}, { 9417, 9443}, { 9418, 9444}, { 9419, 9445}, { 9420, 9446}, +{ 9421, 9447}, { 9422, 9448}, { 9423, 9449}, {65313,65345}, {65314,65346}, {65315,65347}, {65316,65348}, +{65317,65349}, {65318,65350}, {65319,65351}, {65320,65352}, {65321,65353}, {65322,65354}, {65323,65355}, +{65324,65356}, {65325,65357}, {65326,65358}, {65327,65359}, {65328,65360}, {65329,65361}, {65330,65362}, +{65331,65363}, {65332,65364}, {65333,65365}, {65334,65366}, {65335,65367}, {65336,65368}, {65337,65369}, +{65338,65370}, {65535, 0}}; + +int OVR_CDECL OVR_towupper(wchar_t charCode) +{ + // Don't use UnicodeUpperBits! It differs from UnicodeToUpperBits. + if (UnicodeCharIs(UnicodeToUpperBits, charCode)) + { + // To protect from memory overrun in case the character is not found + // we use one extra fake element in the table {65536, 0}. + size_t idx = Alg::LowerBoundSliced( + UnicodeToUpperTable, + 0, + sizeof(UnicodeToUpperTable) / sizeof(UnicodeToUpperTable[0]) - 1, + (uint16_t)charCode, + CmpUnicodeKey); + return UnicodeToUpperTable[idx].Value; + } + return charCode; +} + +int OVR_CDECL OVR_towlower(wchar_t charCode) +{ + // Don't use UnicodeLowerBits! It differs from UnicodeToLowerBits. + if (UnicodeCharIs(UnicodeToLowerBits, charCode)) + { + // To protect from memory overrun in case the character is not found + // we use one extra fake element in the table {65536, 0}. + size_t idx = Alg::LowerBoundSliced( + UnicodeToLowerTable, + 0, + sizeof(UnicodeToLowerTable) / sizeof(UnicodeToLowerTable[0]) - 1, + (uint16_t)charCode, + CmpUnicodeKey); + return UnicodeToLowerTable[idx].Value; + } + return charCode; +} + +#endif //OVR_NO_WCTYPE + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_Std.h b/LibOVRKernel/Src/Kernel/OVR_Std.h new file mode 100644 index 0000000..6a14231 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Std.h @@ -0,0 +1,638 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Std.h +Content : Standard C function interface +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Std_h +#define OVR_Std_h + +#include "OVR_Types.h" +#include <stdarg.h> // for va_list args +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) +#define OVR_MSVC_SAFESTRING +#include <errno.h> +#endif + +// Wide-char funcs +#include <wchar.h> +#include <wctype.h> + +namespace OVR { + +// Has the same behavior as itoa aside from also having a dest size argument. +// Return value: Pointer to the resulting null-terminated string, same as parameter str. +#if defined(OVR_OS_MS) +inline char* OVR_CDECL OVR_itoa(int val, char *dest, size_t destsize, int radix) +{ +#if defined(OVR_MSVC_SAFESTRING) + _itoa_s(val, dest, destsize, radix); + return dest; +#else + OVR_UNUSED(destsize); + return itoa(val, dest, radix); +#endif +} +#else // OVR_OS_MS +inline char* OVR_itoa(int val, char* dest, size_t len, int radix) +{ + if (val == 0) + { + if (len > 1) + { + dest[0] = '0'; + dest[1] = '\0'; + } + else if(len > 0) + dest[0] = '\0'; + return dest; + } + + // FIXME: Fix the following code to avoid memory write overruns when len is in sufficient. + int cur = val; + size_t i = 0; + size_t sign = 0; + + if (val < 0) + { + val = -val; + sign = 1; + } + + while ((val != 0) && (i < (len - 1 - sign))) + { + cur = val % radix; + val /= radix; + + if (radix == 16) + { + switch(cur) + { + case 10: + dest[i] = 'a'; + break; + case 11: + dest[i] = 'b'; + break; + case 12: + dest[i] = 'c'; + break; + case 13: + dest[i] = 'd'; + break; + case 14: + dest[i] = 'e'; + break; + case 15: + dest[i] = 'f'; + break; + default: + dest[i] = (char)('0' + cur); + break; + } + } + else + { + dest[i] = (char)('0' + cur); + } + ++i; + } + + if (sign) + { + dest[i++] = '-'; + } + + for (size_t j = 0; j < i / 2; ++j) + { + char tmp = dest[j]; + dest[j] = dest[i - 1 - j]; + dest[i - 1 - j] = tmp; + } + dest[i] = '\0'; + + return dest; +} + +#endif + + +// String functions + +inline size_t OVR_CDECL OVR_strlen(const char* str) +{ + return strlen(str); +} + +inline char* OVR_CDECL OVR_strcpy(char* dest, size_t destsize, const char* src) +{ +#if defined(OVR_MSVC_SAFESTRING) + strcpy_s(dest, destsize, src); + return dest; +#else + // FIXME: This should be a safer implementation + OVR_UNUSED(destsize); + return strcpy(dest, src); +#endif +} + + +// Acts the same as the strlcpy function. +// Copies src to dest, 0-terminating even if it involves truncating the write. +// Returns the required strlen of dest (which is one less than the required size of dest). +// strlcpy is a safer alternative to strcpy and strncpy and provides size information. +// However, it still may result in an incomplete copy. +// +// Example usage: +// char buffer[256]; +// if(OVR_strlcpy(buffer, "hello world", sizeof(buffer)) < sizeof(buffer)) +// { there was enough space } +// else +// { need a larger buffer } +// +size_t OVR_CDECL OVR_strlcpy(char* dest, const char* src, size_t destsize); + +// Acts the same as the strlcat function. +// Appends src to dest, 0-terminating even if it involves an incomplete write. +// Doesn't 0-terminate in the case that destsize is 0. +// Returns the required strlen of dest (which is one less than the required size of dest). +// The terminating 0 char of dest is overwritten by the first +// character of src, and a new 0 char is appended to dest. The required capacity +// of the destination is (strlen(src) + strlen(dest) + 1). +// strlcat is a safer alternative to strcat and provides size information. +// However, it still may result in an incomplete copy. +// +// Example usage: +// char buffer[256] = "hello "; +// if(OVR_strlcat(buffer, "world", sizeof(buffer)) < sizeof(buffer)) +// { there was enough space } +// else +// { need a larger buffer } +// +size_t OVR_CDECL OVR_strlcat(char* dest, const char* src, size_t destsize); + + +inline char* OVR_CDECL OVR_strncpy(char* dest, size_t destsize, const char* src, size_t count) +{ +#if defined(OVR_MSVC_SAFESTRING) + strncpy_s(dest, destsize, src, count); + return dest; +#else + // FIXME: This should be a safer implementation + OVR_UNUSED(destsize); + return strncpy(dest, src, count); +#endif +} + +inline char * OVR_CDECL OVR_strcat(char* dest, size_t destsize, const char* src) +{ +#if defined(OVR_MSVC_SAFESTRING) + strcat_s(dest, destsize, src); + return dest; +#else + // FIXME: This should be a safer implementation + OVR_UNUSED(destsize); + return strcat(dest, src); +#endif +} + +inline int OVR_CDECL OVR_strcmp(const char* dest, const char* src) +{ + return strcmp(dest, src); +} + +inline const char* OVR_CDECL OVR_strchr(const char* str, char c) +{ + return strchr(str, c); +} + +inline char* OVR_CDECL OVR_strchr(char* str, char c) +{ + return strchr(str, c); +} + +inline const char* OVR_strrchr(const char* str, char c) +{ + size_t len = OVR_strlen(str); + for (size_t i=len; i>0; i--) + if (str[i]==c) + return str+i; + return 0; +} + +inline const uint8_t* OVR_CDECL OVR_memrchr(const uint8_t* str, size_t size, uint8_t c) +{ + for (intptr_t i = (intptr_t)size - 1; i >= 0; i--) + { + if (str[i] == c) + return str + i; + } + return 0; +} + +inline char* OVR_CDECL OVR_strrchr(char* str, char c) +{ + size_t len = OVR_strlen(str); + for (size_t i=len; i>0; i--) + if (str[i]==c) + return str+i; + return 0; +} + + +double OVR_CDECL OVR_strtod(const char* string, char** tailptr); + +inline long OVR_CDECL OVR_strtol(const char* string, char** tailptr, int radix) +{ + return strtol(string, tailptr, radix); +} + +inline long OVR_CDECL OVR_strtoul(const char* string, char** tailptr, int radix) +{ + return strtoul(string, tailptr, radix); +} + +inline int OVR_CDECL OVR_strncmp(const char* ws1, const char* ws2, size_t size) +{ + return strncmp(ws1, ws2, size); +} + +inline uint64_t OVR_CDECL OVR_strtouq(const char *nptr, char **endptr, int base) +{ +#if defined(OVR_CC_MSVC) + return _strtoui64(nptr, endptr, base); +#else + return strtoull(nptr, endptr, base); +#endif +} + +inline int64_t OVR_CDECL OVR_strtoq(const char *nptr, char **endptr, int base) +{ +#if defined(OVR_CC_MSVC) + return _strtoi64(nptr, endptr, base); +#else + return strtoll(nptr, endptr, base); +#endif +} + + +inline int64_t OVR_CDECL OVR_atoq(const char* string) +{ +#if defined(OVR_CC_MSVC) + return _atoi64(string); +#else + return atoll(string); +#endif +} + +inline uint64_t OVR_CDECL OVR_atouq(const char* string) +{ + return OVR_strtouq(string, NULL, 10); +} + + +// Implemented in OVR_Std.cpp in platform-specific manner. +int OVR_CDECL OVR_stricmp(const char* dest, const char* src); +int OVR_CDECL OVR_strnicmp(const char* dest, const char* src, size_t count); + + +// This is like sprintf but with a destination buffer size argument. However, the behavior is different +// from vsnprintf in that the return value semantics are like sprintf (which returns -1 on capacity overflow) and +// not like snprintf (which returns intended strlen on capacity overflow). +inline size_t OVR_CDECL OVR_sprintf(char *dest, size_t destsize, const char* format, ...) +{ + va_list argList; + va_start(argList,format); + size_t ret; +#if defined(OVR_CC_MSVC) + #if defined(OVR_MSVC_SAFESTRING) + ret = _vsnprintf_s(dest, destsize, _TRUNCATE, format, argList); + OVR_ASSERT(ret != -1); + #else + OVR_UNUSED(destsize); + ret = _vsnprintf(dest, destsize - 1, format, argList); // -1 for space for the null character + OVR_ASSERT(ret != -1); + dest[destsize-1] = 0; + #endif +#else + OVR_UNUSED(destsize); + ret = vsprintf(dest, format, argList); + OVR_ASSERT(ret < destsize); +#endif + va_end(argList); + return ret; +} + + +// This is like vsprintf but with a destination buffer size argument. However, the behavior is different +// from vsnprintf in that the return value semantics are like vsprintf (which returns -1 on capacity overflow) and +// not like vsnprintf (which returns intended strlen on capacity overflow). +// Return value: +// On success, the total number of characters written is returned. +// On failure, a negative number is returned. +inline size_t OVR_CDECL OVR_vsprintf(char *dest, size_t destsize, const char * format, va_list argList) +{ + size_t ret; +#if defined(OVR_CC_MSVC) + #if defined(OVR_MSVC_SAFESTRING) + dest[0] = '\0'; + int rv = vsnprintf_s(dest, destsize, _TRUNCATE, format, argList); + if (rv == -1) + { + dest[destsize - 1] = '\0'; + ret = destsize - 1; + } + else + ret = (size_t)rv; + #else + OVR_UNUSED(destsize); + int rv = _vsnprintf(dest, destsize - 1, format, argList); + OVR_ASSERT(rv != -1); + ret = (size_t)rv; + dest[destsize-1] = 0; + #endif +#else + // FIXME: This should be a safer implementation + OVR_UNUSED(destsize); + ret = (size_t)vsprintf(dest, format, argList); + OVR_ASSERT(ret < destsize); +#endif + return ret; +} + +// Same behavior as ISO C99 vsnprintf. +// Returns the strlen of the resulting formatted string, or a negative value if the format is invalid. +// destsize specifies the capacity of the input buffer. +// +// Example usage: +// void Log(char *dest, size_t destsize, const char * format, ...) +// { +// char buffer[1024]; +// va_list argList; +// va_start(argList,format); +// int result = OVR_vsnprintf(dest, destsize, format, argList); +// assert(result < destsize); // Else we'd have to retry with a dynamically allocated buffer (of size=result+1) and new argList copy. +// va_end(argList); +// } + +inline int OVR_CDECL OVR_vsnprintf(char *dest, size_t destsize, const char * format, va_list argList) +{ + int ret; +#if defined(OVR_CC_MSVC) + OVR_DISABLE_MSVC_WARNING(4996) // 'vsnprintf': This function or variable may be unsafe. + ret = vsnprintf(dest, destsize, format, argList); // Microsoft vsnprintf is non-conforming; it returns -1 if destsize is insufficient. + if (ret < 0) // If there was a format error or if destsize was insufficient... + { + ret = _vscprintf(format, argList); // Get the expected dest strlen. If the return value is still -1 then there was a format error. + + if (destsize) // If we can 0-terminate the output... + { + if (ret < 0) + dest[0] = 0; + else + dest[destsize-1] = 0; + } + } + // Else the string was written OK and ret is its strlen. + OVR_RESTORE_MSVC_WARNING() +#else + ret = vsnprintf(dest, destsize, format, argList); +#endif + return ret; +} + + +// Same behavior as ISO C99 snprintf. +// Returns the strlen of the resulting formatted string, or a negative value if the format is invalid. +// destsize specifies the capacity of the input buffer. +// +// Example usage: +// char buffer[16]; +// int result = OVR_snprintf(buffer, sizeof(buffer), "%d", 37); +// if (result >= sizeof(buffer)) // If there was insufficient capacity... +// { +// char* p = new char[result + 1]; // Or char* p = (char*)OVR_ALLOC(result + 1); +// OVR_snprintf(p, (size_t)result, "%d", 37); +// delete[] p; +// } +// +inline int OVR_CDECL OVR_snprintf(char *dest, size_t destsize, const char * format, ...) +{ + va_list argList; + va_start(argList,format); + int ret = OVR_vsnprintf(dest, destsize, format, argList); + va_end(argList); + return ret; +} + + +// Returns the strlen of the resulting formatted string, or a negative value if the format is invalid. +// Note: If you are planning on printing a string then it's more efficient to just use OVR_vsnprintf and +// look at the return value and handle the uncommon case that there wasn't enough space. +inline int OVR_CDECL OVR_vscprintf(const char * format, va_list argList) +{ + int ret; +#if defined(OVR_CC_MSVC) + ret = _vscprintf(format, argList); +#else + ret = vsnprintf(NULL, 0, format, argList); +#endif + return ret; +} + + +wchar_t* OVR_CDECL OVR_wcscpy(wchar_t* dest, size_t destsize, const wchar_t* src); +wchar_t* OVR_CDECL OVR_wcsncpy(wchar_t* dest, size_t destsize, const wchar_t* src, size_t count); +wchar_t* OVR_CDECL OVR_wcscat(wchar_t* dest, size_t destsize, const wchar_t* src); +size_t OVR_CDECL OVR_wcslen(const wchar_t* str); +int OVR_CDECL OVR_wcscmp(const wchar_t* a, const wchar_t* b); +int OVR_CDECL OVR_wcsicmp(const wchar_t* a, const wchar_t* b); + +inline int OVR_CDECL OVR_wcsicoll(const wchar_t* a, const wchar_t* b) +{ +#if defined(OVR_OS_MS) + #if defined(OVR_CC_MSVC) && (OVR_CC_MSVC >= 1400) + return ::_wcsicoll(a, b); + #else + return ::wcsicoll(a, b); + #endif +#else + // not supported, use regular wcsicmp + return OVR_wcsicmp(a, b); +#endif +} + +inline int OVR_CDECL OVR_wcscoll(const wchar_t* a, const wchar_t* b) +{ +#if defined(OVR_OS_MS) || defined(OVR_OS_LINUX) + return wcscoll(a, b); +#else + // not supported, use regular wcscmp + return OVR_wcscmp(a, b); +#endif +} + +#ifndef OVR_NO_WCTYPE + +inline int OVR_CDECL UnicodeCharIs(const uint16_t* table, wchar_t charCode) +{ + unsigned offset = table[charCode >> 8]; + if (offset == 0) return 0; + if (offset == 1) return 1; + return (table[offset + ((charCode >> 4) & 15)] & (1 << (charCode & 15))) != 0; +} + +extern const uint16_t UnicodeAlnumBits[]; +extern const uint16_t UnicodeAlphaBits[]; +extern const uint16_t UnicodeDigitBits[]; +extern const uint16_t UnicodeSpaceBits[]; +extern const uint16_t UnicodeXDigitBits[]; + +// Uncomment if necessary +//extern const uint16_t UnicodeCntrlBits[]; +//extern const uint16_t UnicodeGraphBits[]; +//extern const uint16_t UnicodeLowerBits[]; +//extern const uint16_t UnicodePrintBits[]; +//extern const uint16_t UnicodePunctBits[]; +//extern const uint16_t UnicodeUpperBits[]; + +inline int OVR_CDECL OVR_iswalnum (wchar_t charCode) { return UnicodeCharIs(UnicodeAlnumBits, charCode); } +inline int OVR_CDECL OVR_iswalpha (wchar_t charCode) { return UnicodeCharIs(UnicodeAlphaBits, charCode); } +inline int OVR_CDECL OVR_iswdigit (wchar_t charCode) { return UnicodeCharIs(UnicodeDigitBits, charCode); } +inline int OVR_CDECL OVR_iswspace (wchar_t charCode) { return UnicodeCharIs(UnicodeSpaceBits, charCode); } +inline int OVR_CDECL OVR_iswxdigit(wchar_t charCode) { return UnicodeCharIs(UnicodeXDigitBits, charCode); } + +// Uncomment if necessary +//inline int OVR_CDECL OVR_iswcntrl (wchar_t charCode) { return UnicodeCharIs(UnicodeCntrlBits, charCode); } +//inline int OVR_CDECL OVR_iswgraph (wchar_t charCode) { return UnicodeCharIs(UnicodeGraphBits, charCode); } +//inline int OVR_CDECL OVR_iswlower (wchar_t charCode) { return UnicodeCharIs(UnicodeLowerBits, charCode); } +//inline int OVR_CDECL OVR_iswprint (wchar_t charCode) { return UnicodeCharIs(UnicodePrintBits, charCode); } +//inline int OVR_CDECL OVR_iswpunct (wchar_t charCode) { return UnicodeCharIs(UnicodePunctBits, charCode); } +//inline int OVR_CDECL OVR_iswupper (wchar_t charCode) { return UnicodeCharIs(UnicodeUpperBits, charCode); } + +int OVR_CDECL OVR_towupper(wchar_t charCode); +int OVR_CDECL OVR_towlower(wchar_t charCode); + +#else // OVR_NO_WCTYPE + +inline int OVR_CDECL OVR_iswspace(wchar_t c) +{ + return iswspace(c); +} + +inline int OVR_CDECL OVR_iswdigit(wchar_t c) +{ + return iswdigit(c); +} + +inline int OVR_CDECL OVR_iswxdigit(wchar_t c) +{ + return iswxdigit(c); +} + +inline int OVR_CDECL OVR_iswalpha(wchar_t c) +{ + return iswalpha(c); +} + +inline int OVR_CDECL OVR_iswalnum(wchar_t c) +{ + return iswalnum(c); +} + +inline wchar_t OVR_CDECL OVR_towlower(wchar_t c) +{ + return (wchar_t)towlower(c); +} + +inline wchar_t OVR_towupper(wchar_t c) +{ + return (wchar_t)towupper(c); +} + +#endif // OVR_NO_WCTYPE + +// ASCII versions of tolower and toupper. Don't use "char" +inline int OVR_CDECL OVR_tolower(int c) +{ + return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; +} + +inline int OVR_CDECL OVR_toupper(int c) +{ + return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; +} + + + +inline double OVR_CDECL OVR_wcstod(const wchar_t* string, wchar_t** tailptr) +{ +#if defined(OVR_OS_OTHER) + OVR_UNUSED(tailptr); + char buffer[64]; + char* tp = NULL; + size_t max = OVR_wcslen(string); + if (max > 63) max = 63; + unsigned char c = 0; + for (size_t i=0; i < max; i++) + { + c = (unsigned char)string[i]; + buffer[i] = ((c) < 128 ? (char)c : '!'); + } + buffer[max] = 0; + return OVR_strtod(buffer, &tp); +#else + return wcstod(string, tailptr); +#endif +} + +inline long OVR_CDECL OVR_wcstol(const wchar_t* string, wchar_t** tailptr, int radix) +{ +#if defined(OVR_OS_OTHER) + OVR_UNUSED(tailptr); + char buffer[64]; + char* tp = NULL; + size_t max = OVR_wcslen(string); + if (max > 63) max = 63; + unsigned char c = 0; + for (size_t i=0; i < max; i++) + { + c = (unsigned char)string[i]; + buffer[i] = ((c) < 128 ? (char)c : '!'); + } + buffer[max] = 0; + return strtol(buffer, &tp, radix); +#else + return wcstol(string, tailptr, radix); +#endif +} + +} // OVR + +#endif // OVR_Std_h diff --git a/LibOVRKernel/Src/Kernel/OVR_String.cpp b/LibOVRKernel/Src/Kernel/OVR_String.cpp new file mode 100644 index 0000000..a539992 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_String.cpp @@ -0,0 +1,779 @@ +/************************************************************************************ + +Filename : OVR_String.cpp +Content : String UTF8 string implementation with copy-on-write semantics + (thread-safe for assignment but not modification). +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_String.h" + +#include <stdlib.h> +#include <ctype.h> + +#ifdef OVR_OS_QNX +# include <strings.h> +#endif + +namespace OVR { + +#define String_LengthIsSize (size_t(1) << String::Flag_LengthIsSizeShift) + +String::DataDesc String::NullData = {String_LengthIsSize, 1, {0} }; + + +String::String() +{ + pData = &NullData; + pData->AddRef(); +}; + +String::String(const char* pdata) +{ + // Obtain length in bytes; it doesn't matter if _data is UTF8. + size_t size = pdata ? OVR_strlen(pdata) : 0; + pData = AllocDataCopy1(size, 0, pdata, size); +}; + +String::String(const char* pdata1, const char* pdata2, const char* pdata3) +{ + // Obtain length in bytes; it doesn't matter if _data is UTF8. + size_t size1 = pdata1 ? OVR_strlen(pdata1) : 0; + size_t size2 = pdata2 ? OVR_strlen(pdata2) : 0; + size_t size3 = pdata3 ? OVR_strlen(pdata3) : 0; + + DataDesc *pdataDesc = AllocDataCopy2(size1 + size2 + size3, 0, + pdata1, size1, pdata2, size2); + memcpy(pdataDesc->Data + size1 + size2, pdata3, size3); + pData = pdataDesc; +} + +String::String(const char* pdata, size_t size) +{ + OVR_ASSERT((size == 0) || (pdata != 0)); + pData = AllocDataCopy1(size, 0, pdata, size); +}; + + +String::String(const InitStruct& src, size_t size) +{ + pData = AllocData(size, 0); + src.InitString(GetData()->Data, size); +} + +String::String(const String& src) +{ + pData = src.GetData(); + pData->AddRef(); +} + +String::String(const StringBuffer& src) +{ + pData = AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize()); +} + +String::String(const wchar_t* data) +{ + pData = &NullData; + pData->AddRef(); + // Simplified logic for wchar_t constructor. + if (data) + *this = data; +} + + +String::DataDesc* String::AllocData(size_t size, size_t lengthIsSize) +{ + String::DataDesc* pdesc; + + if (size == 0) + { + pdesc = &NullData; + pdesc->AddRef(); + return pdesc; + } + + pdesc = (DataDesc*)OVR_ALLOC(sizeof(DataDesc)+ size); + pdesc->Data[size] = 0; + pdesc->RefCount = 1; + pdesc->Size = size | lengthIsSize; + return pdesc; +} + + +String::DataDesc* String::AllocDataCopy1(size_t size, size_t lengthIsSize, + const char* pdata, size_t copySize) +{ + String::DataDesc* pdesc = AllocData(size, lengthIsSize); + memcpy(pdesc->Data, pdata, copySize); + return pdesc; +} + +String::DataDesc* String::AllocDataCopy2(size_t size, size_t lengthIsSize, + const char* pdata1, size_t copySize1, + const char* pdata2, size_t copySize2) +{ + String::DataDesc* pdesc = AllocData(size, lengthIsSize); + memcpy(pdesc->Data, pdata1, copySize1); + memcpy(pdesc->Data + copySize1, pdata2, copySize2); + return pdesc; +} + + +size_t String::GetLength() const +{ + // Optimize length accesses for non-UTF8 character strings. + DataDesc* pdata = GetData(); + size_t length, size = pdata->GetSize(); + + if (pdata->LengthIsSize()) + return size; + + length = (size_t)UTF8Util::GetLength(pdata->Data, (size_t)size); + + if (length == size) + pdata->Size |= String_LengthIsSize; + + return length; +} + + +//static uint32_t String_CharSearch(const char* buf, ) + + +uint32_t String::GetCharAt(size_t index) const +{ + intptr_t i = (intptr_t) index; + DataDesc* pdata = GetData(); + const char* buf = pdata->Data; + uint32_t c; + + if (pdata->LengthIsSize()) + { + OVR_ASSERT(index < pdata->GetSize()); + buf += i; + return UTF8Util::DecodeNextChar_Advance0(&buf); + } + + c = UTF8Util::GetCharAt(index, buf, pdata->GetSize()); + return c; +} + +uint32_t String::GetFirstCharAt(size_t index, const char** offset) const +{ + DataDesc* pdata = GetData(); + intptr_t i = (intptr_t) index; + const char* buf = pdata->Data; + const char* end = buf + pdata->GetSize(); + uint32_t c; + + do + { + c = UTF8Util::DecodeNextChar_Advance0(&buf); + i--; + + if (buf >= end) + { + // We've hit the end of the string; don't go further. + OVR_ASSERT(i == 0); + return c; + } + } while (i >= 0); + + *offset = buf; + + return c; +} + +uint32_t String::GetNextChar(const char** offset) const +{ + return UTF8Util::DecodeNextChar(offset); +} + + + +void String::AppendChar(uint32_t ch) +{ + DataDesc* pdata = GetData(); + size_t size = pdata->GetSize(); + char buff[8]; + intptr_t encodeSize = 0; + + // Converts ch into UTF8 string and fills it into buff. + UTF8Util::EncodeChar(buff, &encodeSize, ch); + OVR_ASSERT(encodeSize >= 0); + + SetData(AllocDataCopy2(size + (size_t)encodeSize, 0, + pdata->Data, size, buff, (size_t)encodeSize)); + pdata->Release(); +} + + +void String::AppendString(const wchar_t* pstr, intptr_t len) +{ + if (!pstr) + return; + + DataDesc* pdata = GetData(); + size_t oldSize = pdata->GetSize(); + size_t encodeSize = (size_t)UTF8Util::GetEncodeStringSize(pstr, len); + + DataDesc* pnewData = AllocDataCopy1(oldSize + (size_t)encodeSize, 0, + pdata->Data, oldSize); + UTF8Util::EncodeString(pnewData->Data + oldSize, pstr, len); + + SetData(pnewData); + pdata->Release(); +} + + +void String::AppendString(const char* putf8str, intptr_t utf8StrSz) +{ + if (!putf8str || !utf8StrSz) + return; + if (utf8StrSz == -1) + utf8StrSz = (intptr_t)OVR_strlen(putf8str); + + DataDesc* pdata = GetData(); + size_t oldSize = pdata->GetSize(); + + SetData(AllocDataCopy2(oldSize + (size_t)utf8StrSz, 0, + pdata->Data, oldSize, putf8str, (size_t)utf8StrSz)); + pdata->Release(); +} + +void String::AssignString(const InitStruct& src, size_t size) +{ + DataDesc* poldData = GetData(); + DataDesc* pnewData = AllocData(size, 0); + src.InitString(pnewData->Data, size); + SetData(pnewData); + poldData->Release(); +} + +void String::AssignString(const char* putf8str, size_t size) +{ + DataDesc* poldData = GetData(); + SetData(AllocDataCopy1(size, 0, putf8str, size)); + poldData->Release(); +} + +void String::operator = (const char* pstr) +{ + AssignString(pstr, pstr ? OVR_strlen(pstr) : 0); +} + +void String::operator = (const wchar_t* pwstr) +{ + pwstr = pwstr ? pwstr : L""; + + DataDesc* poldData = GetData(); + size_t size = (size_t)UTF8Util::GetEncodeStringSize(pwstr); + + DataDesc* pnewData = AllocData(size, 0); + UTF8Util::EncodeString(pnewData->Data, pwstr); + SetData(pnewData); + poldData->Release(); +} + + +void String::operator = (const String& src) +{ + DataDesc* psdata = src.GetData(); + DataDesc* pdata = GetData(); + + SetData(psdata); + psdata->AddRef(); + pdata->Release(); +} + + +void String::operator = (const StringBuffer& src) +{ + DataDesc* polddata = GetData(); + SetData(AllocDataCopy1(src.GetSize(), 0, src.ToCStr(), src.GetSize())); + polddata->Release(); +} + +void String::operator += (const String& src) +{ + DataDesc *pourData = GetData(), + *psrcData = src.GetData(); + size_t ourSize = pourData->GetSize(), + srcSize = psrcData->GetSize(); + size_t lflag = pourData->GetLengthFlag() & psrcData->GetLengthFlag(); + + SetData(AllocDataCopy2(ourSize + srcSize, lflag, + pourData->Data, ourSize, psrcData->Data, srcSize)); + pourData->Release(); +} + + +String String::operator + (const char* str) const +{ + String tmp1(*this); + tmp1 += (str ? str : ""); + return tmp1; +} + +String String::operator + (const String& src) const +{ + String tmp1(*this); + tmp1 += src; + return tmp1; +} + +void String::Remove(size_t posAt, intptr_t removeLength) +{ + DataDesc* pdata = GetData(); + size_t oldSize = pdata->GetSize(); + // Length indicates the number of characters to remove. + size_t length = GetLength(); + + // If index is past the string, nothing to remove. + if (posAt >= length) + return; + // Otherwise, cap removeLength to the length of the string. + if ((posAt + removeLength) > length) + removeLength = length - posAt; + + // Get the byte position of the UTF8 char at position posAt. + intptr_t bytePos = UTF8Util::GetByteIndex(posAt, pdata->Data, oldSize); + intptr_t removeSize = UTF8Util::GetByteIndex(removeLength, pdata->Data + bytePos, oldSize-bytePos); + + SetData(AllocDataCopy2(oldSize - removeSize, pdata->GetLengthFlag(), + pdata->Data, bytePos, + pData->Data + bytePos + removeSize, (oldSize - bytePos - removeSize))); + pdata->Release(); +} + + +String String::Substring(size_t start, size_t end) const +{ + size_t length = GetLength(); + if ((start >= length) || (start >= end)) + return String(); + + DataDesc* pdata = GetData(); + + // If size matches, we know the exact index range. + if (pdata->LengthIsSize()) + return String(pdata->Data + start, end - start); + + // Get position of starting character. + intptr_t byteStart = UTF8Util::GetByteIndex(start, pdata->Data, pdata->GetSize()); + intptr_t byteSize = UTF8Util::GetByteIndex(end - start, pdata->Data + byteStart, pdata->GetSize()-byteStart); + return String(pdata->Data + byteStart, (size_t)byteSize); +} + +void String::Clear() +{ + NullData.AddRef(); + GetData()->Release(); + SetData(&NullData); +} + + +String String::ToUpper() const +{ + uint32_t c; + const char* psource = GetData()->Data; + const char* pend = psource + GetData()->GetSize(); + String str; + intptr_t bufferOffset = 0; + char buffer[512]; + + while(psource < pend) + { + do { + c = UTF8Util::DecodeNextChar_Advance0(&psource); + UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towupper(wchar_t(c))); + } while ((psource < pend) && (bufferOffset < intptr_t(sizeof(buffer)-8))); + + // Append string a piece at a time. + str.AppendString(buffer, bufferOffset); + bufferOffset = 0; + } + + return str; +} + +String String::ToLower() const +{ + uint32_t c; + const char* psource = GetData()->Data; + const char* pend = psource + GetData()->GetSize(); + String str; + intptr_t bufferOffset = 0; + char buffer[512]; + + while(psource < pend) + { + do { + c = UTF8Util::DecodeNextChar_Advance0(&psource); + UTF8Util::EncodeChar(buffer, &bufferOffset, OVR_towlower(wchar_t(c))); + } while ((psource < pend) && (bufferOffset < intptr_t(sizeof(buffer)-8))); + + // Append string a piece at a time. + str.AppendString(buffer, bufferOffset); + bufferOffset = 0; + } + + return str; +} + + + +String& String::Insert(const char* substr, size_t posAt, intptr_t strSize) +{ + DataDesc* poldData = GetData(); + size_t oldSize = poldData->GetSize(); + size_t insertSize = (strSize < 0) ? OVR_strlen(substr) : (size_t)strSize; + size_t byteIndex = (poldData->LengthIsSize()) ? + posAt : (size_t)UTF8Util::GetByteIndex(posAt, poldData->Data, oldSize); + + OVR_ASSERT(byteIndex <= oldSize); + + DataDesc* pnewData = AllocDataCopy2(oldSize + insertSize, 0, + poldData->Data, byteIndex, substr, insertSize); + memcpy(pnewData->Data + byteIndex + insertSize, + poldData->Data + byteIndex, oldSize - byteIndex); + SetData(pnewData); + poldData->Release(); + return *this; +} + +/* +String& String::Insert(const uint32_t* substr, size_t posAt, intptr_t len) +{ + for (intptr_t i = 0; i < len; ++i) + { + size_t charw = InsertCharAt(substr[i], posAt); + posAt += charw; + } + return *this; +} +*/ + +size_t String::InsertCharAt(uint32_t c, size_t posAt) +{ + char buf[8]; + intptr_t index = 0; + UTF8Util::EncodeChar(buf, &index, c); + OVR_ASSERT(index >= 0); + buf[(size_t)index] = 0; + + Insert(buf, posAt, index); + return (size_t)index; +} + + +int String::CompareNoCase(const char* a, const char* b) +{ + return OVR_stricmp(a, b); +} + +int String::CompareNoCase(const char* a, const char* b, intptr_t len) +{ + if (len) + { + intptr_t f,l; + intptr_t slen = len; + const char *s = b; + do { + f = (intptr_t)OVR_tolower((int)(*(a++))); + l = (intptr_t)OVR_tolower((int)(*(b++))); + } while (--len && f && (f == l) && *b != 0); + + if (f == l && (len != 0 || *b != 0)) + { + f = (intptr_t)slen; + l = (intptr_t)OVR_strlen(s); + return int(f - l); + } + + return int(f - l); + } + else + return (0-(int)OVR_strlen(b)); +} + +// ***** Implement hash static functions + +// Hash function +size_t String::BernsteinHashFunction(const void* pdataIn, size_t size, size_t seed) +{ + const uint8_t* pdata = (const uint8_t*) pdataIn; + size_t h = seed; + while (size > 0) + { + size--; + h = ((h << 5) + h) ^ (unsigned) pdata[size]; + } + + return h; +} + +// Hash function, case-insensitive +size_t String::BernsteinHashFunctionCIS(const void* pdataIn, size_t size, size_t seed) +{ + const uint8_t* pdata = (const uint8_t*) pdataIn; + size_t h = seed; + while (size > 0) + { + size--; + h = ((h << 5) + h) ^ OVR_tolower(pdata[size]); + } + + // Alternative: "sdbm" hash function, suggested at same web page above. + // h = 0; + // for bytes { h = (h << 16) + (h << 6) - hash + *p; } + return h; +} + + + +// ***** String Buffer used for Building Strings + + +#define OVR_SBUFF_DEFAULT_GROW_SIZE 512 +// Constructors / Destructor. +StringBuffer::StringBuffer() + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ +} + +StringBuffer::StringBuffer(size_t growSize) + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ + SetGrowSize(growSize); +} + +StringBuffer::StringBuffer(const char* data) + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ + AppendString(data); +} + +StringBuffer::StringBuffer(const char* data, size_t dataSize) + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ + AppendString(data, dataSize); +} + +StringBuffer::StringBuffer(const String& src) + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ + AppendString(src.ToCStr(), src.GetSize()); +} + +StringBuffer::StringBuffer(const StringBuffer& src) + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ + AppendString(src.ToCStr(), src.GetSize()); +} + +StringBuffer::StringBuffer(const wchar_t* data) + : pData(NULL), Size(0), BufferSize(0), GrowSize(OVR_SBUFF_DEFAULT_GROW_SIZE), LengthIsSize(false) +{ + *this = data; +} + +StringBuffer::~StringBuffer() +{ + if (pData) + OVR_FREE(pData); +} +void StringBuffer::SetGrowSize(size_t growSize) +{ + if (growSize <= 16) + GrowSize = 16; + else + { + uint8_t bits = Alg::UpperBit(uint32_t(growSize-1)); + size_t size = (size_t)1 << bits; + GrowSize = size == growSize ? growSize : size; + } +} + +size_t StringBuffer::GetLength() const +{ + size_t length, size = GetSize(); + if (LengthIsSize) + return size; + + length = (size_t)UTF8Util::GetLength(pData, (size_t)GetSize()); + + if (length == GetSize()) + LengthIsSize = true; + return length; +} + +void StringBuffer::Reserve(size_t _size) +{ + if (_size >= BufferSize) // >= because of trailing zero! (!AB) + { + BufferSize = (_size + 1 + GrowSize - 1)& ~(GrowSize-1); + if (!pData) + pData = (char*)OVR_ALLOC(BufferSize); + else + pData = (char*)OVR_REALLOC(pData, BufferSize); + } +} +void StringBuffer::Resize(size_t _size) +{ + Reserve(_size); + LengthIsSize = false; + Size = _size; + if (pData) + pData[Size] = 0; +} + +void StringBuffer::Clear() +{ + Resize(0); + /* + if (pData != pEmptyNullData) + { + OVR_FREE(pHeap, pData); + pData = pEmptyNullData; + Size = BufferSize = 0; + LengthIsSize = false; + } + */ +} +// Appends a character +void StringBuffer::AppendChar(uint32_t ch) +{ + char buff[8]; + size_t origSize = GetSize(); + + // Converts ch into UTF8 string and fills it into buff. Also increments index according to the number of bytes + // in the UTF8 string. + intptr_t srcSize = 0; + UTF8Util::EncodeChar(buff, &srcSize, ch); + OVR_ASSERT(srcSize >= 0); + + size_t size = origSize + srcSize; + Resize(size); + OVR_ASSERT(pData != NULL); + memcpy(pData + origSize, buff, srcSize); +} + +// Append a string +void StringBuffer::AppendString(const wchar_t* pstr, intptr_t len) +{ + if (!pstr || !len) + return; + + intptr_t srcSize = UTF8Util::GetEncodeStringSize(pstr, len); + size_t origSize = GetSize(); + size_t size = srcSize + origSize; + + Resize(size); + OVR_ASSERT(pData != NULL); + UTF8Util::EncodeString(pData + origSize, pstr, len); +} + +void StringBuffer::AppendString(const char* putf8str, intptr_t utf8StrSz) +{ + if (!putf8str || !utf8StrSz) + return; + if (utf8StrSz == -1) + utf8StrSz = (intptr_t)OVR_strlen(putf8str); + + size_t origSize = GetSize(); + size_t size = utf8StrSz + origSize; + + Resize(size); + OVR_ASSERT(pData != NULL); + memcpy(pData + origSize, putf8str, utf8StrSz); +} + +// If pstr is NULL then the StringBuffer is cleared. +void StringBuffer::operator = (const char* pstr) +{ + pstr = pstr ? pstr : ""; + size_t size = OVR_strlen(pstr); + Resize(size); + OVR_ASSERT((pData != NULL) || (size == 0)); + memcpy(pData, pstr, size); +} + +// If pstr is NULL then the StringBuffer is cleared. +void StringBuffer::operator = (const wchar_t* pstr) +{ + pstr = pstr ? pstr : L""; + size_t size = (size_t)UTF8Util::GetEncodeStringSize(pstr); + Resize(size); + OVR_ASSERT((pData != NULL) || (size == 0)); + UTF8Util::EncodeString(pData, pstr); +} + +void StringBuffer::operator = (const String& src) +{ + const size_t size = src.GetSize(); + Resize(size); + OVR_ASSERT((pData != NULL) || (size == 0)); + memcpy(pData, src.ToCStr(), size); +} + +void StringBuffer::operator = (const StringBuffer& src) +{ + Clear(); + AppendString(src.ToCStr(), src.GetSize()); +} + + +// Inserts substr at posAt +void StringBuffer::Insert(const char* substr, size_t posAt, intptr_t len) +{ + size_t oldSize = Size; + size_t insertSize = (len < 0) ? OVR_strlen(substr) : (size_t)len; + size_t byteIndex = LengthIsSize ? posAt : + (size_t)UTF8Util::GetByteIndex(posAt, pData, (intptr_t)Size); + + OVR_ASSERT(byteIndex <= oldSize); + Reserve(oldSize + insertSize); + + OVR_ASSERT(pData != NULL); // pData is unilaterally written to below. + memmove(pData + byteIndex + insertSize, pData + byteIndex, oldSize - byteIndex + 1); + memcpy (pData + byteIndex, substr, insertSize); + LengthIsSize = false; + Size = oldSize + insertSize; + pData[Size] = 0; +} + +// Inserts character at posAt +size_t StringBuffer::InsertCharAt(uint32_t c, size_t posAt) +{ + char buf[8]; + intptr_t len = 0; + UTF8Util::EncodeChar(buf, &len, c); + OVR_ASSERT(len >= 0); + buf[(size_t)len] = 0; + + Insert(buf, posAt, len); + return (size_t)len; +} + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_String.h b/LibOVRKernel/Src/Kernel/OVR_String.h new file mode 100644 index 0000000..ecef940 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_String.h @@ -0,0 +1,658 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_String.h +Content : String UTF8 string implementation with copy-on-write semantics + (thread-safe for assignment but not modification). +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_String_h +#define OVR_String_h + +#include "OVR_Types.h" +#include "OVR_Allocator.h" +#include "OVR_UTF8Util.h" +#include "OVR_Atomic.h" +#include "OVR_Std.h" +#include "OVR_Alg.h" + +namespace OVR { + +// ***** Classes + +class String; +class StringBuffer; + + +//----------------------------------------------------------------------------------- +// ***** String Class + +// String is UTF8 based string class with copy-on-write implementation +// for assignment. + +class String +{ +protected: + + enum FlagConstants + { + //Flag_GetLength = 0x7FFFFFFF, + // This flag is set if GetLength() == GetSize() for a string. + // Avoid extra scanning is Substring and indexing logic. + Flag_LengthIsSizeShift = (sizeof(size_t)*8 - 1) + }; + + + // Internal structure to hold string data + struct DataDesc + { + // Number of bytes. Will be the same as the number of chars if the characters + // are ascii, may not be equal to number of chars in case string data is UTF8. + size_t Size; + volatile int32_t RefCount; + char Data[1]; + + void AddRef() + { + AtomicOps<int32_t>::ExchangeAdd_NoSync(&RefCount, 1); + } + // Decrement ref count. This needs to be thread-safe, since + // a different thread could have also decremented the ref count. + // For example, if u start off with a ref count = 2. Now if u + // decrement the ref count and check against 0 in different + // statements, a different thread can also decrement the ref count + // in between our decrement and checking against 0 and will find + // the ref count = 0 and delete the object. This will lead to a crash + // when context switches to our thread and we'll be trying to delete + // an already deleted object. Hence decrementing the ref count and + // checking against 0 needs to made an atomic operation. + void Release() + { + if ((AtomicOps<int32_t>::ExchangeAdd_NoSync(&RefCount, -1) - 1) == 0) + OVR_FREE(this); + } + + static size_t GetLengthFlagBit() { return size_t(1) << Flag_LengthIsSizeShift; } + size_t GetSize() const { return Size & ~GetLengthFlagBit() ; } + size_t GetLengthFlag() const { return Size & GetLengthFlagBit(); } + bool LengthIsSize() const { return GetLengthFlag() != 0; } + }; + + // Heap type of the string is encoded in the lower bits. + enum HeapType + { + HT_Global = 0, // Heap is global. + HT_Local = 1, // SF::String_loc: Heap is determined based on string's address. + HT_Dynamic = 2, // SF::String_temp: Heap is stored as a part of the class. + HT_Mask = 3 + }; + + union { + DataDesc* pData; + size_t HeapTypeBits; + }; + typedef union { + DataDesc* pData; + size_t HeapTypeBits; + } DataDescUnion; + + inline HeapType GetHeapType() const { return (HeapType) (HeapTypeBits & HT_Mask); } + + inline DataDesc* GetData() const + { + DataDescUnion u; + u.pData = pData; + u.HeapTypeBits = (u.HeapTypeBits & ~(size_t)HT_Mask); + return u.pData; + } + + inline void SetData(DataDesc* pdesc) + { + HeapType ht = GetHeapType(); + pData = pdesc; + OVR_ASSERT((HeapTypeBits & HT_Mask) == 0); + HeapTypeBits |= ht; + } + + + DataDesc* AllocData(size_t size, size_t lengthIsSize); + DataDesc* AllocDataCopy1(size_t size, size_t lengthIsSize, + const char* pdata, size_t copySize); + DataDesc* AllocDataCopy2(size_t size, size_t lengthIsSize, + const char* pdata1, size_t copySize1, + const char* pdata2, size_t copySize2); + + // Special constructor to avoid data initalization when used in derived class. + struct NoConstructor { }; + String(const NoConstructor&) { } + +public: + + // For initializing string with dynamic buffer + struct InitStruct + { + virtual ~InitStruct() { } + virtual void InitString(char* pbuffer, size_t size) const = 0; + }; + + + // Constructors / Destructors. + String(); + String(const char* data); + String(const char* data1, const char* pdata2, const char* pdata3 = 0); + String(const char* data, size_t buflen); + String(const String& src); + String(const StringBuffer& src); + String(const InitStruct& src, size_t size); + explicit String(const wchar_t* data); + + // Destructor (Captain Obvious guarantees!) + ~String() + { + GetData()->Release(); + } + + // Declaration of NullString + static DataDesc NullData; + + + // *** General Functions + + void Clear(); + + // For casting to a pointer to char. + operator const char*() const { return GetData()->Data; } + // Pointer to raw buffer. + const char* ToCStr() const { return GetData()->Data; } + + // Returns number of bytes + size_t GetSize() const { return GetData()->GetSize() ; } + // Tells whether or not the string is empty + bool IsEmpty() const { return GetSize() == 0; } + + // Returns number of characters + size_t GetLength() const; + int GetLengthI() const { return (int)GetLength(); } + + // Returns character at the specified index + uint32_t GetCharAt(size_t index) const; + uint32_t GetFirstCharAt(size_t index, const char** offset) const; + uint32_t GetNextChar(const char** offset) const; + + // Appends a character + void AppendChar(uint32_t ch); + + // Append a string + void AppendString(const wchar_t* pstr, intptr_t len = -1); + void AppendString(const char* putf8str, intptr_t utf8StrSz = -1); + + // Assigned a string with dynamic data (copied through initializer). + void AssignString(const InitStruct& src, size_t size); + // Assigns string with known size. + void AssignString(const char* putf8str, size_t size); + + // Resize the string to the new size +// void Resize(size_t _size); + + // Removes the character at posAt + void Remove(size_t posAt, intptr_t len = 1); + + // Returns a String that's a substring of this. + // -start is the index of the first UTF8 character you want to include. + // -end is the index one past the last UTF8 character you want to include. + String Substring(size_t start, size_t end) const; + + // Case-conversion + String ToUpper() const; + String ToLower() const; + + // Inserts substr at posAt + String& Insert (const char* substr, size_t posAt, intptr_t len = -1); + + // Inserts character at posAt + size_t InsertCharAt(uint32_t c, size_t posAt); + + // Inserts substr at posAt, which is an index of a character (not byte). + // Of size is specified, it is in bytes. +// String& Insert(const uint32_t* substr, size_t posAt, intptr_t size = -1); + + // Get Byte index of the character at position = index + size_t GetByteIndex(size_t index) const { return (size_t)UTF8Util::GetByteIndex(index, GetData()->Data); } + + // Utility: case-insensitive string compare. stricmp() & strnicmp() are not + // ANSI or POSIX, do not seem to appear in Linux. + static int OVR_STDCALL CompareNoCase(const char* a, const char* b); + static int OVR_STDCALL CompareNoCase(const char* a, const char* b, intptr_t len); + + // Hash function, case-insensitive + static size_t OVR_STDCALL BernsteinHashFunctionCIS(const void* pdataIn, size_t size, size_t seed = 5381); + + // Hash function, case-sensitive + static size_t OVR_STDCALL BernsteinHashFunction(const void* pdataIn, size_t size, size_t seed = 5381); + + + // ***** File path parsing helper functions. + // Implemented in OVR_String_FilePath.cpp. + + // Absolute paths can star with: + // - protocols: 'file://', 'http://' + // - windows drive: 'c:\' + // - UNC share name: '\\share' + // - unix root '/' + static bool HasAbsolutePath(const char* path); + static bool HasExtension(const char* path); + static bool HasProtocol(const char* path); + + bool HasAbsolutePath() const { return HasAbsolutePath(ToCStr()); } + bool HasExtension() const { return HasExtension(ToCStr()); } + bool HasProtocol() const { return HasProtocol(ToCStr()); } + + String GetProtocol() const; // Returns protocol, if any, with trailing '://'. + String GetPath() const; // Returns path with trailing '/'. + String GetFilename() const; // Returns filename, including extension. + String GetExtension() const; // Returns extension with a dot. + + void StripProtocol(); // Strips front protocol, if any, from the string. + void StripExtension(); // Strips off trailing extension. + + + // Operators + // Assignment + void operator = (const char* str); + void operator = (const wchar_t* str); + void operator = (const String& src); + void operator = (const StringBuffer& src); + + // Addition + void operator += (const String& src); + void operator += (const char* psrc) { AppendString(psrc); } + void operator += (const wchar_t* psrc) { AppendString(psrc); } + void operator += (char ch) { AppendChar(ch); } + String operator + (const char* str) const; + String operator + (const String& src) const; + + // Comparison + bool operator == (const String& str) const + { + return (OVR_strcmp(GetData()->Data, str.GetData()->Data)== 0); + } + + bool operator != (const String& str) const + { + return !operator == (str); + } + + bool operator == (const char* str) const + { + return OVR_strcmp(GetData()->Data, str) == 0; + } + + bool operator != (const char* str) const + { + return !operator == (str); + } + + bool operator < (const char* pstr) const + { + return OVR_strcmp(GetData()->Data, pstr) < 0; + } + + bool operator < (const String& str) const + { + return *this < str.GetData()->Data; + } + + bool operator > (const char* pstr) const + { + return OVR_strcmp(GetData()->Data, pstr) > 0; + } + + bool operator > (const String& str) const + { + return *this > str.GetData()->Data; + } + + int CompareNoCase(const char* pstr) const + { + return CompareNoCase(GetData()->Data, pstr); + } + int CompareNoCase(const String& str) const + { + return CompareNoCase(GetData()->Data, str.ToCStr()); + } + + // Accesses raw bytes + const char& operator [] (int index) const + { + OVR_ASSERT(index >= 0 && (size_t)index < GetSize()); + return GetData()->Data[index]; + } + const char& operator [] (size_t index) const + { + OVR_ASSERT(index < GetSize()); + return GetData()->Data[index]; + } + + + // Case insensitive keys are used to look up insensitive string in hash tables + // for SWF files with version before SWF 7. + struct NoCaseKey + { + const String* pStr; + NoCaseKey(const String &str) : pStr(&str){}; + }; + + bool operator == (const NoCaseKey& strKey) const + { + return (CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0); + } + bool operator != (const NoCaseKey& strKey) const + { + return !(CompareNoCase(ToCStr(), strKey.pStr->ToCStr()) == 0); + } + + // Hash functor used for strings. + struct HashFunctor + { + size_t operator()(const String& data) const + { + size_t size = data.GetSize(); + return String::BernsteinHashFunction((const char*)data, size); + } + }; + // Case-insensitive hash functor used for strings. Supports additional + // lookup based on NoCaseKey. + struct NoCaseHashFunctor + { + size_t operator()(const String& data) const + { + size_t size = data.GetSize(); + return String::BernsteinHashFunctionCIS((const char*)data, size); + } + size_t operator()(const NoCaseKey& data) const + { + size_t size = data.pStr->GetSize(); + return String::BernsteinHashFunctionCIS((const char*)data.pStr->ToCStr(), size); + } + }; + +}; + + +//----------------------------------------------------------------------------------- +// ***** String Buffer used for Building Strings + +class StringBuffer +{ + char* pData; + size_t Size; + size_t BufferSize; + size_t GrowSize; + mutable bool LengthIsSize; + +public: + + // Constructors / Destructor. + StringBuffer(); + explicit StringBuffer(size_t growSize); + StringBuffer(const char* data); + StringBuffer(const char* data, size_t buflen); + StringBuffer(const String& src); + StringBuffer(const StringBuffer& src); + explicit StringBuffer(const wchar_t* data); + ~StringBuffer(); + + + // Modify grow size used for growing/shrinking the buffer. + size_t GetGrowSize() const { return GrowSize; } + void SetGrowSize(size_t growSize); + + + // *** General Functions + // Does not release memory, just sets Size to 0 + void Clear(); + + // For casting to a pointer to char. + operator const char*() const { return (pData) ? pData : ""; } + // Pointer to raw buffer. + const char* ToCStr() const { return (pData) ? pData : ""; } + + // Returns number of bytes. + size_t GetSize() const { return Size ; } + // Tells whether or not the string is empty. + bool IsEmpty() const { return GetSize() == 0; } + + // Returns number of characters + size_t GetLength() const; + + // Returns character at the specified index + uint32_t GetCharAt(size_t index) const; + uint32_t GetFirstCharAt(size_t index, const char** offset) const; + uint32_t GetNextChar(const char** offset) const; + + + // Resize the string to the new size + void Resize(size_t _size); + void Reserve(size_t _size); + + // Appends a character + void AppendChar(uint32_t ch); + + // Append a string + void AppendString(const wchar_t* pstr, intptr_t len = -1); + void AppendString(const char* putf8str, intptr_t utf8StrSz = -1); + void AppendFormat(const char* format, ...); + + // Assigned a string with dynamic data (copied through initializer). + //void AssignString(const InitStruct& src, size_t size); + + // Inserts substr at posAt + void Insert (const char* substr, size_t posAt, intptr_t len = -1); + // Inserts character at posAt + size_t InsertCharAt(uint32_t c, size_t posAt); + + // Assignment + void operator = (const char* str); + void operator = (const wchar_t* str); + void operator = (const String& src); + void operator = (const StringBuffer& src); + + // Addition + void operator += (const String& src) { AppendString(src.ToCStr(),src.GetSize()); } + void operator += (const char* psrc) { AppendString(psrc); } + void operator += (const wchar_t* psrc) { AppendString(psrc); } + void operator += (char ch) { AppendChar(ch); } + //String operator + (const char* str) const ; + //String operator + (const String& src) const ; + + // Accesses raw bytes + char& operator [] (int index) + { + OVR_ASSERT(((size_t)index) < GetSize()); + return pData[index]; + } + char& operator [] (size_t index) + { + OVR_ASSERT(index < GetSize()); + return pData[index]; + } + + const char& operator [] (int index) const + { + OVR_ASSERT(((size_t)index) < GetSize()); + return pData[index]; + } + const char& operator [] (size_t index) const + { + OVR_ASSERT(index < GetSize()); + return pData[index]; + } +}; + + +// +// Wrapper for string data. The data must have a guaranteed +// lifespan throughout the usage of the wrapper. Not intended for +// cached usage. Not thread safe. +// +class StringDataPtr +{ +public: + StringDataPtr() : pStr(NULL), Size(0) {} + StringDataPtr(const StringDataPtr& p) + : pStr(p.pStr), Size(p.Size) {} + StringDataPtr(const char* pstr, size_t sz) + : pStr(pstr), Size(sz) {} + StringDataPtr(const char* pstr) + : pStr(pstr), Size((pstr != NULL) ? OVR_strlen(pstr) : 0) {} + explicit StringDataPtr(const String& str) + : pStr(str.ToCStr()), Size(str.GetSize()) {} + template <typename T, int N> + StringDataPtr(const T (&v)[N]) + : pStr(v), Size(N) {} + +public: + const char* ToCStr() const { return pStr; } + size_t GetSize() const { return Size; } + bool IsEmpty() const { return GetSize() == 0; } + + // value is a prefix of this string + // Character's values are not compared. + bool IsPrefix(const StringDataPtr& value) const + { + return ToCStr() == value.ToCStr() && GetSize() >= value.GetSize(); + } + // value is a suffix of this string + // Character's values are not compared. + bool IsSuffix(const StringDataPtr& value) const + { + return ToCStr() <= value.ToCStr() && (End()) == (value.End()); + } + + // Find first character. + // init_ind - initial index. + intptr_t FindChar(char c, size_t init_ind = 0) const + { + for (size_t i = init_ind; i < GetSize(); ++i) + if (pStr[i] == c) + return static_cast<intptr_t>(i); + + return -1; + } + + // Find last character. + // init_ind - initial index. + intptr_t FindLastChar(char c, size_t init_ind = ~0) const + { + if (init_ind == (size_t)~0 || init_ind > GetSize()) + init_ind = GetSize(); + else + ++init_ind; + + for (size_t i = init_ind; i > 0; --i) + if (pStr[i - 1] == c) + return static_cast<intptr_t>(i - 1); + + return -1; + } + + // Create new object and trim size bytes from the left. + StringDataPtr GetTrimLeft(size_t size) const + { + // Limit trim size to the size of the string. + size = Alg::PMin(GetSize(), size); + + return StringDataPtr(ToCStr() + size, GetSize() - size); + } + // Create new object and trim size bytes from the right. + StringDataPtr GetTrimRight(size_t size) const + { + // Limit trim to the size of the string. + size = Alg::PMin(GetSize(), size); + + return StringDataPtr(ToCStr(), GetSize() - size); + } + + // Create new object, which contains next token. + // Useful for parsing. + StringDataPtr GetNextToken(char separator = ':') const + { + size_t cur_pos = 0; + const char* cur_str = ToCStr(); + + for (; cur_pos < GetSize() && cur_str[cur_pos]; ++cur_pos) + { + if (cur_str[cur_pos] == separator) + { + break; + } + } + + return StringDataPtr(ToCStr(), cur_pos); + } + + // Trim size bytes from the left. + StringDataPtr& TrimLeft(size_t size) + { + // Limit trim size to the size of the string. + size = Alg::PMin(GetSize(), size); + pStr += size; + Size -= size; + + return *this; + } + // Trim size bytes from the right. + StringDataPtr& TrimRight(size_t size) + { + // Limit trim to the size of the string. + size = Alg::PMin(GetSize(), size); + Size -= size; + + return *this; + } + + const char* Begin() const { return ToCStr(); } + const char* End() const { return ToCStr() + GetSize(); } + + // Hash functor used string data pointers + struct HashFunctor + { + size_t operator()(const StringDataPtr& data) const + { + return String::BernsteinHashFunction(data.ToCStr(), data.GetSize()); + } + }; + + bool operator== (const StringDataPtr& data) const + { + return (OVR_strncmp(pStr, data.pStr, data.Size) == 0); + } + +protected: + const char* pStr; + size_t Size; +}; + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_StringHash.h b/LibOVRKernel/Src/Kernel/OVR_StringHash.h new file mode 100644 index 0000000..410a578 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_StringHash.h @@ -0,0 +1,100 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_StringHash.h +Content : String hash table used when optional case-insensitive + lookup is required. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_StringHash_h +#define OVR_StringHash_h + +#include "OVR_String.h" +#include "OVR_Hash.h" + +namespace OVR { + +//----------------------------------------------------------------------------------- +// *** StringHash + +// This is a custom string hash table that supports case-insensitive +// searches through special functions such as GetCaseInsensitive, etc. +// This class is used for Flash labels, exports and other case-insensitive tables. + +template<class U, class Allocator = ContainerAllocator<U> > +class StringHash : public Hash<String, U, String::NoCaseHashFunctor, Allocator> +{ +public: + typedef U ValueType; + typedef StringHash<U, Allocator> SelfType; + typedef Hash<String, U, String::NoCaseHashFunctor, Allocator> BaseType; + +public: + + void operator = (const SelfType& src) { BaseType::operator = (src); } + + bool GetCaseInsensitive(const String& key, U* pvalue) const + { + String::NoCaseKey ikey(key); + return BaseType::GetAlt(ikey, pvalue); + } + // Pointer-returning get variety. + const U* GetCaseInsensitive(const String& key) const + { + String::NoCaseKey ikey(key); + return BaseType::GetAlt(ikey); + } + U* GetCaseInsensitive(const String& key) + { + String::NoCaseKey ikey(key); + return BaseType::GetAlt(ikey); + } + + + typedef typename BaseType::Iterator base_iterator; + + base_iterator FindCaseInsensitive(const String& key) + { + String::NoCaseKey ikey(key); + return BaseType::FindAlt(ikey); + } + + // Set just uses a find and assigns value if found. The key is not modified; + // this behavior is identical to Flash string variable assignment. + void SetCaseInsensitive(const String& key, const U& value) + { + base_iterator it = FindCaseInsensitive(key); + if (it != BaseType::End()) + { + it->Second = value; + } + else + { + BaseType::Add(key, value); + } + } +}; + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_String_FormatUtil.cpp b/LibOVRKernel/Src/Kernel/OVR_String_FormatUtil.cpp new file mode 100644 index 0000000..d52b6bb --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_String_FormatUtil.cpp @@ -0,0 +1,76 @@ +/************************************************************************************ + +Filename : OVR_String_FormatUtil.cpp +Content : String format functions. +Created : February 27, 2013 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_String.h" +#include "OVR_Log.h" + +namespace OVR { + +void StringBuffer::AppendFormat(const char* format, ...) +{ + va_list argList; + char buffer[512]; + char* bufferUsed = buffer; + char* bufferAllocated = NULL; + + va_start(argList, format); + + #if !defined(OVR_CC_MSVC) // Non-Microsoft compilers require you to save a copy of the va_list. + va_list argListSaved; + va_copy(argListSaved, argList); + #endif + + int requiredStrlen = OVR_vsnprintf(bufferUsed, OVR_ARRAY_COUNT(buffer), format, argList); // The large majority of the time this will succeed. + + if(requiredStrlen >= (int)sizeof(buffer)) // If the initial capacity wasn't enough... + { + bufferAllocated = (char*)OVR_ALLOC(sizeof(char) * (requiredStrlen + 1)); + bufferUsed = bufferAllocated; + if(bufferAllocated) + { + #if !defined(OVR_CC_MSVC) + va_end(argList); + va_copy(argList, argListSaved); + #endif + requiredStrlen = OVR_vsnprintf(bufferAllocated, (requiredStrlen + 1), format, argList); + } + } + + if(requiredStrlen < 0) // If there was a printf format error... + { + bufferUsed = NULL; + } + + va_end(argList); + + if(bufferUsed) + AppendString(bufferUsed); + + if(bufferAllocated) + OVR_FREE(bufferAllocated); +} + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_String_PathUtil.cpp b/LibOVRKernel/Src/Kernel/OVR_String_PathUtil.cpp new file mode 100644 index 0000000..8ed826e --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_String_PathUtil.cpp @@ -0,0 +1,210 @@ +/************************************************************************************ + +Filename : OVR_String_PathUtil.cpp +Content : String filename/url helper function +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_String.h" +#include "OVR_UTF8Util.h" + +namespace OVR { + +//-------------------------------------------------------------------- +// ***** Path-Scanner helper function + +// Scans file path finding filename start and extension start, fills in their addess. +void ScanFilePath(const char* url, const char** pfilename, const char** pext) +{ + const char* urlStart = url; + const char *filename = 0; + const char *lastDot = 0; + + uint32_t charVal = UTF8Util::DecodeNextChar(&url); + + while (charVal != 0) + { + if ((charVal == '/') || (charVal == '\\')) + { + filename = url; + lastDot = 0; + } + else if (charVal == '.') + { + lastDot = url - 1; + } + + charVal = UTF8Util::DecodeNextChar(&url); + } + + if (pfilename) + { + if (filename) + *pfilename = filename; + else + *pfilename = urlStart; + } + + if (pext) + { + *pext = lastDot; + } +} + +// Scans till the end of protocol. Returns first character past protocol, +// 0 if not found. +// - protocol: 'file://', 'http://' +const char* ScanPathProtocol(const char* url) +{ + uint32_t charVal = UTF8Util::DecodeNextChar(&url); + uint32_t charVal2; + + while (charVal != 0) + { + // Treat a colon followed by a slash as absolute. + if (charVal == ':') + { + charVal2 = UTF8Util::DecodeNextChar(&url); + charVal = UTF8Util::DecodeNextChar(&url); + if ((charVal == '/') && (charVal2 == '\\')) + return url; + } + charVal = UTF8Util::DecodeNextChar(&url); + } + return 0; +} + + +//-------------------------------------------------------------------- +// ***** String Path API implementation + +bool String::HasAbsolutePath(const char* url) +{ + // Absolute paths can star with: + // - protocols: 'file://', 'http://' + // - windows drive: 'c:\' + // - UNC share name: '\\share' + // - unix root '/' + + // On the other hand, relative paths are: + // - directory: 'directory/file' + // - this directory: './file' + // - parent directory: '../file' + // + // For now, we don't parse '.' or '..' out, but instead let it be concatenated + // to string and let the OS figure it out. This, however, is not good for file + // name matching in library/etc, so it should be improved. + + if (!url || !*url) + return true; // Treat empty strings as absolute. + + uint32_t charVal = UTF8Util::DecodeNextChar(&url); + + // Fist character of '/' or '\\' means absolute url. + if ((charVal == '/') || (charVal == '\\')) + return true; + + while (charVal != 0) + { + // Treat a colon followed by a slash as absolute. + if (charVal == ':') + { + charVal = UTF8Util::DecodeNextChar(&url); + // Protocol or windows drive. Absolute. + if ((charVal == '/') || (charVal == '\\')) + return true; + } + else if ((charVal == '/') || (charVal == '\\')) + { + // Not a first character (else 'if' above the loop would have caught it). + // Must be a relative url. + break; + } + + charVal = UTF8Util::DecodeNextChar(&url); + } + + // We get here for relative paths. + return false; +} + + +bool String::HasExtension(const char* path) +{ + const char* ext = 0; + ScanFilePath(path, 0, &ext); + return ext != 0; +} +bool String::HasProtocol(const char* path) +{ + return ScanPathProtocol(path) != 0; +} + + +String String::GetPath() const +{ + const char* filename = 0; + ScanFilePath(ToCStr(), &filename, 0); + + // Technically we can have extra logic somewhere for paths, + // such as enforcing protocol and '/' only based on flags, + // but we keep it simple for now. + return String(ToCStr(), filename ? (filename-ToCStr()) : GetSize()); +} + +String String::GetProtocol() const +{ + const char* protocolEnd = ScanPathProtocol(ToCStr()); + return String(ToCStr(), protocolEnd ? (protocolEnd-ToCStr()) : 0); +} + +String String::GetFilename() const +{ + const char* filename = 0; + ScanFilePath(ToCStr(), &filename, 0); + return String(filename); +} +String String::GetExtension() const +{ + const char* ext = 0; + ScanFilePath(ToCStr(), 0, &ext); + return String(ext); +} + +void String::StripExtension() +{ + const char* ext = 0; + ScanFilePath(ToCStr(), 0, &ext); + if (ext) + { + *this = String(ToCStr(), ext-ToCStr()); + } +} + +void String::StripProtocol() +{ + const char* protocol = ScanPathProtocol(ToCStr()); + if (protocol) + AssignString(protocol, OVR_strlen(protocol)); +} + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_SysFile.cpp b/LibOVRKernel/Src/Kernel/OVR_SysFile.cpp new file mode 100644 index 0000000..6ef27c7 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_SysFile.cpp @@ -0,0 +1,138 @@ +/************************************************************************** + +Filename : OVR_SysFile.cpp +Content : File wrapper class implementation (Win32) + +Created : April 5, 1999 +Authors : Michael Antonov + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +**************************************************************************/ + +#define GFILE_CXX + +// Standard C library (Captain Obvious guarantees!) +#include <stdio.h> + +#include "OVR_SysFile.h" +#include "OVR_Log.h" + +namespace OVR { + +// This is - a dummy file that fails on all calls. + +class UnopenedFile : public File +{ +public: + UnopenedFile() { } + ~UnopenedFile() { } + + virtual const char* GetFilePath() { return 0; } + + // ** File Information + virtual bool IsValid() { return 0; } + virtual bool IsWritable() { return 0; } + + // Return position / file size + virtual int Tell() { return 0; } + virtual int64_t LTell() { return 0; } + virtual int GetLength() { return 0; } + virtual int64_t LGetLength() { return 0; } + +// virtual bool Stat(FileStats *pfs) { return 0; } + virtual int GetErrorCode() { return Error_FileNotFound; } + + // ** Stream implementation & I/O + virtual int Write(const uint8_t * /*pbuffer*/, int /*numBytes*/) { return -1; } + virtual int Read(uint8_t * /*pbuffer*/, int /*numBytes*/) { return -1; } + virtual int SkipBytes(int /*numBytes*/) { return 0; } + virtual int BytesAvailable() { return 0; } + virtual bool Flush() { return 0; } + virtual int Seek(int /*offset*/, int /*origin*/) { return -1; } + virtual int64_t LSeek(int64_t /*offset*/, int /*origin*/) { return -1; } + + virtual int CopyFromStream(File * /*pstream*/, int /*byteSize*/) { return -1; } + virtual bool Close() { return 0; } +}; + + + +// ***** System File + +// System file is created to access objects on file system directly +// This file can refer directly to path + +// ** Constructor +SysFile::SysFile() : DelegatedFile(0) +{ + pFile = *new UnopenedFile; +} + +Ptr<File> FileFILEOpen(const String& path, int flags, int mode); + +// Opens a file +SysFile::SysFile(const String& path, int flags, int mode) : DelegatedFile(0) +{ + Open(path, flags, mode); +} + + +// ** Open & management +// Will fail if file's already open +bool SysFile::Open(const String& path, int flags, int mode) +{ + pFile = FileFILEOpen(path, flags, mode); + if ((!pFile) || (!pFile->IsValid())) + { + pFile = *new UnopenedFile; + OVR_DEBUG_LOG(("Failed to open file: %s", path.ToCStr())); + return 0; + } + //pFile = *OVR_NEW DelegatedFile(pFile); // MA Testing + if (flags & Open_Buffered) + pFile = *new BufferedFile(pFile); + return 1; +} + + +// ** Overrides + +int SysFile::GetErrorCode() +{ + return pFile ? pFile->GetErrorCode() : Error_FileNotFound; +} + + +// Overrides to provide re-open support +bool SysFile::IsValid() +{ + return pFile && pFile->IsValid(); +} +bool SysFile::Close() +{ + if (IsValid()) + { + DelegatedFile::Close(); + pFile = *new UnopenedFile; + return 1; + } + return 0; +} + +} // OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_SysFile.h b/LibOVRKernel/Src/Kernel/OVR_SysFile.h new file mode 100644 index 0000000..925c51d --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_SysFile.h @@ -0,0 +1,104 @@ +/************************************************************************************ + +PublicHeader: Kernel +Filename : OVR_SysFile.h +Content : Header for all internal file management - functions and structures + to be inherited by OS specific subclasses. +Created : September 19, 2012 +Notes : + +Notes : errno may not be preserved across use of GBaseFile member functions + : Directories cannot be deleted while files opened from them are in use + (For the GetFullName function) + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_SysFile_h +#define OVR_SysFile_h + +#include "OVR_File.h" + +namespace OVR { + +// ***** Declared classes +class SysFile; + +//----------------------------------------------------------------------------------- +// *** File Statistics + +// This class contents are similar to _stat, providing +// creation, modify and other information about the file. +struct FileStat +{ + // No change or create time because they are not available on most systems + int64_t ModifyTime; + int64_t AccessTime; + int64_t FileSize; + + bool operator== (const FileStat& stat) const + { + return ( (ModifyTime == stat.ModifyTime) && + (AccessTime == stat.AccessTime) && + (FileSize == stat.FileSize) ); + } +}; + +//----------------------------------------------------------------------------------- +// *** System File + +// System file is created to access objects on file system directly +// This file can refer directly to path. +// System file can be open & closed several times; however, such use is not recommended +// This class is realy a wrapper around an implementation of File interface for a +// particular platform. + +class SysFile : public DelegatedFile +{ +protected: + SysFile(const SysFile &source) : DelegatedFile () { OVR_UNUSED(source); } +public: + + // ** Constructor + SysFile(); + // Opens a file + SysFile(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite); + + // ** Open & management + bool Open(const String& path, int flags = Open_Read|Open_Buffered, int mode = Mode_ReadWrite); + + OVR_FORCE_INLINE bool Create(const String& path, int mode = Mode_ReadWrite) + { return Open(path, Open_ReadWrite|Open_Create, mode); } + + // Helper function: obtain file statistics information. In OVR, this is used to detect file changes. + // Return 0 if function failed, most likely because the file doesn't exist. + static bool OVR_CDECL GetFileStat(FileStat* pfileStats, const String& path); + + // ** Overrides + // Overridden to provide re-open support + virtual int GetErrorCode(); + + virtual bool IsValid(); + + virtual bool Close(); +}; + +} // Namespace OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_System.cpp b/LibOVRKernel/Src/Kernel/OVR_System.cpp new file mode 100644 index 0000000..6ab1294 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_System.cpp @@ -0,0 +1,148 @@ +/************************************************************************************ + +Filename : OVR_System.cpp +Content : General kernel initialization/cleanup, including that + of the memory allocator. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_System.h" +#include "OVR_Threads.h" +#include "OVR_Timer.h" +#include "OVR_DebugHelp.h" + +#ifdef OVR_OS_MS + #pragma warning(push, 0) + #include "OVR_Win32_IncludeWindows.h" // GetModuleHandleEx + #pragma warning(pop) +#endif + +namespace OVR { + + +//----------------------------------------------------------------------------- +// Initialization/Shutdown Callbacks + +static SystemSingletonInternal *SystemShutdownListenerList = nullptr; // Points to the most recent SystemSingletonInternal added to the list. + +static Lock& GetSSILock() +{ // Put listLock in a function so that it can be constructed on-demand. + static Lock listLock; // Will construct on the first usage. However, the guarding of this construction is not thread-safe + return listLock; // under all compilers. However, since we are initially calling this on startup before other threads +} // could possibly exist, the first usage of this will be before other threads exist. + +void SystemSingletonInternal::RegisterDestroyCallback() +{ + Lock::Locker locker(&GetSSILock()); + + // Insert the listener at the front of the list (top of the stack). This is an analogue of a C++ forward_list::push_front or stack::push. + NextShutdownSingleton = SystemShutdownListenerList; + SystemShutdownListenerList = this; +} + + +//----------------------------------------------------------------------------- +// System + +// Initializes System core, installing allocator. +void System::Init(Log* log, Allocator *palloc) +{ + if (!Allocator::GetInstance()) + { + if (Allocator::IsTrackingLeaks()) + { + SymbolLookup::Initialize(); + } + + Log::SetGlobalLog(log); + Timer::initializeTimerSystem(); + Allocator::setInstance(palloc); + } + else + { + OVR_DEBUG_LOG(("[System] Init failed - duplicate call.")); + } +} + +void System::Destroy() +{ + if (Allocator::GetInstance()) + { + // Invoke all of the post-finish callbacks (normal case) + for (SystemSingletonInternal *listener = SystemShutdownListenerList; listener; listener = listener->NextShutdownSingleton) + { + listener->OnThreadDestroy(); + } + + #ifdef OVR_ENABLE_THREADS + // Wait for all threads to finish; this must be done so that memory + // allocator and all destructors finalize correctly. + Thread::FinishAllThreads(); + #endif + + // Invoke all of the post-finish callbacks (normal case) + for (SystemSingletonInternal* next, *listener = SystemShutdownListenerList; listener; listener = next) + { + next = listener->NextShutdownSingleton; + + listener->OnSystemDestroy(); + } + + SystemShutdownListenerList = nullptr; + + // Shutdown heap and destroy SysAlloc singleton, if any. + Allocator::GetInstance()->onSystemShutdown(); + Allocator::setInstance(nullptr); + + if (Allocator::IsTrackingLeaks()) + { + SymbolLookup::Shutdown(); + } + + Timer::shutdownTimerSystem(); + Log::SetGlobalLog(Log::GetDefaultLog()); + + if (Allocator::IsTrackingLeaks()) + { + int ovrLeakCount = DumpMemory(); + + OVR_ASSERT(ovrLeakCount == 0); + if (ovrLeakCount == 0) + { + OVR_DEBUG_LOG(("[System] No OVR object leaks detected.")); + } + } + } + else + { + OVR_DEBUG_LOG(("[System] Destroy failed - System not initialized.")); + } +} + +// Returns 'true' if system was properly initialized. +bool System::IsInitialized() +{ + return Allocator::GetInstance() != nullptr; +} + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_System.h b/LibOVRKernel/Src/Kernel/OVR_System.h new file mode 100644 index 0000000..d66fbe7 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_System.h @@ -0,0 +1,174 @@ +/************************************************************************************ + +PublicHeader: OVR +Filename : OVR_System.h +Content : General kernel initialization/cleanup, including that + of the memory allocator. +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_System_h +#define OVR_System_h + +#include "OVR_Allocator.h" +#include "OVR_Log.h" +#include "OVR_Atomic.h" + +namespace OVR { + + +//----------------------------------------------------------------------------- +// SystemSingleton + +// Subsystems are implemented using the Singleton pattern. +// To avoid code duplication in all the places where Singletons are defined, +// The pattern is defined once here and used everywhere. + +class SystemSingletonInternal +{ + friend class System; + + // Allows for including this class in the shutdown list. + SystemSingletonInternal* NextShutdownSingleton; + + // No copying allowed + OVR_NON_COPYABLE(SystemSingletonInternal); + +public: + // Call this to register for a call to OnThreadDestroy and OnSystemDestroy before the + // Kernel is shut down. OnThreadDestroy is called before any remaining existing threads + // are exited. Registered callbacks are called in the reverse order they were registered. + // You would typically call this at the end of your SystemSingletonInternal subclass' constructor. + // The registered objects are not deleted on shutdown; they would have to do that themselves within + // OnSystemDestroy or via a compiler-generated static destruction. + void RegisterDestroyCallback(); + void PushDestroyCallbacks() { RegisterDestroyCallback(); } // For backward compatibility. + +protected: + SystemSingletonInternal() : + NextShutdownSingleton(nullptr) + { + } + + virtual ~SystemSingletonInternal(){} + + // Initializes the SystemSingletonInternal. + // You can register for an automatic call to this function by calling PushInitCallbacks. + // The registration of an automatic call to this is not required, but may be useful if + // you need to postpone your initialization until after Kernel is initialized. + // You cannot call PushInitCallbacks or PushDestroyCallbacks while within this function. + virtual void OnSystemInit() {} + + // Called just before waiting for threads to exit. + // Listeners are called in the opposite order they were registered. + // This function is useful for terminating threads at the right time before the rest of the system is shut down. + // Note: The singleton must not delete itself here, as OnSystemDestroy will subsequently be called for it. + virtual void OnThreadDestroy() {} + + // Shuts down the SystemSingletonInternal. + // You can register for an automatic call to this function by calling PushDestroyCallbacks. + // The registration of an automatic call to this is not required, but may be useful if + // you need to delay your shutdown until application exit time. + // You cannot call PushInitCallbacks or PushDestroyCallbacks while within this function. + // This function may delete this. + virtual void OnSystemDestroy() {} +}; + +// Singletons derive from this class +template<class T> +class SystemSingletonBase : public SystemSingletonInternal +{ + static AtomicPtr<T> SingletonInstance; + static T* SlowGetInstance(); + +protected: + ~SystemSingletonBase() + { + // Make sure the instance gets set to zero on dtor + if (SingletonInstance == this) + SingletonInstance = nullptr; + } + +public: + static OVR_FORCE_INLINE T* GetInstance() + { + // Fast version + // Note: The singleton instance is stored in an AtomicPtr<> to allow it to be accessed + // atomically from multiple threads without locks. + T* instance = SingletonInstance; + return instance ? instance : SlowGetInstance(); + } +}; + +// For reference, see N3337 14.5.1.3 (Static data members of class templates): +template<class T> OVR::AtomicPtr<T> OVR::SystemSingletonBase<T>::SingletonInstance; + +// Place this in the singleton class in the header file +#define OVR_DECLARE_SINGLETON(T) \ + friend class OVR::SystemSingletonBase<T>; \ +private: \ + T(); \ + virtual ~T(); \ + virtual void OnSystemDestroy(); + +// Place this in the singleton class source file +#define OVR_DEFINE_SINGLETON(T) \ + namespace OVR { \ + template<> T* SystemSingletonBase<T>::SlowGetInstance() \ + { \ + static OVR::Lock lock; \ + OVR::Lock::Locker locker(&lock); \ + if (!SingletonInstance) \ + SingletonInstance = new T; \ + return SingletonInstance; \ + } \ + } + + +// ***** System Core Initialization class + +// System initialization must take place before any other OVR_Kernel objects are used; +// this is done my calling System::Init(). Among other things, this is necessary to +// initialize the memory allocator. Similarly, System::Destroy must be +// called before program exist for proper cleanup. Both of these tasks can be achieved by +// simply creating System object first, allowing its constructor/destructor do the work. + +class System +{ +public: + // Returns 'true' if system was properly initialized. + static bool OVR_CDECL IsInitialized(); + + // Initializes System core. Users can override memory implementation by passing + // a different Allocator here. + static void OVR_CDECL Init(Log* log = Log::ConfigureDefaultLog(LogMask_Debug), + Allocator *palloc = DefaultAllocator::InitSystemSingleton()); + + // De-initializes System more, finalizing the threading system and destroying + // the global memory allocator. + static void OVR_CDECL Destroy(); +}; + + +} // namespace OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_ThreadCommandQueue.cpp b/LibOVRKernel/Src/Kernel/OVR_ThreadCommandQueue.cpp new file mode 100644 index 0000000..8c36ac7 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_ThreadCommandQueue.cpp @@ -0,0 +1,405 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_ThreadCommandQueue.cpp +Content : Command queue for operations executed on a thread +Created : October 29, 2012 + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_ThreadCommandQueue.h" + +namespace OVR { + + +//------------------------------------------------------------------------ +// ***** CircularBuffer + +// CircularBuffer is a FIFO buffer implemented in a single block of memory, +// which allows writing and reading variable-size data chucks. Write fails +// if buffer is full. + +class CircularBuffer +{ + enum { + AlignSize = 16, + AlignMask = AlignSize - 1 + }; + + uint8_t* pBuffer; + size_t Size; + size_t Tail; // Byte offset of next item to be popped. + size_t Head; // Byte offset of where next push will take place. + size_t End; // When Head < Tail, this is used instead of Size. + + inline size_t roundUpSize(size_t size) + { return (size + AlignMask) & ~(size_t)AlignMask; } + +public: + + CircularBuffer(size_t size) + : Size(size), Tail(0), Head(0), End(0) + { + pBuffer = (uint8_t*)OVR_ALLOC_ALIGNED(roundUpSize(size), AlignSize); + } + ~CircularBuffer() + { + // For ThreadCommands, we must consume everything before shutdown. + OVR_ASSERT(IsEmpty()); + OVR_FREE_ALIGNED(pBuffer); + } + + bool IsEmpty() const { return (Head == Tail); } + + // Allocates a state block of specified size and advances pointers, + // returning 0 if buffer is full. + uint8_t* Write(size_t size); + + // Returns a pointer to next available data block; 0 if none available. + uint8_t* ReadBegin() + { return (Head != Tail) ? (pBuffer + Tail) : 0; } + // Consumes data of specified size; this must match size passed to Write. + void ReadEnd(size_t size); +}; + + +// Allocates a state block of specified size and advances pointers, +// returning 0 if buffer is full. +uint8_t* CircularBuffer::Write(size_t size) +{ + uint8_t* p = 0; + + size = roundUpSize(size); + // Since this is circular buffer, always allow at least one item. + OVR_ASSERT(size < Size/2); + + if (Head >= Tail) + { + OVR_ASSERT(End == 0); + + if (size <= (Size - Head)) + { + p = pBuffer + Head; + Head += size; + } + else if (size < Tail) + { + p = pBuffer; + End = Head; + Head = size; + OVR_ASSERT(Head != Tail); + } + } + else + { + OVR_ASSERT(End != 0); + + if ((Tail - Head) > size) + { + p = pBuffer + Head; + Head += size; + OVR_ASSERT(Head != Tail); + } + } + + return p; +} + +void CircularBuffer::ReadEnd(size_t size) +{ + OVR_ASSERT(Head != Tail); + size = roundUpSize(size); + + Tail += size; + if (Tail == End) + { + Tail = End = 0; + } + else if (Tail == Head) + { + OVR_ASSERT(End == 0); + Tail = Head = 0; + } +} + + +//------------------------------------------------------------------------------------- +// ***** ThreadCommand + +ThreadCommand::PopBuffer::~PopBuffer() +{ + if (Size) { + Destruct<ThreadCommand>(toCommand()); + } +} + +void ThreadCommand::PopBuffer::InitFromBuffer(void* data) +{ + ThreadCommand* cmd = (ThreadCommand*)data; + + if (Size) { + Destruct<ThreadCommand>(toCommand()); + } + Size = cmd->Size; + if (Size > MaxSize) + Size = MaxSize; + memcpy(Buffer, (void*)cmd, Size); +} + +void ThreadCommand::PopBuffer::Execute() +{ + ThreadCommand* command = toCommand(); + OVR_ASSERT(command); + if (command) + { + command->Execute(); + } + if (NeedsWait()) { + GetEvent()->PulseEvent(); + } +} + +//------------------------------------------------------------------------------------- + +class ThreadCommandQueueImpl : public NewOverrideBase +{ + typedef ThreadCommand::NotifyEvent NotifyEvent; + friend class ThreadCommandQueue; + +public: + + ThreadCommandQueueImpl(ThreadCommandQueue* queue) : + pQueue(queue), + ExitEnqueued(false), + ExitProcessed(false), + CommandBuffer(2048), + PullThreadId(0) + { + } + ~ThreadCommandQueueImpl(); + + + bool PushCommand(const ThreadCommand& command); + bool PopCommand(ThreadCommand::PopBuffer* popBuffer); + + + // ExitCommand is used by notify us that Thread is shutting down. + struct ExitCommand : public ThreadCommand + { + ThreadCommandQueueImpl* pImpl; + + ExitCommand(ThreadCommandQueueImpl* impl, bool wait) + : ThreadCommand(sizeof(ExitCommand), wait, true), pImpl(impl) { } + + virtual void Execute() const + { + Lock::Locker lock(&pImpl->QueueLock); + pImpl->ExitProcessed = true; + } + virtual ThreadCommand* CopyConstruct(void* p) const + { return Construct<ExitCommand>(p, *this); } + }; + + + NotifyEvent* AllocNotifyEvent_NTS() + { + NotifyEvent* p = AvailableEvents.GetFirst(); + + if (!AvailableEvents.IsNull(p)) + p->RemoveNode(); + else + p = new NotifyEvent; + return p; + } + + void FreeNotifyEvent_NTS(NotifyEvent* p) + { + AvailableEvents.PushBack(p); + } + + void FreeNotifyEvents_NTS() + { + while(!AvailableEvents.IsEmpty()) + { + NotifyEvent* p = AvailableEvents.GetFirst(); + p->RemoveNode(); + delete p; + } + } + + ThreadCommandQueue* pQueue; + Lock QueueLock; + volatile bool ExitEnqueued; + volatile bool ExitProcessed; + List<NotifyEvent> AvailableEvents; + List<NotifyEvent> BlockedProducers; + CircularBuffer CommandBuffer; + + // The pull thread id is set to the last thread that pulled commands. + // Since this thread command queue is designed for a single thread, + // reentrant behavior that would cause a dead-lock for messages that + // wait for completion can be avoided by simply comparing the + // thread id of the last pull. + OVR::ThreadId PullThreadId; +}; + +ThreadCommandQueueImpl::~ThreadCommandQueueImpl() +{ + Lock::Locker lock(&QueueLock); + OVR_ASSERT(BlockedProducers.IsEmpty()); + FreeNotifyEvents_NTS(); +} + +bool ThreadCommandQueueImpl::PushCommand(const ThreadCommand& command) +{ + if (command.NeedsWait() && PullThreadId == OVR::GetCurrentThreadId()) + { + command.Execute(); + return true; + } + + ThreadCommand::NotifyEvent* completeEvent = 0; + ThreadCommand::NotifyEvent* queueAvailableEvent = 0; + + // Repeat writing command into buffer until it is available. + for (;;) { + { // Lock Scope + Lock::Locker lock(&QueueLock); + + if (queueAvailableEvent) { + FreeNotifyEvent_NTS(queueAvailableEvent); + queueAvailableEvent = 0; + } + + // Don't allow any commands after PushExitCommand() is called. + if (ExitEnqueued && !command.ExitFlag) { + return false; + } + + bool bufferWasEmpty = CommandBuffer.IsEmpty(); + uint8_t* buffer = CommandBuffer.Write(command.GetSize()); + + if (buffer) { + ThreadCommand* c = command.CopyConstruct(buffer); + + if (c->NeedsWait()) { + completeEvent = c->pEvent = AllocNotifyEvent_NTS(); + } + + // Signal-waker consumer when we add data to buffer. + if (bufferWasEmpty) { + pQueue->OnPushNonEmpty_Locked(); + } + + break; + } + + queueAvailableEvent = AllocNotifyEvent_NTS(); + BlockedProducers.PushBack(queueAvailableEvent); + } // Lock Scope + + queueAvailableEvent->Wait(); + } // Intentional infinite loop + + // Command was enqueued, wait if necessary. + if (completeEvent) { + completeEvent->Wait(); + Lock::Locker lock(&QueueLock); + FreeNotifyEvent_NTS(completeEvent); + } + + return true; +} + + +// Pops the next command from the thread queue, if any is available. +bool ThreadCommandQueueImpl::PopCommand(ThreadCommand::PopBuffer* popBuffer) +{ + PullThreadId = OVR::GetCurrentThreadId(); + + Lock::Locker lock(&QueueLock); + + uint8_t* buffer = CommandBuffer.ReadBegin(); + if (!buffer) + { + // Notify thread while in lock scope, enabling initialization of wait. + pQueue->OnPopEmpty_Locked(); + return false; + } + + popBuffer->InitFromBuffer(buffer); + CommandBuffer.ReadEnd(popBuffer->GetSize()); + + if (!BlockedProducers.IsEmpty()) + { + ThreadCommand::NotifyEvent* queueAvailableEvent = BlockedProducers.GetFirst(); + queueAvailableEvent->RemoveNode(); + queueAvailableEvent->PulseEvent(); + // Event is freed later by waiter. + } + return true; +} + + +//------------------------------------------------------------------------------------- + +ThreadCommandQueue::ThreadCommandQueue() +{ + pImpl = new ThreadCommandQueueImpl(this); +} +ThreadCommandQueue::~ThreadCommandQueue() +{ + delete pImpl; +} + +bool ThreadCommandQueue::PushCommand(const ThreadCommand& command) +{ + return pImpl->PushCommand(command); +} + +bool ThreadCommandQueue::PopCommand(ThreadCommand::PopBuffer* popBuffer) +{ + return pImpl->PopCommand(popBuffer); +} + +void ThreadCommandQueue::PushExitCommand(bool wait) +{ + // Exit is processed in two stages: + // - First, ExitEnqueued flag is set to block further commands from queuing up. + // - Second, the actual exit call is processed on the consumer thread, flushing + // any prior commands. + // IsExiting() only returns true after exit has flushed. + { + Lock::Locker lock(&pImpl->QueueLock); + if (pImpl->ExitEnqueued) + return; + pImpl->ExitEnqueued = true; + } + + PushCommand(ThreadCommandQueueImpl::ExitCommand(pImpl, wait)); +} + +bool ThreadCommandQueue::IsExiting() const +{ + return pImpl->ExitProcessed; +} + + +} // namespace OVR diff --git a/LibOVRKernel/Src/Kernel/OVR_ThreadCommandQueue.h b/LibOVRKernel/Src/Kernel/OVR_ThreadCommandQueue.h new file mode 100644 index 0000000..d8aa14e --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_ThreadCommandQueue.h @@ -0,0 +1,318 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_ThreadCommandQueue.h +Content : Command queue for operations executed on a thread +Created : October 29, 2012 +Author : Michael Antonov + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_ThreadCommandQueue_h +#define OVR_ThreadCommandQueue_h + +#include "OVR_Types.h" +#include "OVR_List.h" +#include "OVR_Atomic.h" +#include "OVR_Threads.h" + +namespace OVR { + +class ThreadCommand; +class ThreadCommandQueue; + + +//------------------------------------------------------------------------------------- +// ***** ThreadCommand + +// ThreadCommand is a base class implementation for commands stored in ThreadCommandQueue. +class ThreadCommand +{ +public: + // NotifyEvent is used by ThreadCommandQueue::PushCallAndWait to notify the + // calling (producer) thread when command is completed or queue slot is available. + class NotifyEvent : public ListNode<NotifyEvent>, public NewOverrideBase + { + Event E; + public: + NotifyEvent() { } + + void Wait() { E.Wait(); } + void PulseEvent() { E.PulseEvent(); } + }; + + // ThreadCommand::PopBuffer is temporary storage for a command popped off + // by ThreadCommandQueue::PopCommand. + class PopBuffer + { + enum { MaxSize = 256 }; + + size_t Size; + union { + uint8_t Buffer[MaxSize]; + size_t Align; + }; + + ThreadCommand* toCommand() const { return (ThreadCommand*)Buffer; } + + public: + PopBuffer() : Size(0) { } + ~PopBuffer(); + + void InitFromBuffer(void* data); + + bool HasCommand() const { return Size != 0; } + size_t GetSize() const { return Size; } + bool NeedsWait() const { return toCommand()->NeedsWait(); } + NotifyEvent* GetEvent() const { return toCommand()->pEvent; } + + // Execute the command and also notifies caller to finish waiting, + // if necessary. + void Execute(); + }; + + uint16_t Size; + bool WaitFlag; + bool ExitFlag; // Marks the last exit command. + NotifyEvent* pEvent; + + ThreadCommand(size_t size, bool waitFlag, bool exitFlag = false) + : Size((uint16_t)size), WaitFlag(waitFlag), ExitFlag(exitFlag), pEvent(0) { } + virtual ~ThreadCommand() { } + + bool NeedsWait() const { return WaitFlag; } + size_t GetSize() const { return Size; } + + virtual void Execute() const = 0; + // Copy constructor used for serializing this to memory buffer. + virtual ThreadCommand* CopyConstruct(void* p) const = 0; +}; + + +//------------------------------------------------------------------------------------- + +// CleanType is a template that strips 'const' and '&' modifiers from the argument type; +// for example, typename CleanType<A&>::Type is equivalent to A. +template<class T> struct CleanType { typedef T Type; }; +template<class T> struct CleanType<T&> { typedef T Type; }; +template<class T> struct CleanType<const T> { typedef T Type; }; +template<class T> struct CleanType<const T&> { typedef T Type; }; + +// SelfType is a template that yields the argument type. This helps avoid conflicts with +// automatic template argument deduction for function calls when identical argument +// is already defined. +template<class T> struct SelfType { typedef T Type; }; + + + +//------------------------------------------------------------------------------------- +// ThreadCommand specializations for member functions with different number of +// arguments and argument types. + +// Used to return nothing from a ThreadCommand, to avoid problems with 'void'. +struct Void +{ + Void() {} + Void(int) {} +}; + +// ThreadCommand for member function with 0 arguments. +template<class C, class R> +class ThreadCommandMF0 : public ThreadCommand +{ + typedef R (C::*FnPtr)(); + C* pClass; + FnPtr pFn; + R* pRet; + + void executeImpl() const + { + pRet ? (void)(*pRet = (pClass->*pFn)()) : + (void)(pClass->*pFn)(); + } + +public: + ThreadCommandMF0(C* pclass, FnPtr fn, R* ret, bool needsWait) + : ThreadCommand(sizeof(ThreadCommandMF0), needsWait), + pClass(pclass), pFn(fn), pRet(ret) { } + + virtual void Execute() const { executeImpl(); } + virtual ThreadCommand* CopyConstruct(void* p) const + { return Construct<ThreadCommandMF0>(p, *this); } +}; + + +// ThreadCommand for member function with 1 argument. +template<class C, class R, class A0> +class ThreadCommandMF1 : public ThreadCommand +{ + typedef R (C::*FnPtr)(A0); + C* pClass; + FnPtr pFn; + R* pRet; + typename CleanType<A0>::Type AVal0; + + void executeImpl() const + { + pRet ? (void)(*pRet = (pClass->*pFn)(AVal0)) : + (void)(pClass->*pFn)(AVal0); + } + +public: + ThreadCommandMF1(C* pclass, FnPtr fn, R* ret, A0 a0, bool needsWait) + : ThreadCommand(sizeof(ThreadCommandMF1), needsWait), + pClass(pclass), pFn(fn), pRet(ret), AVal0(a0) { } + + virtual void Execute() const { executeImpl(); } + virtual ThreadCommand* CopyConstruct(void* p) const + { return Construct<ThreadCommandMF1>(p, *this); } +}; + +// ThreadCommand for member function with 2 arguments. +template<class C, class R, class A0, class A1> +class ThreadCommandMF2 : public ThreadCommand +{ + typedef R (C::*FnPtr)(A0, A1); + C* pClass; + FnPtr pFn; + R* pRet; + typename CleanType<A0>::Type AVal0; + typename CleanType<A1>::Type AVal1; + + void executeImpl() const + { + pRet ? (void)(*pRet = (pClass->*pFn)(AVal0, AVal1)) : + (void)(pClass->*pFn)(AVal0, AVal1); + } + +public: + ThreadCommandMF2(C* pclass, FnPtr fn, R* ret, A0 a0, A1 a1, bool needsWait) + : ThreadCommand(sizeof(ThreadCommandMF2), needsWait), + pClass(pclass), pFn(fn), pRet(ret), AVal0(a0), AVal1(a1) { } + + virtual void Execute() const { executeImpl(); } + virtual ThreadCommand* CopyConstruct(void* p) const + { return Construct<ThreadCommandMF2>(p, *this); } +}; + + +//------------------------------------------------------------------------------------- +// ***** ThreadCommandQueue + +// ThreadCommandQueue is a queue of executable function-call commands intended to be +// serviced by a single consumer thread. Commands are added to the queue with PushCall +// and removed with PopCall; they are processed in FIFO order. Multiple producer threads +// are supported and will be blocked if internal data buffer is full. + +class ThreadCommandQueue +{ +public: + + ThreadCommandQueue(); + virtual ~ThreadCommandQueue(); + + + // Pops the next command from the thread queue, if any is available. + // The command should be executed by calling popBuffer->Execute(). + // Returns 'false' if no command is available at the time of the call. + bool PopCommand(ThreadCommand::PopBuffer* popBuffer); + + // Generic implementaion of PushCommand; enqueues a command for execution. + // Returns 'false' if push failed, usually indicating thread shutdown. + bool PushCommand(const ThreadCommand& command); + + // + void PushExitCommand(bool wait); + + // Returns 'true' once ExitCommand has been processed, so the thread can shut down. + bool IsExiting() const; + + + // These two virtual functions serve as notifications for derived + // thread waiting. + virtual void OnPushNonEmpty_Locked() { } + virtual void OnPopEmpty_Locked() { } + + + // *** PushCall with no result + + // Enqueue a member function of 'this' class to be called on consumer thread. + // By default the function returns immediately; set 'wait' argument to 'true' to + // wait for completion. + template<class C, class R> + bool PushCall(R (C::*fn)(), bool wait = false) + { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, 0, wait)); } + template<class C, class R, class A0> + bool PushCall(R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false) + { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, 0, a0, wait)); } + template<class C, class R, class A0, class A1> + bool PushCall(R (C::*fn)(A0, A1), + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false) + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, 0, a0, a1, wait)); } + // Enqueue a specified member function call of class C. + // By default the function returns immediately; set 'wait' argument to 'true' to + // wait for completion. + template<class C, class R> + bool PushCall(C* p, R (C::*fn)(), bool wait = false) + { return PushCommand(ThreadCommandMF0<C,R>(p, fn, 0, wait)); } + template<class C, class R, class A0> + bool PushCall(C* p, R (C::*fn)(A0), typename SelfType<A0>::Type a0, bool wait = false) + { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, 0, a0, wait)); } + template<class C, class R, class A0, class A1> + bool PushCall(C* p, R (C::*fn)(A0, A1), + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1, bool wait = false) + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, 0, a0, a1, wait)); } + + + // *** PushCall with Result + + // Enqueue a member function of 'this' class call and wait for call to complete + // on consumer thread before returning. + template<class C, class R> + bool PushCallAndWaitResult(R (C::*fn)(), R* ret) + { return PushCommand(ThreadCommandMF0<C,R>(static_cast<C*>(this), fn, ret, true)); } + template<class C, class R, class A0> + bool PushCallAndWaitResult(R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0) + { return PushCommand(ThreadCommandMF1<C,R,A0>(static_cast<C*>(this), fn, ret, a0, true)); } + template<class C, class R, class A0, class A1> + bool PushCallAndWaitResult(R (C::*fn)(A0, A1), R* ret, + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1) + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(static_cast<C*>(this), fn, ret, a0, a1, true)); } + // Enqueue a member function call for class C and wait for the call to complete + // on consumer thread before returning. + template<class C, class R> + bool PushCallAndWaitResult(C* p, R (C::*fn)(), R* ret) + { return PushCommand(ThreadCommandMF0<C,R>(p, fn, ret, true)); } + template<class C, class R, class A0> + bool PushCallAndWaitResult(C* p, R (C::*fn)(A0), R* ret, typename SelfType<A0>::Type a0) + { return PushCommand(ThreadCommandMF1<C,R,A0>(p, fn, ret, a0, true)); } + template<class C, class R, class A0, class A1> + bool PushCallAndWaitResult(C* p, R (C::*fn)(A0, A1), R* ret, + typename SelfType<A0>::Type a0, typename SelfType<A1>::Type a1) + { return PushCommand(ThreadCommandMF2<C,R,A0,A1>(p, fn, ret, a0, a1, true)); } + +private: + class ThreadCommandQueueImpl* pImpl; +}; + + +} // namespace OVR + +#endif // OVR_ThreadCommandQueue_h diff --git a/LibOVRKernel/Src/Kernel/OVR_Threads.h b/LibOVRKernel/Src/Kernel/OVR_Threads.h new file mode 100644 index 0000000..fb5c9f1 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Threads.h @@ -0,0 +1,437 @@ +/************************************************************************************ + +PublicHeader: None +Filename : OVR_Threads.h +Content : Contains thread-related (safe) functionality +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Threads_h +#define OVR_Threads_h + +#include "OVR_Types.h" +#include "OVR_Atomic.h" +#include "OVR_RefCount.h" +#include "OVR_Array.h" + +// Defines the infinite wait delay timeout +#define OVR_WAIT_INFINITE 0xFFFFFFFF + +// To be defined in the project configuration options +#ifdef OVR_ENABLE_THREADS + + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ****** Declared classes + +// Declared with thread support only +class Mutex; +class WaitCondition; +class Event; +// Implementation forward declarations +class MutexImpl; +class WaitConditionImpl; + + + +//----------------------------------------------------------------------------------- +// ***** Mutex + +// Mutex class represents a system Mutex synchronization object that provides access +// serialization between different threads, allowing one thread mutually exclusive access +// to a resource. Mutex is more heavy-weight then Lock, but supports WaitCondition. + +class Mutex +{ + friend class WaitConditionImpl; + friend class MutexImpl; + + MutexImpl *pImpl; + +public: + // Constructor/destructor + Mutex(bool recursive = 1); + ~Mutex(); + + // Locking functions + void DoLock(); + bool TryLock(); + void Unlock(); + + // Returns 1 if the mutes is currently locked by another thread + // Returns 0 if the mutex is not locked by another thread, and can therefore be acquired. + bool IsLockedByAnotherThread(); + + // Locker class; Used for automatic locking of a mutex withing scope + class Locker + { + public: + Mutex *pMutex; + Locker(Mutex *pmutex) + { pMutex = pmutex; pMutex->DoLock(); } + ~Locker() + { pMutex->Unlock(); } + }; +}; + + +//----------------------------------------------------------------------------------- +// ***** WaitCondition + +/* + WaitCondition is a synchronization primitive that can be used to implement what is known as a monitor. + Dependent threads wait on a wait condition by calling Wait(), and get woken up by other threads that + call Notify() or NotifyAll(). + + The unique feature of this class is that it provides an atomic way of first releasing a Mutex, and then + starting a wait on a wait condition. If both the mutex and the wait condition are associated with the same + resource, this ensures that any condition checked for while the mutex was locked does not change before + the wait on the condition is actually initiated. +*/ + +class WaitCondition +{ + friend class WaitConditionImpl; + // Internal implementation structure + WaitConditionImpl *pImpl; + +public: + // Constructor/destructor + WaitCondition(); + ~WaitCondition(); + + // Release mutex and wait for condition. The mutex is re-aquired after the wait. + // Delay is specified in milliseconds (1/1000 of a second). + bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); + + // Notify a condition, releasing at one object waiting + void Notify(); + // Notify a condition, releasing all objects waiting + void NotifyAll(); +}; + + +//----------------------------------------------------------------------------------- +// ***** Event + +// Event is a wait-able synchronization object similar to Windows event. +// Event can be waited on until it's signaled by another thread calling +// either SetEvent or PulseEvent. + +class Event +{ + // Event state, its mutex and the wait condition + volatile bool State; + volatile bool Temporary; + mutable Mutex StateMutex; + WaitCondition StateWaitCondition; + + void updateState(bool newState, bool newTemp, bool mustNotify); + +public: + Event(bool setInitially = 0) : State(setInitially), Temporary(false) { } + ~Event() { } + + // Wait on an event condition until it is set + // Delay is specified in milliseconds (1/1000 of a second). + bool Wait(unsigned delay = OVR_WAIT_INFINITE); + + // Set an event, releasing objects waiting on it + void SetEvent() + { updateState(true, false, true); } + + // Reset an event, un-signaling it + void ResetEvent() + { updateState(false, false, false); } + + // Set and then reset an event once a waiter is released. + // If threads are already waiting, they will be notified and released + // If threads are not waiting, the event is set until the first thread comes in + void PulseEvent() + { updateState(true, true, true); } +}; + + +//----------------------------------------------------------------------------------- +// ***** Thread class + +// ThreadHandle is a handle to a thread, which on some platforms (e.g. Windows) is +// different from ThreadId. On Unix platforms, a ThreadHandle is the same as a +// ThreadId and is pthread_t. +typedef void* ThreadHandle; + +// ThreadId uniquely identifies a thread; returned by Windows GetCurrentThreadId(), +// Unix pthread_self() and Thread::GetThreadId. +typedef void* ThreadId; + + +// *** Thread flags + +// Indicates that the thread is has been started, i.e. Start method has been called, and threads +// OnExit() method has not yet been called/returned. +#define OVR_THREAD_STARTED 0x01 +// This flag is set once the thread has ran, and finished. +#define OVR_THREAD_FINISHED 0x02 +// This flag is set temporarily if this thread was started suspended. It is used internally. +#define OVR_THREAD_START_SUSPENDED 0x08 +// This flag is used to ask a thread to exit. Message driven threads will usually check this flag +// and finish once it is set. +#define OVR_THREAD_EXIT 0x10 + + +class Thread : public RefCountBase<Thread> +{ // NOTE: Waitable must be the first base since it implements RefCountImpl. +public: + // *** Callback functions, can be used instead of overriding Run + + // Run function prototypes. + // Thread function and user handle passed to it, executed by the default + // Thread::Run implementation if not null. + typedef int (*ThreadFn)(Thread *pthread, void* h); + + // Thread ThreadFunction1 is executed if not 0, otherwise ThreadFunction2 is tried + ThreadFn ThreadFunction; + // User handle passes to a thread + void* UserHandle; + + // Thread state to start a thread with + enum ThreadState + { + NotRunning = 0, + Running = 1, + Suspended = 2 + }; + + // Thread priority + enum ThreadPriority + { + CriticalPriority, + HighestPriority, + AboveNormalPriority, + NormalPriority, + BelowNormalPriority, + LowestPriority, + IdlePriority, + }; + + // Thread constructor parameters + struct CreateParams + { + CreateParams(ThreadFn func = 0, void* hand = 0, size_t ssize = 128 * 1024, + int proc = -1, ThreadState state = NotRunning, ThreadPriority prior = NormalPriority) + : threadFunction(func), userHandle(hand), stackSize(ssize), + processor(proc), initialState(state), priority(prior) {} + ThreadFn threadFunction; // Thread function + void* userHandle; // User handle passes to a thread + size_t stackSize; // Thread stack size + int processor; // Thread hardware processor + ThreadState initialState; // + ThreadPriority priority; // Thread priority + }; + + + // *** Constructors + + // A default constructor always creates a thread in NotRunning state, because + // the derived class has not yet been initialized. The derived class can call Start explicitly. + // "processor" parameter specifies which hardware processor this thread will be run on. + // -1 means OS decides this. Implemented only on Win32 + Thread(size_t stackSize = 128 * 1024, int processor = -1); + // Constructors that initialize the thread with a pointer to function. + // An option to start a thread is available, but it should not be used if classes are derived from Thread. + // "processor" parameter specifies which hardware processor this thread will be run on. + // -1 means OS decides this. Implemented only on Win32 + Thread(ThreadFn threadFunction, void* userHandle = 0, size_t stackSize = 128 * 1024, + int processor = -1, ThreadState initialState = NotRunning); + // Constructors that initialize the thread with a create parameters structure. + explicit Thread(const CreateParams& params); + + // Destructor. + virtual ~Thread(); + + // Waits for all Threads to finish; should be called only from the root + // application thread. Once this function returns, we know that all other + // thread's references to Thread object have been released. + static void OVR_CDECL FinishAllThreads(); + + + // *** Overridable Run function for thread processing + + // - returning from this method will end the execution of the thread + // - return value is usually 0 for success + virtual int Run(); + // Called after return/exit function + virtual void OnExit(); + + + // *** Thread management + + // Starts the thread if its not already running + // - internally sets up the threading and calls Run() + // - initial state can either be Running or Suspended, NotRunning will just fail and do nothing + // - returns the exit code + virtual bool Start(ThreadState initialState = Running); + + // Quits with an exit code + virtual void Exit(int exitCode=0); + + // Suspend the thread until resumed + // Returns 1 for success, 0 for failure. + bool Suspend(); + // Resumes currently suspended thread + // Returns 1 for success, 0 for failure. + bool Resume(); + + // Static function to return a pointer to the current thread + //static Thread* GetThread(); + + + // *** Thread status query functions + + bool GetExitFlag() const; + void SetExitFlag(bool exitFlag); + + // Determines whether the thread was running and is now finished + bool IsFinished() const; + // Determines if the thread is currently suspended + bool IsSuspended() const; + // Returns current thread state + ThreadState GetThreadState() const; + + // Wait for thread to finish for a maxmimum number of milliseconds + // For maxWaitMs = 0 it simply polls and then returns if the thread is not finished + // For maxWaitMs < 0 it will wait forever + bool Join(int maxWaitMs = -1) const; + + // Returns the number of available CPUs on the system + static int GetCPUCount(); + + // Returns the thread exit code. Exit code is initialized to 0, + // and set to the return value if Run function after the thread is finished. + inline int GetExitCode() const { return ExitCode; } + // Returns an OS handle +#if defined(OVR_OS_MS) + void* GetOSHandle() const { return ThreadHandle; } +#else + pthread_t GetOSHandle() const { return ThreadHandle; } +#endif + +#if defined(OVR_OS_MS) + ThreadId GetThreadId() const { return IdValue; } +#else + ThreadId GetThreadId() const { return (ThreadId)GetOSHandle(); } +#endif + + // Returns the platform-specific equivalent const that corresponds to the given ThreadPriority. + static int GetOSPriority(ThreadPriority); + static ThreadPriority GetOVRPriority(int osPriority); // May return a value outside the ThreadPriority enum range in unusual cases. + + // Gets this instance's priority. + ThreadPriority GetPriority(); + + // Gets the current thread's priority. + static ThreadPriority GetCurrentPriority(); + + // Sets this instance's thread's priority. + // Some platforms (e.g. Unix) don't let you set thread priorities unless you have root privileges/ + bool SetPriority(ThreadPriority); + + // Sets the current thread's priority. + static bool SetCurrentPriority(ThreadPriority); + + // *** Sleep + + // Sleep secs seconds + static bool Sleep(unsigned secs); + // Sleep msecs milliseconds + static bool MSleep(unsigned msecs); + + // Notifies the scheduler that this thread is willing to release its processor + // to other threads of equal or higher priority. + static void YieldCurrentThread(); + + // *** Debugging functionality + virtual void SetThreadName(const char* name); + static void SetThreadName(const char* name, ThreadId threadId); + static void SetCurrentThreadName(const char* name); + + static void GetThreadName(char* name, size_t nameCapacity, ThreadId threadId); + static void GetCurrentThreadName(char* name, size_t nameCapacity); + +private: +#if defined(OVR_OS_WIN32) + friend unsigned WINAPI Thread_Win32StartFn(void *phandle); +#elif defined(OVR_OS_MS) // Any other Microsoft OS... + friend DWORD WINAPI Thread_Win32StartFn(void *phandle); +#else + friend void *Thread_PthreadStartFn(void * phandle); + + static int InitAttr; + static pthread_attr_t Attr; +#endif + +protected: + // Thread state flags + AtomicInt<uint32_t> ThreadFlags; + AtomicInt<int32_t> SuspendCount; + size_t StackSize; + + // Hardware processor which this thread is running on. + int Processor; + ThreadPriority Priority; + +#if defined(OVR_OS_MS) + void* ThreadHandle; + volatile ThreadId IdValue; + + // System-specific cleanup function called from destructor + void CleanupSystemThread(); + +#else + pthread_t ThreadHandle; +#endif + + // Exit code of the thread, as returned by Run. + int ExitCode; + + // Internal run function. + int PRun(); + // Finishes the thread and releases internal reference to it. + void FinishAndRelease(); + + void Init(const CreateParams& params); + + // Protected copy constructor + Thread(const Thread &source) : RefCountBase<Thread>() { OVR_UNUSED(source); } + +}; + +// Returns the unique Id of a thread it is called on, intended for +// comparison purposes. +ThreadId GetCurrentThreadId(); + + +} // OVR + +#endif // OVR_ENABLE_THREADS +#endif // OVR_Threads_h diff --git a/LibOVRKernel/Src/Kernel/OVR_ThreadsPthread.cpp b/LibOVRKernel/Src/Kernel/OVR_ThreadsPthread.cpp new file mode 100644 index 0000000..0d8851b --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_ThreadsPthread.cpp @@ -0,0 +1,1006 @@ +/************************************************************************************ + +Filename : OVR_ThreadsPthread.cpp +Content : +Created : +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#if !defined(_WIN32) // Skip the entire file under Windows + +#include "OVR_Threads.h" +#include "OVR_Hash.h" + +#ifdef OVR_ENABLE_THREADS + +#include "OVR_Timer.h" +#include "OVR_Log.h" + +#include <pthread.h> +#include <sched.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> +#include <errno.h> + +#if defined(OVR_OS_MAC) || defined(OVR_OS_BSD) + #include <sys/sysctl.h> + #include <sys/param.h> + #if !defined(OVR_OS_MAC) + #include <pthread_np.h> + #endif +#endif + + + +namespace OVR { + +// ***** Mutex implementation + + +// *** Internal Mutex implementation structure + +class MutexImpl : public NewOverrideBase +{ + // System mutex or semaphore + pthread_mutex_t SMutex; + bool Recursive; + unsigned LockCount; + pthread_t LockedBy; + + friend class WaitConditionImpl; + +public: + // Constructor/destructor + MutexImpl(Mutex* pmutex, bool recursive = 1); + ~MutexImpl(); + + // Locking functions + void DoLock(); + bool TryLock(); + void Unlock(Mutex* pmutex); + // Returns 1 if the mutes is currently locked + bool IsLockedByAnotherThread(Mutex* pmutex); + bool IsSignaled() const; +}; + +pthread_mutexattr_t Lock::RecursiveAttr; +bool Lock::RecursiveAttrInit = 0; + +// *** Constructor/destructor +MutexImpl::MutexImpl(Mutex* pmutex, bool recursive) +{ + OVR_UNUSED(pmutex); + Recursive = recursive; + LockCount = 0; + + if (Recursive) + { + if (!Lock::RecursiveAttrInit) + { + pthread_mutexattr_init(&Lock::RecursiveAttr); + pthread_mutexattr_settype(&Lock::RecursiveAttr, PTHREAD_MUTEX_RECURSIVE); + Lock::RecursiveAttrInit = 1; + } + + pthread_mutex_init(&SMutex, &Lock::RecursiveAttr); + } + else + pthread_mutex_init(&SMutex, 0); +} + +MutexImpl::~MutexImpl() +{ + pthread_mutex_destroy(&SMutex); +} + + +// Lock and try lock +void MutexImpl::DoLock() +{ + while (pthread_mutex_lock(&SMutex)) + ; + LockCount++; + LockedBy = pthread_self(); +} + +bool MutexImpl::TryLock() +{ + if (!pthread_mutex_trylock(&SMutex)) + { + LockCount++; + LockedBy = pthread_self(); + return 1; + } + + return 0; +} + +void MutexImpl::Unlock(Mutex* pmutex) +{ + OVR_UNUSED(pmutex); + OVR_ASSERT(pthread_self() == LockedBy && LockCount > 0); + + //unsigned lockCount; + LockCount--; + //lockCount = LockCount; + + pthread_mutex_unlock(&SMutex); +} + +bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) +{ + OVR_UNUSED(pmutex); + // There could be multiple interpretations of IsLocked with respect to current thread + if (LockCount == 0) + return 0; + if (pthread_self() != LockedBy) + return 1; + return 0; +} + +bool MutexImpl::IsSignaled() const +{ + // An mutex is signaled if it is not locked ANYWHERE + // Note that this is different from IsLockedByAnotherThread function, + // that takes current thread into account + return LockCount == 0; +} + + +// *** Actual Mutex class implementation + +Mutex::Mutex(bool recursive) +{ + // NOTE: RefCount mode already thread-safe for all waitables. + pImpl = new MutexImpl(this, recursive); +} + +Mutex::~Mutex() +{ + delete pImpl; +} + +// Lock and try lock +void Mutex::DoLock() +{ + pImpl->DoLock(); +} +bool Mutex::TryLock() +{ + return pImpl->TryLock(); +} +void Mutex::Unlock() +{ + pImpl->Unlock(this); +} +bool Mutex::IsLockedByAnotherThread() +{ + return pImpl->IsLockedByAnotherThread(this); +} + + + +//----------------------------------------------------------------------------------- +// ***** Event + +bool Event::Wait(unsigned delay) +{ + Mutex::Locker lock(&StateMutex); + + // Do the correct amount of waiting + if (delay == OVR_WAIT_INFINITE) + { + while(!State) + StateWaitCondition.Wait(&StateMutex); + } + else if (delay) + { + if (!State) + StateWaitCondition.Wait(&StateMutex, delay); + } + + bool state = State; + // Take care of temporary 'pulsing' of a state + if (Temporary) + { + Temporary = false; + State = false; + } + return state; +} + +void Event::updateState(bool newState, bool newTemp, bool mustNotify) +{ + Mutex::Locker lock(&StateMutex); + State = newState; + Temporary = newTemp; + if (mustNotify) + StateWaitCondition.NotifyAll(); +} + + + +// ***** Wait Condition Implementation + +// Internal implementation class +class WaitConditionImpl : public NewOverrideBase +{ + pthread_mutex_t SMutex; + pthread_cond_t Condv; + +public: + + // Constructor/destructor + WaitConditionImpl(); + ~WaitConditionImpl(); + + // Release mutex and wait for condition. The mutex is re-aqured after the wait. + bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); + + // Notify a condition, releasing at one object waiting + void Notify(); + // Notify a condition, releasing all objects waiting + void NotifyAll(); +}; + + +WaitConditionImpl::WaitConditionImpl() +{ + pthread_mutex_init(&SMutex, 0); + pthread_cond_init(&Condv, 0); +} + +WaitConditionImpl::~WaitConditionImpl() +{ + pthread_mutex_destroy(&SMutex); + pthread_cond_destroy(&Condv); +} + +bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay) +{ + bool result = 1; + unsigned lockCount = pmutex->pImpl->LockCount; + + // Mutex must have been locked + if (lockCount == 0) + return 0; + + pthread_mutex_lock(&SMutex); + + // Finally, release a mutex or semaphore + if (pmutex->pImpl->Recursive) + { + // Release the recursive mutex N times + pmutex->pImpl->LockCount = 0; + for(unsigned i=0; i<lockCount; i++) + pthread_mutex_unlock(&pmutex->pImpl->SMutex); + } + else + { + pmutex->pImpl->LockCount = 0; + pthread_mutex_unlock(&pmutex->pImpl->SMutex); + } + + // Note that there is a gap here between mutex.Unlock() and Wait(). + // The other mutex protects this gap. + + if (delay == OVR_WAIT_INFINITE) + pthread_cond_wait(&Condv,&SMutex); + else + { + timespec ts; + + struct timeval tv; + gettimeofday(&tv, 0); + + ts.tv_sec = tv.tv_sec + (delay / 1000); + ts.tv_nsec = (tv.tv_usec + (delay % 1000) * 1000) * 1000; + + if (ts.tv_nsec > 999999999) + { + ts.tv_sec++; + ts.tv_nsec -= 1000000000; + } + int r = pthread_cond_timedwait(&Condv,&SMutex, &ts); + OVR_ASSERT(r == 0 || r == ETIMEDOUT); + if (r) + result = 0; + } + + pthread_mutex_unlock(&SMutex); + + // Re-aquire the mutex + for(unsigned i=0; i<lockCount; i++) + pmutex->DoLock(); + + // Return the result + return result; +} + +// Notify a condition, releasing the least object in a queue +void WaitConditionImpl::Notify() +{ + pthread_mutex_lock(&SMutex); + pthread_cond_signal(&Condv); + pthread_mutex_unlock(&SMutex); +} + +// Notify a condition, releasing all objects waiting +void WaitConditionImpl::NotifyAll() +{ + pthread_mutex_lock(&SMutex); + pthread_cond_broadcast(&Condv); + pthread_mutex_unlock(&SMutex); +} + + + +// *** Actual implementation of WaitCondition + +WaitCondition::WaitCondition() +{ + pImpl = new WaitConditionImpl; +} +WaitCondition::~WaitCondition() +{ + delete pImpl; +} + +bool WaitCondition::Wait(Mutex *pmutex, unsigned delay) +{ + return pImpl->Wait(pmutex, delay); +} +// Notification +void WaitCondition::Notify() +{ + pImpl->Notify(); +} +void WaitCondition::NotifyAll() +{ + pImpl->NotifyAll(); +} + + +// ***** Current thread + +// Per-thread variable +/* +static __thread Thread* pCurrentThread = 0; + +// Static function to return a pointer to the current thread +void Thread::InitCurrentThread(Thread *pthread) +{ + pCurrentThread = pthread; +} + +// Static function to return a pointer to the current thread +Thread* Thread::GetThread() +{ + return pCurrentThread; +} +*/ + + +// *** Thread constructors. + +Thread::Thread(UPInt stackSize, int processor) +{ + // NOTE: RefCount mode already thread-safe for all Waitable objects. + CreateParams params; + params.stackSize = stackSize; + params.processor = processor; + Init(params); +} + +Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, UPInt stackSize, + int processor, Thread::ThreadState initialState) +{ + CreateParams params(threadFunction, userHandle, stackSize, processor, initialState); + Init(params); +} + +Thread::Thread(const CreateParams& params) +{ + Init(params); +} + +void Thread::Init(const CreateParams& params) +{ + // Clear the variables + ThreadFlags = 0; + ThreadHandle = 0; + ExitCode = 0; + SuspendCount = 0; + StackSize = params.stackSize; + Processor = params.processor; + Priority = params.priority; + + // Clear Function pointers + ThreadFunction = params.threadFunction; + UserHandle = params.userHandle; + if (params.initialState != NotRunning) + Start(params.initialState); +} + +Thread::~Thread() +{ + // Thread should not running while object is being destroyed, + // this would indicate ref-counting issue. + //OVR_ASSERT(IsRunning() == 0); + + // Clean up thread. + ThreadHandle = 0; +} + + + +// *** Overridable User functions. + +// Default Run implementation +int Thread::Run() +{ + // Call pointer to function, if available. + return (ThreadFunction) ? ThreadFunction(this, UserHandle) : 0; +} +void Thread::OnExit() +{ +} + + +// Finishes the thread and releases internal reference to it. +void Thread::FinishAndRelease() +{ + // Note: thread must be US. + ThreadFlags &= (UInt32)~(OVR_THREAD_STARTED); + ThreadFlags |= OVR_THREAD_FINISHED; + + // Release our reference; this is equivalent to 'delete this' + // from the point of view of our thread. + Release(); +} + + + +// *** ThreadList - used to track all created threads + +class ThreadList : public NewOverrideBase +{ + //------------------------------------------------------------------------ + struct ThreadHashOp + { + size_t operator()(const Thread* ptr) + { + return (((size_t)ptr) >> 6) ^ (size_t)ptr; + } + }; + + HashSet<Thread*, ThreadHashOp> ThreadSet; + Mutex ThreadMutex; + WaitCondition ThreadsEmpty; + // Track the root thread that created us. + pthread_t RootThreadId; + + static ThreadList* volatile pRunningThreads; + + void addThread(Thread *pthread) + { + Mutex::Locker lock(&ThreadMutex); + ThreadSet.Add(pthread); + } + + void removeThread(Thread *pthread) + { + Mutex::Locker lock(&ThreadMutex); + ThreadSet.Remove(pthread); + if (ThreadSet.GetSize() == 0) + ThreadsEmpty.Notify(); + } + + void finishAllThreads() + { + // Only original root thread can call this. + OVR_ASSERT(pthread_self() == RootThreadId); + + Mutex::Locker lock(&ThreadMutex); + while (ThreadSet.GetSize() != 0) + ThreadsEmpty.Wait(&ThreadMutex); + } + +public: + + ThreadList() + { + RootThreadId = pthread_self(); + } + ~ThreadList() { } + + + static void AddRunningThread(Thread *pthread) + { + // Non-atomic creation ok since only the root thread + if (!pRunningThreads) + { + pRunningThreads = new ThreadList; + OVR_ASSERT(pRunningThreads); + } + pRunningThreads->addThread(pthread); + } + + // NOTE: 'pthread' might be a dead pointer when this is + // called so it should not be accessed; it is only used + // for removal. + static void RemoveRunningThread(Thread *pthread) + { + OVR_ASSERT(pRunningThreads); + pRunningThreads->removeThread(pthread); + } + + static void FinishAllThreads() + { + // This is ok because only root thread can wait for other thread finish. + if (pRunningThreads) + { + pRunningThreads->finishAllThreads(); + delete pRunningThreads; + pRunningThreads = 0; + } + } +}; + +// By default, we have no thread list. +ThreadList* volatile ThreadList::pRunningThreads = 0; + + +// FinishAllThreads - exposed publicly in Thread. +void Thread::FinishAllThreads() +{ + ThreadList::FinishAllThreads(); +} + +// *** Run override + +int Thread::PRun() +{ + // Suspend us on start, if requested + if (ThreadFlags & OVR_THREAD_START_SUSPENDED) + { + Suspend(); + ThreadFlags &= (UInt32)~OVR_THREAD_START_SUSPENDED; + } + + // Call the virtual run function + ExitCode = Run(); + return ExitCode; +} + + + + +// *** User overridables + +bool Thread::GetExitFlag() const +{ + return (ThreadFlags & OVR_THREAD_EXIT) != 0; +} + +void Thread::SetExitFlag(bool exitFlag) +{ + // The below is atomic since ThreadFlags is AtomicInt. + if (exitFlag) + ThreadFlags |= OVR_THREAD_EXIT; + else + ThreadFlags &= (UInt32) ~OVR_THREAD_EXIT; +} + + +// Determines whether the thread was running and is now finished +bool Thread::IsFinished() const +{ + return (ThreadFlags & OVR_THREAD_FINISHED) != 0; +} +// Determines whether the thread is suspended +bool Thread::IsSuspended() const +{ + return SuspendCount > 0; +} +// Returns current thread state +Thread::ThreadState Thread::GetThreadState() const +{ + if (IsSuspended()) + return Suspended; + if (ThreadFlags & OVR_THREAD_STARTED) + return Running; + return NotRunning; +} + +// Join thread +bool Thread::Join(int maxWaitMs) const +{ + // If polling, + if (maxWaitMs == 0) + { + // Just return if finished + return IsFinished(); + } + // If waiting forever, + else if (maxWaitMs > 0) + { + UInt32 t0 = Timer::GetTicksMs(); + + while (!IsFinished()) + { + UInt32 t1 = Timer::GetTicksMs(); + + // If the wait has expired, + int delta = (int)(t1 - t0); + if (delta >= maxWaitMs) + { + return false; + } + + Thread::MSleep(10); + } + + return true; + } + else + { + while (!IsFinished()) + { + pthread_join(ThreadHandle, NULL); + } + } + + return true; +} + +/* +static const char* mapsched_policy(int policy) +{ + switch(policy) + { + case SCHED_OTHER: + return "SCHED_OTHER"; + case SCHED_RR: + return "SCHED_RR"; + case SCHED_FIFO: + return "SCHED_FIFO"; + + } + return "UNKNOWN"; +} + int policy; + sched_param sparam; + pthread_getschedparam(pthread_self(), &policy, &sparam); + int max_prior = sched_get_priority_max(policy); + int min_prior = sched_get_priority_min(policy); + printf(" !!!! policy: %s, priority: %d, max priority: %d, min priority: %d\n", mapsched_policy(policy), sparam.sched_priority, max_prior, min_prior); +#include <stdio.h> +*/ +// ***** Thread management + +// The actual first function called on thread start +void* Thread_PthreadStartFn(void* phandle) +{ + Thread* pthread = (Thread*)phandle; + int result = pthread->PRun(); + // Signal the thread as done and release it atomically. + pthread->FinishAndRelease(); + // At this point Thread object might be dead; however we can still pass + // it to RemoveRunningThread since it is only used as a key there. + ThreadList::RemoveRunningThread(pthread); + return reinterpret_cast<void*>(result); +} + +int Thread::InitAttr = 0; +pthread_attr_t Thread::Attr; + +/* static */ +int Thread::GetOSPriority(ThreadPriority p) +{ + OVR_UNUSED(p); + return -1; +} + +/* static */ +Thread::ThreadPriority Thread::GetOVRPriority(int osPriority) +{ + #if defined(OVR_OS_LINUX) + return (ThreadPriority)(Thread::NormalPriority - osPriority); // This works for both SCHED_OTHER, SCHED_RR, and SCHED_FIFO. + #else + // Apple priorities are such that the min is a value less than the max. + static int minPriority = sched_get_priority_min(SCHED_FIFO); // We don't have a means to pass a policy type to this function. + static int maxPriority = sched_get_priority_max(SCHED_FIFO); + + return (ThreadPriority)(Thread::NormalPriority - (osPriority - ((minPriority + maxPriority) / 2))); + #endif +} + + +Thread::ThreadPriority Thread::GetPriority() +{ + int policy; + sched_param param; + + int result = pthread_getschedparam(ThreadHandle, &policy, ¶m); + + if(result == 0) + { + #if !defined(OVR_OS_LINUX) + if(policy == SCHED_OTHER) + { + return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X. + } + #endif + + return GetOVRPriority(param.sched_priority); + } + + return Thread::NormalPriority; +} + +/* static */ +Thread::ThreadPriority Thread::GetCurrentPriority() +{ + int policy; + sched_param param; + pthread_t currentThreadId = pthread_self(); + + int result = pthread_getschedparam(currentThreadId, &policy, ¶m); + + if(result == 0) + { + #if !defined(OVR_OS_LINUX) + if(policy == SCHED_OTHER) + { + return Thread::NormalPriority; //SCHED_OTHER allows only normal priority on BSD-style Unix and Mac OS X. + } + #endif + + return GetOVRPriority(param.sched_priority); + } + + return Thread::NormalPriority; +} + + +bool Thread::SetPriority(ThreadPriority) +{ + // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam + // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges. + return false; +} + +/* static */ +bool Thread::SetCurrentPriority(ThreadPriority) +{ + // We currently fail. To do: add code to support this via pthread_getschedparam/pthread_attr_setschedparam + // This won't work unless using SCHED_FIFO or SCHED_RR anyway, which require root privileges. + return false; +} + +bool Thread::Start(ThreadState initialState) +{ + if (initialState == NotRunning) + return 0; + if (GetThreadState() != NotRunning) + { + OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this)); + return 0; + } + + if (!InitAttr) + { + pthread_attr_init(&Attr); + pthread_attr_setdetachstate(&Attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&Attr, 128 * 1024); + sched_param sparam; + sparam.sched_priority = Thread::GetOSPriority(NormalPriority); + pthread_attr_setschedparam(&Attr, &sparam); + InitAttr = 1; + } + + ExitCode = 0; + SuspendCount = 0; + ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED; + + // AddRef to us until the thread is finished + AddRef(); + ThreadList::AddRunningThread(this); + + int result; + if (StackSize != 128 * 1024 || Priority != NormalPriority) + { + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + pthread_attr_setstacksize(&attr, StackSize); + sched_param sparam; + sparam.sched_priority = Thread::GetOSPriority(Priority); + pthread_attr_setschedparam(&attr, &sparam); + result = pthread_create(&ThreadHandle, &attr, Thread_PthreadStartFn, this); + pthread_attr_destroy(&attr); + } + else + result = pthread_create(&ThreadHandle, &Attr, Thread_PthreadStartFn, this); + + if (result) + { + ThreadFlags = 0; + Release(); + ThreadList::RemoveRunningThread(this); + return 0; + } + return 1; +} + + +// Suspend the thread until resumed +bool Thread::Suspend() +{ + OVR_DEBUG_LOG(("Thread::Suspend - cannot suspend threads on this system")); + return 0; +} + +// Resumes currently suspended thread +bool Thread::Resume() +{ + return 0; +} + + +// Quits with an exit code +void Thread::Exit(int exitCode) +{ + // Can only exist the current thread + // if (GetThread() != this) + // return; + + // Call the virtual OnExit function + OnExit(); + + // Signal this thread object as done and release it's references. + FinishAndRelease(); + ThreadList::RemoveRunningThread(this); + + pthread_exit(reinterpret_cast<void*>(exitCode)); +} + +ThreadId GetCurrentThreadId() +{ + return (void*)pthread_self(); +} + +// *** Sleep functions + +/* static */ +bool Thread::Sleep(unsigned secs) +{ + sleep(secs); + return 1; +} +/* static */ +bool Thread::MSleep(unsigned msecs) +{ + usleep(msecs*1000); + return 1; +} + +/* static */ +void Thread::YieldCurrentThread() +{ + #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD) + pthread_yield_np(); + #elif defined(OVR_OS_ANDROID) + sched_yield(); + #else // Linux + pthread_yield(); + #endif +} + +/* static */ +int Thread::GetCPUCount() +{ + #if defined(OVR_OS_MAC) || defined(OVR_OS_BSD) + // http://developer.apple.com/mac/library/documentation/Darwin/Reference/ManPages/man3/sysctlbyname.3.html + int cpuCount = 0; + size_t len = sizeof(cpuCount); + + if(sysctlbyname("hw.logicalcpu", &cpuCount, &len, NULL, 0) != 0) + cpuCount = 1; + + return cpuCount; + + #else // Linux, Android + + // Alternative: read /proc/cpuinfo + #ifdef _SC_NPROCESSORS_ONLN + return (int)sysconf(_SC_NPROCESSORS_ONLN); + #else + return 1; + #endif + #endif +} + + +void Thread::SetThreadName( const char* name ) +{ + #if defined (OVR_OS_APPLE) + if(ThreadHandle == pthread_self()) + pthread_setname_np(name); + // Else there's nothing we can do. + #else + if(ThreadHandle != 0) + pthread_setname_np(ThreadHandle, name); + // Else we can possibly save this name and set it later when the thread starts. + #endif +} + + +void Thread::SetThreadName(const char* name, ThreadId threadId) +{ + #if defined (OVR_OS_APPLE) + if(pthread_equal((pthread_t)threadId, pthread_self())) + pthread_setname_np(name); + // Else there's no way to set the name of another thread. + #else + pthread_setname_np((pthread_t)threadId, name); + #endif +} + + +void Thread::SetCurrentThreadName(const char* name) +{ + #if defined (OVR_OS_APPLE) + pthread_setname_np(name); + #else + pthread_setname_np(pthread_self(), name); + #endif +} + + +void Thread::GetThreadName(char* name, size_t nameCapacity, ThreadId threadId) +{ + name[0] = 0; +#if !defined (OVR_OS_ANDROID) + // Android does not have pthread_getname_np (or an equivalent) + pthread_getname_np((pthread_t)threadId, name, nameCapacity); +#endif +} + + +void Thread::GetCurrentThreadName(char* name, size_t nameCapacity) +{ + name[0] = 0; +#if !defined (OVR_OS_ANDROID) + // Android does not have pthread_getname_np (or an equivalent) + pthread_getname_np(pthread_self(), name, nameCapacity); +#endif +} + + +} // namespace OVR + +#endif // OVR_ENABLE_THREADS + +#endif // _WIN32 diff --git a/LibOVRKernel/Src/Kernel/OVR_ThreadsWinAPI.cpp b/LibOVRKernel/Src/Kernel/OVR_ThreadsWinAPI.cpp new file mode 100644 index 0000000..736b734 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_ThreadsWinAPI.cpp @@ -0,0 +1,1151 @@ +/************************************************************************************ + +Filename : OVR_ThreadsWinAPI.cpp +Platform : WinAPI +Content : Windows specific thread-related (safe) functionality +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Threads.h" +#include "OVR_Hash.h" +#include "OVR_Log.h" +#include "OVR_Timer.h" + +#ifdef OVR_ENABLE_THREADS + +// For _beginthreadex / _endtheadex +#include <process.h> + +namespace OVR { + + +//----------------------------------------------------------------------------------- +// *** Internal Mutex implementation class + +class MutexImpl : public NewOverrideBase +{ + // System mutex or semaphore + HANDLE hMutexOrSemaphore; + bool Recursive; + volatile unsigned LockCount; + + friend class WaitConditionImpl; + +public: + // Constructor/destructor + MutexImpl(bool recursive = 1); + ~MutexImpl(); + + // Locking functions + void DoLock(); + bool TryLock(); + void Unlock(Mutex* pmutex); + // Returns 1 if the mutes is currently locked + bool IsLockedByAnotherThread(Mutex* pmutex); +}; + +// *** Constructor/destructor +MutexImpl::MutexImpl(bool recursive) +{ + Recursive = recursive; + LockCount = 0; +#if defined(OVR_OS_WIN32) // Older versions of Windows don't support CreateSemaphoreEx, so stick with CreateSemaphore for portability. + hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphore(NULL, 1, 1, NULL); +#else + // No CreateSemaphore() call, so emulate it. + hMutexOrSemaphore = Recursive ? CreateMutex(NULL, 0, NULL) : CreateSemaphoreEx(NULL, 1, 1, NULL, 0, SEMAPHORE_ALL_ACCESS); +#endif +} +MutexImpl::~MutexImpl() +{ + CloseHandle(hMutexOrSemaphore); +} + + +// Lock and try lock +void MutexImpl::DoLock() +{ + if (::WaitForSingleObject(hMutexOrSemaphore, INFINITE) != WAIT_OBJECT_0) + return; + LockCount++; +} + +bool MutexImpl::TryLock() +{ + DWORD ret; + if ((ret=::WaitForSingleObject(hMutexOrSemaphore, 0)) != WAIT_OBJECT_0) + return 0; + LockCount++; + return 1; +} + +void MutexImpl::Unlock(Mutex* pmutex) +{ + OVR_UNUSED(pmutex); + + unsigned lockCount; + LockCount--; + lockCount = LockCount; + + // Release mutex + if ((Recursive ? ReleaseMutex(hMutexOrSemaphore) : + ReleaseSemaphore(hMutexOrSemaphore, 1, NULL)) != 0) + { + // This used to call Wait handlers if lockCount == 0. + } +} + +bool MutexImpl::IsLockedByAnotherThread(Mutex* pmutex) +{ + // There could be multiple interpretations of IsLocked with respect to current thread + if (LockCount == 0) + return 0; + if (!TryLock()) + return 1; + Unlock(pmutex); + return 0; +} + +/* +bool MutexImpl::IsSignaled() const +{ + // An mutex is signaled if it is not locked ANYWHERE + // Note that this is different from IsLockedByAnotherThread function, + // that takes current thread into account + return LockCount == 0; +} +*/ + + +// *** Actual Mutex class implementation + +Mutex::Mutex(bool recursive) +{ + pImpl = new MutexImpl(recursive); +} +Mutex::~Mutex() +{ + delete pImpl; +} + +// Lock and try lock +void Mutex::DoLock() +{ + pImpl->DoLock(); +} +bool Mutex::TryLock() +{ + return pImpl->TryLock(); +} +void Mutex::Unlock() +{ + pImpl->Unlock(this); +} +bool Mutex::IsLockedByAnotherThread() +{ + return pImpl->IsLockedByAnotherThread(this); +} + +//----------------------------------------------------------------------------------- +// ***** Event + +bool Event::Wait(unsigned delay) +{ + Mutex::Locker lock(&StateMutex); + + // Do the correct amount of waiting + if (delay == OVR_WAIT_INFINITE) + { + while(!State) + StateWaitCondition.Wait(&StateMutex); + } + else if (delay) + { + if (!State) + StateWaitCondition.Wait(&StateMutex, delay); + } + + bool state = State; + // Take care of temporary 'pulsing' of a state + if (Temporary) + { + Temporary = false; + State = false; + } + return state; +} + +void Event::updateState(bool newState, bool newTemp, bool mustNotify) +{ + Mutex::Locker lock(&StateMutex); + State = newState; + Temporary = newTemp; + if (mustNotify) + StateWaitCondition.NotifyAll(); +} + + +//----------------------------------------------------------------------------------- +// ***** Win32 Wait Condition Implementation + +// Internal implementation class +class WaitConditionImpl : public NewOverrideBase +{ + // Event pool entries for extra events + struct EventPoolEntry : public NewOverrideBase + { + HANDLE hEvent; + EventPoolEntry *pNext; + EventPoolEntry *pPrev; + }; + + Lock WaitQueueLoc; + // Stores free events that can be used later + EventPoolEntry * pFreeEventList; + + // A queue of waiting objects to be signaled + EventPoolEntry* pQueueHead; + EventPoolEntry* pQueueTail; + + // Allocation functions for free events + EventPoolEntry* GetNewEvent(); + void ReleaseEvent(EventPoolEntry* pevent); + + // Queue operations + void QueuePush(EventPoolEntry* pentry); + EventPoolEntry* QueuePop(); + void QueueFindAndRemove(EventPoolEntry* pentry); + +public: + + // Constructor/destructor + WaitConditionImpl(); + ~WaitConditionImpl(); + + // Release mutex and wait for condition. The mutex is re-acqured after the wait. + bool Wait(Mutex *pmutex, unsigned delay = OVR_WAIT_INFINITE); + + // Notify a condition, releasing at one object waiting + void Notify(); + // Notify a condition, releasing all objects waiting + void NotifyAll(); +}; + + + +WaitConditionImpl::WaitConditionImpl() +{ + pFreeEventList = 0; + pQueueHead = + pQueueTail = 0; +} + +WaitConditionImpl::~WaitConditionImpl() +{ + // Free all the resources + EventPoolEntry* p = pFreeEventList; + EventPoolEntry* pentry; + + while(p) + { + // Move to next + pentry = p; + p = p->pNext; + // Delete old + ::CloseHandle(pentry->hEvent); + delete pentry; + } + // Shouldn't we also consider the queue? + + // To be safe + pFreeEventList = 0; + pQueueHead = + pQueueTail = 0; +} + + +// Allocation functions for free events +WaitConditionImpl::EventPoolEntry* WaitConditionImpl::GetNewEvent() +{ + EventPoolEntry* pentry; + + // If there are any free nodes, use them + if (pFreeEventList) + { + pentry = pFreeEventList; + pFreeEventList = pFreeEventList->pNext; + } + else + { + // Allocate a new node + pentry = new EventPoolEntry; + pentry->pNext = 0; + pentry->pPrev = 0; + // Non-signaled manual event + pentry->hEvent = ::CreateEvent(NULL, TRUE, 0, NULL); + } + + return pentry; +} + +void WaitConditionImpl::ReleaseEvent(EventPoolEntry* pevent) +{ + // Mark event as non-signaled + ::ResetEvent(pevent->hEvent); + // And add it to free pool + pevent->pNext = pFreeEventList; + pevent->pPrev = 0; + pFreeEventList = pevent; +} + +// Queue operations +void WaitConditionImpl::QueuePush(EventPoolEntry* pentry) +{ + // Items already exist? Just add to tail + if (pQueueTail) + { + pentry->pPrev = pQueueTail; + pQueueTail->pNext = pentry; + pentry->pNext = 0; + pQueueTail = pentry; + } + else + { + // No items in queue + pentry->pNext = + pentry->pPrev = 0; + pQueueHead = + pQueueTail = pentry; + } +} + +WaitConditionImpl::EventPoolEntry* WaitConditionImpl::QueuePop() +{ + EventPoolEntry* pentry = pQueueHead; + + // No items, null pointer + if (pentry) + { + // More items after this one? just grab the first item + if (pQueueHead->pNext) + { + pQueueHead = pentry->pNext; + pQueueHead->pPrev = 0; + } + else + { + // Last item left + pQueueTail = + pQueueHead = 0; + } + } + return pentry; +} + +void WaitConditionImpl::QueueFindAndRemove(EventPoolEntry* pentry) +{ + // Do an exhaustive search looking for an entry + EventPoolEntry* p = pQueueHead; + + while(p) + { + // Entry found? Remove. + if (p == pentry) + { + + // Remove the node form the list + // Prev link + if (pentry->pPrev) + pentry->pPrev->pNext = pentry->pNext; + else + pQueueHead = pentry->pNext; + // Next link + if (pentry->pNext) + pentry->pNext->pPrev = pentry->pPrev; + else + pQueueTail = pentry->pPrev; + // Done + return; + } + + // Move to next item + p = p->pNext; + } +} + + +bool WaitConditionImpl::Wait(Mutex *pmutex, unsigned delay) +{ + bool result = 0; + unsigned i; + unsigned lockCount = pmutex->pImpl->LockCount; + EventPoolEntry* pentry; + + // Mutex must have been locked + if (lockCount == 0) + return 0; + + // Add an object to the wait queue + WaitQueueLoc.DoLock(); + QueuePush(pentry = GetNewEvent()); + WaitQueueLoc.Unlock(); + + // Finally, release a mutex or semaphore + if (pmutex->pImpl->Recursive) + { + // Release the recursive mutex N times + pmutex->pImpl->LockCount = 0; + for(i=0; i<lockCount; i++) + ::ReleaseMutex(pmutex->pImpl->hMutexOrSemaphore); + } + else + { + pmutex->pImpl->LockCount = 0; + ::ReleaseSemaphore(pmutex->pImpl->hMutexOrSemaphore, 1, NULL); + } + + // Note that there is a gap here between mutex.Unlock() and Wait(). However, + // if notify() comes in at this point in the other thread it will set our + // corresponding event so wait will just fall through, as expected. + + // Block and wait on the event + DWORD waitResult = ::WaitForSingleObject(pentry->hEvent, + (delay == OVR_WAIT_INFINITE) ? INFINITE : delay); + /* +repeat_wait: + DWORD waitResult = + + ::MsgWaitForMultipleObjects(1, &pentry->hEvent, FALSE, + (delay == OVR_WAIT_INFINITE) ? INFINITE : delay, + QS_ALLINPUT); + */ + + WaitQueueLoc.DoLock(); + switch(waitResult) + { + case WAIT_ABANDONED: + case WAIT_OBJECT_0: + result = 1; + // Wait was successful, therefore the event entry should already be removed + // So just add entry back to a free list + ReleaseEvent(pentry); + break; + /* + case WAIT_OBJECT_0 + 1: + // Messages in WINDOWS queue + { + MSG msg; + PeekMessage(&msg, NULL, 0U, 0U, PM_NOREMOVE); + WaitQueueLoc.Unlock(); + goto repeat_wait; + } + break; */ + default: + // Timeout, our entry should still be in a queue + QueueFindAndRemove(pentry); + ReleaseEvent(pentry); + } + WaitQueueLoc.Unlock(); + + // Re-aquire the mutex + for(i=0; i<lockCount; i++) + pmutex->DoLock(); + + // Return the result + return result; +} + +// Notify a condition, releasing the least object in a queue +void WaitConditionImpl::Notify() +{ + Lock::Locker lock(&WaitQueueLoc); + + // Pop last entry & signal it + EventPoolEntry* pentry = QueuePop(); + if (pentry) + ::SetEvent(pentry->hEvent); +} + +// Notify a condition, releasing all objects waiting +void WaitConditionImpl::NotifyAll() +{ + Lock::Locker lock(&WaitQueueLoc); + + // Pop and signal all events + // NOTE : There is no need to release the events, it's the waiters job to do so + EventPoolEntry* pentry = QueuePop(); + while (pentry) + { + ::SetEvent(pentry->hEvent); + pentry = QueuePop(); + } +} + + + +// *** Actual implementation of WaitCondition + +WaitCondition::WaitCondition() +{ + pImpl = new WaitConditionImpl; +} +WaitCondition::~WaitCondition() +{ + delete pImpl; +} + +// Wait without a mutex +bool WaitCondition::Wait(Mutex *pmutex, unsigned delay) +{ + return pImpl->Wait(pmutex, delay); +} +// Notification +void WaitCondition::Notify() +{ + pImpl->Notify(); +} +void WaitCondition::NotifyAll() +{ + pImpl->NotifyAll(); +} + + + +//----------------------------------------------------------------------------------- +// ***** Thread Class + +// Per-thread variable +// MA: Don't use TLS for now - portability issues with DLLs, etc. +/* +#if !defined(OVR_CC_MSVC) || (OVR_CC_MSVC < 1300) +__declspec(thread) Thread* pCurrentThread = 0; +#else +#pragma data_seg(".tls$") +__declspec(thread) Thread* pCurrentThread = 0; +#pragma data_seg(".rwdata") +#endif +*/ + +// *** Thread constructors. + +Thread::Thread(size_t stackSize, int processor) +{ + CreateParams params; + params.stackSize = stackSize; + params.processor = processor; + Init(params); +} + +Thread::Thread(Thread::ThreadFn threadFunction, void* userHandle, size_t stackSize, + int processor, Thread::ThreadState initialState) +{ + CreateParams params(threadFunction, userHandle, stackSize, processor, initialState); + Init(params); +} + +Thread::Thread(const CreateParams& params) +{ + Init(params); +} +void Thread::Init(const CreateParams& params) +{ + // Clear the variables + ThreadFlags = 0; + ThreadHandle = 0; + IdValue = 0; + ExitCode = 0; + SuspendCount = 0; + StackSize = params.stackSize; + Processor = params.processor; + Priority = params.priority; + + // Clear Function pointers + ThreadFunction = params.threadFunction; + UserHandle = params.userHandle; + if (params.initialState != NotRunning) + Start(params.initialState); + +} + +Thread::~Thread() +{ + // Thread should not running while object is being destroyed, + // this would indicate ref-counting issue. + //OVR_ASSERT(IsRunning() == 0); + + // Clean up thread. + CleanupSystemThread(); + ThreadHandle = 0; +} + + +// *** Overridable User functions. + +// Default Run implementation +int Thread::Run() +{ + if (!ThreadFunction) + return 0; + + int ret = ThreadFunction(this, UserHandle); + + return ret; +} + +void Thread::OnExit() +{ +} + +// Finishes the thread and releases internal reference to it. +void Thread::FinishAndRelease() +{ + // Note: thread must be US. + ThreadFlags &= (uint32_t)~(OVR_THREAD_STARTED); + ThreadFlags |= OVR_THREAD_FINISHED; + + // Release our reference; this is equivalent to 'delete this' + // from the point of view of our thread. + Release(); +} + + +// *** ThreadList - used to tack all created threads + +class ThreadList : public NewOverrideBase +{ + //------------------------------------------------------------------------ + struct ThreadHashOp + { + size_t operator()(const Thread* ptr) + { + return (((size_t)ptr) >> 6) ^ (size_t)ptr; + } + }; + + HashSet<Thread*, ThreadHashOp> ThreadSet; + Mutex ThreadMutex; + WaitCondition ThreadsEmpty; + // Track the root thread that created us. + ThreadId RootThreadId; + + static ThreadList* volatile pRunningThreads; + + void addThread(Thread *pthread) + { + Mutex::Locker lock(&ThreadMutex); + ThreadSet.Add(pthread); + } + + void removeThread(Thread *pthread) + { + Mutex::Locker lock(&ThreadMutex); + ThreadSet.Remove(pthread); + if (ThreadSet.GetSize() == 0) + ThreadsEmpty.Notify(); + } + + void finishAllThreads() + { + // Only original root thread can call this. + OVR_ASSERT(GetCurrentThreadId() == RootThreadId); + + Mutex::Locker lock(&ThreadMutex); + while (ThreadSet.GetSize() != 0) + ThreadsEmpty.Wait(&ThreadMutex); + } + +public: + + ThreadList() + { + RootThreadId = GetCurrentThreadId(); + } + ~ThreadList() { } + + + static void AddRunningThread(Thread *pthread) + { + // Non-atomic creation ok since only the root thread + if (!pRunningThreads) + { + pRunningThreads = new ThreadList; + OVR_ASSERT(pRunningThreads); + } + pRunningThreads->addThread(pthread); + } + + // NOTE: 'pthread' might be a dead pointer when this is + // called so it should not be accessed; it is only used + // for removal. + static void RemoveRunningThread(Thread *pthread) + { + OVR_ASSERT(pRunningThreads); + pRunningThreads->removeThread(pthread); + } + + static void FinishAllThreads() + { + // This is ok because only root thread can wait for other thread finish. + if (pRunningThreads) + { + pRunningThreads->finishAllThreads(); + delete pRunningThreads; + pRunningThreads = 0; + } + } +}; + +// By default, we have no thread list. +ThreadList* volatile ThreadList::pRunningThreads = 0; + + +// FinishAllThreads - exposed publicly in Thread. +void Thread::FinishAllThreads() +{ + ThreadList::FinishAllThreads(); +} + + +// *** Run override + +int Thread::PRun() +{ + // Suspend us on start, if requested + if (ThreadFlags & OVR_THREAD_START_SUSPENDED) + { + Suspend(); + ThreadFlags &= (uint32_t)~OVR_THREAD_START_SUSPENDED; + } + + // Call the virtual run function + ExitCode = Run(); + + return ExitCode; +} + + + +/* MA: Don't use TLS for now. + +// Static function to return a pointer to the current thread +void Thread::InitCurrentThread(Thread *pthread) +{ + pCurrentThread = pthread; +} + +// Static function to return a pointer to the current thread +Thread* Thread::GetThread() +{ + return pCurrentThread; +} +*/ + + +// *** User overridables + +bool Thread::GetExitFlag() const +{ + return (ThreadFlags & OVR_THREAD_EXIT) != 0; +} + +void Thread::SetExitFlag(bool exitFlag) +{ + // The below is atomic since ThreadFlags is AtomicInt. + if (exitFlag) + ThreadFlags |= OVR_THREAD_EXIT; + else + ThreadFlags &= (uint32_t) ~OVR_THREAD_EXIT; +} + + +// Determines whether the thread was running and is now finished +bool Thread::IsFinished() const +{ + return (ThreadFlags & OVR_THREAD_FINISHED) != 0; +} +// Determines whether the thread is suspended +bool Thread::IsSuspended() const +{ + return SuspendCount > 0; +} +// Returns current thread state +Thread::ThreadState Thread::GetThreadState() const +{ + if (IsSuspended()) + return Suspended; + if (ThreadFlags & OVR_THREAD_STARTED) + return Running; + return NotRunning; +} +// Join thread +bool Thread::Join(int maxWaitMs) const +{ + // If polling, + if (maxWaitMs == 0) + { + // Just return if finished + return IsFinished(); + } + // If waiting forever, + else if (maxWaitMs > 0) + { + // Try waiting once + WaitForSingleObject(ThreadHandle, maxWaitMs); + + // Return if the wait succeeded + return IsFinished(); + } + + // While not finished, + while (!IsFinished()) + { + // Wait for the thread handle to signal + WaitForSingleObject(ThreadHandle, INFINITE); + } + + return true; +} + + +// ***** Thread management +/* static */ +int Thread::GetOSPriority(ThreadPriority p) +{ + switch(p) + { + // If the process is REALTIME_PRIORITY_CLASS then it could have priority values 3 through14 and -3 through -14. + case Thread::CriticalPriority: return THREAD_PRIORITY_TIME_CRITICAL; // 15 + case Thread::HighestPriority: return THREAD_PRIORITY_HIGHEST; // 2 + case Thread::AboveNormalPriority: return THREAD_PRIORITY_ABOVE_NORMAL; // 1 + case Thread::NormalPriority: return THREAD_PRIORITY_NORMAL; // 0 + case Thread::BelowNormalPriority: return THREAD_PRIORITY_BELOW_NORMAL; // -1 + case Thread::LowestPriority: return THREAD_PRIORITY_LOWEST; // -2 + case Thread::IdlePriority: return THREAD_PRIORITY_IDLE; // -15 + } + return THREAD_PRIORITY_NORMAL; +} + +/* static */ +Thread::ThreadPriority Thread::GetOVRPriority(int osPriority) +{ + // If the process is REALTIME_PRIORITY_CLASS then it could have priority values 3 through14 and -3 through -14. + // As a result, it's possible for those cases that an unknown/invalid ThreadPriority enum be returned. However, + // in practice we don't expect to be using such processes. + + // The ThreadPriority types aren't linearly distributed, so we need to check for some values explicitly. + if(osPriority == THREAD_PRIORITY_TIME_CRITICAL) + return Thread::CriticalPriority; + if(osPriority == THREAD_PRIORITY_IDLE) + return Thread::IdlePriority; + return (ThreadPriority)(Thread::NormalPriority - osPriority); +} + +Thread::ThreadPriority Thread::GetPriority() +{ + int osPriority = ::GetThreadPriority(ThreadHandle); + + if(osPriority != THREAD_PRIORITY_ERROR_RETURN) + { + return GetOVRPriority(osPriority); + } + + return NormalPriority; +} + +/* static */ +Thread::ThreadPriority Thread::GetCurrentPriority() +{ + int osPriority = ::GetThreadPriority(::GetCurrentThread()); + + if(osPriority != THREAD_PRIORITY_ERROR_RETURN) + { + return GetOVRPriority(osPriority); + } + + return NormalPriority; +} + +bool Thread::SetPriority(ThreadPriority p) +{ + BOOL ret = ::SetThreadPriority(ThreadHandle, Thread::GetOSPriority(p)); + return (ret != FALSE); +} + +/* static */ +bool Thread::SetCurrentPriority(ThreadPriority p) +{ + BOOL ret = ::SetThreadPriority(::GetCurrentThread(), Thread::GetOSPriority(p)); + return (ret != FALSE); +} + + + +// The actual first function called on thread start +#if defined(OVR_OS_WIN32) +unsigned WINAPI Thread_Win32StartFn(void * phandle) +#else // Other Micorosft OSs... +DWORD WINAPI Thread_Win32StartFn(void *phandle) +#endif +{ + Thread * pthread = (Thread*)phandle; + if (pthread->Processor != -1) + { + DWORD_PTR ret = SetThreadAffinityMask(GetCurrentThread(), (DWORD)pthread->Processor); + if (ret == 0) + OVR_DEBUG_LOG(("Could not set hardware processor for the thread")); + } + BOOL ret = ::SetThreadPriority(GetCurrentThread(), Thread::GetOSPriority(pthread->Priority)); + if (ret == 0) + OVR_DEBUG_LOG(("Could not set thread priority")); + OVR_UNUSED(ret); + + // Ensure that ThreadId is assigned once thread is running, in case + // beginthread hasn't filled it in yet. + pthread->IdValue = (ThreadId)(intptr_t)::GetCurrentThreadId(); // should be: typedef intptr_t ThreadId; + + DWORD result = pthread->PRun(); + // Signal the thread as done and release it atomically. + pthread->FinishAndRelease(); + // At this point Thread object might be dead; however we can still pass + // it to RemoveRunningThread since it is only used as a key there. + ThreadList::RemoveRunningThread(pthread); + return (unsigned) result; +} + +bool Thread::Start(ThreadState initialState) +{ + if (initialState == NotRunning) + return 0; + if (GetThreadState() != NotRunning) + { + OVR_DEBUG_LOG(("Thread::Start failed - thread %p already running", this)); + return 0; + } + + // Free old thread handle before creating the new one + CleanupSystemThread(); + + // AddRef to us until the thread is finished. + AddRef(); + ThreadList::AddRunningThread(this); + + ExitCode = 0; + SuspendCount = 0; + ThreadFlags = (initialState == Running) ? 0 : OVR_THREAD_START_SUSPENDED; +#if defined(OVR_OS_WIN32) + ThreadHandle = (HANDLE) _beginthreadex(0, (unsigned)StackSize, + Thread_Win32StartFn, this, 0, (unsigned*)&IdValue); +#else // Other Micorosft OSs... + DWORD TheThreadId; + ThreadHandle = CreateThread(0, (unsigned)StackSize, + Thread_Win32StartFn, this, 0, &TheThreadId); + IdValue = (ThreadId)TheThreadId; +#endif + + // Failed? Fail the function + if (ThreadHandle == 0) + { + ThreadFlags = 0; + Release(); + ThreadList::RemoveRunningThread(this); + return 0; + } + return 1; +} + + +// Suspend the thread until resumed +bool Thread::Suspend() +{ + // Can't suspend a thread that wasn't started + if (!(ThreadFlags & OVR_THREAD_STARTED)) + return 0; + + if (::SuspendThread(ThreadHandle) != 0xFFFFFFFF) + { + SuspendCount++; + return 1; + } + return 0; +} + +// Resumes currently suspended thread +bool Thread::Resume() +{ + // Can't suspend a thread that wasn't started + if (!(ThreadFlags & OVR_THREAD_STARTED)) + return 0; + + // Decrement count, and resume thread if it is 0 + int32_t oldCount = SuspendCount.ExchangeAdd_Acquire(-1); + if (oldCount >= 1) + { + if (oldCount == 1) + { + if (::ResumeThread(ThreadHandle) != 0xFFFFFFFF) + { + return 1; + } + } + else + { + return 1; + } + } + return 0; +} + + +// Quits with an exit code +void Thread::Exit(int exitCode) +{ + // Can only exist the current thread. + // MA: Don't use TLS for now. + //if (GetThread() != this) + // return; + + // Call the virtual OnExit function. + OnExit(); + + // Signal this thread object as done and release it's references. + FinishAndRelease(); + ThreadList::RemoveRunningThread(this); + + // Call the exit function. +#if defined(OVR_OS_WIN32) // _endthreadex doesn't exist on other Microsoft OSs and instead we need to call ExitThread directly. + _endthreadex((unsigned)exitCode); +#else + ExitThread((unsigned)exitCode); +#endif +} + + +void Thread::CleanupSystemThread() +{ + if (ThreadHandle != 0) + { + ::CloseHandle(ThreadHandle); + ThreadHandle = 0; + } +} + +// *** Sleep functions +// static +bool Thread::Sleep(unsigned secs) +{ + ::Sleep(secs*1000); + return 1; +} + +// static +bool Thread::MSleep(unsigned msecs) +{ + ::Sleep(msecs); + return 1; +} + +// static +void Thread::YieldCurrentThread() +{ + YieldProcessor(); +} + +void Thread::SetThreadName( const char* name ) +{ + if(IdValue) + SetThreadName(name, IdValue); + // Else we don't know what thread to name. We can save the name and wait until the thread is created. +} + + +void Thread::SetThreadName(const char* name, ThreadId threadId) +{ + // MinGW does not support SEH exceptions, hence CPP: && defined(OVR_CC_MSVC) + #if ( !defined(OVR_BUILD_SHIPPING) || defined(OVR_BUILD_PROFILING) ) && defined(OVR_CC_MSVC) + // http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx + #pragma pack(push,8) + struct THREADNAME_INFO { + DWORD dwType; // Must be 0x1000 + LPCSTR szName; // Pointer to name (in user address space) + DWORD dwThreadID; // Thread ID (-1 for caller thread) + DWORD dwFlags; // Reserved for future use; must be zero + }; + #pragma pack(pop) + + THREADNAME_INFO info = { 0x1000, name, (DWORD)threadId, 0 }; + + __try + { + RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(ULONG_PTR), reinterpret_cast<ULONG_PTR*>(&info)); + } + __except( GetExceptionCode()==0x406D1388 ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER ) + { + return; + } + #endif // OVR_BUILD_SHIPPING +} + + +void Thread::SetCurrentThreadName( const char* name ) +{ + SetThreadName(name, (ThreadId)(intptr_t)::GetCurrentThreadId()); // should be: typedef intptr_t ThreadId; +} + + +void Thread::GetThreadName(char* name, size_t /*nameCapacity*/, ThreadId /*threadId*/) +{ + // Not possible on Windows. + name[0] = 0; +} + + +void Thread::GetCurrentThreadName(char* name, size_t /*nameCapacity*/) +{ + // Not possible on Windows. + name[0] = 0; +} + + +// static +int Thread::GetCPUCount() +{ + SYSTEM_INFO sysInfo; + + #if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) // GetNativeSystemInfo requires WinXP+ and a corresponding SDK (0x0501) or later. + GetNativeSystemInfo(&sysInfo); + #else + GetSystemInfo(&sysInfo); + #endif + + return (int) sysInfo.dwNumberOfProcessors; +} + +// Returns the unique Id of a thread it is called on, intended for +// comparison purposes. +ThreadId GetCurrentThreadId() +{ + return (ThreadId)(intptr_t)::GetCurrentThreadId(); // should be: typedef intptr_t ThreadId; +} + +} // OVR + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Timer.cpp b/LibOVRKernel/Src/Kernel/OVR_Timer.cpp new file mode 100644 index 0000000..5230c14 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Timer.cpp @@ -0,0 +1,460 @@ +/************************************************************************************ + +Filename : OVR_Timer.cpp +Content : Provides static functions for precise timing +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_Timer.h" +#include "OVR_Log.h" + +#if defined(OVR_OS_MS) && !defined(OVR_OS_MS_MOBILE) +#include "OVR_Win32_IncludeWindows.h" +#include <MMSystem.h> +#pragma comment(lib, "winmm.lib") +#elif defined(OVR_OS_ANDROID) +#include <time.h> +#include <android/log.h> +#else +#include <chrono> +#endif + + +#if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32) + typedef NTSTATUS (NTAPI* NtQueryTimerResolutionType)(PULONG MaximumTime, PULONG MinimumTime, PULONG CurrentTime); + NtQueryTimerResolutionType pNtQueryTimerResolution; +#endif + + + +#if defined(OVR_OS_MS) && !defined(OVR_OS_WIN32) // Non-desktop Microsoft platforms... + +// Add this alias here because we're not going to include OVR_CAPI.cpp +extern "C" { + double ovr_GetTimeInSeconds() + { + return Timer::GetSeconds(); + } +} + +#endif + + + + +namespace OVR { + +// For recorded data playback +bool Timer::useFakeSeconds = false; +double Timer::FakeSeconds = 0; + + + + +//------------------------------------------------------------------------ +// *** Android Specific Timer + +#if defined(OVR_OS_ANDROID) // To consider: This implementation can also work on most Linux distributions + +//------------------------------------------------------------------------ +// *** Timer - Platform Independent functions + +// Returns global high-resolution application timer in seconds. +double Timer::GetSeconds() +{ + if(useFakeSeconds) + return FakeSeconds; + + // Choreographer vsync timestamp is based on. + struct timespec tp; + const int status = clock_gettime(CLOCK_MONOTONIC, &tp); + +#ifdef OVR_BUILD_DEBUG + if (status != 0) + { + OVR_DEBUG_LOG(("clock_gettime status=%i", status )); + } +#else + OVR_UNUSED(status); +#endif + + return (double)tp.tv_sec; +} + + + +uint64_t Timer::GetTicksNanos() +{ + if (useFakeSeconds) + return (uint64_t) (FakeSeconds * NanosPerSecond); + + // Choreographer vsync timestamp is based on. + struct timespec tp; + const int status = clock_gettime(CLOCK_MONOTONIC, &tp); + +#ifdef OVR_BUILD_DEBUG + if (status != 0) + { + OVR_DEBUG_LOG(("clock_gettime status=%i", status )); + } +#else + OVR_UNUSED(status); +#endif + + const uint64_t result = (uint64_t)tp.tv_sec * (uint64_t)(1000 * 1000 * 1000) + uint64_t(tp.tv_nsec); + return result; +} + + +void Timer::initializeTimerSystem() +{ + // Empty for this platform. +} + +void Timer::shutdownTimerSystem() +{ + // Empty for this platform. +} + + + + + +//------------------------------------------------------------------------ +// *** Win32 Specific Timer + +#elif defined (OVR_OS_MS) + + +// This helper class implements high-resolution wrapper that combines timeGetTime() output +// with QueryPerformanceCounter. timeGetTime() is lower precision but drives the high bits, +// as it's tied to the system clock. +struct PerformanceTimer +{ + PerformanceTimer() + : UsingVistaOrLater(false), + TimeCS(), + OldMMTimeMs(0), + MMTimeWrapCounter(0), + PerfFrequency(0), + PerfFrequencyInverse(0), + PerfFrequencyInverseNanos(0), + PerfMinusTicksDeltaNanos(0), + LastResultNanos(0) + { } + + enum { + MMTimerResolutionNanos = 1000000 + }; + + void Initialize(); + void Shutdown(); + + uint64_t GetTimeSeconds(); + double GetTimeSecondsDouble(); + uint64_t GetTimeNanos(); + + UINT64 getFrequency() + { + if (PerfFrequency == 0) + { + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + PerfFrequency = freq.QuadPart; + PerfFrequencyInverse = 1.0 / (double)PerfFrequency; + PerfFrequencyInverseNanos = 1000000000.0 / (double)PerfFrequency; + } + return PerfFrequency; + } + + double GetFrequencyInverse() + { + OVR_ASSERT(PerfFrequencyInverse != 0.0); // Assert that the frequency has been initialized. + return PerfFrequencyInverse; + } + + bool UsingVistaOrLater; + + CRITICAL_SECTION TimeCS; + // timeGetTime() support with wrap. + uint32_t OldMMTimeMs; + uint32_t MMTimeWrapCounter; + // Cached performance frequency result. + uint64_t PerfFrequency; // cycles per second, typically a large value like 3000000, but usually not the same as the CPU clock rate. + double PerfFrequencyInverse; // seconds per cycle (will be a small fractional value). + double PerfFrequencyInverseNanos; // nanoseconds per cycle. + + // Computed as (perfCounterNanos - ticksCounterNanos) initially, + // and used to adjust timing. + uint64_t PerfMinusTicksDeltaNanos; + // Last returned value in nanoseconds, to ensure we don't back-step in time. + uint64_t LastResultNanos; +}; + +static PerformanceTimer Win32_PerfTimer; + + +void PerformanceTimer::Initialize() +{ + #if defined(OVR_OS_WIN32) // Desktop Windows only + // The following has the effect of setting the NT timer resolution (NtSetTimerResolution) to 1 millisecond. + MMRESULT mmr = timeBeginPeriod(1); + OVR_ASSERT(TIMERR_NOERROR == mmr); + OVR_UNUSED(mmr); + #endif + + InitializeCriticalSection(&TimeCS); + MMTimeWrapCounter = 0; + getFrequency(); + + #if defined(OVR_OS_WIN32) // Desktop Windows only + // Set Vista flag. On Vista, we can just use QPC() without all the extra work + OSVERSIONINFOEX ver; + ZeroMemory(&ver, sizeof(OSVERSIONINFOEX)); + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + ver.dwMajorVersion = 6; // Vista+ + + DWORDLONG condMask = 0; + VER_SET_CONDITION(condMask, VER_MAJORVERSION, VER_GREATER_EQUAL); + + // VerifyVersionInfo returns true if the OS meets the conditions set above + UsingVistaOrLater = VerifyVersionInfo(&ver, VER_MAJORVERSION, condMask) != 0; + #else + UsingVistaOrLater = true; + #endif + + OVR_DEBUG_LOG(("PerformanceTimer UsingVistaOrLater = %d", (int)UsingVistaOrLater)); + + #if defined(OVR_BUILD_DEBUG) && defined(OVR_OS_WIN32) + HMODULE hNtDll = LoadLibraryW(L"NtDll.dll"); + if (hNtDll) + { + pNtQueryTimerResolution = (NtQueryTimerResolutionType)GetProcAddress(hNtDll, "NtQueryTimerResolution"); + //pNtSetTimerResolution = (NtSetTimerResolutionType)GetProcAddress(hNtDll, "NtSetTimerResolution"); + + if(pNtQueryTimerResolution) + { + ULONG MinimumResolution; // in 100-ns units + ULONG MaximumResolution; + ULONG ActualResolution; + pNtQueryTimerResolution(&MinimumResolution, &MaximumResolution, &ActualResolution); + OVR_DEBUG_LOG(("NtQueryTimerResolution = Min %ld us, Max %ld us, Current %ld us", MinimumResolution / 10, MaximumResolution / 10, ActualResolution / 10)); + } + + FreeLibrary(hNtDll); + } + #endif +} + +void PerformanceTimer::Shutdown() +{ + DeleteCriticalSection(&TimeCS); + + #if defined(OVR_OS_WIN32) // Desktop Windows only + MMRESULT mmr = timeEndPeriod(1); + OVR_ASSERT(TIMERR_NOERROR == mmr); + OVR_UNUSED(mmr); + #endif +} + + +uint64_t PerformanceTimer::GetTimeSeconds() +{ + if (UsingVistaOrLater) + { + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + OVR_ASSERT(PerfFrequencyInverse != 0); // Initialize should have been called earlier. + return (uint64_t)(li.QuadPart * PerfFrequencyInverse); + } + + return (uint64_t)(GetTimeNanos() * .0000000001); +} + + +double PerformanceTimer::GetTimeSecondsDouble() +{ + if (UsingVistaOrLater) + { + LARGE_INTEGER li; + QueryPerformanceCounter(&li); + OVR_ASSERT(PerfFrequencyInverse != 0); + return (li.QuadPart * PerfFrequencyInverse); + } + + return (GetTimeNanos() * .0000000001); +} + + +uint64_t PerformanceTimer::GetTimeNanos() +{ + uint64_t resultNanos; + LARGE_INTEGER li; + + OVR_ASSERT(PerfFrequencyInverseNanos != 0); // Initialize should have been called earlier. + + if (UsingVistaOrLater) // Includes non-desktop platforms + { + // Then we can use QPC() directly without all that extra work + QueryPerformanceCounter(&li); + resultNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos); + } + else + { + // On Win32 QueryPerformanceFrequency is unreliable due to SMP and + // performance levels, so use this logic to detect wrapping and track + // high bits. + ::EnterCriticalSection(&TimeCS); + + // Get raw value and perf counter "At the same time". + QueryPerformanceCounter(&li); + + DWORD mmTimeMs = timeGetTime(); + if (OldMMTimeMs > mmTimeMs) + MMTimeWrapCounter++; + OldMMTimeMs = mmTimeMs; + + // Normalize to nanoseconds. + uint64_t perfCounterNanos = (uint64_t)(li.QuadPart * PerfFrequencyInverseNanos); + uint64_t mmCounterNanos = ((uint64_t(MMTimeWrapCounter) << 32) | mmTimeMs) * 1000000; + if (PerfMinusTicksDeltaNanos == 0) + PerfMinusTicksDeltaNanos = perfCounterNanos - mmCounterNanos; + + // Compute result before snapping. + // + // On first call, this evaluates to: + // resultNanos = mmCounterNanos. + // Next call, assuming no wrap: + // resultNanos = prev_mmCounterNanos + (perfCounterNanos - prev_perfCounterNanos). + // After wrap, this would be: + // resultNanos = snapped(prev_mmCounterNanos +/- 1ms) + (perfCounterNanos - prev_perfCounterNanos). + // + resultNanos = perfCounterNanos - PerfMinusTicksDeltaNanos; + + // Snap the range so that resultNanos never moves further apart then its target resolution. + // It's better to allow more slack on the high side as timeGetTime() may be updated at sporadically + // larger then 1 ms intervals even when 1 ms resolution is requested. + if (resultNanos > (mmCounterNanos + MMTimerResolutionNanos*2)) + { + resultNanos = mmCounterNanos + MMTimerResolutionNanos*2; + if (resultNanos < LastResultNanos) + resultNanos = LastResultNanos; + PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos; + } + else if (resultNanos < (mmCounterNanos - MMTimerResolutionNanos)) + { + resultNanos = mmCounterNanos - MMTimerResolutionNanos; + if (resultNanos < LastResultNanos) + resultNanos = LastResultNanos; + PerfMinusTicksDeltaNanos = perfCounterNanos - resultNanos; + } + + LastResultNanos = resultNanos; + ::LeaveCriticalSection(&TimeCS); + } + + //Tom's addition, to keep precision + //static uint64_t initial_time = 0; + //if (!initial_time) initial_time = resultNanos; + //resultNanos -= initial_time; + // FIXME: This cannot be used for cross-process timestamps + + return resultNanos; +} + + +//------------------------------------------------------------------------ +// *** Timer - Platform Independent functions + +// Returns global high-resolution application timer in seconds. +double Timer::GetSeconds() +{ + if(useFakeSeconds) + return FakeSeconds; + + return Win32_PerfTimer.GetTimeSecondsDouble(); +} + + + +// Delegate to PerformanceTimer. +uint64_t Timer::GetTicksNanos() +{ + if (useFakeSeconds) + return (uint64_t) (FakeSeconds * NanosPerSecond); + + return Win32_PerfTimer.GetTimeNanos(); +} + +// Windows version also provides the performance frequency inverse. +double Timer::GetPerfFrequencyInverse() +{ + return Win32_PerfTimer.GetFrequencyInverse(); +} + +void Timer::initializeTimerSystem() +{ + Win32_PerfTimer.Initialize(); +} +void Timer::shutdownTimerSystem() +{ + Win32_PerfTimer.Shutdown(); +} + + +#else // C++11 standard compliant platforms + +double Timer::GetSeconds() +{ + if(useFakeSeconds) + return FakeSeconds; + + using FpSeconds = std::chrono::duration<double, std::chrono::seconds::period>; + + auto now = std::chrono::high_resolution_clock::now(); + return FpSeconds(now.time_since_epoch()).count(); +} + + +uint64_t Timer::GetTicksNanos() +{ + if (useFakeSeconds) + return (uint64_t) (FakeSeconds * NanosPerSecond); + + using Uint64Nanoseconds = std::chrono::duration<uint64_t, std::chrono::nanoseconds::period>; + + auto now = std::chrono::high_resolution_clock::now(); + return Uint64Nanoseconds(now.time_since_epoch()).count(); +} + +void Timer::initializeTimerSystem() +{ +} + +void Timer::shutdownTimerSystem() +{ +} + +#endif // OS-specific + +} // OVR + diff --git a/LibOVRKernel/Src/Kernel/OVR_Timer.h b/LibOVRKernel/Src/Kernel/OVR_Timer.h new file mode 100644 index 0000000..b6717ba --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Timer.h @@ -0,0 +1,98 @@ +/************************************************************************************ + +PublicHeader: OVR +Filename : OVR_Timer.h +Content : Provides static functions for precise timing +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Timer_h +#define OVR_Timer_h + +#include "OVR_Types.h" + +namespace OVR { + +//----------------------------------------------------------------------------------- +// ***** Timer + +// Timer class defines a family of static functions used for application +// timing and profiling. + +class Timer +{ +public: + enum { + MsPerSecond = 1000, // Milliseconds in one second. + MksPerSecond = 1000 * 1000, // Microseconds in one second. + NanosPerSecond = 1000 * 1000 * 1000, // Nanoseconds in one second. + }; + + // ***** Timing APIs for Application + + // These APIs should be used to guide animation and other program functions + // that require precision. + + // Returns global high-resolution application timer in seconds. + static double OVR_STDCALL GetSeconds(); + + // Returns time in Nanoseconds, using highest possible system resolution. + static uint64_t OVR_STDCALL GetTicksNanos(); + +#ifdef OVR_OS_MS + static double OVR_STDCALL GetPerfFrequencyInverse(); +#endif + + // Kept for compatibility. + // Returns ticks in milliseconds, as a 32-bit number. May wrap around every 49.2 days. + // Use either time difference of two values of GetTicks to avoid wrap-around. + static uint32_t OVR_STDCALL GetTicksMs() + { return uint32_t(GetTicksNanos() / 1000000); } + + // for recorded data playback + static void SetFakeSeconds(double fakeSeconds, bool enable = true) + { + FakeSeconds = fakeSeconds; + useFakeSeconds = enable; + } + +private: + friend class System; + // System called during program startup/shutdown. + static void initializeTimerSystem(); + static void shutdownTimerSystem(); + + // for recorded data playback + static double FakeSeconds; + static bool useFakeSeconds; + + #if defined(OVR_OS_ANDROID) + // Android-specific data + #elif defined (OVR_OS_MS) + // Microsoft-specific data + #endif +}; + + +} // OVR::Timer + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Types.h b/LibOVRKernel/Src/Kernel/OVR_Types.h new file mode 100644 index 0000000..967389d --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Types.h @@ -0,0 +1,1055 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_Types.h +Content : Standard library defines and simple types +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Types_h +#define OVR_Types_h + +#include "OVR_Compiler.h" + + +// Unsupported compiler configurations +#if _MSC_VER == 0x1600 +# if _MSC_FULL_VER < 160040219 +# error "Oculus does not support VS2010 without SP1 installed: It will crash in Release mode" +# endif +#endif + + +//----------------------------------------------------------------------------------- +// ****** Operating system identification +// +// Try to use the most generic version of these defines as possible in order to achieve +// the simplest portable code. For example, instead of using #if (defined(OVR_OS_IPHONE) || defined(OVR_OS_MAC)), +// consider using #if defined(OVR_OS_APPLE). +// +// Type definitions exist for the following operating systems: (OVR_OS_x) +// +// WIN32 - Win32 and Win64 (Windows XP and later) Does not include Microsoft phone and console platforms, despite that Microsoft's _WIN32 may be defined by the compiler for them. +// WIN64 - Win64 (Windows XP and later) +// MAC - Mac OS X (may be defined in addition to BSD) +// LINUX - Linux +// BSD - BSD Unix +// ANDROID - Android (may be defined in addition to LINUX) +// IPHONE - iPhone +// MS_MOBILE - Microsoft mobile OS. +// +// Meta platforms +// MS - Any OS by Microsoft (e.g. Win32, Win64, phone, console) +// APPLE - Any OS by Apple (e.g. iOS, OS X) +// UNIX - Linux, BSD, Mac OS X. +// MOBILE - iOS, Android, Microsoft phone +// CONSOLE - Console platforms. +// + +#if (defined(__APPLE__) && (defined(__GNUC__) ||\ + defined(__xlC__) || defined(__xlc__))) || defined(__MACOS__) +# if (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) || defined(__IPHONE_OS_VERSION_MIN_REQUIRED)) +# if !defined(OVR_OS_IPHONE) +# define OVR_OS_IPHONE +# endif +# else +# if !defined(OVR_OS_MAC) +# define OVR_OS_MAC +# endif +# if !defined(OVR_OS_DARWIN) +# define OVR_OS_DARWIN +# endif +# if !defined(OVR_OS_BSD) +# define OVR_OS_BSD +# endif +# endif +#elif (defined(WIN64) || defined(_WIN64) || defined(__WIN64__)) +# if !defined(OVR_OS_WIN64) +# define OVR_OS_WIN64 +# endif +# if !defined(OVR_OS_WIN32) +# define OVR_OS_WIN32 //Can be a 32 bit Windows build or a WOW64 support for Win32. In this case WOW64 support for Win32. +# endif +#elif (defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)) +# if !defined(OVR_OS_WIN32) +# define OVR_OS_WIN32 //Can be a 32 bit Windows build or a WOW64 support for Win32. In this case WOW64 support for Win32. +# endif +#elif defined(ANDROID) || defined(__ANDROID__) +# if !defined(OVR_OS_ANDROID) +# define OVR_OS_ANDROID +# endif +# if !defined(OVR_OS_LINUX) +# define OVR_OS_LINUX +# endif +#elif defined(__linux__) || defined(__linux) +# if !defined(OVR_OS_LINUX) +# define OVR_OS_LINUX +# endif +#elif defined(_BSD_) || defined(__FreeBSD__) +# if !defined(OVR_OS_BSD) +# define OVR_OS_BSD +# endif +#else +# if !defined(OVR_OS_OTHER) +# define OVR_OS_OTHER +# endif +#endif + +#if !defined(OVR_OS_MS_MOBILE) +# if (defined(_M_ARM) || defined(_M_IX86) || defined(_M_AMD64)) && !defined(OVR_OS_WIN32) && !defined(OVR_OS_CONSOLE) +# define OVR_OS_MS_MOBILE +# endif +#endif + +#if !defined(OVR_OS_MS) +# if defined(OVR_OS_WIN32) || defined(OVR_OS_WIN64) || defined(OVR_OS_MS_MOBILE) +# define OVR_OS_MS +# endif +#endif + +#if !defined(OVR_OS_APPLE) +# if defined(OVR_OS_MAC) || defined(OVR_OS_IPHONE) +# define OVR_OS_APPLE +# endif +#endif + +#if !defined(OVR_OS_UNIX) +# if defined(OVR_OS_ANDROID) || defined(OVR_OS_BSD) || defined(OVR_OS_LINUX) || defined(OVR_OS_MAC) +# define OVR_OS_UNIX +# endif +#endif + +#if !defined(OVR_OS_MOBILE) +# if defined(OVR_OS_ANDROID) || defined(OVR_OS_IPHONE) || defined(OVR_OS_MS_MOBILE) +# define OVR_OS_MOBILE +# endif +#endif + + + + +//----------------------------------------------------------------------------------- +// ***** CPU Architecture +// +// The following CPUs are defined: (OVR_CPU_x) +// +// X86 - x86 (IA-32) +// X86_64 - x86_64 (amd64) +// PPC - PowerPC +// PPC64 - PowerPC64 +// MIPS - MIPS +// OTHER - CPU for which no special support is present or needed + + +#if defined(__x86_64__) || defined(WIN64) || defined(_WIN64) || defined(__WIN64__) || defined(_M_AMD64) +# define OVR_CPU_X86_64 +# define OVR_64BIT_POINTERS +#elif defined(__i386__) || defined(OVR_OS_WIN32) +# define OVR_CPU_X86 +#elif defined(__powerpc64__) +# define OVR_CPU_PPC64 +#elif defined(__ppc__) +# define OVR_CPU_PPC +#elif defined(__mips__) || defined(__MIPSEL__) +# define OVR_CPU_MIPS +#elif defined(__arm__) +# define OVR_CPU_ARM +#else +# define OVR_CPU_OTHER +#endif + +//----------------------------------------------------------------------------------- +// ***** Co-Processor Architecture +// +// The following co-processors are defined: (OVR_CPU_x) +// +// SSE - Available on all modern x86 processors. +// Altivec - Available on all modern ppc processors. +// Neon - Available on some armv7+ processors. + +#if defined(__SSE__) || defined(_M_IX86) || defined(_M_AMD64) // _M_IX86 and _M_AMD64 are Microsoft identifiers for Intel-based platforms. +# define OVR_CPU_SSE +#endif // __SSE__ + +#if defined( __ALTIVEC__ ) +# define OVR_CPU_ALTIVEC +#endif // __ALTIVEC__ + +#if defined(__ARM_NEON__) +# define OVR_CPU_ARM_NEON +#endif // __ARM_NEON__ + + +//----------------------------------------------------------------------------------- +// ***** Compiler Warnings + +// Disable MSVC warnings +#if defined(OVR_CC_MSVC) +# pragma warning(disable : 4127) // Inconsistent dll linkage +# pragma warning(disable : 4530) // Exception handling +# if (OVR_CC_MSVC<1300) +# pragma warning(disable : 4514) // Unreferenced inline function has been removed +# pragma warning(disable : 4710) // Function not inlined +# pragma warning(disable : 4714) // _force_inline not inlined +# pragma warning(disable : 4786) // Debug variable name longer than 255 chars +# endif // (OVR_CC_MSVC<1300) +#endif // (OVR_CC_MSVC) + + + +// *** Linux Unicode - must come before Standard Includes + +#ifdef OVR_OS_LINUX +// Use glibc unicode functions on linux. +# ifndef _GNU_SOURCE +# define _GNU_SOURCE +# endif +#endif + +//----------------------------------------------------------------------------------- +// ***** Standard Includes +// +#include <stddef.h> +#include <limits.h> +#include <float.h> + + +// MSVC Based Memory Leak checking - for now +#if defined(OVR_CC_MSVC) && defined(OVR_BUILD_DEBUG) +# define _CRTDBG_MAP_ALLOC +# include <stdlib.h> +# include <crtdbg.h> +#endif + + +//----------------------------------------------------------------------------------- +// ***** int8_t, int16_t, etc. + +#if defined(OVR_CC_MSVC) && (OVR_CC_VER <= 1500) // VS2008 and earlier + typedef signed char int8_t; + typedef unsigned char uint8_t; + typedef signed short int16_t; + typedef unsigned short uint16_t; + typedef signed int int32_t; + typedef unsigned int uint32_t; + typedef signed __int64 int64_t; + typedef unsigned __int64 uint64_t; +#else + #include <stdint.h> +#endif + + +//----------------------------------------------------------------------------------- +// ***** Type definitions for Common Systems + +namespace OVR { + +typedef char Char; + +// Pointer-sized integer +typedef size_t UPInt; +typedef ptrdiff_t SPInt; + + +#if defined(OVR_OS_MS) + +typedef char SByte; // 8 bit Integer (Byte) +typedef unsigned char UByte; +typedef short SInt16; // 16 bit Integer (Word) +typedef unsigned short UInt16; +typedef long SInt32; // 32 bit Integer +typedef unsigned long UInt32; +typedef __int64 SInt64; // 64 bit Integer (QWord) +typedef unsigned __int64 UInt64; + + +#elif defined(OVR_OS_MAC) || defined(OVR_OS_IPHONE) || defined(OVR_CC_GNU) + +typedef int SByte __attribute__((__mode__ (__QI__))); +typedef unsigned int UByte __attribute__((__mode__ (__QI__))); +typedef int SInt16 __attribute__((__mode__ (__HI__))); +typedef unsigned int UInt16 __attribute__((__mode__ (__HI__))); +typedef int SInt32 __attribute__((__mode__ (__SI__))); +typedef unsigned int UInt32 __attribute__((__mode__ (__SI__))); +typedef int SInt64 __attribute__((__mode__ (__DI__))); +typedef unsigned int UInt64 __attribute__((__mode__ (__DI__))); + +#else + +#include <sys/types.h> +typedef int8_t SByte; +typedef uint8_t UByte; +typedef int16_t SInt16; +typedef uint16_t UInt16; +typedef int32_t SInt32; +typedef uint32_t UInt32; +typedef int64_t SInt64; +typedef uint64_t UInt64; + +#endif + + +//osx PID is a signed int32 (already defined to pid_t in OSX framework) +//linux PID is a signed int32 (already defined) +//win32 PID is an unsigned int64 +#ifdef OVR_OS_WIN32 +//process ID representation +typedef unsigned long pid_t; +#endif + +struct OVR_GUID +{ + uint32_t Data1; + uint16_t Data2; + uint16_t Data3; + uint8_t Data4[8]; +}; + + + +} // OVR + + + +//----------------------------------------------------------------------------------- +// ****** Standard C/C++ Library +// +// Identifies which standard library is currently being used. +// +// LIBSTDCPP - GNU libstdc++, used by GCC. +// LIBCPP - LLVM libc++, typically used by clang and GCC. +// DINKUMWARE - Used by Microsoft and various non-Microsoft compilers (e.g. Sony clang). + +#if !defined(OVR_STDLIB_LIBSTDCPP) + #if defined(__GLIBCXX__) + #define OVR_STDLIB_LIBSTDCPP 1 + #endif +#endif + +#if !defined(OVR_STDLIB_LIBCPP) + #if defined(__clang__) + #if defined(__cplusplus) && __has_include(<__config>) + #define OVR_STDLIB_LIBCPP 1 + #endif + #endif +#endif + +#if !defined(OVR_STDLIB_DINKUMWARE) + #if defined(_YVALS) // Dinkumware globally #defines _YVALS from the #includes above. + #define OVR_STDLIB_DINKUMWARE 1 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** Macro Definitions +// +// We define the following: +// +// OVR_BYTE_ORDER - Defined to either OVR_LITTLE_ENDIAN or OVR_BIG_ENDIAN +// OVR_FORCE_INLINE - Forces inline expansion of function +// OVR_ASM - Assembly language prefix +// OVR_STR - Prefixes string with L"" if building unicode +// +// OVR_STDCALL - Use stdcall calling convention (Pascal arg order) +// OVR_CDECL - Use cdecl calling convention (C argument order) +// OVR_FASTCALL - Use fastcall calling convention (registers) +// + +// Byte order constants, OVR_BYTE_ORDER is defined to be one of these. +#define OVR_LITTLE_ENDIAN 1 +#define OVR_BIG_ENDIAN 2 + + +#if defined(OVR_OS_MS) + + // ***** Windows and non-desktop platforms + + // Byte order + #define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN + + // Calling convention - goes after function return type but before function name + #ifdef __cplusplus_cli + # define OVR_FASTCALL __stdcall + #else + # define OVR_FASTCALL __fastcall + #endif + + #define OVR_STDCALL __stdcall + #define OVR_CDECL __cdecl + + + // Assembly macros + #if defined(OVR_CC_MSVC) + # define OVR_ASM _asm + #else + # define OVR_ASM asm + #endif // (OVR_CC_MSVC) + + #ifdef UNICODE + # define OVR_STR(str) L##str + #else + # define OVR_STR(str) str + #endif // UNICODE + +#else + + // **** Standard systems + + #if (defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN))|| \ + (defined(_BYTE_ORDER) && (_BYTE_ORDER == _BIG_ENDIAN)) + # define OVR_BYTE_ORDER OVR_BIG_ENDIAN + #elif (defined(__ARMEB__) || defined(OVR_CPU_PPC) || defined(OVR_CPU_PPC64)) + # define OVR_BYTE_ORDER OVR_BIG_ENDIAN + #else + # define OVR_BYTE_ORDER OVR_LITTLE_ENDIAN + #endif + + // Assembly macros + #define OVR_ASM __asm__ + #define OVR_ASM_PROC(procname) OVR_ASM + #define OVR_ASM_END OVR_ASM + + // Calling convention - goes after function return type but before function name + #define OVR_FASTCALL + #define OVR_STDCALL + #define OVR_CDECL + +#endif // defined(OVR_OS_WIN32) + + +//----------------------------------------------------------------------------------- +// ***** OVR_PTR_SIZE +// +// Specifies the byte size of pointers (same as sizeof void*). + +#if !defined(OVR_PTR_SIZE) + #if defined(__WORDSIZE) + #define OVR_PTR_SIZE ((__WORDSIZE) / 8) + #elif defined(_WIN64) || defined(__LP64__) || defined(_LP64) || defined(_M_IA64) || defined(__ia64__) || defined(__arch64__) || defined(__64BIT__) || defined(__Ptr_Is_64) + #define OVR_PTR_SIZE 8 + #elif defined(__CC_ARM) && (__sizeof_ptr == 8) + #define OVR_PTR_SIZE 8 + #else + #define OVR_PTR_SIZE 4 + #endif +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_WORD_SIZE +// +// Specifies the byte size of a machine word/register. Not necessarily the same as +// the size of pointers, but usually >= the size of pointers. + +#if !defined(OVR_WORD_SIZE) + #define OVR_WORD_SIZE OVR_PTR_SIZE // For our currently supported platforms these are equal. +#endif + + +// ------------------------------------------------------------------------ +// ***** OVR_FORCE_INLINE +// +// Force inline substitute - goes before function declaration +// Example usage: +// OVR_FORCE_INLINE void Test(); + +#if !defined(OVR_FORCE_INLINE) + #if defined(OVR_CC_MSVC) + #define OVR_FORCE_INLINE __forceinline + #elif defined(OVR_CC_GNU) + #define OVR_FORCE_INLINE __attribute__((always_inline)) inline + #else + #define OVR_FORCE_INLINE inline + #endif // OVR_CC_MSVC +#endif + + +// ------------------------------------------------------------------------ +// ***** OVR_NO_INLINE +// +// Cannot be used with inline or OVR_FORCE_INLINE. +// Example usage: +// OVR_NO_INLINE void Test(); + +#if !defined(OVR_NO_INLINE) + #if defined(OVR_CC_MSVC) && (_MSC_VER >= 1500) // VS2008+ + #define OVR_NO_INLINE __declspec(noinline) + #elif !defined(OVR_CC_MSVC) + #define OVR_NO_INLINE __attribute__((noinline)) + #endif +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_STRINGIZE +// +// Converts a preprocessor symbol to a string. +// +// Example usage: +// printf("Line: %s", OVR_STRINGIZE(__LINE__)); +// +#if !defined(OVR_STRINGIZE) + #define OVR_STRINGIZEIMPL(x) #x + #define OVR_STRINGIZE(x) OVR_STRINGIZEIMPL(x) +#endif + + +// ----------------------------------------------------------------------------------- +// ***** OVR_JOIN +// +// Joins two preprocessing symbols together. Supports the case when either or the +// the symbols are macros themselves. +// +// Example usage: +// char OVR_JOIN(unique_, __LINE__); // Results in (e.g.) char unique_123; +// +#if !defined(OVR_JOIN) + #define OVR_JOIN(a, b) OVR_JOIN1(a, b) + #define OVR_JOIN1(a, b) OVR_JOIN2(a, b) + #define OVR_JOIN2(a, b) a##b +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_OFFSETOF +// +// Portable implementation of offsetof for structs and classes. offsetof and GCC's +// __builtin_offsetof work only with POD types (standard-layout types under C++11), +// despite that it can safely work with a number of types that aren't POD. This +// version works with more types without generating compiler warnings or errors. +// Returns the offset as a size_t, as per offsetof. +// +// Example usage: +// struct Test{ int i; float f; }; +// size_t fPos = OVR_OFFSETOF(Test, f); + +#if defined(OVR_CC_GNU) + #define OVR_OFFSETOF(class_, member_) ((size_t)(((uintptr_t)&reinterpret_cast<const volatile char&>((((class_*)65536)->member_))) - 65536)) +#else + #define OVR_OFFSETOF(class_, member_) offsetof(class_, member_) +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_SIZEOF_MEMBER +// +// Implements a portable way to determine the size of struct or class data member. +// C++11 allows this directly via sizeof (see OVR_CPP_NO_EXTENDED_SIZEOF), and this +// macro exists to handle pre-C++11 compilers. +// Returns the offset as a size_t, as per sizeof. +// +// Example usage: +// struct Test{ int i; float f; }; +// size_t fSize = OVR_SIZEOF_MEMBER(Test, f); +// +#if defined(OVR_CPP_NO_EXTENDED_SIZEOF) + #define OVR_SIZEOF_MEMBER(class_, member_) (sizeof(((class_*)0)->member_)) +#else + #define OVR_SIZEOF_MEMBER(class_, member_) (sizeof(class_::member_)) +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_DEBUG_BREAK, OVR_DEBUG_CODE, +// OVR_ASSERT, OVR_ASSERT_M, OVR_ASSERT_AND_UNUSED +// +// Macros have effect only in debug builds. +// +// Example OVR_DEBUG_BREAK usage (note the lack of parentheses): +// #define MY_ASSERT(expression) do { if (!(expression)) { OVR_DEBUG_BREAK; } } while(0) +// +// Example OVR_DEBUG_CODE usage: +// OVR_DEBUG_CODE(printf("debug test\n");) +// or +// OVR_DEBUG_CODE(printf("debug test\n")); +// +// Example OVR_ASSERT usage: +// OVR_ASSERT(count < 100); +// OVR_ASSERT_M(count < 100, "count is too high"); +// +#if defined(OVR_BUILD_DEBUG) + // Causes a debugger breakpoint in debug builds. Has no effect in release builds. + // Microsoft Win32 specific debugging support + #if defined(OVR_CC_MSVC) + // The __debugbreak() intrinsic works for the MSVC debugger, but when the debugger + // is not attached we want our VectoredExceptionHandler to catch assertions, and + // VEH does not trap "int 3" breakpoints. + #define OVR_DEBUG_BREAK __debugbreak() + #elif defined(OVR_CC_GNU) || defined(OVR_CC_CLANG) + #if defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + #define OVR_DEBUG_BREAK do { OVR_ASM("int $3\n\t"); } while(0) + #else + #define OVR_DEBUG_BREAK __builtin_trap() + #endif + #else + #define OVR_DEBUG_BREAK do { *((int *) 0) = 1; } while(0) + #endif + + // The expression is defined only in debug builds. It is defined away in release builds. + #define OVR_DEBUG_CODE(c) c + + // In debug builds this tests the given expression; if false then executes OVR_DEBUG_BREAK, + // if true then no action. Has no effect in release builds. + #if defined(__clang_analyzer__) // During static analysis, make it so the analyzer thinks that failed asserts result in program exit. Reduced false positives. + #include <stdlib.h> + #define OVR_FAIL_M(message) do { OVR_DEBUG_BREAK; exit(0); } while(0) + #define OVR_FAIL() do { OVR_DEBUG_BREAK; exit(0); } while(0) + #define OVR_ASSERT_M(p, message) do { if (!(p)) { OVR_DEBUG_BREAK; exit(0); } } while(0) + #define OVR_ASSERT(p) do { if (!(p)) { OVR_DEBUG_BREAK; exit(0); } } while(0) + #else + #define OVR_FAIL_M(message) \ + { \ + intptr_t ovrAssertUserParam; \ + OVR::OVRAssertionHandler ovrAssertUserHandler = OVR::GetAssertionHandler(&ovrAssertUserParam); \ + \ + if (ovrAssertUserHandler && !OVR::OVRIsDebuggerPresent()) \ + { \ + ovrAssertUserHandler(ovrAssertUserParam, "Assertion failure", message); \ + } \ + else \ + { \ + OVR_DEBUG_BREAK; \ + } \ + } \ + + #define OVR_FAIL() \ + OVR_FAIL_M("Assertion failure") + + // void OVR_ASSERT_M(bool expression, const char message); + // Note: The expression below is expanded into all usage of this assertion macro. + // We should try to minimize the size of the expanded code to the extent possible. + #define OVR_ASSERT_M(p, message) \ + do { \ + if (!(p)) \ + OVR_FAIL_M(message) \ + } while(0) + + // void OVR_ASSERT(bool expression); + #define OVR_ASSERT(p) OVR_ASSERT_M((p), (#p)) + #endif + + // Acts the same as OVR_ASSERT in debug builds. Acts the same as OVR_UNUSED in release builds. + // Example usage: OVR_ASSERT_AND_UNUSED(x < 30, x); + #define OVR_ASSERT_AND_UNUSED(expression, value) OVR_ASSERT(expression); OVR_UNUSED(value) + +#else + + // The expression is defined only in debug builds. It is defined away in release builds. + #define OVR_DEBUG_CODE(c) + + // Causes a debugger breakpoint in debug builds. Has no effect in release builds. + #define OVR_DEBUG_BREAK ((void)0) + + // In debug builds this tests the given expression; if false then executes OVR_DEBUG_BREAK, + // if true then no action. Has no effect in release builds. + #define OVR_FAIL_M(message) ((void)0) + #define OVR_FAIL() ((void)0) + #define OVR_ASSERT_M(p, m) ((void)0) + #define OVR_ASSERT(p) ((void)0) + + // Acts the same as OVR_ASSERT in debug builds. Acts the same as OVR_UNUSED in release builds. + // Example usage: OVR_ASSERT_AND_UNUSED(x < 30, x); + #define OVR_ASSERT_AND_UNUSED(expression, value) OVR_UNUSED(value) + +#endif // OVR_BUILD_DEBUG + + + +// Assert handler +// The user of this library can override the default assertion handler and provide their own. +namespace OVR +{ + // The return value meaning is reserved for future definition and currently has no effect. + typedef intptr_t (*OVRAssertionHandler)(intptr_t userParameter, const char* title, const char* message); + + // Returns the current assertion handler. + OVRAssertionHandler GetAssertionHandler(intptr_t* userParameter = NULL); + + // Sets the current assertion handler. + // The default assertion handler if none is set simply issues a debug break. + // Example usage: + // intptr_t CustomAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message)) { + // MessageBox(title, message); + // OVR_DEBUG_BREAK; + // } + void SetAssertionHandler(OVRAssertionHandler assertionHandler, intptr_t userParameter = 0); + + // Implements the default assertion handler. + intptr_t DefaultAssertionHandler(intptr_t userParameter, const char* title, const char* message); + + // Currently defined in OVR_DebugHelp.cpp + bool OVRIsDebuggerPresent(); +} + + +// ------------------------------------------------------------------------ +// ***** static_assert +// +// Portable support for C++11 static_assert. +// Acts as if the following were declared: +// void static_assert(bool const_expression, const char* msg); +// +// Example usage: +// static_assert(sizeof(int32_t) == 4, "int32_t expected to be 4 bytes."); + +#if defined(OVR_CPP_NO_STATIC_ASSERT) // If the compiler doesn't provide it intrinsically... + #if !defined(OVR_SA_UNUSED) + #if defined(OVR_CC_GNU) || defined(OVR_CC_CLANG) + #define OVR_SA_UNUSED __attribute__((unused)) + #else + #define OVR_SA_UNUSED + #endif + #define OVR_SA_PASTE(a,b) a##b + #define OVR_SA_HELP(a,b) OVR_SA_PASTE(a,b) + #endif + + #if defined(__COUNTER__) + #define static_assert(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __COUNTER__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED + #else + #define static_assert(expression, msg) typedef char OVR_SA_HELP(compileTimeAssert, __LINE__) [((expression) != 0) ? 1 : -1] OVR_SA_UNUSED + #endif +#endif + + +// ------------------------------------------------------------------------ +// ***** OVR_COMPILER_ASSERT +// +// Compile-time assert; produces compiler error if condition is false. +// The expression must be a compile-time constant expression. +// This macro is deprecated in favor of static_assert, which provides better +// compiler output and works in a broader range of contexts. +// +// Example usage: +// OVR_COMPILER_ASSERT(sizeof(int32_t == 4)); + +#if !defined(OVR_COMPILER_ASSERT) + #define OVR_COMPILER_ASSERT(expression) static_assert(expression, #expression) + #define OVR_COMPILER_ASSERT_M(expression, msg) static_assert(expression, msg) +#endif + + +// ***** OVR_PROCESSOR_PAUSE +// +// Yields the processor for other hyperthreads, usually for the purpose of implementing spins and spin locks. +// +// Example usage: +// while(!finished()) +// OVR_PROCESSOR_PAUSE(); + +#if !defined(OVR_PROCESSOR_PAUSE) + #if defined(OVR_CPU_X86) || defined(OVR_CPU_X86_64) + #if defined(OVR_CC_GNU) || defined(OVR_CC_CLANG) + #define OVR_PROCESSOR_PAUSE() asm volatile("pause" ::: "memory") // Consumes 38-40 clocks on current Intel x86 and x64 hardware. + #elif defined(OVR_CC_MSVC) + #include <emmintrin.h> + #pragma intrinsic(_mm_pause) // Maps to asm pause. + #define OVR_PROCESSOR_PAUSE _mm_pause + #else + #define OVR_PROCESSOR_PAUSE() + #endif + #else + #define OVR_PROCESSOR_PAUSE() + #endif +#endif + + + +// ------------------------------------------------------------------------ +// ***** OVR_union_cast +// +// Implements a reinterpret cast which is strict-aliasing safe. Recall that +// it's not sufficient to do a C++ reinterpret_cast or C-style cast in order +// to avoid strict-aliasing violation. The downside to this utility is that +// it works by copying the variable through a union, and this can be have +// a performance hit if the type is not small. +// +// Requires both types to be POD (plain old data), such as built-in types +// or C style structs. +// +// Example usage: +// double d = 1.0; +// int64_t i = union_cast<int64_t>(d); +// +// Note that you cannot safetly use union_cast to alias the contents of two +// unrelated pointers. It can be used to alias values, not pointers to values. + +namespace OVR +{ + template <class DestType, class SourceType> + DestType union_cast(SourceType sourceValue) + { + static_assert(sizeof(DestType) == sizeof(SourceType), "union_cast size mismatch"); + static_assert(OVR_ALIGNOF(DestType) == OVR_ALIGNOF(SourceType), "union_cast alignment mismatch"); + + union SourceDest + { + SourceType sourceValue; + DestType destValue; + }; + + SourceDest sd = { sourceValue }; + return sd.destValue; + } +} + + + +// ------------------------------------------------------------------------ +// ***** OVR_VA_COPY +// +// Implements a version of C++11's va_copy that works with pre-C++11 compilers. +// +// Example usage: +// void Printf(char* pFormat, ...) +// { +// va_list argList; +// va_list argListCopy; +// +// va_start(argList, pFormat); +// OVR_VA_COPY(argListCopy, argList); +// <use argList and argListCopy> +// +// va_end(argList); +// va_end(argListCopy); +// } +// +#if !defined(OVR_VA_COPY) + #if defined(__GNUC__) || defined(__clang__) // GCC / clang + #define OVR_VA_COPY(dest, src) va_copy((dest), (src)) + #elif defined(_MSC_VER) && (_MSC_VER >= 1800) // VS2013+ + #define OVR_VA_COPY(dest, src) va_copy((dest), (src)) + #else + // This may not work for some platforms, depending on their ABI. + // It works for many Microsoft platforms. + #define OVR_VA_COPY(dest, src) memcpy(&(dest), &(src), sizeof(va_list)) + #endif +#endif + + + + + + +// ------------------------------------------------------------------------ +// ***** OVR_ARRAY_COUNT +// +// Returns the element count of a C array. +// +// Example usage: +// float itemArray[16]; +// for(size_t i = 0; i < OVR_ARRAY_COUNT(itemArray); i++) { ... } + +#if defined(OVR_CPP_NO_CONSTEXPR) + #ifndef OVR_ARRAY_COUNT + #define OVR_ARRAY_COUNT(x) (sizeof(x) / sizeof(x[0])) + #endif +#else + // Smarter C++11 version which knows the difference between arrays and pointers. + template <typename T, size_t N> + char (&OVRArrayCountHelper(T (&x)[N]))[N]; + #define OVR_ARRAY_COUNT(x) (sizeof(OVRArrayCountHelper(x))) +#endif + + +// ------------------------------------------------------------------------ +// ***** OVR_CURRENT_FUNCTION +// +// Portable wrapper for __PRETTY_FUNCTION__, C99 __func__, __FUNCTION__. +// This represents the most expressive version available. +// Acts as if the following were declared: +// static const char OVR_CURRENT_FUNCTION[] = "function-name"; +// +// Example usage: +// void Test() { printf("%s", OVR_CURRENT_FUNCTION); } + +#if defined(OVR_CC_GNU) || defined(OVR_CC_CLANG) || (defined(__ICC) && (__ICC >= 600)) // GCC, clang, Intel + #define OVR_CURRENT_FUNCTION __PRETTY_FUNCTION__ +#elif defined(__FUNCSIG__) // VC++ + #define OVR_CURRENT_FUNCTION __FUNCSIG__ +#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901) // C99 compilers + #define OVR_CURRENT_FUNCTION __func__ +#else + #define OVR_CURRENT_FUNCTION __FUNCTION__ +#endif + + +//----------------------------------------------------------------------------------- +// ***** OVR_DEPRECATED / OVR_DEPRECATED_MSG +// +// Portably annotates a function or struct as deprecated. +// Note that clang supports __deprecated_enum_msg, which may be useful to support. +// +// Example usage: +// OVR_DEPRECATED void Test(); // Use on the function declaration, as opposed to definition. +// +// struct OVR_DEPRECATED Test{ ... }; +// +// OVR_DEPRECATED_MSG("Test is deprecated") +// void Test(); + +#if !defined(OVR_DEPRECATED) + #if defined(OVR_CC_MSVC) && (OVR_CC_VERSION > 1400) // VS2005+ + #define OVR_DEPRECATED __declspec(deprecated) + #define OVR_DEPRECATED_MSG(msg) __declspec(deprecated(msg)) + #elif defined(OVR_CC_CLANG) && OVR_CC_HAS_FEATURE(attribute_deprecated_with_message) + #define OVR_DEPRECATED __declspec(deprecated) + #define OVR_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) + #elif defined(OVR_CC_GNU) && (OVR_CC_VERSION >= 405) + #define OVR_DEPRECATED __declspec(deprecated) + #define OVR_DEPRECATED_MSG(msg) __attribute__((deprecated(msg))) + #elif !defined(OVR_CC_MSVC) + #define OVR_DEPRECATED __attribute__((deprecated)) + #define OVR_DEPRECATED_MSG(msg) __attribute__((deprecated)) + #else + #define OVR_DEPRECATED + #define OVR_DEPRECATED_MSG(msg) + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_SELECTANY +// +// Implements a wrapper for Microsoft's __declspec(selectany) +// +// Example usage: +// SomeFile.h: +// extern const OVR_SELECTANY float OVR_Pi = 3.14f; // Allows you to declare floating point constants in header files. +// +// Example usage: +// SomeStruct.h: +// struct Some { +// static const x = 37; // See below for definition, which is required by C++11: 9.4.2p3. +// }; +// +// SomeStruct.cpp: +// OVR_SELECTANY const int Some::x; // You need to use selectany here for static const member definitions because the VC++ linker requires it. Other linkers do not. +// + +#if !defined(OVR_SELECTANY) + #if defined(_MSC_VER) + #define OVR_SELECTANY __declspec(selectany) + #else + #define OVR_SELECTANY // selectany is similar to weak linking but not enough to attempt to use __attribute__((weak)) here. + #endif +#endif + + + +//----------------------------------------------------------------------------------- +// ***** OVR_UNUSED - Unused Argument handling +// Macro to quiet compiler warnings about unused parameters/variables. +// +// Example usage: +// void Test() { +// int x = SomeFunction(); +// OVR_UNUSED(x); +// } +// + +#if defined(OVR_CC_GNU) +# define OVR_UNUSED(a) do {__typeof__ (&a) __attribute__ ((unused)) __tmp = &a; } while(0) +#else +# define OVR_UNUSED(a) (a) +#endif + +#define OVR_UNUSED1(a1) OVR_UNUSED(a1) +#define OVR_UNUSED2(a1,a2) OVR_UNUSED(a1); OVR_UNUSED(a2) +#define OVR_UNUSED3(a1,a2,a3) OVR_UNUSED2(a1,a2); OVR_UNUSED(a3) +#define OVR_UNUSED4(a1,a2,a3,a4) OVR_UNUSED3(a1,a2,a3); OVR_UNUSED(a4) +#define OVR_UNUSED5(a1,a2,a3,a4,a5) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED(a5) +#define OVR_UNUSED6(a1,a2,a3,a4,a5,a6) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED2(a5,a6) +#define OVR_UNUSED7(a1,a2,a3,a4,a5,a6,a7) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED3(a5,a6,a7) +#define OVR_UNUSED8(a1,a2,a3,a4,a5,a6,a7,a8) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED4(a5,a6,a7,a8) +#define OVR_UNUSED9(a1,a2,a3,a4,a5,a6,a7,a8,a9) OVR_UNUSED4(a1,a2,a3,a4); OVR_UNUSED5(a5,a6,a7,a8,a9) + + +//----------------------------------------------------------------------------------- +// ***** Configuration Macros +// +// Expands to the current build type as a const char string literal. +// Acts as the following declaration: const char OVR_BUILD_STRING[]; + +#ifdef OVR_BUILD_DEBUG +# define OVR_BUILD_STRING "Debug" +#else +# define OVR_BUILD_STRING "Release" +#endif + + +//// Enables SF Debugging information +//# define OVR_BUILD_DEBUG + +// OVR_DEBUG_STATEMENT injects a statement only in debug builds. +// OVR_DEBUG_SELECT injects first argument in debug builds, second argument otherwise. +#ifdef OVR_BUILD_DEBUG +#define OVR_DEBUG_STATEMENT(s) s +#define OVR_DEBUG_SELECT(d, nd) d +#else +#define OVR_DEBUG_STATEMENT(s) +#define OVR_DEBUG_SELECT(d, nd) nd +#endif + + +#define OVR_ENABLE_THREADS +// +// Prevents OVR from defining new within +// type macros, so developers can override +// new using the #define new new(...) trick +// - used with OVR_DEFINE_NEW macro +//# define OVR_BUILD_DEFINE_NEW +// + + +//----------------------------------------------------------------------------------- +// ***** Find normal allocations +// +// Our allocations are all supposed to go through the OVR System Allocator, so that +// they can be run through a game's own preferred allocator. Occasionally we will +// accidentally introduce new code that doesn't adhere to this contract. And it +// then becomes difficult to track down these normal allocations. This piece of +// code makes it easy to check for normal allocations by asserting whenever they +// happen in our code. + +//#define OVR_FIND_NORMAL_ALLOCATIONS +#ifdef OVR_FIND_NORMAL_ALLOCATIONS + +inline void* operator new (size_t size, const char* filename, int line) +{ + void* ptr = new char[size]; + OVR_ASSERT(false); + return ptr; +} + +#define new new(__FILE__, __LINE__) + +#endif // OVR_FIND_NORMAL_ALLOCATIONS + + +#include "OVR_Nullptr.h" + + + + +#endif // OVR_Types_h diff --git a/LibOVRKernel/Src/Kernel/OVR_UTF8Util.cpp b/LibOVRKernel/Src/Kernel/OVR_UTF8Util.cpp new file mode 100644 index 0000000..68e58ea --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_UTF8Util.cpp @@ -0,0 +1,556 @@ +/************************************************************************** + +Filename : OVR_UTF8Util.cpp +Content : UTF8 Unicode character encoding/decoding support +Created : September 19, 2012 +Notes : +Notes : Much useful info at "UTF-8 and Unicode FAQ" + http://www.cl.cam.ac.uk/~mgk25/unicode.html + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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. + +************************************************************************************/ + +#include "OVR_UTF8Util.h" + +namespace OVR { namespace UTF8Util { + +intptr_t OVR_STDCALL GetLength(const char* buf, intptr_t buflen) +{ + const char* p = buf; + intptr_t length = 0; + + if (buflen != -1) + { + while (p - buf < buflen) + { + // We should be able to have ASStrings with 0 in the middle. + UTF8Util::DecodeNextChar_Advance0(&p); + length++; + } + } + else + { + while (UTF8Util::DecodeNextChar_Advance0(&p)) + length++; + } + + return length; +} + +uint32_t OVR_STDCALL GetCharAt(intptr_t index, const char* putf8str, intptr_t length) +{ + const char* buf = putf8str; + uint32_t c = 0; + + if (length != -1) + { + while (buf - putf8str < length) + { + c = UTF8Util::DecodeNextChar_Advance0(&buf); + if (index == 0) + return c; + index--; + } + + return c; + } + + do + { + c = UTF8Util::DecodeNextChar_Advance0(&buf); + index--; + + if (c == 0) + { + // We've hit the end of the string; don't go further. + OVR_ASSERT(index == 0); + return c; + } + } while (index >= 0); + + return c; +} + +intptr_t OVR_STDCALL GetByteIndex(intptr_t index, const char *putf8str, intptr_t length) +{ + const char* buf = putf8str; + + if (length != -1) + { + while ((buf - putf8str) < length && index > 0) + { + UTF8Util::DecodeNextChar_Advance0(&buf); + index--; + } + + return buf-putf8str; + } + + while (index > 0) + { + uint32_t c = UTF8Util::DecodeNextChar_Advance0(&buf); + index--; + + if (c == 0) + return buf-putf8str; + }; + + return buf-putf8str; +} + +int OVR_STDCALL GetEncodeCharSize(uint32_t ucs_character) +{ + if (ucs_character <= 0x7F) + return 1; + else if (ucs_character <= 0x7FF) + return 2; + else if (ucs_character <= 0xFFFF) + return 3; + else if (ucs_character <= 0x1FFFFF) + return 4; + else if (ucs_character <= 0x3FFFFFF) + return 5; + else if (ucs_character <= 0x7FFFFFFF) + return 6; + else + return 0; +} + +uint32_t OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer) +{ + uint32_t uc; + char c; + + // Security considerations: + // + // Changed, this is now only the case for DecodeNextChar: + // - If we hit a zero byte, we want to return 0 without stepping + // the buffer pointer past the 0. th + // + // If we hit an "overlong sequence"; i.e. a character encoded + // in a longer multibyte string than is necessary, then we + // need to discard the character. This is so attackers can't + // disguise dangerous characters or character sequences -- + // there is only one valid encoding for each character. + // + // If we decode characters { 0xD800 .. 0xDFFF } or { 0xFFFE, + // 0xFFFF } then we ignore them; they are not valid in UTF-8. + + // This isn't actually an invalid character; it's a valid char that + // looks like an inverted question mark. +#define INVALID_CHAR 0x0FFFD + +#define FIRST_BYTE(mask, shift) \ + uc = (c & (mask)) << (shift); + +#define NEXT_BYTE(shift) \ + c = **putf8Buffer; \ + if (c == 0) return 0; /* end of buffer, do not advance */ \ + if ((c & 0xC0) != 0x80) return INVALID_CHAR; /* standard check */ \ + (*putf8Buffer)++; \ + uc |= (c & 0x3F) << shift; + + c = **putf8Buffer; + (*putf8Buffer)++; + if (c == 0) + return 0; // End of buffer. + + if ((c & 0x80) == 0) return (uint32_t) c; // Conventional 7-bit ASCII. + + // Multi-byte sequences. + if ((c & 0xE0) == 0xC0) + { + // Two-byte sequence. + FIRST_BYTE(0x1F, 6); + NEXT_BYTE(0); + if (uc < 0x80) return INVALID_CHAR; // overlong + return uc; + } + else if ((c & 0xF0) == 0xE0) + { + // Three-byte sequence. + FIRST_BYTE(0x0F, 12); + NEXT_BYTE(6); + NEXT_BYTE(0); + if (uc < 0x800) return INVALID_CHAR; // overlong + // Not valid ISO 10646, but Flash requires these to work + // see AS3 test e15_5_3_2_3 for String.fromCharCode().charCodeAt(0) + // if (uc >= 0x0D800 && uc <= 0x0DFFF) return INVALID_CHAR; + // if (uc == 0x0FFFE || uc == 0x0FFFF) return INVALID_CHAR; // not valid ISO 10646 + return uc; + } + else if ((c & 0xF8) == 0xF0) + { + // Four-byte sequence. + FIRST_BYTE(0x07, 18); + NEXT_BYTE(12); + NEXT_BYTE(6); + NEXT_BYTE(0); + if (uc < 0x010000) return INVALID_CHAR; // overlong + return uc; + } + else if ((c & 0xFC) == 0xF8) + { + // Five-byte sequence. + FIRST_BYTE(0x03, 24); + NEXT_BYTE(18); + NEXT_BYTE(12); + NEXT_BYTE(6); + NEXT_BYTE(0); + if (uc < 0x0200000) return INVALID_CHAR; // overlong + return uc; + } + else if ((c & 0xFE) == 0xFC) + { + // Six-byte sequence. + FIRST_BYTE(0x01, 30); + NEXT_BYTE(24); + NEXT_BYTE(18); + NEXT_BYTE(12); + NEXT_BYTE(6); + NEXT_BYTE(0); + if (uc < 0x04000000) return INVALID_CHAR; // overlong + return uc; + } + else + { + // Invalid. + return INVALID_CHAR; + } +} + + +void OVR_STDCALL EncodeChar(char* pbuffer, intptr_t* pindex, uint32_t ucs_character) +{ + if (ucs_character <= 0x7F) + { + // Plain single-byte ASCII. + pbuffer[(*pindex)++] = (char) ucs_character; + } + else if (ucs_character <= 0x7FF) + { + // Two bytes. + pbuffer[(*pindex)++] = 0xC0 | (char)(ucs_character >> 6); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F); + } + else if (ucs_character <= 0xFFFF) + { + // Three bytes. + pbuffer[(*pindex)++] = 0xE0 | (char)(ucs_character >> 12); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F); + } + else if (ucs_character <= 0x1FFFFF) + { + // Four bytes. + pbuffer[(*pindex)++] = 0xF0 | (char)(ucs_character >> 18); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F); + } + else if (ucs_character <= 0x3FFFFFF) + { + // Five bytes. + pbuffer[(*pindex)++] = 0xF8 | (char)(ucs_character >> 24); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F); + } + else if (ucs_character <= 0x7FFFFFFF) + { + // Six bytes. + pbuffer[(*pindex)++] = 0xFC | (char)(ucs_character >> 30); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 24) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 18) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 12) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 6) & 0x3F); + pbuffer[(*pindex)++] = 0x80 | (char)((ucs_character >> 0) & 0x3F); + } + else + { + // Invalid char; don't encode anything. + } +} + +intptr_t OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, intptr_t length) +{ + intptr_t len = 0; + if (length != -1) + for (int i = 0; i < length; i++) + { + len += GetEncodeCharSize(pchar[i]); + } + else + for (int i = 0;; i++) + { + if (pchar[i] == 0) + return len; + len += GetEncodeCharSize(pchar[i]); + } + return len; +} + +void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, intptr_t length) +{ + intptr_t ofs = 0; + if (length != -1) + { + for (int i = 0; i < length; i++) + { + EncodeChar(pbuff, &ofs, pchar[i]); + } + } + else + { + for (int i = 0;; i++) + { + if (pchar[i] == 0) + break; + EncodeChar(pbuff, &ofs, pchar[i]); + } + } + pbuff[ofs] = 0; +} + +size_t OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, intptr_t bytesLen) +{ + wchar_t *pbegin = pbuff; + if (bytesLen == -1) + { + while (1) + { + uint32_t ch = DecodeNextChar_Advance0(&putf8str); + if (ch == 0) + break; + else if (ch >= 0xFFFF) + ch = 0xFFFD; + *pbuff++ = wchar_t(ch); + } + } + else + { + const char* p = putf8str; + while ((p - putf8str) < bytesLen) + { + uint32_t ch = DecodeNextChar_Advance0(&p); + if (ch >= 0xFFFF) + ch = 0xFFFD; + *pbuff++ = wchar_t(ch); + } + } + + *pbuff = 0; + return pbuff - pbegin; +} + + +#ifdef UTF8_UNIT_TEST + +// Compile this test case with something like: +// +// gcc utf8.cpp -g -I.. -DUTF8_UNIT_TEST -lstdc++ -o utf8_test +// +// or +// +// cl utf8.cpp -Zi -Od -DUTF8_UNIT_TEST -I.. +// +// If possible, try running the test program with the first arg +// pointing at the file: +// +// http://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt +// +// and examine the results by eye to make sure they are acceptable to +// you. + + +#include "base/utility.h" +#include <stdio.h> + + +bool check_equal(const char* utf8_in, const uint32_t* ucs_in) +{ + for (;;) + { + uint32_t next_ucs = *ucs_in++; + uint32_t next_ucs_from_utf8 = utf8::decode_next_unicode_character(&utf8_in); + if (next_ucs != next_ucs_from_utf8) + { + return false; + } + if (next_ucs == 0) + { + OVR_ASSERT(next_ucs_from_utf8 == 0); + break; + } + } + + return true; +} + + +void log_ascii(const char* line) +{ + for (;;) + { + unsigned char c = (unsigned char) *line++; + if (c == 0) + { + // End of line. + return; + } + else if (c != '\n' + && (c < 32 || c > 127)) + { + // Non-printable as plain ASCII. + printf("<0x%02X>", (int) c); + } + else + { + printf("%c", c); + } + } +} + + +void log_ucs(const uint32_t* line) +{ + for (;;) + { + uint32_t uc = *line++; + if (uc == 0) + { + // End of line. + return; + } + else if (uc != '\n' + && (uc < 32 || uc > 127)) + { + // Non-printable as plain ASCII. + printf("<U-%04X>", uc); + } + else + { + printf("%c", (char) uc); + } + } +} + + +// Simple canned test. +int main(int argc, const char* argv[]) +{ + { + const char* test8 = "Ignacio Castaño"; + const uint32_t test32[] = + { + 0x49, 0x67, 0x6E, 0x61, 0x63, + 0x69, 0x6F, 0x20, 0x43, 0x61, + 0x73, 0x74, 0x61, 0xF1, 0x6F, + 0x00 + }; + + OVR_ASSERT(check_equal(test8, test32)); + } + + // If user passed an arg, try reading the file as UTF-8 encoded text. + if (argc > 1) + { + const char* filename = argv[1]; + FILE* fp = fopen(filename, "rb"); + if (fp == NULL) + { + printf("Can't open file '%s'\n", filename); + return 1; + } + + // Read lines from the file, encode/decode them, and highlight discrepancies. + const int LINE_SIZE = 200; // max line size + char line_buffer_utf8[LINE_SIZE]; + char reencoded_utf8[6 * LINE_SIZE]; + uint32_t line_buffer_ucs[LINE_SIZE]; + + int byte_counter = 0; + for (;;) + { + int c = fgetc(fp); + if (c == EOF) + { + // Done. + break; + } + line_buffer_utf8[byte_counter++] = c; + if (c == '\n' || byte_counter >= LINE_SIZE - 2) + { + // End of line. Process the line. + line_buffer_utf8[byte_counter++] = 0; // terminate. + + // Decode into UCS. + const char* p = line_buffer_utf8; + uint32_t* q = line_buffer_ucs; + for (;;) + { + uint32_t uc = UTF8Util::DecodeNextChar(&p); + *q++ = uc; + + OVR_ASSERT(q < line_buffer_ucs + LINE_SIZE); + OVR_ASSERT(p < line_buffer_utf8 + LINE_SIZE); + + if (uc == 0) break; + } + + // Encode back into UTF-8. + q = line_buffer_ucs; + int index = 0; + for (;;) + { + uint32_t uc = *q++; + OVR_ASSERT(index < LINE_SIZE * 6 - 6); + int last_index = index; + UTF8Util::EncodeChar(reencoded_utf8, &index, uc); + OVR_ASSERT(index <= last_index + 6); + if (uc == 0) break; + } + + // This can be useful for debugging. +#if 0 + // Show the UCS and the re-encoded UTF-8. + log_ucs(line_buffer_ucs); + log_ascii(reencoded_utf8); +#endif // 0 + + OVR_ASSERT(check_equal(line_buffer_utf8, line_buffer_ucs)); + OVR_ASSERT(check_equal(reencoded_utf8, line_buffer_ucs)); + + // Start next line. + byte_counter = 0; + } + } + + fclose(fp); + } + + return 0; +} + + +#endif // UTF8_UNIT_TEST + +}} // namespace UTF8Util::OVR + diff --git a/LibOVRKernel/Src/Kernel/OVR_UTF8Util.h b/LibOVRKernel/Src/Kernel/OVR_UTF8Util.h new file mode 100644 index 0000000..3b640f0 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_UTF8Util.h @@ -0,0 +1,99 @@ +/************************************************************************************ + +PublicHeader: OVR_Kernel.h +Filename : OVR_UTF8Util.h +Content : UTF8 Unicode character encoding/decoding support +Created : September 19, 2012 +Notes : + +Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_UTF8Util_h +#define OVR_UTF8Util_h + +#include "OVR_Types.h" + +namespace OVR { namespace UTF8Util { + +//----------------------------------------------------------------------------------- + +// *** UTF8 string length and indexing. + +// Determines the length of UTF8 string in characters. +// If source length is specified (in bytes), null 0 character is counted properly. +intptr_t OVR_STDCALL GetLength(const char* putf8str, intptr_t length = -1); + +// Gets a decoded UTF8 character at index; you can access up to the index returned +// by GetLength. 0 will be returned for out of bounds access. +uint32_t OVR_STDCALL GetCharAt(intptr_t index, const char* putf8str, intptr_t length = -1); + +// Converts UTF8 character index into byte offset. +// -1 is returned if index was out of bounds. +intptr_t OVR_STDCALL GetByteIndex(intptr_t index, const char* putf8str, intptr_t length = -1); + + +// *** 16-bit Unicode string Encoding/Decoding routines. + +// Determines the number of bytes necessary to encode a string. +// Does not count the terminating 0 (null) character. +intptr_t OVR_STDCALL GetEncodeStringSize(const wchar_t* pchar, intptr_t length = -1); + +// Encodes a unicode (UCS-2 only) string into a buffer. The size of buffer must be at +// least GetEncodeStringSize() + 1. +void OVR_STDCALL EncodeString(char *pbuff, const wchar_t* pchar, intptr_t length = -1); + +// Decode UTF8 into a wchar_t buffer. Must have GetLength()+1 characters available. +// Characters over 0xFFFF are replaced with 0xFFFD. +// Returns the length of resulting string (number of characters) +size_t OVR_STDCALL DecodeString(wchar_t *pbuff, const char* putf8str, intptr_t bytesLen = -1); + + +// *** Individual character Encoding/Decoding. + +// Determined the number of bytes necessary to encode a UCS character. +int OVR_STDCALL GetEncodeCharSize(uint32_t ucsCharacter); + +// Encodes the given UCS character into the given UTF-8 buffer. +// Writes the data starting at buffer[offset], and +// increments offset by the number of bytes written. +// May write up to 6 bytes, so make sure there's room in the buffer +void OVR_STDCALL EncodeChar(char* pbuffer, intptr_t* poffset, uint32_t ucsCharacter); + +// Return the next Unicode character in the UTF-8 encoded buffer. +// Invalid UTF-8 sequences produce a U+FFFD character as output. +// Advances *utf8_buffer past the character returned. Pointer advance +// occurs even if the terminating 0 character is hit, since that allows +// strings with middle '\0' characters to be supported. +uint32_t OVR_STDCALL DecodeNextChar_Advance0(const char** putf8Buffer); + +// Safer version of DecodeNextChar, which doesn't advance pointer if +// null character is hit. +inline uint32_t DecodeNextChar(const char** putf8Buffer) +{ + uint32_t ch = DecodeNextChar_Advance0(putf8Buffer); + if (ch == 0) + (*putf8Buffer)--; + return ch; +} + + +}} // OVR::UTF8Util + +#endif diff --git a/LibOVRKernel/Src/Kernel/OVR_Win32_IncludeWindows.h b/LibOVRKernel/Src/Kernel/OVR_Win32_IncludeWindows.h new file mode 100644 index 0000000..dc4c416 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_Win32_IncludeWindows.h @@ -0,0 +1,223 @@ +/************************************************************************************ + +Filename : OVR_Win32_IncludeWindows.h +Content : Small helper header to include Windows.h properly +Created : Oct 16, 2014 +Authors : Chris Taylor, Scott Bassett + +Copyright : Copyright 2014 Oculus, Inc. All Rights reserved. + +Licensed under the Oculus VR Rift SDK License Version 3.2 (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.2 + +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_Win32_IncludeWindows_h +#define OVR_Win32_IncludeWindows_h + +#include "OVR_Types.h" + +// Automatically avoid including the Windows header on non-Windows platforms. +#ifdef OVR_OS_MS + +// It is common practice to define WIN32_LEAN_AND_MEAN to reduce compile times. +// However this then requires us to define our own NTSTATUS data type and other +// irritations throughout our code-base. +//#define WIN32_LEAN_AND_MEAN + +// Prevents <Windows.h> from #including <Winsock.h>, as we use <Winsock2.h> instead. +#ifndef _WINSOCKAPI_ +#define _WINSOCKAPI_ +#endif + +// Prevents <Windows.h> from defining min() and max() macro symbols. +#ifndef NOMINMAX +#define NOMINMAX +#endif + +// We support Windows Windows 7 or newer. +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0601 /* Windows 7+ */ +#endif + +#include <Windows.h> + +namespace OVR { + + +//----------------------------------------------------------------------------- +// ScopedHANDLE +// +// MSVC 2010, and MSVC 2012 do not support the <wrl.h> utility header. +// So we provide our own version of HandleRAII, which is an incredibly +// useful pattern for working with Windows HANDLE values. +// +// HANDLEs have two invalid values in Windows, either nullptr or +// INVALID_HANDLE_VALUE. The invalid value that is correct for the usage must +// be provided as the template argument. + +struct ScopedHANDLE_NullTraits +{ + // We cannot make this a static member variable as it is not an integral type. + inline static HANDLE InvalidValue() + { + return nullptr; + } +}; +struct ScopedHANDLE_InvalidTraits +{ + inline static HANDLE InvalidValue() + { + return INVALID_HANDLE_VALUE; + } +}; + +template<typename Traits> +class ScopedHANDLE +{ + HANDLE hAttachedHandle; + +public: + ScopedHANDLE(HANDLE handle) : + hAttachedHandle(handle) + { + } + ScopedHANDLE() + { + hAttachedHandle = Traits::InvalidValue(); + } + ScopedHANDLE& operator=(HANDLE handle) + { + Close(); + hAttachedHandle = handle; + return *this; + } + ~ScopedHANDLE() + { + Close(); + } + + bool IsValid() + { + return hAttachedHandle != Traits::InvalidValue(); + } + HANDLE Get() + { + return hAttachedHandle; + } + HANDLE& GetRawRef() + { + return hAttachedHandle; + } + void Attach(HANDLE handle) + { + Close(); + hAttachedHandle = handle; + } + void Detach() + { + // Do not close handle + hAttachedHandle = Traits::InvalidValue(); + } + bool Close() + { + bool success = true; + if (hAttachedHandle != Traits::InvalidValue()) + { + if (::CloseHandle(hAttachedHandle) != TRUE) + { + success = false; + } + hAttachedHandle = Traits::InvalidValue(); + } + return success; + } +}; + +// Different Windows API functions have different invalid values. +// These types are provided to improve readability. +typedef ScopedHANDLE < ScopedHANDLE_NullTraits > ScopedEventHANDLE; +typedef ScopedHANDLE < ScopedHANDLE_InvalidTraits > ScopedFileHANDLE; +typedef ScopedHANDLE < ScopedHANDLE_NullTraits > ScopedProcessHANDLE; + +// Scoped registry keys +class ScopedHKEY +{ + HKEY hAttachedHandle; + +public: + ScopedHKEY(HKEY handle) : + hAttachedHandle(handle) + { + } + ScopedHKEY() + { + hAttachedHandle = nullptr; + } + ScopedHKEY& operator=(HKEY handle) + { + Close(); + hAttachedHandle = handle; + return *this; + } + ~ScopedHKEY() + { + Close(); + } + + bool IsValid() + { + return hAttachedHandle != nullptr; + } + HKEY Get() + { + return hAttachedHandle; + } + HKEY& GetRawRef() + { + return hAttachedHandle; + } + void Attach(HKEY handle) + { + Close(); + hAttachedHandle = handle; + } + void Detach() + { + // Do not close handle + hAttachedHandle = nullptr; + } + bool Close() + { + bool success = true; + if (hAttachedHandle != nullptr) + { + if (::RegCloseKey(hAttachedHandle) == ERROR_SUCCESS) + { + success = false; + } + hAttachedHandle = nullptr; + } + return success; + } +}; + + +} // namespace OVR + + +#endif // OVR_OS_WIN32 + +#endif // OVR_Win32_IncludeWindows_h diff --git a/LibOVRKernel/Src/Kernel/OVR_mach_exc_OSX.c b/LibOVRKernel/Src/Kernel/OVR_mach_exc_OSX.c new file mode 100644 index 0000000..59b9345 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_mach_exc_OSX.c @@ -0,0 +1,2961 @@ +/* This file was generated by the MIG utility with: + mig /usr/include/mach/mach_exc.defs + We pre-generate them instead of generate them at compile-time because we + need to rename some of the functions to append _OVR so we don't get conflicts + with any other versions of these functions the application may have. +*/ + +/* Begin mach_excUser.c */ + +#if defined(__APPLE__) + +#define __MIG_check__Reply__mach_exc_subsystem__ 1 +#define __NDR_convert__Reply__mach_exc_subsystem__ 1 +#define __NDR_convert__mig_reply_error_subsystem__ 1 + +#include "OVR_mach_exc_OSX.h" + +#if defined(__cplusplus) + extern "C" { +#endif + +#ifndef mig_internal +#define mig_internal static __inline__ +#endif /* mig_internal */ + +#ifndef mig_external +#define mig_external +#endif /* mig_external */ + +#if !defined(__MigTypeCheck) && defined(TypeCheck) +#define __MigTypeCheck TypeCheck /* Legacy setting */ +#endif /* !defined(__MigTypeCheck) */ + +#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_) +#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */ +#endif /* !defined(__MigKernelSpecificCode) */ + +#ifndef LimitCheck +#define LimitCheck 0 +#endif /* LimitCheck */ + +#ifndef min +#define min(a,b) ( ((a) < (b))? (a): (b) ) +#endif /* min */ + +#if !defined(_WALIGN_) +#define _WALIGN_(x) (((x) + 3) & ~3) +#endif /* !defined(_WALIGN_) */ + +#if !defined(_WALIGNSZ_) +#define _WALIGNSZ_(x) _WALIGN_(sizeof(x)) +#endif /* !defined(_WALIGNSZ_) */ + +#ifndef UseStaticTemplates +#define UseStaticTemplates 0 +#endif /* UseStaticTemplates */ + +#ifndef __MachMsgErrorWithTimeout +#define __MachMsgErrorWithTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + case MACH_SEND_TIMED_OUT: \ + case MACH_RCV_TIMED_OUT: \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithTimeout */ + +#ifndef __MachMsgErrorWithoutTimeout +#define __MachMsgErrorWithoutTimeout(_R_) { \ + switch (_R_) { \ + case MACH_SEND_INVALID_DATA: \ + case MACH_SEND_INVALID_DEST: \ + case MACH_SEND_INVALID_HEADER: \ + mig_put_reply_port(InP->Head.msgh_reply_port); \ + break; \ + default: \ + mig_dealloc_reply_port(InP->Head.msgh_reply_port); \ + } \ +} +#endif /* __MachMsgErrorWithoutTimeout */ + +#ifndef __DeclareSendRpc +#define __DeclareSendRpc(_NUM_, _NAME_) +#endif /* __DeclareSendRpc */ + +#ifndef __BeforeSendRpc +#define __BeforeSendRpc(_NUM_, _NAME_) +#endif /* __BeforeSendRpc */ + +#ifndef __AfterSendRpc +#define __AfterSendRpc(_NUM_, _NAME_) +#endif /* __AfterSendRpc */ + +#ifndef __DeclareSendSimple +#define __DeclareSendSimple(_NUM_, _NAME_) +#endif /* __DeclareSendSimple */ + +#ifndef __BeforeSendSimple +#define __BeforeSendSimple(_NUM_, _NAME_) +#endif /* __BeforeSendSimple */ + +#ifndef __AfterSendSimple +#define __AfterSendSimple(_NUM_, _NAME_) +#endif /* __AfterSendSimple */ + +#ifndef msgh_request_port + #define msgh_request_port msgh_remote_port +#endif + +#ifndef msgh_reply_port + #define msgh_reply_port msgh_local_port +#endif + + +#if ( __MigTypeCheck || __NDR_convert__ ) +#if __MIG_check__Reply__mach_exc_subsystem__ +#if !defined(__MIG_check__Reply__mach_exception_raise_t__defined) +#define __MIG_check__Reply__mach_exception_raise_t__defined +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode__defined +#if defined(__NDR_convert__int_rep__mach_exc__kern_return_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode(a, f) \ + __NDR_convert__int_rep__mach_exc__kern_return_t((kern_return_t *)(a), f) +#elif defined(__NDR_convert__int_rep__kern_return_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode(a, f) \ + __NDR_convert__int_rep__kern_return_t((kern_return_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode__defined */ + + + + + +mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_t_OVR(__Reply__mach_exception_raise_t *Out0P) +{ + + typedef __Reply__mach_exception_raise_t __Reply; + if (Out0P->Head.msgh_id != 2505) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + + #if __MigTypeCheck + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply))) + { return MIG_TYPE_ERROR ; } + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode__defined) + if (Out0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode(&Out0P->RetCode, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_t__RetCode__defined */ + { + return Out0P->RetCode; + } +} +#endif /* !defined(__MIG_check__Reply__mach_exception_raise_t__defined) */ +#endif /* __MIG_check__Reply__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck || __NDR_convert__ ) */ + + +/* Routine mach_exception_raise_OVR */ +mig_external kern_return_t mach_exception_raise_OVR +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt +) +{ + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } Request; + #ifdef __MigPackStructs + #pragma pack() + #endif + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + mach_msg_trailer_t trailer; + } Reply; + #ifdef __MigPackStructs + #pragma pack() + #endif + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply; + #ifdef __MigPackStructs + #pragma pack() + #endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + + #ifdef __MIG_check__Reply__mach_exception_raise_t__defined + kern_return_t check_result; + #endif /* __MIG_check__Reply__mach_exception_raise_t__defined */ + + __DeclareSendRpc(2405, "mach_exception_raise_OVR") + + #if UseStaticTemplates + const static mach_msg_port_descriptor_t threadTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; + #endif /* UseStaticTemplates */ + + #if UseStaticTemplates + const static mach_msg_port_descriptor_t taskTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; + #endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 2; + #if UseStaticTemplates + InP->thread = threadTemplate; + InP->thread.name = thread; + #else /* UseStaticTemplates */ + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; + #endif /* UseStaticTemplates */ + + #if UseStaticTemplates + InP->task = taskTemplate; + InP->task.name = task; + #else /* UseStaticTemplates */ + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; + #endif /* UseStaticTemplates */ + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size = (mach_msg_size_t)(sizeof(Request) - 16) + ((8 * codeCnt)); + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2405; + + __BeforeSendRpc(2405, "mach_exception_raise_OVR") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2405, "mach_exception_raise_OVR") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + + #if defined(__MIG_check__Reply__mach_exception_raise_t__defined) + check_result = __MIG_check__Reply__mach_exception_raise_t_OVR((__Reply__mach_exception_raise_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } + #endif /* defined(__MIG_check__Reply__mach_exception_raise_t__defined) */ + + return KERN_SUCCESS; +} + +#if ( __MigTypeCheck || __NDR_convert__ ) +#if __MIG_check__Reply__mach_exc_subsystem__ +#if !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) +#define __MIG_check__Reply__mach_exception_raise_state_t__defined +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined +#if defined(__NDR_convert__int_rep__mach_exc__kern_return_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode(a, f) \ + __NDR_convert__int_rep__mach_exc__kern_return_t((kern_return_t *)(a), f) +#elif defined(__NDR_convert__int_rep__kern_return_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode(a, f) \ + __NDR_convert__int_rep__kern_return_t((kern_return_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined */ + + +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined +#if defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined */ + + +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#if defined(__NDR_convert__int_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__int_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__thread_state_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__int_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__natural_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__int_rep__natural_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__natural_t) +#elif defined(__NDR_convert__int_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__int_rep__uint32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined */ + + +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined */ + + + +#ifndef __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined +#if defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined */ + + +#ifndef __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#if defined(__NDR_convert__char_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__char_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__thread_state_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__char_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__natural_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__char_rep__natural_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__natural_t) +#elif defined(__NDR_convert__char_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__char_rep__uint32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined */ + + + + +#ifndef __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined +#if defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined */ + + +#ifndef __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#if defined(__NDR_convert__float_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__float_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__thread_state_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__float_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__natural_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__float_rep__natural_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__natural_t) +#elif defined(__NDR_convert__float_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__float_rep__uint32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined */ + + + + +mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_t_OVR(__Reply__mach_exception_raise_state_t *Out0P) +{ + + typedef __Reply__mach_exception_raise_state_t __Reply; + #if __MigTypeCheck + unsigned int msgh_size; + #endif /* __MigTypeCheck */ + + if (Out0P->Head.msgh_id != 2506) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + + #if __MigTypeCheck + msgh_size = Out0P->Head.msgh_size; + + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 576)) && + (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) || + Out0P->RetCode == KERN_SUCCESS))) + { return MIG_TYPE_ERROR ; } + #endif /* __MigTypeCheck */ + + if (Out0P->RetCode != KERN_SUCCESS) { + #ifdef __NDR_convert__mig_reply_error_t__defined + __NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P); + #endif /* __NDR_convert__mig_reply_error_t__defined */ + return ((mig_reply_error_t *)Out0P)->RetCode; + } + + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined) + if (Out0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt(&Out0P->new_stateCnt, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined */ + #if __MigTypeCheck + if ( Out0P->new_stateCnt > 144 ) + return MIG_TYPE_ERROR; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 576)) / 4 != Out0P->new_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 576) + Out0P->new_stateCnt * 4)) + { return MIG_TYPE_ERROR ; } + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined) || \ + defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined) || \ + defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined) || \ + defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_stateCnt__defined) + if (Out0P->NDR.int_rep != NDR_record.int_rep) { + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode(&Out0P->RetCode, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__RetCode__defined */ + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor(&Out0P->flavor, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__flavor__defined */ + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state(&Out0P->new_state, Out0P->NDR.int_rep, Out0P->new_stateCnt); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_t__new_state__defined */ + } + #endif /* defined(__NDR_convert__int_rep...) */ + + #if 0 || \ + defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined) || \ + defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined) || \ + 0 + if (Out0P->NDR.char_rep != NDR_record.char_rep) { + #if defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined) + __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor(&Out0P->flavor, Out0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__flavor__defined */ + #if defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined) + __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state(&Out0P->new_state, Out0P->NDR.char_rep, Out0P->new_stateCnt); + #endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_t__new_state__defined */ + } + #endif /* defined(__NDR_convert__char_rep...) */ + + #if 0 || \ + defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined) || \ + defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined) || \ + 0 + if (Out0P->NDR.float_rep != NDR_record.float_rep) { + #if defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined) + __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor(&Out0P->flavor, Out0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__flavor__defined */ + #if defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined) + __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state(&Out0P->new_state, Out0P->NDR.float_rep, Out0P->new_stateCnt); + #endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_t__new_state__defined */ + } + #endif /* defined(__NDR_convert__float_rep...) */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */ +#endif /* __MIG_check__Reply__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck || __NDR_convert__ ) */ + + +/* Routine mach_exception_raise_state_OVR */ +mig_external kern_return_t mach_exception_raise_state_OVR +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +) +{ + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + } Request; + #ifdef __MigPackStructs + #pragma pack() + #endif + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + mach_msg_trailer_t trailer; + } Reply; + #ifdef __MigPackStructs + #pragma pack() + #endif + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + } __Reply; + #ifdef __MigPackStructs + #pragma pack() + #endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + + #ifdef __MIG_check__Reply__mach_exception_raise_state_t__defined + kern_return_t check_result; + #endif /* __MIG_check__Reply__mach_exception_raise_state_t__defined */ + + __DeclareSendRpc(2406, "mach_exception_raise_state_OVR") + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size_delta = (8 * codeCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 592) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16); + + InP->flavor = *flavor; + + if (old_stateCnt > 144) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); + + InP->old_stateCnt = old_stateCnt; + + msgh_size += (4 * old_stateCnt); + InP = &Mess.In; + InP->Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2406; + + __BeforeSendRpc(2406, "mach_exception_raise_state_OVR") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2406, "mach_exception_raise_state_OVR") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + + #if defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) + check_result = __MIG_check__Reply__mach_exception_raise_state_t_OVR((__Reply__mach_exception_raise_state_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } + #endif /* defined(__MIG_check__Reply__mach_exception_raise_state_t__defined) */ + + *flavor = Out0P->flavor; + + if (Out0P->new_stateCnt > 144) { + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 144); + *new_stateCnt = Out0P->new_stateCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); + + *new_stateCnt = Out0P->new_stateCnt; + + return KERN_SUCCESS; +} + +#if ( __MigTypeCheck || __NDR_convert__ ) +#if __MIG_check__Reply__mach_exc_subsystem__ +#if !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) +#define __MIG_check__Reply__mach_exception_raise_state_identity_t__defined +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined +#if defined(__NDR_convert__int_rep__mach_exc__kern_return_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode(a, f) \ + __NDR_convert__int_rep__mach_exc__kern_return_t((kern_return_t *)(a), f) +#elif defined(__NDR_convert__int_rep__kern_return_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode(a, f) \ + __NDR_convert__int_rep__kern_return_t((kern_return_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined */ + + +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#if defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined */ + + +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#if defined(__NDR_convert__int_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__int_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__thread_state_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__int_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__natural_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__int_rep__natural_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__natural_t) +#elif defined(__NDR_convert__int_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__int_rep__uint32_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined */ + + +#ifndef __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined +#define __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined */ + + + +#ifndef __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#if defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined */ + + +#ifndef __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#if defined(__NDR_convert__char_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__char_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__thread_state_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__char_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__natural_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__char_rep__natural_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__natural_t) +#elif defined(__NDR_convert__char_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__char_rep__uint32_t__defined) +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined */ + + + + +#ifndef __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#if defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined */ + + +#ifndef __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#if defined(__NDR_convert__float_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__float_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__thread_state_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__float_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__natural_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__float_rep__natural_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__natural_t) +#elif defined(__NDR_convert__float_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__float_rep__uint32_t__defined) +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined +#define __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined */ + + + + +mig_internal kern_return_t __MIG_check__Reply__mach_exception_raise_state_identity_t(__Reply__mach_exception_raise_state_identity_t *Out0P) +{ + + typedef __Reply__mach_exception_raise_state_identity_t __Reply; + #if __MigTypeCheck + unsigned int msgh_size; + #endif /* __MigTypeCheck */ + + if (Out0P->Head.msgh_id != 2507) { + if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE) + { return MIG_SERVER_DIED; } + else + { return MIG_REPLY_MISMATCH; } + } + + #if __MigTypeCheck + msgh_size = Out0P->Head.msgh_size; + + if ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < (mach_msg_size_t)(sizeof(__Reply) - 576)) && + (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) || + Out0P->RetCode == KERN_SUCCESS))) + { return MIG_TYPE_ERROR ; } + #endif /* __MigTypeCheck */ + + if (Out0P->RetCode != KERN_SUCCESS) { + #ifdef __NDR_convert__mig_reply_error_t__defined + __NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P); + #endif /* __NDR_convert__mig_reply_error_t__defined */ + return ((mig_reply_error_t *)Out0P)->RetCode; + } + + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined) + if (Out0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt(&Out0P->new_stateCnt, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined */ + #if __MigTypeCheck + if ( Out0P->new_stateCnt > 144 ) + return MIG_TYPE_ERROR; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Reply) - 576)) / 4 != Out0P->new_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Reply) - 576) + Out0P->new_stateCnt * 4)) + { return MIG_TYPE_ERROR ; } + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined) || \ + defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined) || \ + defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined) || \ + defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_stateCnt__defined) + if (Out0P->NDR.int_rep != NDR_record.int_rep) { + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode(&Out0P->RetCode, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__RetCode__defined */ + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor(&Out0P->flavor, Out0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined */ + #if defined(__NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined) + __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state(&Out0P->new_state, Out0P->NDR.int_rep, Out0P->new_stateCnt); + #endif /* __NDR_convert__int_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined */ + } + #endif /* defined(__NDR_convert__int_rep...) */ + + #if 0 || \ + defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined) || \ + defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined) || \ + 0 + if (Out0P->NDR.char_rep != NDR_record.char_rep) { + #if defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined) + __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor(&Out0P->flavor, Out0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined */ + #if defined(__NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined) + __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state(&Out0P->new_state, Out0P->NDR.char_rep, Out0P->new_stateCnt); + #endif /* __NDR_convert__char_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined */ + } + #endif /* defined(__NDR_convert__char_rep...) */ + + #if 0 || \ + defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined) || \ + defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined) || \ + 0 + if (Out0P->NDR.float_rep != NDR_record.float_rep) { + #if defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined) + __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor(&Out0P->flavor, Out0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__flavor__defined */ + #if defined(__NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined) + __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state(&Out0P->new_state, Out0P->NDR.float_rep, Out0P->new_stateCnt); + #endif /* __NDR_convert__float_rep__Reply__mach_exception_raise_state_identity_t__new_state__defined */ + } + #endif /* defined(__NDR_convert__float_rep...) */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */ +#endif /* __MIG_check__Reply__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck || __NDR_convert__ ) */ + + +/* Routine mach_exception_raise_state_identity_OVR */ +mig_external kern_return_t mach_exception_raise_state_identity_OVR +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +) +{ + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + } Request; + #ifdef __MigPackStructs + #pragma pack() + #endif + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + mach_msg_trailer_t trailer; + } Reply; + #ifdef __MigPackStructs + #pragma pack() + #endif + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + } __Reply; + #ifdef __MigPackStructs + #pragma pack() + #endif + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + union { + Request In; + Reply Out; + } Mess; + + Request *InP = &Mess.In; + Reply *Out0P = &Mess.Out; + + mach_msg_return_t msg_result; + unsigned int msgh_size; + unsigned int msgh_size_delta; + + + #ifdef __MIG_check__Reply__mach_exception_raise_state_identity_t__defined + kern_return_t check_result; + #endif /* __MIG_check__Reply__mach_exception_raise_state_identity_t__defined */ + + __DeclareSendRpc(2407, "mach_exception_raise_state_identity_OVR") + + #if UseStaticTemplates + const static mach_msg_port_descriptor_t threadTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; + #endif /* UseStaticTemplates */ + + #if UseStaticTemplates + const static mach_msg_port_descriptor_t taskTemplate = { + /* name = */ MACH_PORT_NULL, + /* pad1 = */ 0, + /* pad2 = */ 0, + /* disp = */ 19, + /* type = */ MACH_MSG_PORT_DESCRIPTOR, + }; + #endif /* UseStaticTemplates */ + + InP->msgh_body.msgh_descriptor_count = 2; + #if UseStaticTemplates + InP->thread = threadTemplate; + InP->thread.name = thread; + #else /* UseStaticTemplates */ + InP->thread.name = thread; + InP->thread.disposition = 19; + InP->thread.type = MACH_MSG_PORT_DESCRIPTOR; + #endif /* UseStaticTemplates */ + + #if UseStaticTemplates + InP->task = taskTemplate; + InP->task.name = task; + #else /* UseStaticTemplates */ + InP->task.name = task; + InP->task.disposition = 19; + InP->task.type = MACH_MSG_PORT_DESCRIPTOR; + #endif /* UseStaticTemplates */ + + InP->NDR = NDR_record; + + InP->exception = exception; + + if (codeCnt > 2) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->code, (const char *) code, 8 * codeCnt); + + InP->codeCnt = codeCnt; + + msgh_size_delta = (8 * codeCnt); + msgh_size = (mach_msg_size_t)(sizeof(Request) - 592) + msgh_size_delta; + InP = (Request *) ((pointer_t) InP + msgh_size_delta - 16); + + InP->flavor = *flavor; + + if (old_stateCnt > 144) { + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) InP->old_state, (const char *) old_state, 4 * old_stateCnt); + + InP->old_stateCnt = old_stateCnt; + + msgh_size += (4 * old_stateCnt); + InP = &Mess.In; + InP->Head.msgh_bits = MACH_MSGH_BITS_COMPLEX| + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + InP->Head.msgh_request_port = exception_port; + InP->Head.msgh_reply_port = mig_get_reply_port(); + InP->Head.msgh_id = 2407; + + __BeforeSendRpc(2407, "mach_exception_raise_state_identity_OVR") + msg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_MSG_OPTION_NONE, msgh_size, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + __AfterSendRpc(2407, "mach_exception_raise_state_identity_OVR") + if (msg_result != MACH_MSG_SUCCESS) { + __MachMsgErrorWithoutTimeout(msg_result); + { return msg_result; } + } + + + #if defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) + check_result = __MIG_check__Reply__mach_exception_raise_state_identity_t((__Reply__mach_exception_raise_state_identity_t *)Out0P); + if (check_result != MACH_MSG_SUCCESS) + { return check_result; } + #endif /* defined(__MIG_check__Reply__mach_exception_raise_state_identity_t__defined) */ + + *flavor = Out0P->flavor; + + if (Out0P->new_stateCnt > 144) { + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * 144); + *new_stateCnt = Out0P->new_stateCnt; + { return MIG_ARRAY_TOO_LARGE; } + } + (void)memcpy((char *) new_state, (const char *) Out0P->new_state, 4 * Out0P->new_stateCnt); + + *new_stateCnt = Out0P->new_stateCnt; + + return KERN_SUCCESS; +} + +#if defined(__cplusplus) + } /* extern "C" */ +#endif + +/* End mach_excUser.c */ + + + + +/* Begin mach_excServer.c */ + +/* Module mach_exc */ + +#define __MIG_check__Request__mach_exc_subsystem__ 1 +#define __NDR_convert__Request__mach_exc_subsystem__ 1 + +#include <string.h> +#include <mach/ndr.h> +#include <mach/boolean.h> +#include <mach/kern_return.h> +#include <mach/notify.h> +#include <mach/mach_types.h> +#include <mach/message.h> +#include <mach/mig_errors.h> +#include <mach/port.h> + +#include <mach/std_types.h> +#include <mach/mig.h> +#include <mach/mig.h> +#include <mach/mach_types.h> + +#if defined(__cplusplus) + extern "C" { +#endif + +#ifndef mig_internal +#define mig_internal static __inline__ +#endif /* mig_internal */ + +#ifndef mig_external +#define mig_external +#endif /* mig_external */ + +#if !defined(__MigTypeCheck) && defined(TypeCheck) +#define __MigTypeCheck TypeCheck /* Legacy setting */ +#endif /* !defined(__MigTypeCheck) */ + +#if !defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_) +#define __MigKernelSpecificCode _MIG_KERNEL_SPECIFIC_CODE_ /* Legacy setting */ +#endif /* !defined(__MigKernelSpecificCode) */ + +#ifndef LimitCheck +#define LimitCheck 0 +#endif /* LimitCheck */ + +#ifndef min +#define min(a,b) ( ((a) < (b))? (a): (b) ) +#endif /* min */ + +#if !defined(_WALIGN_) +#define _WALIGN_(x) (((x) + 3) & ~3) +#endif /* !defined(_WALIGN_) */ + +#if !defined(_WALIGNSZ_) +#define _WALIGNSZ_(x) _WALIGN_(sizeof(x)) +#endif /* !defined(_WALIGNSZ_) */ + +#ifndef UseStaticTemplates +#define UseStaticTemplates 0 +#endif /* UseStaticTemplates */ + +#ifndef __DeclareRcvRpc +#define __DeclareRcvRpc(_NUM_, _NAME_) +#endif /* __DeclareRcvRpc */ + +#ifndef __BeforeRcvRpc +#define __BeforeRcvRpc(_NUM_, _NAME_) +#endif /* __BeforeRcvRpc */ + +#ifndef __AfterRcvRpc +#define __AfterRcvRpc(_NUM_, _NAME_) +#endif /* __AfterRcvRpc */ + +#ifndef __DeclareRcvSimple +#define __DeclareRcvSimple(_NUM_, _NAME_) +#endif /* __DeclareRcvSimple */ + +#ifndef __BeforeRcvSimple +#define __BeforeRcvSimple(_NUM_, _NAME_) +#endif /* __BeforeRcvSimple */ + +#ifndef __AfterRcvSimple +#define __AfterRcvSimple(_NUM_, _NAME_) +#endif /* __AfterRcvSimple */ + +#define novalue void + +#ifndef msgh_request_port + #define msgh_request_port msgh_local_port +#endif +#define MACH_MSGH_BITS_REQUEST(bits) MACH_MSGH_BITS_LOCAL(bits) +#ifndef msgh_reply_port + #define msgh_reply_port msgh_remote_port +#endif +#define MACH_MSGH_BITS_REPLY(bits) MACH_MSGH_BITS_REMOTE(bits) + +#define MIG_RETURN_ERROR(X, code) {\ + ((mig_reply_error_t *)X)->RetCode = code;\ + ((mig_reply_error_t *)X)->NDR = NDR_record;\ + return;\ + } + +/* typedefs for all requests */ + +#ifndef __Request__mach_exc_subsystem__defined +#define __Request__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } __Request__mach_exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + } __Request__mach_exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + } __Request__mach_exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Request__mach_exc_subsystem__defined */ + +/* typedefs for all replies */ + +#ifndef __Reply__mach_exc_subsystem__defined +#define __Reply__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__mach_exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + } __Reply__mach_exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + } __Reply__mach_exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Reply__mach_exc_subsystem__defined */ + + +/* union of all replies */ + +#ifndef __ReplyUnion__catch_mach_exc_subsystem__defined +#define __ReplyUnion__catch_mach_exc_subsystem__defined +union __ReplyUnion__catch_mach_exc_subsystem { + __Reply__mach_exception_raise_t Reply_mach_exception_raise; + __Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state; + __Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity; +}; +#endif /* __RequestUnion__catch_mach_exc_subsystem__defined */ +/* Forward Declarations */ + + +mig_internal novalue _Xmach_exception_raise_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + +mig_internal novalue _Xmach_exception_raise_state_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + +mig_internal novalue _Xmach_exception_raise_state_identity_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + + +#if ( __MigTypeCheck || __NDR_convert__ ) +#if __MIG_check__Request__mach_exc_subsystem__ +#if !defined(__MIG_check__Request__mach_exception_raise_t__defined) +#define __MIG_check__Request__mach_exception_raise_t__defined +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#if defined(__NDR_convert__int_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__int_rep__exception_type_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__int_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__int_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exception_data_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__int_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__int64_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__int_rep__int64_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__int_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#if defined(__NDR_convert__char_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__char_rep__exception_type_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__char_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined +#if defined(__NDR_convert__char_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__char_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exception_data_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__char_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__int64_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__char_rep__int64_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__char_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#if defined(__NDR_convert__float_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__float_rep__exception_type_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__float_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined +#if defined(__NDR_convert__float_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__float_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exception_data_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__float_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__int64_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__float_rep__int64_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__float_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined */ + + +mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_t_OVR(__attribute__((__unused__)) __Request__mach_exception_raise_t *In0P) +{ + const size_t sizeofRequest = sizeof(__Request__mach_exception_raise_t); + + typedef __Request__mach_exception_raise_t __Request; + #if __MigTypeCheck + unsigned int msgh_size; + #endif /* __MigTypeCheck */ + + #if __MigTypeCheck + msgh_size = In0P->Head.msgh_size; + if (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (In0P->msgh_body.msgh_descriptor_count != 2) || + (msgh_size < (mach_msg_size_t)(sizeofRequest - 16)) || (msgh_size > (mach_msg_size_t)sizeofRequest)) + return MIG_BAD_ARGUMENTS; + #endif /* __MigTypeCheck */ + + #if __MigTypeCheck + if (In0P->thread.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->thread.disposition != 17) + return MIG_TYPE_ERROR; + #endif /* __MigTypeCheck */ + + #if __MigTypeCheck + if (In0P->task.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->task.disposition != 17) + return MIG_TYPE_ERROR; + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined */ + #if __MigTypeCheck + if ( In0P->codeCnt > 2 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeofRequest - 16)) / 8 != In0P->codeCnt) || + (msgh_size != (mach_msg_size_t)(sizeofRequest - 16) + (8 * In0P->codeCnt))) + return MIG_BAD_ARGUMENTS; + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) { + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_t__exception(&In0P->exception, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__exception__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_t__code(&In0P->code, In0P->NDR.int_rep, In0P->codeCnt); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_t__code__defined */ + } + #endif /* defined(__NDR_convert__int_rep...) */ + + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined) || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined) || \ + 0 + if (In0P->NDR.char_rep != NDR_record.char_rep) { + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_t__exception(&In0P->exception, In0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_t__exception__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_t__code(&In0P->code, In0P->NDR.char_rep, In0P->codeCnt); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_t__code__defined */ + } + #endif /* defined(__NDR_convert__char_rep...) */ + + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined) || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined) || \ + 0 + if (In0P->NDR.float_rep != NDR_record.float_rep) { + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_t__exception(&In0P->exception, In0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_t__exception__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_t__code(&In0P->code, In0P->NDR.float_rep, In0P->codeCnt); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_t__code__defined */ + } + #endif /* defined(__NDR_convert__float_rep...) */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Request__mach_exception_raise_t__defined) */ +#endif /* __MIG_check__Request__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck || __NDR_convert__ ) */ + + +/* Routine catch_mach_exception_raise_OVR */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t catch_mach_exception_raise_OVR +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt +); + +/* Routine _Xmach_exception_raise_OVR */ +mig_internal novalue _Xmach_exception_raise_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + mach_msg_trailer_t trailer; + } Request; + #ifdef __MigPackStructs + #pragma pack() + #endif + typedef __Request__mach_exception_raise_t __Request; + typedef __Reply__mach_exception_raise_t Reply; + + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + Request *In0P = (Request *) InHeadP; + Reply *OutP = (Reply *) OutHeadP; + #ifdef __MIG_check__Request__mach_exception_raise_t__defined + kern_return_t check_result; + #endif /* __MIG_check__Request__mach_exception_raise_t__defined */ + + __DeclareRcvRpc(2405, "mach_exception_raise_OVR") + __BeforeRcvRpc(2405, "mach_exception_raise_OVR") + + #if defined(__MIG_check__Request__mach_exception_raise_t__defined) + check_result = __MIG_check__Request__mach_exception_raise_t_OVR((__Request *)In0P); + if (check_result != MACH_MSG_SUCCESS) + { MIG_RETURN_ERROR(OutP, check_result); } + #endif /* defined(__MIG_check__Request__mach_exception_raise_t__defined) */ + + OutP->RetCode = catch_mach_exception_raise_OVR(In0P->Head.msgh_request_port, In0P->thread.name, In0P->task.name, In0P->exception, In0P->code, In0P->codeCnt); + + OutP->NDR = NDR_record; + + + __AfterRcvRpc(2405, "mach_exception_raise_OVR") +} + +#if ( __MigTypeCheck || __NDR_convert__ ) +#if __MIG_check__Request__mach_exc_subsystem__ +#if !defined(__MIG_check__Request__mach_exception_raise_state_t__defined) +#define __MIG_check__Request__mach_exception_raise_state_t__defined +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#if defined(__NDR_convert__int_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__int_rep__exception_type_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__int_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__int_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exception_data_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__int_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__int64_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__int_rep__int64_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__int_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined +#if defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#if defined(__NDR_convert__int_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__int_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__thread_state_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__int_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__natural_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__int_rep__natural_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__natural_t) +#elif defined(__NDR_convert__int_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__int_rep__uint32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#if defined(__NDR_convert__char_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__char_rep__exception_type_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__char_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined +#if defined(__NDR_convert__char_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__char_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exception_data_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__char_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__int64_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__char_rep__int64_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__char_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined +#if defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#if defined(__NDR_convert__char_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__char_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__thread_state_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__char_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__natural_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__char_rep__natural_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__natural_t) +#elif defined(__NDR_convert__char_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__char_rep__uint32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#if defined(__NDR_convert__float_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__float_rep__exception_type_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__float_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined +#if defined(__NDR_convert__float_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__float_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exception_data_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__float_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__int64_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__float_rep__int64_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__float_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined +#if defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#if defined(__NDR_convert__float_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__float_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__thread_state_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__float_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__natural_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__float_rep__natural_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__natural_t) +#elif defined(__NDR_convert__float_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__float_rep__uint32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined */ + + +mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_state_t_OVR(__attribute__((__unused__)) __Request__mach_exception_raise_state_t *In0P, __attribute__((__unused__)) __Request__mach_exception_raise_state_t **In1PP) +{ + + typedef __Request__mach_exception_raise_state_t __Request; + __Request *In1P; + #if __MigTypeCheck + unsigned int msgh_size; + #endif /* __MigTypeCheck */ + unsigned int msgh_size_delta; + + #if __MigTypeCheck + msgh_size = In0P->Head.msgh_size; + if ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 592)) || (msgh_size > (mach_msg_size_t)sizeof(__Request))) + return MIG_BAD_ARGUMENTS; + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined */ + msgh_size_delta = (8 * In0P->codeCnt); + #if __MigTypeCheck + if ( In0P->codeCnt > 2 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 592)) / 8 < In0P->codeCnt) || + (msgh_size < (mach_msg_size_t)(sizeof(__Request) - 592) + (8 * In0P->codeCnt))) + return MIG_BAD_ARGUMENTS; + msgh_size -= msgh_size_delta; + #endif /* __MigTypeCheck */ + + *In1PP = In1P = (__Request *) ((pointer_t) In0P + msgh_size_delta - 16); + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt(&In1P->old_stateCnt, In1P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined */ + #if __MigTypeCheck + if ( In1P->old_stateCnt > 144 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeof(__Request) - 592)) / 4 != In1P->old_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeof(__Request) - 592) + (4 * In1P->old_stateCnt))) + return MIG_BAD_ARGUMENTS; + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__codeCnt__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_stateCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) { + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception(&In0P->exception, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__exception__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code(&In0P->code, In0P->NDR.int_rep, In0P->codeCnt); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__code__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor(&In1P->flavor, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__flavor__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state(&In1P->old_state, In0P->NDR.int_rep, In1P->old_stateCnt); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_t__old_state__defined */ + } + #endif /* defined(__NDR_convert__int_rep...) */ + + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined) || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined) || \ + 0 || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined) || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined) || \ + 0 + if (In0P->NDR.char_rep != NDR_record.char_rep) { + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception(&In0P->exception, In0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__exception__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code(&In0P->code, In0P->NDR.char_rep, In0P->codeCnt); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__code__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor(&In1P->flavor, In0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__flavor__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state(&In1P->old_state, In0P->NDR.char_rep, In1P->old_stateCnt); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_t__old_state__defined */ + } + #endif /* defined(__NDR_convert__char_rep...) */ + + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined) || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined) || \ + 0 || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined) || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined) || \ + 0 + if (In0P->NDR.float_rep != NDR_record.float_rep) { + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception(&In0P->exception, In0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__exception__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code(&In0P->code, In0P->NDR.float_rep, In0P->codeCnt); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__code__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor(&In1P->flavor, In0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__flavor__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state(&In1P->old_state, In0P->NDR.float_rep, In1P->old_stateCnt); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_t__old_state__defined */ + } + #endif /* defined(__NDR_convert__float_rep...) */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Request__mach_exception_raise_state_t__defined) */ +#endif /* __MIG_check__Request__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck || __NDR_convert__ ) */ + + +/* Routine mach_exception_raise_state_OVR */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t catch_mach_exception_raise_state_OVR +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine _Xmach_exception_raise_state_OVR */ +mig_internal novalue _Xmach_exception_raise_state_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + mach_msg_trailer_t trailer; + } Request; + #ifdef __MigPackStructs + #pragma pack() + #endif + typedef __Request__mach_exception_raise_state_t __Request; + typedef __Reply__mach_exception_raise_state_t Reply; + + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + Request *In0P = (Request *) InHeadP; + Request *In1P; + Reply *OutP = (Reply *) OutHeadP; + #ifdef __MIG_check__Request__mach_exception_raise_state_t__defined + kern_return_t check_result; + #endif /* __MIG_check__Request__mach_exception_raise_state_t__defined */ + + __DeclareRcvRpc(2406, "mach_exception_raise_state_OVR") + __BeforeRcvRpc(2406, "mach_exception_raise_state_OVR") + + #if defined(__MIG_check__Request__mach_exception_raise_state_t__defined) + check_result = __MIG_check__Request__mach_exception_raise_state_t_OVR((__Request *)In0P, (__Request **)&In1P); + if (check_result != MACH_MSG_SUCCESS) + { MIG_RETURN_ERROR(OutP, check_result); } + #endif /* defined(__MIG_check__Request__mach_exception_raise_state_t__defined) */ + + OutP->new_stateCnt = 144; + + OutP->RetCode = catch_mach_exception_raise_state_OVR(In0P->Head.msgh_request_port, In0P->exception, In0P->code, In0P->codeCnt, &In1P->flavor, In1P->old_state, In1P->old_stateCnt, OutP->new_state, &OutP->new_stateCnt); + if (OutP->RetCode != KERN_SUCCESS) { + MIG_RETURN_ERROR(OutP, OutP->RetCode); + } + + OutP->NDR = NDR_record; + + + OutP->flavor = In1P->flavor; + OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 576) + (((4 * OutP->new_stateCnt))); + + __AfterRcvRpc(2406, "mach_exception_raise_state_OVR") +} + +#if ( __MigTypeCheck || __NDR_convert__ ) +#if __MIG_check__Request__mach_exc_subsystem__ +#if !defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) +#define __MIG_check__Request__mach_exception_raise_state_identity_t__defined +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#if defined(__NDR_convert__int_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__int_rep__exception_type_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__int_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__int_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exception_data_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__int_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__int64_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__int_rep__int64_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__int_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#if defined(__NDR_convert__int_rep__mach_exc__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__int__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__int((int *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_exc__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__int_rep__int32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__int_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#if defined(__NDR_convert__int_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__int_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__thread_state_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__int_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__int_rep__mach_exc__natural_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__int_rep__natural_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__int_rep__natural_t) +#elif defined(__NDR_convert__int_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__int_rep__uint32_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__int_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined */ + +#ifndef __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined +#if defined(__NDR_convert__int_rep__mach_exc__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_exc__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#elif defined(__NDR_convert__int_rep__mach_msg_type_number_t__defined) +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined +#define __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt(a, f) \ + __NDR_convert__int_rep__mach_msg_type_number_t((mach_msg_type_number_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#if defined(__NDR_convert__char_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__char_rep__exception_type_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__char_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined +#if defined(__NDR_convert__char_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__char_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exception_data_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__char_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__int64_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__char_rep__int64_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__char_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#if defined(__NDR_convert__char_rep__mach_exc__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__int__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__int((int *)(a), f) +#elif defined(__NDR_convert__char_rep__mach_exc__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__char_rep__int32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__char_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined */ + +#ifndef __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#if defined(__NDR_convert__char_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__char_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__thread_state_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__char_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__char_rep__mach_exc__natural_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__char_rep__natural_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__char_rep__natural_t) +#elif defined(__NDR_convert__char_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__char_rep__uint32_t__defined) +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__char_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#if defined(__NDR_convert__float_rep__mach_exc__exception_type_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__float_rep__exception_type_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__float_rep__exception_type_t((exception_type_t *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined +#if defined(__NDR_convert__float_rep__mach_exc__mach_exception_data_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__float_rep__mach_exc__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exception_data_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__float_rep__mach_exception_data_t((mach_exception_data_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__int64_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__int64_t) +#elif defined(__NDR_convert__float_rep__int64_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code(a, f, c) \ + __NDR_convert__ARRAY((int64_t *)(a), f, c, __NDR_convert__float_rep__int64_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#if defined(__NDR_convert__float_rep__mach_exc__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__int__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__int((int *)(a), f) +#elif defined(__NDR_convert__float_rep__mach_exc__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__mach_exc__int32_t((int32_t *)(a), f) +#elif defined(__NDR_convert__float_rep__int32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor(a, f) \ + __NDR_convert__float_rep__int32_t((int32_t *)(a), f) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined */ + +#ifndef __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#if defined(__NDR_convert__float_rep__mach_exc__thread_state_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__float_rep__mach_exc__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__thread_state_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__float_rep__thread_state_t((thread_state_t *)(a), f, c) +#elif defined(__NDR_convert__float_rep__mach_exc__natural_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__natural_t) +#elif defined(__NDR_convert__float_rep__natural_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((natural_t *)(a), f, c, __NDR_convert__float_rep__natural_t) +#elif defined(__NDR_convert__float_rep__mach_exc__uint32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__mach_exc__uint32_t) +#elif defined(__NDR_convert__float_rep__uint32_t__defined) +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined +#define __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(a, f, c) \ + __NDR_convert__ARRAY((uint32_t *)(a), f, c, __NDR_convert__float_rep__uint32_t) +#endif /* defined(__NDR_convert__*__defined) */ +#endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined */ + + +mig_internal kern_return_t __MIG_check__Request__mach_exception_raise_state_identity_t_OVR(__attribute__((__unused__)) __Request__mach_exception_raise_state_identity_t *In0P, __attribute__((__unused__)) __Request__mach_exception_raise_state_identity_t **In1PP) +{ + const size_t sizeofRequest = sizeof(__Request__mach_exception_raise_state_identity_t); + + typedef __Request__mach_exception_raise_state_identity_t __Request; + __Request *In1P; + #if __MigTypeCheck + unsigned int msgh_size; + #endif /* __MigTypeCheck */ + unsigned int msgh_size_delta; + + #if __MigTypeCheck + msgh_size = In0P->Head.msgh_size; + if (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) || + (In0P->msgh_body.msgh_descriptor_count != 2) || + (msgh_size < (mach_msg_size_t)(sizeofRequest - 592)) || (msgh_size > (mach_msg_size_t)sizeofRequest)) + return MIG_BAD_ARGUMENTS; + #endif /* __MigTypeCheck */ + + #if __MigTypeCheck + if (In0P->thread.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->thread.disposition != 17) + return MIG_TYPE_ERROR; + #endif /* __MigTypeCheck */ + + #if __MigTypeCheck + if (In0P->task.type != MACH_MSG_PORT_DESCRIPTOR || + In0P->task.disposition != 17) + return MIG_TYPE_ERROR; + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt(&In0P->codeCnt, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined */ + msgh_size_delta = (8 * In0P->codeCnt); + #if __MigTypeCheck + if ( In0P->codeCnt > 2 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeofRequest - 592)) / 8 < In0P->codeCnt) || + (msgh_size < (mach_msg_size_t)(sizeofRequest - 592) + (8 * In0P->codeCnt))) + return MIG_BAD_ARGUMENTS; + msgh_size -= msgh_size_delta; + #endif /* __MigTypeCheck */ + + *In1PP = In1P = (__Request *) ((pointer_t) In0P + msgh_size_delta - 16); + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt(&In1P->old_stateCnt, In1P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined */ + #if __MigTypeCheck + if ( In1P->old_stateCnt > 144 ) + return MIG_BAD_ARGUMENTS; + if (((msgh_size - (mach_msg_size_t)(sizeofRequest - 592)) / 4 != In1P->old_stateCnt) || + (msgh_size != (mach_msg_size_t)(sizeofRequest - 592) + (4 * In1P->old_stateCnt))) + return MIG_BAD_ARGUMENTS; + #endif /* __MigTypeCheck */ + + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__codeCnt__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined) || \ + defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_stateCnt__defined) + if (In0P->NDR.int_rep != NDR_record.int_rep) { + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception(&In0P->exception, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__exception__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code(&In0P->code, In0P->NDR.int_rep, In0P->codeCnt); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__code__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor(&In1P->flavor, In0P->NDR.int_rep); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__flavor__defined */ + #if defined(__NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined) + __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state(&In1P->old_state, In0P->NDR.int_rep, In1P->old_stateCnt); + #endif /* __NDR_convert__int_rep__Request__mach_exception_raise_state_identity_t__old_state__defined */ + } + #endif /* defined(__NDR_convert__int_rep...) */ + + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined) || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined) || \ + 0 || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined) || \ + defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined) || \ + 0 + if (In0P->NDR.char_rep != NDR_record.char_rep) { + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception(&In0P->exception, In0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__exception__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code(&In0P->code, In0P->NDR.char_rep, In0P->codeCnt); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__code__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor(&In1P->flavor, In0P->NDR.char_rep); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__flavor__defined */ + #if defined(__NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined) + __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state(&In1P->old_state, In0P->NDR.char_rep, In1P->old_stateCnt); + #endif /* __NDR_convert__char_rep__Request__mach_exception_raise_state_identity_t__old_state__defined */ + } + #endif /* defined(__NDR_convert__char_rep...) */ + + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined) || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined) || \ + 0 || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined) || \ + defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined) || \ + 0 + if (In0P->NDR.float_rep != NDR_record.float_rep) { + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception(&In0P->exception, In0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__exception__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code(&In0P->code, In0P->NDR.float_rep, In0P->codeCnt); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__code__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor(&In1P->flavor, In0P->NDR.float_rep); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__flavor__defined */ + #if defined(__NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined) + __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state(&In1P->old_state, In0P->NDR.float_rep, In1P->old_stateCnt); + #endif /* __NDR_convert__float_rep__Request__mach_exception_raise_state_identity_t__old_state__defined */ + } + #endif /* defined(__NDR_convert__float_rep...) */ + + return MACH_MSG_SUCCESS; +} +#endif /* !defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) */ +#endif /* __MIG_check__Request__mach_exc_subsystem__ */ +#endif /* ( __MigTypeCheck || __NDR_convert__ ) */ + + +/* Routine catch_mach_exception_raise_state_identity_OVR */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t catch_mach_exception_raise_state_identity_OVR +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine mach_exception_raise_state_identity_OVR */ +mig_internal novalue _Xmach_exception_raise_state_identity_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + + #ifdef __MigPackStructs + #pragma pack(4) + #endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + mach_msg_trailer_t trailer; + } Request; + #ifdef __MigPackStructs + #pragma pack() + #endif + typedef __Request__mach_exception_raise_state_identity_t __Request; + typedef __Reply__mach_exception_raise_state_identity_t Reply; + + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + Request *In0P = (Request *) InHeadP; + Request *In1P; + Reply *OutP = (Reply *) OutHeadP; + #ifdef __MIG_check__Request__mach_exception_raise_state_identity_t__defined + kern_return_t check_result; + #endif /* __MIG_check__Request__mach_exception_raise_state_identity_t__defined */ + + __DeclareRcvRpc(2407, "mach_exception_raise_state_identity_OVR") + __BeforeRcvRpc(2407, "mach_exception_raise_state_identity_OVR") + + #if defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) + check_result = __MIG_check__Request__mach_exception_raise_state_identity_t_OVR((__Request *)In0P, (__Request **)&In1P); + if (check_result != MACH_MSG_SUCCESS) + { MIG_RETURN_ERROR(OutP, check_result); } + #endif /* defined(__MIG_check__Request__mach_exception_raise_state_identity_t__defined) */ + + OutP->new_stateCnt = 144; + + OutP->RetCode = catch_mach_exception_raise_state_identity_OVR(In0P->Head.msgh_request_port, In0P->thread.name, In0P->task.name, In0P->exception, In0P->code, In0P->codeCnt, &In1P->flavor, In1P->old_state, In1P->old_stateCnt, OutP->new_state, &OutP->new_stateCnt); + if (OutP->RetCode != KERN_SUCCESS) { + MIG_RETURN_ERROR(OutP, OutP->RetCode); + } + + OutP->NDR = NDR_record; + + + OutP->flavor = In1P->flavor; + OutP->Head.msgh_size = (mach_msg_size_t)(sizeof(Reply) - 576) + (((4 * OutP->new_stateCnt))); + + __AfterRcvRpc(2407, "mach_exception_raise_state_identity_OVR") +} + + +#ifdef mig_external + mig_external +#else + extern +#endif /* mig_external */ + boolean_t mach_exc_server_OVR(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP); + +#ifdef mig_external + mig_external +#else + extern +#endif /* mig_external */ + mig_routine_t mach_exc_server_routine_OVR(mach_msg_header_t *InHeadP); + + +/* Description of this subsystem, for use in direct RPC */ +const struct catch_mach_exc_subsystem_OVR { + mig_server_routine_t server; /* Server routine */ + mach_msg_id_t start; /* Min routine number */ + mach_msg_id_t end; /* Max routine number + 1 */ + unsigned int maxsize; /* Max msg size */ + vm_address_t reserved; /* Reserved */ + struct routine_descriptor /*Array of routine descriptors */ + routine[3]; +} catch_mach_exc_subsystem_OVR = { + mach_exc_server_routine_OVR, + 2405, + 2408, + (mach_msg_size_t)sizeof(union __ReplyUnion__catch_mach_exc_subsystem), + (vm_address_t)0, + { + { (mig_impl_routine_t) 0, + (mig_stub_routine_t) _Xmach_exception_raise_OVR, 6, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_t)}, + { (mig_impl_routine_t) 0, + (mig_stub_routine_t) _Xmach_exception_raise_state_OVR, 9, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_state_t)}, + { (mig_impl_routine_t) 0, + (mig_stub_routine_t) _Xmach_exception_raise_state_identity_OVR, 11, 0, (routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__mach_exception_raise_state_identity_t)}, + } +}; + +mig_external boolean_t mach_exc_server_OVR + (mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP) +{ + /* + * typedef struct { + * mach_msg_header_t Head; + * NDR_record_t NDR; + * kern_return_t RetCode; + * } mig_reply_error_t; + */ + + register mig_routine_t routine; + + OutHeadP->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0); + OutHeadP->msgh_remote_port = InHeadP->msgh_reply_port; + /* Minimal size: routine() will update it if different */ + OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t); + OutHeadP->msgh_local_port = MACH_PORT_NULL; + OutHeadP->msgh_id = InHeadP->msgh_id + 100; + + if ((InHeadP->msgh_id > 2407) || (InHeadP->msgh_id < 2405) || + ((routine = catch_mach_exc_subsystem_OVR.routine[InHeadP->msgh_id - 2405].stub_routine) == 0)) + { + ((mig_reply_error_t *)OutHeadP)->NDR = NDR_record; + ((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID; + return FALSE; + } + (*routine) (InHeadP, OutHeadP); + return TRUE; +} + +mig_external mig_routine_t mach_exc_server_routine_OVR + (mach_msg_header_t *InHeadP) +{ + register int msgh_id; + + msgh_id = InHeadP->msgh_id - 2405; + + if ((msgh_id > 2) || (msgh_id < 0)) + return 0; + + return catch_mach_exc_subsystem_OVR.routine[msgh_id].stub_routine; +} + +#if defined(__cplusplus) + } /* extern "C" */ +#endif +/* End mach_excServer.c */ + +#elif defined(_MSC_VER) + +#pragma warning(disable: 4206) // nonstandard extension used : translation unit is empty + +#endif // __APPLE__ + diff --git a/LibOVRKernel/Src/Kernel/OVR_mach_exc_OSX.h b/LibOVRKernel/Src/Kernel/OVR_mach_exc_OSX.h new file mode 100644 index 0000000..4a1bcf0 --- /dev/null +++ b/LibOVRKernel/Src/Kernel/OVR_mach_exc_OSX.h @@ -0,0 +1,277 @@ +#ifndef _mach_exc_user_ +#define _mach_exc_user_ + +/* Module mach_exc */ + +#include <string.h> +#include <mach/ndr.h> +#include <mach/boolean.h> +#include <mach/kern_return.h> +#include <mach/notify.h> +#include <mach/mach_types.h> +#include <mach/message.h> +#include <mach/mig_errors.h> +#include <mach/port.h> + +#ifdef AUTOTEST +#ifndef FUNCTION_PTR_T +#define FUNCTION_PTR_T +typedef void (*function_ptr_t)(mach_port_t, char *, mach_msg_type_number_t); +typedef struct { + char *name; + function_ptr_t function; +} function_table_entry; +typedef function_table_entry *function_table_t; +#endif /* FUNCTION_PTR_T */ +#endif /* AUTOTEST */ + +#ifndef mach_exc_MSG_COUNT +#define mach_exc_MSG_COUNT 3 +#endif /* mach_exc_MSG_COUNT */ + +#include <mach/std_types.h> +#include <mach/mig.h> +#include <mach/mig.h> +#include <mach/mach_types.h> + +#ifdef __BeforeMigUserHeader +__BeforeMigUserHeader +#endif /* __BeforeMigUserHeader */ + +#include <sys/cdefs.h> +__BEGIN_DECLS + +#if defined(__cplusplus) + extern "C" { +#endif + +/* Routine mach_exception_raise_OVR */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_OVR +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt +); + +/* Routine mach_exception_raise_state_OVR */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_state_OVR +( + mach_port_t exception_port, + exception_type_t exception, + const mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + const thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +/* Routine mach_exception_raise_state_identity_OVR */ +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +kern_return_t mach_exception_raise_state_identity_OVR +( + mach_port_t exception_port, + mach_port_t thread, + mach_port_t task, + exception_type_t exception, + mach_exception_data_t code, + mach_msg_type_number_t codeCnt, + int *flavor, + thread_state_t old_state, + mach_msg_type_number_t old_stateCnt, + thread_state_t new_state, + mach_msg_type_number_t *new_stateCnt +); + +__END_DECLS + +/********************** Caution **************************/ +/* The following data types should be used to calculate */ +/* maximum message sizes only. The actual message may be */ +/* smaller, and the position of the arguments within the */ +/* message layout may vary from what is presented here. */ +/* For example, if any of the arguments are variable- */ +/* sized, and less than the maximum is sent, the data */ +/* will be packed tight in the actual message to reduce */ +/* the presence of holes. */ +/********************** Caution **************************/ + +/* typedefs for all requests */ + +#ifndef __Request__mach_exc_subsystem__defined +#define __Request__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + } __Request__mach_exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + } __Request__mach_exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[144]; + } __Request__mach_exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Request__mach_exc_subsystem__defined */ + +/* union of all requests */ + +#ifndef __RequestUnion__mach_exc_subsystem__defined +#define __RequestUnion__mach_exc_subsystem__defined +union __RequestUnion__mach_exc_subsystem { + __Request__mach_exception_raise_t Request_mach_exception_raise; + __Request__mach_exception_raise_state_t Request_mach_exception_raise_state; + __Request__mach_exception_raise_state_identity_t Request_mach_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__mach_exc_subsystem__defined */ +/* typedefs for all replies */ + +#ifndef __Reply__mach_exc_subsystem__defined +#define __Reply__mach_exc_subsystem__defined + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + } __Reply__mach_exception_raise_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + } __Reply__mach_exception_raise_state_t; +#ifdef __MigPackStructs +#pragma pack() +#endif + +#ifdef __MigPackStructs +#pragma pack(4) +#endif + typedef struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[144]; + } __Reply__mach_exception_raise_state_identity_t; +#ifdef __MigPackStructs +#pragma pack() +#endif +#endif /* !__Reply__mach_exc_subsystem__defined */ + +/* union of all replies */ + +#ifndef __ReplyUnion__mach_exc_subsystem__defined +#define __ReplyUnion__mach_exc_subsystem__defined +union __ReplyUnion__mach_exc_subsystem { + __Reply__mach_exception_raise_t Reply_mach_exception_raise; + __Reply__mach_exception_raise_state_t Reply_mach_exception_raise_state; + __Reply__mach_exception_raise_state_identity_t Reply_mach_exception_raise_state_identity; +}; +#endif /* !__RequestUnion__mach_exc_subsystem__defined */ + +#ifndef subsystem_to_name_map_mach_exc +#define subsystem_to_name_map_mach_exc \ + { "mach_exception_raise_OVR", 2405 },\ + { "mach_exception_raise_state_OVR", 2406 },\ + { "mach_exception_raise_state_identity_OVR", 2407 } +#endif + +#ifdef __AfterMigUserHeader +__AfterMigUserHeader +#endif /* __AfterMigUserHeader */ + + +#ifdef mig_external +mig_external +#else +extern +#endif /* mig_external */ +boolean_t mach_exc_server_OVR( + mach_msg_header_t *InHeadP, + mach_msg_header_t *OutHeadP); + + +#if defined(__cplusplus) + } // extern"C" +#endif + + +#endif /* _mach_exc_user_ */ |