Cuda use streams and async to avoid busywaiting
[blender.git] / intern / atomic / atomic_ops.h
1 /*
2  * Adopted from jemalloc with this license:
3  *
4  * Copyright (C) 2002-2013 Jason Evans <jasone@canonware.com>.
5  * All rights reserved.
6  * Copyright (C) 2007-2012 Mozilla Foundation.  All rights reserved.
7  * Copyright (C) 2009-2013 Facebook, Inc.  All rights reserved.
8
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  * 1. Redistributions of source code must retain the above copyright notice(s),
12  *    this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright notice(s),
14  *    this list of conditions and the following disclaimer in the documentation
15  *    and/or other materials provided with the distribution.
16
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
20  * EVENT SHALL THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #ifndef __ATOMIC_OPS_H__
30 #define __ATOMIC_OPS_H__
31
32 #include <assert.h>
33
34 #if defined (__APPLE__)
35 #  include <libkern/OSAtomic.h>
36 #elif defined(_MSC_VER)
37 #  include <windows.h>
38 #elif defined(__arm__)
39 /* Attempt to fix compilation error on Debian armel kernel.
40  * arm7 architecture does have both 32 and 64bit atomics, however
41  * it's gcc doesn't have __GCC_HAVE_SYNC_COMPARE_AND_SWAP_n defined.
42  */
43 #  define JE_FORCE_SYNC_COMPARE_AND_SWAP_8
44 #  define JE_FORCE_SYNC_COMPARE_AND_SWAP_4
45 #endif
46
47 /* needed for int types */
48 #include "../../source/blender/blenlib/BLI_sys_types.h"
49 #include <stdlib.h>
50 #include <stddef.h>
51
52 /* little macro so inline keyword works */
53 #if defined(_MSC_VER)
54 #  define ATOMIC_INLINE static __forceinline
55 #else
56 #  if (defined(__APPLE__) && defined(__ppc__))
57 /* static inline __attribute__ here breaks osx ppc gcc42 build */
58 #    define ATOMIC_INLINE static __attribute__((always_inline))
59 #  else
60 #    define ATOMIC_INLINE static inline __attribute__((always_inline))
61 #  endif
62 #endif
63
64 #if defined(_M_X64) || defined(__amd64__) || defined(__x86_64__)
65 #  define LG_SIZEOF_PTR 3
66 #  define LG_SIZEOF_INT 2
67 #else
68 #  define LG_SIZEOF_PTR 2
69 #  define LG_SIZEOF_INT 2
70 #endif
71
72 /******************************************************************************/
73 /* 64-bit operations. */
74 #if (LG_SIZEOF_PTR == 3 || LG_SIZEOF_INT == 3)
75 #  ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
76 ATOMIC_INLINE uint64_t
77 atomic_add_uint64(uint64_t *p, uint64_t x)
78 {
79         return (__sync_add_and_fetch(p, x));
80 }
81
82 ATOMIC_INLINE uint64_t
83 atomic_sub_uint64(uint64_t *p, uint64_t x)
84 {
85         return (__sync_sub_and_fetch(p, x));
86 }
87 #elif (defined(_MSC_VER))
88 ATOMIC_INLINE uint64_t
89 atomic_add_uint64(uint64_t *p, uint64_t x)
90 {
91         return (InterlockedExchangeAdd64(p, x));
92 }
93
94 ATOMIC_INLINE uint64_t
95 atomic_sub_uint64(uint64_t *p, uint64_t x)
96 {
97         return (InterlockedExchangeAdd64(p, -((int64_t)x)));
98 }
99 #elif (defined(__APPLE__))
100 ATOMIC_INLINE uint64_t
101 atomic_add_uint64(uint64_t *p, uint64_t x)
102 {
103         return (uint64_t)(OSAtomicAdd64((int64_t)x, (int64_t *)p));
104 }
105
106 ATOMIC_INLINE uint64_t
107 atomic_sub_uint64(uint64_t *p, uint64_t x)
108 {
109         return (uint64_t)(OSAtomicAdd64(-((int64_t)x), (int64_t *)p));
110 }
111 #  elif (defined(__amd64__) || defined(__x86_64__))
112 ATOMIC_INLINE uint64_t
113 atomic_add_uint64(uint64_t *p, uint64_t x)
114 {
115         asm volatile (
116             "lock; xaddq %0, %1;"
117             : "+r" (x), "=m" (*p) /* Outputs. */
118             : "m" (*p) /* Inputs. */
119             );
120         return (x);
121 }
122
123 ATOMIC_INLINE uint64_t
124 atomic_sub_uint64(uint64_t *p, uint64_t x)
125 {
126         x = (uint64_t)(-(int64_t)x);
127         asm volatile (
128             "lock; xaddq %0, %1;"
129             : "+r" (x), "=m" (*p) /* Outputs. */
130             : "m" (*p) /* Inputs. */
131             );
132         return (x);
133 }
134 #  elif (defined(JEMALLOC_ATOMIC9))
135 ATOMIC_INLINE uint64_t
136 atomic_add_uint64(uint64_t *p, uint64_t x)
137 {
138         /*
139          * atomic_fetchadd_64() doesn't exist, but we only ever use this
140          * function on LP64 systems, so atomic_fetchadd_long() will do.
141          */
142         assert(sizeof(uint64_t) == sizeof(unsigned long));
143
144         return (atomic_fetchadd_long(p, (unsigned long)x) + x);
145 }
146
147 ATOMIC_INLINE uint64_t
148 atomic_sub_uint64(uint64_t *p, uint64_t x)
149 {
150         assert(sizeof(uint64_t) == sizeof(unsigned long));
151
152         return (atomic_fetchadd_long(p, (unsigned long)(-(long)x)) - x);
153 }
154 #  elif (defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_8))
155 ATOMIC_INLINE uint64_t
156 atomic_add_uint64(uint64_t *p, uint64_t x)
157 {
158         return (__sync_add_and_fetch(p, x));
159 }
160
161 ATOMIC_INLINE uint64_t
162 atomic_sub_uint64(uint64_t *p, uint64_t x)
163 {
164         return (__sync_sub_and_fetch(p, x));
165 }
166 #  else
167 #    error "Missing implementation for 64-bit atomic operations"
168 #  endif
169 #endif
170
171 /******************************************************************************/
172 /* 32-bit operations. */
173 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4
174 ATOMIC_INLINE uint32_t
175 atomic_add_uint32(uint32_t *p, uint32_t x)
176 {
177         return (__sync_add_and_fetch(p, x));
178 }
179
180 ATOMIC_INLINE uint32_t
181 atomic_sub_uint32(uint32_t *p, uint32_t x)
182 {
183         return (__sync_sub_and_fetch(p, x));
184 }
185 #elif (defined(_MSC_VER))
186 ATOMIC_INLINE uint32_t
187 atomic_add_uint32(uint32_t *p, uint32_t x)
188 {
189         return (InterlockedExchangeAdd(p, x));
190 }
191
192 ATOMIC_INLINE uint32_t
193 atomic_sub_uint32(uint32_t *p, uint32_t x)
194 {
195         return (InterlockedExchangeAdd(p, -((int32_t)x)));
196 }
197 #elif (defined(__APPLE__))
198 ATOMIC_INLINE uint32_t
199 atomic_add_uint32(uint32_t *p, uint32_t x)
200 {
201         return (uint32_t)(OSAtomicAdd32((int32_t)x, (int32_t *)p));
202 }
203
204 ATOMIC_INLINE uint32_t
205 atomic_sub_uint32(uint32_t *p, uint32_t x)
206 {
207         return (uint32_t)(OSAtomicAdd32(-((int32_t)x), (int32_t *)p));
208 }
209 #elif (defined(__i386__) || defined(__amd64__) || defined(__x86_64__))
210 ATOMIC_INLINE uint32_t
211 atomic_add_uint32(uint32_t *p, uint32_t x)
212 {
213         asm volatile (
214             "lock; xaddl %0, %1;"
215             : "+r" (x), "=m" (*p) /* Outputs. */
216             : "m" (*p) /* Inputs. */
217             );
218         return (x);
219 }
220
221 ATOMIC_INLINE uint32_t
222 atomic_sub_uint32(uint32_t *p, uint32_t x)
223 {
224         x = (uint32_t)(-(int32_t)x);
225         asm volatile (
226             "lock; xaddl %0, %1;"
227             : "+r" (x), "=m" (*p) /* Outputs. */
228             : "m" (*p) /* Inputs. */
229             );
230         return (x);
231 }
232 #elif (defined(JEMALLOC_ATOMIC9))
233 ATOMIC_INLINE uint32_t
234 atomic_add_uint32(uint32_t *p, uint32_t x)
235 {
236         return (atomic_fetchadd_32(p, x) + x);
237 }
238
239 ATOMIC_INLINE uint32_t
240 atomic_sub_uint32(uint32_t *p, uint32_t x)
241 {
242         return (atomic_fetchadd_32(p, (uint32_t)(-(int32_t)x)) - x);
243 }
244 #elif (defined(JE_FORCE_SYNC_COMPARE_AND_SWAP_4))
245 ATOMIC_INLINE uint32_t
246 atomic_add_uint32(uint32_t *p, uint32_t x)
247 {
248         return (__sync_add_and_fetch(p, x));
249 }
250
251 ATOMIC_INLINE uint32_t
252 atomic_sub_uint32(uint32_t *p, uint32_t x)
253 {
254         return (__sync_sub_and_fetch(p, x));
255 }
256 #else
257 #  error "Missing implementation for 32-bit atomic operations"
258 #endif
259
260 /******************************************************************************/
261 /* size_t operations. */
262 ATOMIC_INLINE size_t
263 atomic_add_z(size_t *p, size_t x)
264 {
265         assert(sizeof(size_t) == 1 << LG_SIZEOF_PTR);
266
267 #if (LG_SIZEOF_PTR == 3)
268         return ((size_t)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
269 #elif (LG_SIZEOF_PTR == 2)
270         return ((size_t)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
271 #endif
272 }
273
274 ATOMIC_INLINE size_t
275 atomic_sub_z(size_t *p, size_t x)
276 {
277         assert(sizeof(size_t) == 1 << LG_SIZEOF_PTR);
278
279 #if (LG_SIZEOF_PTR == 3)
280         return ((size_t)atomic_add_uint64((uint64_t *)p,
281             (uint64_t)-((int64_t)x)));
282 #elif (LG_SIZEOF_PTR == 2)
283         return ((size_t)atomic_add_uint32((uint32_t *)p,
284             (uint32_t)-((int32_t)x)));
285 #endif
286 }
287
288 /******************************************************************************/
289 /* unsigned operations. */
290 ATOMIC_INLINE unsigned
291 atomic_add_u(unsigned *p, unsigned x)
292 {
293         assert(sizeof(unsigned) == 1 << LG_SIZEOF_INT);
294
295 #if (LG_SIZEOF_INT == 3)
296         return ((unsigned)atomic_add_uint64((uint64_t *)p, (uint64_t)x));
297 #elif (LG_SIZEOF_INT == 2)
298         return ((unsigned)atomic_add_uint32((uint32_t *)p, (uint32_t)x));
299 #endif
300 }
301
302 ATOMIC_INLINE unsigned
303 atomic_sub_u(unsigned *p, unsigned x)
304 {
305         assert(sizeof(unsigned) == 1 << LG_SIZEOF_INT);
306
307 #if (LG_SIZEOF_INT == 3)
308         return ((unsigned)atomic_add_uint64((uint64_t *)p,
309             (uint64_t)-((int64_t)x)));
310 #elif (LG_SIZEOF_INT == 2)
311         return ((unsigned)atomic_add_uint32((uint32_t *)p,
312             (uint32_t)-((int32_t)x)));
313 #endif
314 }
315
316 #endif /* __ATOMIC_OPS_H__ */