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#if !defined(__FreeBSD__)
74 #include <alloca.h>
75#endif
76#include <string.h>
77#include <pthread.h>
78
79#ifdef __APPLE__
80#include <os/lock.h>
81#include <sys/types.h>
82#include <unistd.h>
83#define PTEX_PLATFORM_MACOS
84#else
85#define PTEX_PLATFORM_UNIX
86#endif
87#endif
88
89// general includes
90#include <stdio.h>
91#include <math.h>
92#include <assert.h>
93
94// missing functions on Windows
95#ifdef PTEX_PLATFORM_WINDOWS
96typedef __int64 FilePos;
97#define fseeko _fseeki64
98#define ftello _ftelli64
99
100#else
101typedef off_t FilePos;
102#endif
103
104#include "PtexVersion.h"
105
107
108/*
109 * Mutex
110 */
111
112#ifdef PTEX_PLATFORM_WINDOWS
113
114class Mutex {
115public:
116 Mutex() { _mutex = CreateMutex(NULL, FALSE, NULL); }
117 ~Mutex() { CloseHandle(_mutex); }
118 void lock() { WaitForSingleObject(_mutex, INFINITE); }
119 bool trylock() { return WAIT_TIMEOUT != WaitForSingleObject(_mutex,0);}
120 void unlock() { ReleaseMutex(_mutex); }
121private:
122 HANDLE _mutex;
123};
124
125class SpinLock {
126public:
127 SpinLock() { InitializeCriticalSection(&_spinlock); }
128 ~SpinLock() { DeleteCriticalSection(&_spinlock); }
129 void lock() { EnterCriticalSection(&_spinlock); }
130 bool trylock() { return TryEnterCriticalSection(&_spinlock); }
131 void unlock() { LeaveCriticalSection(&_spinlock); }
132private:
133 CRITICAL_SECTION _spinlock;
134};
135
136#else
137// assume linux/unix/posix
138
139class Mutex {
140public:
141 Mutex() { pthread_mutex_init(&_mutex, 0); }
142 ~Mutex() { pthread_mutex_destroy(&_mutex); }
143 void lock() { pthread_mutex_lock(&_mutex); }
144 bool trylock() { return 0 == pthread_mutex_trylock(&_mutex); }
145 void unlock() { pthread_mutex_unlock(&_mutex); }
146private:
147 pthread_mutex_t _mutex;
148};
149
150#ifdef __APPLE__
151class SpinLock {
152public:
153 SpinLock() { _spinlock = OS_UNFAIR_LOCK_INIT; }
154 ~SpinLock() { }
155 void lock() { os_unfair_lock_lock(&_spinlock); }
156 bool trylock() { return os_unfair_lock_trylock(&_spinlock); }
157 void unlock() { os_unfair_lock_unlock(&_spinlock); }
158private:
159 os_unfair_lock _spinlock;
160};
161#else
162class SpinLock {
163public:
164 SpinLock() { pthread_spin_init(&_spinlock, PTHREAD_PROCESS_PRIVATE); }
165 ~SpinLock() { pthread_spin_destroy(&_spinlock); }
166 void lock() { pthread_spin_lock(&_spinlock); }
167 bool trylock() { return 0 == pthread_spin_trylock(&_spinlock); }
168 void unlock() { pthread_spin_unlock(&_spinlock); }
169private:
170 pthread_spinlock_t _spinlock;
171};
172#endif // __APPLE__
173#endif
174
175/*
176 * Atomics
177 */
178
179#ifdef PTEX_PLATFORM_WINDOWS
180 #define ATOMIC_ALIGNED __declspec(align(8))
181 #define ATOMIC_ADD32(x,y) (InterlockedExchangeAdd((volatile long*)(x),(long)(y)) + (y))
182 #define ATOMIC_ADD64(x,y) (InterlockedExchangeAdd64((volatile long long*)(x),(long long)(y)) + (y))
183 #define ATOMIC_SUB32(x,y) (InterlockedExchangeAdd((volatile long*)(x),-((long)(y))) - (y))
184 #define ATOMIC_SUB64(x,y) (InterlockedExchangeAdd64((volatile long long*)(x),-((long long)(y))) - (y))
185 #define MEM_FENCE() MemoryBarrier()
186 #define BOOL_CMPXCH32(x,y,z) (InterlockedCompareExchange((volatile long*)(x),(long)(z),(long)(y)) == (y))
187 #define BOOL_CMPXCH64(x,y,z) (InterlockedCompareExchange64((volatile long long*)(x),(long long)(z),(long long)(y)) == (y))
188 #ifdef NDEBUG
189 #define PTEX_INLINE __forceinline
190 #else
191 #define PTEX_INLINE inline
192 #endif
193#else
194 #define ATOMIC_ALIGNED __attribute__((aligned(8)))
195 #define ATOMIC_ADD32(x,y) __sync_add_and_fetch(x,y)
196 #define ATOMIC_ADD64(x,y) __sync_add_and_fetch(x,y)
197 #define ATOMIC_SUB32(x,y) __sync_sub_and_fetch(x,y)
198 #define ATOMIC_SUB64(x,y) __sync_sub_and_fetch(x,y)
199 #define MEM_FENCE() __sync_synchronize()
200 #define BOOL_CMPXCH32(x,y,z) __sync_bool_compare_and_swap((x),(y),(z))
201 #define BOOL_CMPXCH64(x,y,z) __sync_bool_compare_and_swap((x),(y),(z))
202
203 #ifdef NDEBUG
204 #define PTEX_INLINE inline __attribute__((always_inline))
205 #else
206 #define PTEX_INLINE inline
207 #endif
208#endif
209
210template <typename T>
211PTEX_INLINE T AtomicAdd(volatile T* target, T value)
212{
213 switch(sizeof(T)){
214 case 4:
215 return (T)ATOMIC_ADD32(target, value);
216 break;
217 case 8:
218 return (T)ATOMIC_ADD64(target, value);
219 break;
220 default:
221 assert(0=="Can only use 32 or 64 bit atomics");
222 return *(T*)NULL;
223 }
224}
225
226template <typename T>
227PTEX_INLINE T AtomicIncrement(volatile T* target)
228{
229 return AtomicAdd(target, (T)1);
230}
231
232template <typename T>
233PTEX_INLINE T AtomicSubtract(volatile T* target, T value)
234{
235 switch(sizeof(T)){
236 case 4:
237 return (T)ATOMIC_SUB32(target, value);
238 break;
239 case 8:
240 return (T)ATOMIC_SUB64(target, value);
241 break;
242 default:
243 assert(0=="Can only use 32 or 64 bit atomics");
244 return *(T*)NULL;
245 }
246}
247
248template <typename T>
249PTEX_INLINE T AtomicDecrement(volatile T* target)
250{
251 return AtomicSubtract(target, (T)1);
252}
253
254// GCC is pretty forgiving, but ICC only allows int, long and long long
255// so use partial specialization over structs (C(98)) to get certain compilers
256// to do the specialization to sizeof(T) before doing typechecking and
257// throwing errors for no good reason.
258template <typename T, size_t n>
260
261template <typename T>
262struct AtomicCompareAndSwapImpl<T, sizeof(uint32_t)> {
263 PTEX_INLINE bool operator()(T volatile* target, T oldvalue, T newvalue){
264 return BOOL_CMPXCH32((volatile uint32_t*)target,
265 (uint32_t)oldvalue,
266 (uint32_t)newvalue);
267 }
268};
269
270template <typename T>
271struct AtomicCompareAndSwapImpl<T, sizeof(uint64_t)> {
272 PTEX_INLINE bool operator()(T volatile* target, T oldvalue, T newvalue){
273 return BOOL_CMPXCH64((volatile uint64_t*)target,
274 (uint64_t)oldvalue,
275 (uint64_t)newvalue);
276 }
277};
278
279template <typename T>
280PTEX_INLINE bool AtomicCompareAndSwap(T volatile* target, T oldvalue, T newvalue)
281{
282 return AtomicCompareAndSwapImpl<T, sizeof(T)>()(target, oldvalue, newvalue);
283}
284
285template <typename T>
286PTEX_INLINE void AtomicStore(T volatile* target, T value)
287{
288 MEM_FENCE();
289 *target = value;
290}
291
293{
294 MEM_FENCE();
295}
296
297
298#ifndef CACHE_LINE_SIZE
299#define CACHE_LINE_SIZE 64
300#endif
301
302#define CACHE_LINE_PAD(var,type) char var##_pad[CACHE_LINE_SIZE - sizeof(type)]
303#define CACHE_LINE_PAD_INIT(var) memset(&var##_pad[0], 0, sizeof(var##_pad))
304
306
307#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)