atomic: Separate bool and old-value compare-and-exchange

Some implementations only offer one version of compare-and-exchange,
thus we expose both through cairo-atomic, implementing what is missing
through appropriate fallbacks.
*_cmpxchg() now return a boolean (this unbreaks _cairo_atomic_uint_cmpxchg)
*_cmpxchg_return_old() return the old value
Code is updated everywhere to reflect this, by using *_cmpxchg()
wherever the returned value was only tested to check if the exchange
had really taken place.

Reviewed-by: Chris Wilson <chris@chris-wilson.co.uk>
This commit is contained in:
Andrea Canciani 2010-04-28 16:23:15 +02:00
parent a0bf424b82
commit d66b1ca1cf
6 changed files with 72 additions and 16 deletions

View file

@ -61,7 +61,8 @@ typedef int cairo_atomic_int_t;
# define _cairo_atomic_int_inc(x) ((void) __sync_fetch_and_add(x, 1))
# define _cairo_atomic_int_dec_and_test(x) (__sync_fetch_and_add(x, -1) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) __sync_bool_compare_and_swap (x, oldv, newv)
# define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) __sync_val_compare_and_swap (x, oldv, newv)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef int cairo_atomic_intptr_t;
@ -74,7 +75,10 @@ typedef long long cairo_atomic_intptr_t;
#endif
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
(void*)__sync_val_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
__sync_bool_compare_and_swap ((cairo_atomic_intptr_t*)x, (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
# define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) \
_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))
#endif
@ -89,7 +93,7 @@ typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec_and_test(x) (AO_fetch_and_sub1_full(x) == 1)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) ((cairo_atomic_int_t) AO_compare_and_swap_full(x, oldv, newv) ? oldv : *x)
# define _cairo_atomic_int_cmpxchg(x, oldv, newv) AO_compare_and_swap_full(x, oldv, newv)
#if SIZEOF_VOID_P==SIZEOF_INT
typedef unsigned int cairo_atomic_intptr_t;
@ -101,8 +105,9 @@ typedef unsigned long long cairo_atomic_intptr_t;
#error No matching integer pointer type
#endif
# define _cairo_atomic_ptr_get(x) _cairo_atomic_intptr_to_voidptr (AO_load_full (x))
# define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) \
(void*) (cairo_atomic_intptr_t) _cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
_cairo_atomic_int_cmpxchg ((cairo_atomic_intptr_t*)(x), (cairo_atomic_intptr_t)oldv, (cairo_atomic_intptr_t)newv)
#endif
@ -118,10 +123,13 @@ cairo_private cairo_bool_t
_cairo_atomic_int_dec_and_test (int *x);
cairo_private int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv);
_cairo_atomic_int_cmpxchg_return_old_impl (int *x, int oldv, int newv);
cairo_private void *
_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv);
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_impl (x, oldv, newv)
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_impl (x, oldv, newv)
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_private int
@ -130,6 +138,54 @@ _cairo_atomic_int_get (int *x);
# define _cairo_atomic_int_get(x) (*x)
#endif
#else
/* Workaround GCC complaining about casts */
static cairo_always_inline void *
_cairo_atomic_intptr_to_voidptr (cairo_atomic_intptr_t x)
{
return (void *) x;
}
static cairo_always_inline cairo_atomic_int_t
_cairo_atomic_int_cmpxchg_return_old_fallback(cairo_atomic_int_t *x, cairo_atomic_int_t oldv, cairo_atomic_int_t newv)
{
cairo_atomic_int_t curr;
do {
curr = _cairo_atomic_int_get (x);
} while (curr == oldv && !_cairo_atomic_int_cmpxchg (x, oldv, newv));
return curr;
}
static cairo_always_inline void *
_cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
{
void *curr;
do {
curr = _cairo_atomic_ptr_get (x);
} while (curr == oldv && !_cairo_atomic_ptr_cmpxchg (x, oldv, newv));
return curr;
}
#endif
#ifndef _cairo_atomic_int_cmpxchg_return_old
#define _cairo_atomic_int_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_int_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
#ifndef _cairo_atomic_ptr_cmpxchg_return_old
#define _cairo_atomic_ptr_cmpxchg_return_old(x, oldv, newv) _cairo_atomic_ptr_cmpxchg_return_old_fallback (x, oldv, newv)
#endif
#ifndef _cairo_atomic_int_cmpxchg
#define _cairo_atomic_int_cmpxchg(x, oldv, newv) (_cairo_atomic_int_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
#ifndef _cairo_atomic_ptr_cmpxchg
#define _cairo_atomic_ptr_cmpxchg(x, oldv, newv) (_cairo_atomic_ptr_cmpxchg_return_old (x, oldv, newv) == oldv)
#endif
#define _cairo_atomic_uint_get(x) _cairo_atomic_int_get(x)

