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 #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
94 typedef __int64 FilePos;
95 #define fseeko _fseeki64
96 #define ftello _ftelli64
97 
98 #else
99 typedef off_t FilePos;
100 #endif
101 
102 #include "PtexVersion.h"
103 
105 
106 /*
107  * Mutex
108  */
109 
110 #ifdef PTEX_PLATFORM_WINDOWS
111 
112 class Mutex {
113 public:
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); }
119 private:
120  HANDLE _mutex;
121 };
122 
123 class SpinLock {
124 public:
125  SpinLock() { InitializeCriticalSection(&_spinlock); }
126  ~SpinLock() { DeleteCriticalSection(&_spinlock); }
127  void lock() { EnterCriticalSection(&_spinlock); }
128  bool trylock() { return TryEnterCriticalSection(&_spinlock); }
129  void unlock() { LeaveCriticalSection(&_spinlock); }
130 private:
131  CRITICAL_SECTION _spinlock;
132 };
133 
134 #else
135 // assume linux/unix/posix
136 
137 class Mutex {
138 public:
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); }
144 private:
145  pthread_mutex_t _mutex;
146 };
147 
148 #ifdef __APPLE__
149 class SpinLock {
150 public:
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); }
156 private:
157  os_unfair_lock _spinlock;
158 };
159 #else
160 class SpinLock {
161 public:
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); }
167 private:
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 
208 template <typename T>
209 PTEX_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 
224 template <typename T>
225 PTEX_INLINE T AtomicIncrement(volatile T* target)
226 {
227  return AtomicAdd(target, (T)1);
228 }
229 
230 template <typename T>
231 PTEX_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 
246 template <typename T>
247 PTEX_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.
256 template <typename T, size_t n>
258 
259 template <typename T>
260 struct 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 
268 template <typename T>
269 struct 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 
277 template <typename T>
278 PTEX_INLINE bool AtomicCompareAndSwap(T volatile* target, T oldvalue, T newvalue)
279 {
280  return AtomicCompareAndSwapImpl<T, sizeof(T)>()(target, oldvalue, newvalue);
281 }
282 
283 template <typename T>
284 PTEX_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)
Definition: PtexPlatform.h:193
#define ATOMIC_SUB64(x, y)
Definition: PtexPlatform.h:196
off_t FilePos
Definition: PtexPlatform.h:99
#define PTEX_INLINE
Definition: PtexPlatform.h:202
PTEX_INLINE T AtomicAdd(volatile T *target, T value)
Definition: PtexPlatform.h:209
#define BOOL_CMPXCH32(x, y, z)
Definition: PtexPlatform.h:198
#define ATOMIC_SUB32(x, y)
Definition: PtexPlatform.h:195
PTEX_INLINE T AtomicDecrement(volatile T *target)
Definition: PtexPlatform.h:247
#define ATOMIC_ADD64(x, y)
Definition: PtexPlatform.h:194
PTEX_INLINE void AtomicStore(T volatile *target, T value)
Definition: PtexPlatform.h:284
#define MEM_FENCE()
Definition: PtexPlatform.h:197
PTEX_INLINE T AtomicIncrement(volatile T *target)
Definition: PtexPlatform.h:225
PTEX_INLINE void PtexMemoryFence()
Definition: PtexPlatform.h:290
PTEX_INLINE bool AtomicCompareAndSwap(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:278
#define BOOL_CMPXCH64(x, y, z)
Definition: PtexPlatform.h:199
PTEX_INLINE T AtomicSubtract(volatile T *target, T value)
Definition: PtexPlatform.h:231
#define PTEX_NAMESPACE_END
Definition: PtexVersion.h:62
bool trylock()
Definition: PtexPlatform.h:142
void unlock()
Definition: PtexPlatform.h:143
pthread_mutex_t _mutex
Definition: PtexPlatform.h:145
void lock()
Definition: PtexPlatform.h:141
void unlock()
Definition: PtexPlatform.h:166
void lock()
Definition: PtexPlatform.h:164
pthread_spinlock_t _spinlock
Definition: PtexPlatform.h:168
bool trylock()
Definition: PtexPlatform.h:165
PTEX_INLINE bool operator()(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:261
PTEX_INLINE bool operator()(T volatile *target, T oldvalue, T newvalue)
Definition: PtexPlatform.h:270