Line data Source code
1 : /* cairo - a vector graphics library with display and print output
2 : *
3 : * Copyright © 2007 Chris Wilson
4 : * Copyright © 2010 Andrea Canciani
5 : *
6 : * This library is free software; you can redistribute it and/or
7 : * modify it either under the terms of the GNU Lesser General Public
8 : * License version 2.1 as published by the Free Software Foundation
9 : * (the "LGPL") or, at your option, under the terms of the Mozilla
10 : * Public License Version 1.1 (the "MPL"). If you do not alter this
11 : * notice, a recipient may use your version of this file under either
12 : * the MPL or the LGPL.
13 : *
14 : * You should have received a copy of the LGPL along with this library
15 : * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 : * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 : * You should have received a copy of the MPL along with this library
18 : * in the file COPYING-MPL-1.1
19 : *
20 : * The contents of this file are subject to the Mozilla Public License
21 : * Version 1.1 (the "License"); you may not use this file except in
22 : * compliance with the License. You may obtain a copy of the License at
23 : * http://www.mozilla.org/MPL/
24 : *
25 : * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 : * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 : * the specific language governing rights and limitations.
28 : *
29 : * The Original Code is the cairo graphics library.
30 : *
31 : * The Initial Developer of the Original Code is University of Southern
32 : * California.
33 : *
34 : * Contributor(s):
35 : * Chris Wilson <chris@chris-wilson.co.uk>
36 : * Andrea Canciani <ranma42@gmail.com>
37 : */
38 :
39 : #ifndef CAIRO_ATOMIC_PRIVATE_H
40 : #define CAIRO_ATOMIC_PRIVATE_H
41 :
42 : # include "cairo-compiler-private.h"
43 :
44 : #if HAVE_CONFIG_H
45 : #include "config.h"
46 : #endif
47 :
48 : #if HAVE_WIN32_ATOMIC_PRIMITIVES
49 : #include <Windows.h>
50 : #endif
51 :
52 : /* The autoconf on OpenBSD 4.5 produces the malformed constant name
53 : * SIZEOF_VOID__ rather than SIZEOF_VOID_P. Work around that here. */
54 : #if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__)
55 : # define SIZEOF_VOID_P SIZEOF_VOID__
56 : #endif
57 :
58 : CAIRO_BEGIN_DECLS
59 :
60 : /* C++11 atomic primitives were designed to be more flexible than the
61 : * __sync_* family of primitives. Despite the name, they are available
62 : * in C as well as C++. The motivating reason for using them is that
63 : * for _cairo_atomic_{int,ptr}_get, the compiler is able to see that
64 : * the load is intended to be atomic, as opposed to the __sync_*
65 : * version, below, where the load looks like a plain load. Having
66 : * the load appear atomic to the compiler is particular important for
67 : * tools like ThreadSanitizer so they don't report false positives on
68 : * memory operations that we intend to be atomic.
69 : */
70 : #if HAVE_CXX11_ATOMIC_PRIMITIVES
71 :
72 : #define HAS_ATOMIC_OPS 1
73 :
74 : typedef int cairo_atomic_int_t;
75 :
76 : static cairo_always_inline cairo_atomic_int_t
77 : _cairo_atomic_int_get (cairo_atomic_int_t *x)
78 : {
79 232 : return __atomic_load_n(x, __ATOMIC_SEQ_CST);
80 : }
81 :
82 : static cairo_always_inline cairo_atomic_int_t
83 : _cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
84 : {
85 0 : return __atomic_load_n(x, __ATOMIC_RELAXED);
86 : }
87 :
88 : static cairo_always_inline void
89 : _cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
90 : {
91 0 : __atomic_store_n(x, val, __ATOMIC_RELAXED);
92 : }
93 :
94 : static cairo_always_inline void *
95 : _cairo_atomic_ptr_get (void **x)
96 : {
97 0 : return __atomic_load_n(x, __ATOMIC_SEQ_CST);
98 : }
99 :
100 : # define _cairo_atomic_int_inc(x) ((void) __atomic_fetch_add(x, 1, __ATOMIC_SEQ_CST))
101 : # define _cairo_atomic_int_dec(x) ((void) __atomic_fetch_sub(x, 1, __ATOMIC_SEQ_CST))
102 : # define _cairo_atomic_int_dec_and_test(x) (__atomic_fetch_sub(x, 1, __ATOMIC_SEQ_CST) == 1)
103 :
104 : #if SIZEOF_VOID_P==SIZEOF_INT
105 : typedef int cairo_atomic_intptr_t;
106 : #elif SIZEOF_VOID_P==SIZEOF_LONG
107 : typedef long cairo_atomic_intptr_t;
108 : #elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
109 : typedef long long cairo_atomic_intptr_t;
110 : #else
111 : #error No matching integer pointer type
112 : #endif
113 :
114 : static cairo_always_inline cairo_bool_t
115 : _cairo_atomic_int_cmpxchg_impl(cairo_atomic_int_t *x,
116 : cairo_atomic_int_t oldv,
117 : cairo_atomic_int_t newv)
118 : {
119 5 : cairo_atomic_int_t expected = oldv;
120 5 : return __atomic_compare_exchange_n(x, &expected, newv, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
121 : }
122 :
123 : #define _cairo_atomic_int_cmpxchg(x, oldv, newv) \
124 : _cairo_atomic_int_cmpxchg_impl(x, oldv, newv)
125 :
126 : static cairo_always_inline cairo_atomic_int_t
127 : _cairo_atomic_int_cmpxchg_return_old_impl(cairo_atomic_int_t *x,
128 : cairo_atomic_int_t oldv,
129 : cairo_atomic_int_t newv)
130 : {
131 : cairo_atomic_int_t expected = oldv;
132 : (void) __atomic_compare_exchange_n(x, &expected, newv, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
133 : return expected;
134 : }
135 :
136 : #define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) \
137 : _cairo_atomic_int_cmpxchg_return_old_impl(x, oldv, newv)
138 :
139 : static cairo_always_inline cairo_bool_t
140 : _cairo_atomic_ptr_cmpxchg_impl(void **x, void *oldv, void *newv)
141 : {
142 0 : void *expected = oldv;
143 0 : return __atomic_compare_exchange_n(x, &expected, newv, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
144 : }
145 :
146 : #define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
147 : _cairo_atomic_ptr_cmpxchg_impl(x, oldv, newv)
148 :
149 : static cairo_always_inline void *
150 : _cairo_atomic_ptr_cmpxchg_return_old_impl(void **x, void *oldv, void *newv)
151 : {
152 : void *expected = oldv;
153 : (void) __atomic_compare_exchange_n(x, &expected, newv, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
154 : return expected;
155 : }
156 :
157 : #define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
158 : _cairo_atomic_ptr_cmpxchg_return_old_impl(x, oldv, newv)
159 :
160 : #endif
161 :
162 : #if HAVE_WIN32_ATOMIC_PRIMITIVES
163 :
164 : #define HAS_ATOMIC_OPS 1
165 :
166 : typedef volatile long cairo_atomic_int_t;
167 :
168 : # define _cairo_atomic_int_get(x) ((int)*x)
169 : # define _cairo_atomic_int_get_relaxed(x) ((int)*(x))
170 : # define _cairo_atomic_int_set_relaxed(x, val) (*(x) = (val))
171 : # define _cairo_atomic_ptr_get(x) ((void*)*x)
172 :
173 : # define _cairo_atomic_int_inc(x) ((void) InterlockedIncrement(x))
174 : # define _cairo_atomic_int_dec(x) ((void) InterlockedDecrement(x))
175 : # define _cairo_atomic_int_dec_and_test(x) (InterlockedDecrement(x) == 0)
176 : # define _cairo_atomic_int_cmpxchg(x, oldv, newv) (InterlockedCompareExchange(x, newv, oldv) == oldv)
177 : # define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) InterlockedCompareExchange(x, newv, oldv)
178 :
179 : typedef volatile void* cairo_atomic_intptr_t;
180 :
181 : #define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (InterlockedCompareExchangePointer(x, newv, oldv) == oldv)
182 : #define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) (InterlockedCompareExchangePointer(x, newv, oldv))
183 :
184 : #endif
185 :
186 : #if HAVE_INTEL_ATOMIC_PRIMITIVES
187 :
188 : #define HAS_ATOMIC_OPS 1
189 :
190 : typedef int cairo_atomic_int_t;
191 :
192 : #ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
193 : static cairo_always_inline cairo_atomic_int_t
194 : _cairo_atomic_int_get (cairo_atomic_int_t *x)
195 : {
196 : __sync_synchronize ();
197 : return *x;
198 : }
199 :
200 : static cairo_always_inline cairo_atomic_int_t
201 : _cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
202 : {
203 : return *x;
204 : }
205 :
206 : static cairo_always_inline void
207 : _cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
208 : {
209 : *x = val;
210 : }
211 :
212 : static cairo_always_inline void *
213 : _cairo_atomic_ptr_get (void **x)
214 : {
215 : __sync_synchronize ();
216 : return *x;
217 : }
218 : #else
219 : # define _cairo_atomic_int_get(x) (*x)
220 : # define _cairo_atomic_int_get_relaxed(x) (*(x))
221 : # define _cairo_atomic_int_set_relaxed(x, val) (*(x) = (val))
222 : # define _cairo_atomic_ptr_get(x) (*x)
223 : #endif
224 :
225 : # define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
226 : # define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
227 : # define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
228 : # define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
229 :
230 : #if SIZEOF_VOID_P==SIZEOF_INT
231 : typedef int cairo_atomic_intptr_t;
232 : #elif SIZEOF_VOID_P==SIZEOF_LONG
233 : typedef long cairo_atomic_intptr_t;
234 : #elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
235 : typedef long long cairo_atomic_intptr_t;
236 : #else
237 : #error No matching integer pointer type
238 : #endif
239 :
240 : # define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
241 : __sync_bool_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
242 :
243 : # define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
244 : _cairo_atomic_intptr_to_voidptr (__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv))
245 :
246 : #endif
247 :
248 : #if HAVE_LIB_ATOMIC_OPS
249 : #include <atomic_ops.h>
250 :
251 : #define HAS_ATOMIC_OPS 1
252 :
253 : typedef AO_t cairo_atomic_int_t;
254 :
255 : # define _cairo_atomic_int_get(x) (AO_load_full (x))
256 : # define _cairo_atomic_int_get_relaxed(x) (AO_load_full (x))
257 : # define _cairo_atomic_int_set_relaxed(x, val) (AO_store_full ((x), (val)))
258 :
259 : # define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
260 : # define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
261 : # define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
262 :
263 : #if SIZEOF_VOID_P==SIZEOF_INT
264 : typedef unsigned int cairo_atomic_intptr_t;
265 : #elif SIZEOF_VOID_P==SIZEOF_LONG
266 : typedef unsigned long cairo_atomic_intptr_t;
267 : #elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
268 : typedef unsigned long long cairo_atomic_intptr_t;
269 : #else
270 : #error No matching integer pointer type
271 : #endif
272 :
273 : # define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x))
274 : # define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
275 : _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
276 :
277 : #endif
278 :
279 : #if HAVE_OS_ATOMIC_OPS
280 : #include <libkern/OSAtomic.h>
281 :
282 : #define HAS_ATOMIC_OPS 1
283 :
284 : typedef int32_t cairo_atomic_int_t;
285 :
286 : # define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
287 : # define _cairo_atomic_int_get_relaxed(x) (*(x))
288 : # define _cairo_atomic_int_set_relaxed(x, val) (*(x) = (val))
289 :
290 : # define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
291 : # define _cairo_atomic_int_dec_and_test(x) (OSAtomicDecrement32Barrier (x) == 0)
292 : # define _cairo_atomic_int_cmpxchg(x, oldv, newv) OSAtomicCompareAndSwap32Barrier(oldv, newv, x)
293 :
294 : #if SIZEOF_VOID_P==4
295 : typedef int32_t cairo_atomic_intptr_t;
296 : # define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
297 : OSAtomicCompareAndSwap32Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
298 :
299 : #elif SIZEOF_VOID_P==8
300 : typedef int64_t cairo_atomic_intptr_t;
301 : # define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
302 : OSAtomicCompareAndSwap64Barrier((cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv, (cairo_atomic_intptr_t *)x)
303 :
304 : #else
305 : #error No matching integer pointer type
306 : #endif
307 :
308 : # define _cairo_atomic_ptr_get(x) (OSMemoryBarrier(), *(x))
309 :
310 : #endif
311 :
312 : #ifndef HAS_ATOMIC_OPS
313 :
314 : #if SIZEOF_VOID_P==SIZEOF_INT
315 : typedef unsigned int cairo_atomic_intptr_t;
316 : #elif SIZEOF_VOID_P==SIZEOF_LONG
317 : typedef unsigned long cairo_atomic_intptr_t;
318 : #elif SIZEOF_VOID_P==SIZEOF_LONG_LONG
319 : typedef unsigned long long cairo_atomic_intptr_t;
320 : #else
321 : #error No matching integer pointer type
322 : #endif
323 :
324 : typedef cairo_atomic_intptr_t cairo_atomic_int_t;
325 :
326 : cairo_private void
327 : _cairo_atomic_int_inc (cairo_atomic_int_t *x);
328 :
329 : cairo_private cairo_bool_t
330 : _cairo_atomic_int_dec_and_test (cairo_atomic_int_t *x);
331 :
332 : cairo_private cairo_atomic_int_t
333 : _cairo_atomic_int_cmpxchg_return_old_impl (cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv);
334 :
335 : cairo_private void *
336 : _cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
337 :
338 : #define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_impl (x, oldv, newv)
339 : #define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_impl (x, oldv, newv)
340 :
341 : #ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
342 : cairo_private cairo_atomic_int_t
343 : _cairo_atomic_int_get (cairo_atomic_int_t *x);
344 : cairo_private cairo_atomic_int_t
345 : _cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x);
346 : void
347 : _cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val);
348 : # define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
349 : #else
350 : # define _cairo_atomic_int_get(x) (*x)
351 : # define _cairo_atomic_int_get_relaxed(x) (*(x))
352 : # define _cairo_atomic_int_set_relaxed(x, val) (*(x) = (val))
353 : # define _cairo_atomic_ptr_get(x) (*x)
354 : #endif
355 :
356 : #else
357 :
358 : /* Workaround GCC complaining about casts */
359 : static cairo_always_inline void *
360 : _cairo_atomic_intptr_to_voidptr (cairo_atomic_intptr_t x)
361 : {
362 : return (void *) x;
363 : }
364 :
365 : static cairo_always_inline cairo_atomic_int_t
366 : _cairo_atomic_int_cmpxchg_return_old_fallback(cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv)
367 : {
368 : cairo_atomic_int_t curr;
369 :
370 : do {
371 : curr = _cairo_atomic_int_get (x);
372 : } while (curr == oldv && !_cairo_atomic_int_cmpxchg (x, oldv, newv));
373 :
374 : return curr;
375 : }
376 :
377 : static cairo_always_inline void *
378 : _cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
379 : {
380 : void *curr;
381 :
382 : do {
383 : curr = _cairo_atomic_ptr_get (x);
384 : } while (curr == oldv && !_cairo_atomic_ptr_cmpxchg (x, oldv, newv));
385 :
386 : return curr;
387 : }
388 : #endif
389 :
390 : #ifndef _cairo_atomic_int_cmpxchg_return_old
391 : #define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_fallback (x, oldv, newv)
392 : #endif
393 :
394 : #ifndef _cairo_atomic_ptr_cmpxchg_return_old
395 : #define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_fallback (x, oldv, newv)
396 : #endif
397 :
398 : #ifndef _cairo_atomic_int_cmpxchg
399 : #define _cairo_atomic_int_cmpxchg(x, oldv, newv) (_cairo_atomic_int_cmpxchg_return_old (x, oldv, newv) == oldv)
400 : #endif
401 :
402 : #ifndef _cairo_atomic_ptr_cmpxchg
403 : #define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (_cairo_atomic_ptr_cmpxchg_return_old (x, oldv, newv) == oldv)
404 : #endif
405 :
406 : #define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)
407 : #define _cairo_atomic_uint_cmpxchg(x, oldv, newv) \
408 : _cairo_atomic_int_cmpxchg((cairo_atomic_int_t *)x, oldv, newv)
409 :
410 : #define _cairo_status_set_error(status, err) do { \
411 : /* hide compiler warnings about cairo_status_t != int (gcc treats its as \
412 : * an unsigned integer instead, and about ignoring the return value. */ \
413 : int ret__ = _cairo_atomic_int_cmpxchg ((cairo_atomic_int_t *) status, CAIRO_STATUS_SUCCESS, err); \
414 : (void) ret__; \
415 : } while (0)
416 :
417 : CAIRO_END_DECLS
418 :
419 : #endif
|