Ptex
PtexPlatform.h
Go to the documentation of this file.
1 #ifndef PtexPlatform_h
2 #define PtexPlatform_h
3 /*
4 PTEX SOFTWARE
5 Copyright 2014 Disney Enterprises, Inc. All rights reserved
6 
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are
9 met:
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 
24 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
25 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
26 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
27 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
28 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
29 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
33 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 OF 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
96 typedef __int64 FilePos;
97 #define fseeko _fseeki64
98 #define ftello _ftelli64
99 
100 #else
101 typedef off_t FilePos;
102 #endif
103 
104 #include "PtexVersion.h"
105 
107 
108 /*
109  * Mutex
110  */
111 
112 #ifdef PTEX_PLATFORM_WINDOWS
113 
114 class Mutex {
115 public:
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); }
121 private:
122  HANDLE _mutex;
123 };
124 
125 class SpinLock {
126 public:
127  SpinLock() { InitializeCriticalSection(&_spinlock); }
128  ~SpinLock() { DeleteCriticalSection(&_spinlock); }
129  void lock() { EnterCriticalSection(&_spinlock); }
130  bool trylock() { return TryEnterCriticalSection(&_spinlock); }
131  void unlock() { LeaveCriticalSection(&_spinlock); }
132 private:
133  CRITICAL_SECTION _spinlock;
134 };
135 
136 #else
137 // assume linux/unix/posix
138 
139 class Mutex {
140 public:
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); }
146 private:
147  pthread_mutex_t _mutex;
148 };
149 
150 #ifdef __APPLE__
151 class SpinLock {
152 public:
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); }
158 private:
159  os_unfair_lock _spinlock;
160 };
161 #else
162 class SpinLock {
163 public:
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); }
169 private:
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 
210 template <typename T>
211 PTEX_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 
226 template <typename T>
227 PTEX_INLINE T AtomicIncrement(volatile T* target)
228 {
229  return AtomicAdd(target, (T)1);
230 }
231 
232 template <typename T>
233 PTEX_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 
248 template <typename T>
249 PTEX_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.
258 template <typename T, size_t n>
260 
261 template <typename T>
262 struct 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 
270 template <typename T>
271 struct 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 
279 template <typename T>
280 PTEX_INLINE bool AtomicCompareAndSwap(T volatile* target, T oldvalue, T newvalue)
281 {
282  return AtomicCompareAndSwapImpl<T, sizeof(T)>()(target, oldvalue, newvalue);
283 }
284 
285 template <typename T>
286 PTEX_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
#define BOOL_CMPXCH32(x, y, z)
Definition: PtexPlatform.h:200
#define BOOL_CMPXCH64(x, y, z)
Definition: PtexPlatform.h:201
PTEX_INLINE T AtomicSubtract(volatile T *target, T value)
Definition: PtexPlatform.h:233
void unlock()
Definition: PtexPlatform.h:168
bool trylock()
Definition: PtexPlatform.h:167
PTEX_INLINE T AtomicIncrement(volatile T *target)
Definition: PtexPlatform.h:227
bool trylock()
Definition: PtexPlatform.h:144
#define ATOMIC_SUB64(x, y)
Definition: PtexPlatform.h:198
PTEX_INLINE T AtomicDecrement(volatile T *target)
Definition: PtexPlatform.h:249
PTEX_INLINE bool operator()(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:272
PTEX_INLINE T AtomicAdd(volatile T *target, T value)
Definition: PtexPlatform.h:211
#define ATOMIC_SUB32(x, y)
Definition: PtexPlatform.h:197
off_t FilePos
Definition: PtexPlatform.h:101
PTEX_INLINE bool AtomicCompareAndSwap(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:280
#define PTEX_INLINE
Definition: PtexPlatform.h:204
PTEX_INLINE void PtexMemoryFence()
Definition: PtexPlatform.h:292
pthread_spinlock_t _spinlock
Definition: PtexPlatform.h:170
#define MEM_FENCE()
Definition: PtexPlatform.h:199
pthread_mutex_t _mutex
Definition: PtexPlatform.h:147
void lock()
Definition: PtexPlatform.h:166
void unlock()
Definition: PtexPlatform.h:145
#define ATOMIC_ADD64(x, y)
Definition: PtexPlatform.h:196
PTEX_INLINE void AtomicStore(T volatile *target, T value)
Definition: PtexPlatform.h:286
Portable fixed-width integer types.
#define PTEX_NAMESPACE_END
Definition: PtexVersion.h:62
void lock()
Definition: PtexPlatform.h:143
#define ATOMIC_ADD32(x, y)
Definition: PtexPlatform.h:195
PTEX_INLINE bool operator()(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:263