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