Ptex
PtexPlatform.h
Go to the documentation of this file.
1#ifndef PtexPlatform_h
2#define PtexPlatform_h
3/*
4PTEX SOFTWARE
5Copyright 2014 Disney Enterprises, Inc. All rights reserved
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10
11 * Redistributions of source code must retain the above copyright
12 notice, this list of conditions and the following disclaimer.
13
14 * Redistributions in binary form must reproduce the above copyright
15 notice, this list of conditions and the following disclaimer in
16 the documentation and/or other materials provided with the
17 distribution.
18
19 * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
20 Studios" or the names of its contributors may NOT be used to
21 endorse or promote products derived from this software without
22 specific prior written permission from Walt Disney Pictures.
23
24Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
25CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
26BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
28IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
29CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
33THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
36*/
37
42#include "PtexInt.h"
43
44// compiler-specific defines: PTEX_COMPILER_{CLANG,GCC,ICC,MSVC}
45#if defined(__clang__)
46# define PTEX_COMPILER_CLANG
47#elif defined(__GNUC__)
48# define PTEX_COMPILER_GCC
49#elif defined(__ICC)
50# define PTEX_COMPILER_ICC
51#elif defined(_MSC_VER)
52# define PTEX_COMPILER_MSVC
53#endif
54
55// platform-specific includes
56#if defined(_WIN32) || defined(_WIN64) || defined(_WINDOWS) || defined(_MSC_VER)
57#define PTEX_PLATFORM_WINDOWS
58#define _CRT_NONSTDC_NO_DEPRECATE 1
59#define _CRT_SECURE_NO_DEPRECATE 1
60#define NOMINMAX 1
61
62// windows - defined for both Win32 and Win64
63#include <Windows.h>
64#include <malloc.h>
65#include <io.h>
66#include <tchar.h>
67#include <process.h>
68
69#else
70
71// linux/unix/posix
72#include <stdlib.h>
73#include <alloca.h>
74#include <string.h>
75#include <pthread.h>
76
77#ifdef __APPLE__
78#include <os/lock.h>
79#include <sys/types.h>
80#include <unistd.h>
81#define PTEX_PLATFORM_MACOS
82#else
83#define PTEX_PLATFORM_UNIX
84#endif
85#endif
86
87// general includes
88#include <stdio.h>
89#include <math.h>
90#include <assert.h>
91
92// missing functions on Windows
93#ifdef PTEX_PLATFORM_WINDOWS
94typedef __int64 FilePos;
95#define fseeko _fseeki64
96#define ftello _ftelli64
97
98#else
99typedef off_t FilePos;
100#endif
101
102#include "PtexVersion.h"
103
105
106/*
107 * Mutex
108 */
109
110#ifdef PTEX_PLATFORM_WINDOWS
111
112class Mutex {
113public:
114 Mutex() { _mutex = CreateMutex(NULL, FALSE, NULL); }
115 ~Mutex() { CloseHandle(_mutex); }
116 void lock() { WaitForSingleObject(_mutex, INFINITE); }
117 bool trylock() { return WAIT_TIMEOUT != WaitForSingleObject(_mutex,0);}
118 void unlock() { ReleaseMutex(_mutex); }
119private:
120 HANDLE _mutex;
121};
122
123class SpinLock {
124public:
125 SpinLock() { InitializeCriticalSection(&_spinlock); }
126 ~SpinLock() { DeleteCriticalSection(&_spinlock); }
127 void lock() { EnterCriticalSection(&_spinlock); }
128 bool trylock() { return TryEnterCriticalSection(&_spinlock); }
129 void unlock() { LeaveCriticalSection(&_spinlock); }
130private:
131 CRITICAL_SECTION _spinlock;
132};
133
134#else
135// assume linux/unix/posix
136
137class Mutex {
138public:
139 Mutex() { pthread_mutex_init(&_mutex, 0); }
140 ~Mutex() { pthread_mutex_destroy(&_mutex); }
141 void lock() { pthread_mutex_lock(&_mutex); }
142 bool trylock() { return 0 == pthread_mutex_trylock(&_mutex); }
143 void unlock() { pthread_mutex_unlock(&_mutex); }
144private:
145 pthread_mutex_t _mutex;
146};
147
148#ifdef __APPLE__
149class SpinLock {
150public:
151 SpinLock() { _spinlock = OS_UNFAIR_LOCK_INIT; }
152 ~SpinLock() { }
153 void lock() { os_unfair_lock_lock(&_spinlock); }
154 bool trylock() { return os_unfair_lock_trylock(&_spinlock); }
155 void unlock() { os_unfair_lock_unlock(&_spinlock); }
156private:
157 os_unfair_lock _spinlock;
158};
159#else
160class SpinLock {
161public:
162 SpinLock() { pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); }
163 ~SpinLock() { pthread_spin_destroy(&_spinlock); }
164 void lock() { pthread_spin_lock(&_spinlock); }
165 bool trylock() { return 0 == pthread_spin_trylock(&_spinlock); }
166 void unlock() { pthread_spin_unlock(&_spinlock); }
167private:
168 pthread_spinlock_t _spinlock;
169};
170#endif // __APPLE__
171#endif
172
173/*
174 * Atomics
175 */
176
177#ifdef PTEX_PLATFORM_WINDOWS
178 #define ATOMIC_ALIGNED __declspec(align(8))
179 #define ATOMIC_ADD32(x,y) (InterlockedExchangeAdd((volatile long*)(x),(long)(y)) + (y))
180 #define ATOMIC_ADD64(x,y) (InterlockedExchangeAdd64((volatile long long*)(x),(long long)(y)) + (y))
181 #define ATOMIC_SUB32(x,y) (InterlockedExchangeAdd((volatile long*)(x),-((long)(y))) - (y))
182 #define ATOMIC_SUB64(x,y) (InterlockedExchangeAdd64((volatile long long*)(x),-((long long)(y))) - (y))
183 #define MEM_FENCE() MemoryBarrier()
184 #define BOOL_CMPXCH32(x,y,z) (InterlockedCompareExchange((volatile long*)(x),(long)(z),(long)(y)) == (y))
185 #define BOOL_CMPXCH64(x,y,z) (InterlockedCompareExchange64((volatile long long*)(x),(long long)(z),(long long)(y)) == (y))
186 #ifdef NDEBUG
187 #define PTEX_INLINE __forceinline
188 #else
189 #define PTEX_INLINE inline
190 #endif
191#else
192 #define ATOMIC_ALIGNED __attribute__((aligned(8)))
193 #define ATOMIC_ADD32(x,y) __sync_add_and_fetch(x,y)
194 #define ATOMIC_ADD64(x,y) __sync_add_and_fetch(x,y)
195 #define ATOMIC_SUB32(x,y) __sync_sub_and_fetch(x,y)
196 #define ATOMIC_SUB64(x,y) __sync_sub_and_fetch(x,y)
197 #define MEM_FENCE() __sync_synchronize()
198 #define BOOL_CMPXCH32(x,y,z) __sync_bool_compare_and_swap((x),(y),(z))
199 #define BOOL_CMPXCH64(x,y,z) __sync_bool_compare_and_swap((x),(y),(z))
200
201 #ifdef NDEBUG
202 #define PTEX_INLINE inline __attribute__((always_inline))
203 #else
204 #define PTEX_INLINE inline
205 #endif
206#endif
207
208template <typename T>
209PTEX_INLINE T AtomicAdd(volatile T* target, T value)
210{
211 switch(sizeof(T)){
212 case 4:
213 return (T)ATOMIC_ADD32(target, value);
214 break;
215 case 8:
216 return (T)ATOMIC_ADD64(target, value);
217 break;
218 default:
219 assert(0=="Can only use 32 or 64 bit atomics");
220 return *(T*)NULL;
221 }
222}
223
224template <typename T>
225PTEX_INLINE T AtomicIncrement(volatile T* target)
226{
227 return AtomicAdd(target, (T)1);
228}
229
230template <typename T>
231PTEX_INLINE T AtomicSubtract(volatile T* target, T value)
232{
233 switch(sizeof(T)){
234 case 4:
235 return (T)ATOMIC_SUB32(target, value);
236 break;
237 case 8:
238 return (T)ATOMIC_SUB64(target, value);
239 break;
240 default:
241 assert(0=="Can only use 32 or 64 bit atomics");
242 return *(T*)NULL;
243 }
244}
245
246template <typename T>
247PTEX_INLINE T AtomicDecrement(volatile T* target)
248{
249 return AtomicSubtract(target, (T)1);
250}
251
252// GCC is pretty forgiving, but ICC only allows int, long and long long
253// so use partial specialization over structs (C(98)) to get certain compilers
254// to do the specialization to sizeof(T) before doing typechecking and
255// throwing errors for no good reason.
256template <typename T, size_t n>
258
259template <typename T>
260struct AtomicCompareAndSwapImpl<T, sizeof(uint32_t)> {
261 PTEX_INLINE bool operator()(T volatile* target, T oldvalue, T newvalue){
262 return BOOL_CMPXCH32((volatile uint32_t*)target,
263 (uint32_t)oldvalue,
264 (uint32_t)newvalue);
265 }
266};
267
268template <typename T>
269struct AtomicCompareAndSwapImpl<T, sizeof(uint64_t)> {
270 PTEX_INLINE bool operator()(T volatile* target, T oldvalue, T newvalue){
271 return BOOL_CMPXCH64((volatile uint64_t*)target,
272 (uint64_t)oldvalue,
273 (uint64_t)newvalue);
274 }
275};
276
277template <typename T>
278PTEX_INLINE bool AtomicCompareAndSwap(T volatile* target, T oldvalue, T newvalue)
279{
280 return AtomicCompareAndSwapImpl<T, sizeof(T)>()(target, oldvalue, newvalue);
281}
282
283template <typename T>
284PTEX_INLINE void AtomicStore(T volatile* target, T value)
285{
286 MEM_FENCE();
287 *target = value;
288}
289
291{
292 MEM_FENCE();
293}
294
295
296#ifndef CACHE_LINE_SIZE
297#define CACHE_LINE_SIZE 64
298#endif
299
300#define CACHE_LINE_PAD(var,type) char var##_pad[CACHE_LINE_SIZE - sizeof(type)]
301#define CACHE_LINE_PAD_INIT(var) memset(&var##_pad[0], 0, sizeof(var##_pad))
302
304
305#endif // PtexPlatform_h
Portable fixed-width integer types.
#define ATOMIC_ADD32(x, y)
#define ATOMIC_SUB64(x, y)
off_t FilePos
#define PTEX_INLINE
PTEX_INLINE T AtomicAdd(volatile T *target, T value)
#define BOOL_CMPXCH32(x, y, z)
#define ATOMIC_SUB32(x, y)
PTEX_INLINE T AtomicDecrement(volatile T *target)
#define ATOMIC_ADD64(x, y)
PTEX_INLINE void AtomicStore(T volatile *target, T value)
#define MEM_FENCE()
PTEX_INLINE T AtomicIncrement(volatile T *target)
PTEX_INLINE void PtexMemoryFence()
PTEX_INLINE bool AtomicCompareAndSwap(T volatile *target, T oldvalue, T newvalue)
#define BOOL_CMPXCH64(x, y, z)
PTEX_INLINE T AtomicSubtract(volatile T *target, T value)
#define PTEX_NAMESPACE_END
Definition PtexVersion.h:62
bool trylock()
void unlock()
pthread_mutex_t _mutex
void lock()
void unlock()
void lock()
pthread_spinlock_t _spinlock
bool trylock()
PTEX_INLINE bool operator()(T volatile *target, T oldvalue, T newvalue)
PTEX_INLINE bool operator()(T volatile *target, T oldvalue, T newvalue)