View file

@ -62,7 +62,7 @@ _cairo_atomic_int_dec_and_test (int *x)
}
int
_cairo_atomic_int_cmpxchg (int *x, int oldv, int newv)
_cairo_atomic_int_cmpxchg_return_old_impl (int *x, int oldv, int newv)
{
int ret;
@ -76,7 +76,7 @@ _cairo_atomic_int_cmpxchg (int *x, int oldv, int newv)
}
void *
_cairo_atomic_ptr_cmpxchg (void **x, void *oldv, void *newv)
_cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv)
{
void *ret;

View file

@ -53,13 +53,13 @@ typedef struct {
static inline void *
_atomic_fetch (void **slot)
{
return _cairo_atomic_ptr_cmpxchg (slot, *slot, NULL);
return _cairo_atomic_ptr_cmpxchg_return_old (slot, *slot, NULL);
}
static inline cairo_bool_t
_atomic_store (void **slot, void *ptr)
{
return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr) == NULL;
return _cairo_atomic_ptr_cmpxchg (slot, NULL, ptr);
}
cairo_private void *

View file

@ -873,7 +873,7 @@ _pixman_transparent_image (void)
image = pixman_image_create_solid_fill (&color);
if (_cairo_atomic_ptr_cmpxchg (&__pixman_transparent_image,
NULL, image) == NULL)
NULL, image))
{
pixman_image_ref (image);
}
@ -902,7 +902,7 @@ _pixman_black_image (void)
image = pixman_image_create_solid_fill (&color);
if (_cairo_atomic_ptr_cmpxchg (&__pixman_black_image,
NULL, image) == NULL)
NULL, image))
{
pixman_image_ref (image);
}
@ -931,7 +931,7 @@ _pixman_white_image (void)
image = pixman_image_create_solid_fill (&color);
if (_cairo_atomic_ptr_cmpxchg (&__pixman_white_image,
NULL, image) == NULL)
NULL, image))
{
pixman_image_ref (image);
}

View file

@ -142,7 +142,7 @@ _context_get (void)
return malloc (sizeof (cairo_t));
new = old | (1 << avail);
} while (_cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new) != old);
} while (! _cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new));
return &_context_stash.pool[avail];
}
@ -163,7 +163,7 @@ _context_put (cairo_t *cr)
do {
old = _cairo_atomic_int_get (&_context_stash.occupied);
new = old & avail;
} while (_cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new) != old);
} while (! _cairo_atomic_int_cmpxchg (&_context_stash.occupied, old, new));
}
#else
#define _context_get() malloc (sizeof (cairo_t))

View file

@ -84,7 +84,7 @@ _device_finish (void *abstract_device)
CAIRO_MUTEX_UNLOCK (_cairo_drm_device_mutex);
if (_cairo_atomic_ptr_cmpxchg (&_cairo_drm_default_device,
device, NULL) == device)
device, NULL))
{
cairo_device_destroy (&device->base);
}