[cairo-commit] src/cairo-atomic-private.h src/cairo-atomic.c src/cairo-freed-pool-private.h src/cairo-freed-pool.c
Uli Schlachter
psychon at kemper.freedesktop.org
Sat Mar 5 13:36:49 UTC 2016
src/cairo-atomic-private.h | 36 ++++++++++++++++++++++++++++++++++++
src/cairo-atomic.c | 14 ++++++++++++++
src/cairo-freed-pool-private.h | 10 +++++-----
src/cairo-freed-pool.c | 10 +++++-----
4 files changed, 60 insertions(+), 10 deletions(-)
New commits:
commit 3538ac3e68f997d95d76865247717c90ae73630d
Author: Wan-Teh Chang <wtc at google.com>
Date: Tue Mar 1 17:48:55 2016 -0800
Fix data race in freed_pool
This adds _cairo_atomic_int_get_relaxed and _cairo_atomic_int_set_relaxed which
are meant to have a behaviour of relaxed read/writes in C11's memory model. This
patch also uses these new function to fix a data race with freed_pool_t's |top|
data member.
Fixes: https://bugs.freedesktop.org/show_bug.cgi?id=90318
Signed-off-by: Wan-Teh Chang <wtc at google.com>
Signed-off-by: Uli Schlachter <psychon at znc.in>
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index 11b2887..5001290 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -75,6 +75,18 @@ _cairo_atomic_int_get (cairo_atomic_int_t *x)
return __atomic_load_n(x, __ATOMIC_SEQ_CST);
}
+static cairo_always_inline cairo_atomic_int_t
+_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
+{
+ return __atomic_load_n(x, __ATOMIC_RELAXED);
+}
+
+static cairo_always_inline void
+_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
+{
+ __atomic_store_n(x, val, __ATOMIC_RELAXED);
+}
+
static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
@@ -157,6 +169,18 @@ _cairo_atomic_int_get (cairo_atomic_int_t *x)
return *x;
}
+static cairo_always_inline cairo_atomic_int_t
+_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x)
+{
+ return *x;
+}
+
+static cairo_always_inline void
+_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val)
+{
+ *x = val;
+}
+
static cairo_always_inline void *
_cairo_atomic_ptr_get (void **x)
{
@@ -165,6 +189,8 @@ _cairo_atomic_ptr_get (void **x)
}
#else
# define _cairo_atomic_int_get(x) (*x)
+# define _cairo_atomic_int_get_relaxed(x) (*x)
+# define _cairo_atomic_int_set_relaxed(x, val) (*x) = (val)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
@@ -200,6 +226,8 @@ typedef long long cairo_atomic_intptr_t;
typedef AO_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (AO_load_full (x))
+# define _cairo_atomic_int_get_relaxed(x) (AO_load_full (x))
+# define _cairo_atomic_int_set_relaxed(x, val) (AO_store_full ((x), (val)))
# define _cairo_atomic_int_inc(x) ((void) AO_fetch_and_add1_full(x))
# define _cairo_atomic_int_dec(x) ((void) AO_fetch_and_sub1_full(x))
@@ -230,6 +258,8 @@ typedef unsigned long long cairo_atomic_intptr_t;
typedef int32_t cairo_atomic_int_t;
# define _cairo_atomic_int_get(x) (OSMemoryBarrier(), *(x))
+# define _cairo_atomic_int_get_relaxed(x) *(x)
+# define _cairo_atomic_int_set_relaxed(x, val) *(x) = (val)
# define _cairo_atomic_int_inc(x) ((void) OSAtomicIncrement32Barrier (x))
# define _cairo_atomic_int_dec(x) ((void) OSAtomicDecrement32Barrier (x))
@@ -288,9 +318,15 @@ _cairo_atomic_ptr_cmpxchg_return_old_impl (void **x, void *oldv, void *newv);
#ifdef ATOMIC_OP_NEEDS_MEMORY_BARRIER
cairo_private cairo_atomic_int_t
_cairo_atomic_int_get (cairo_atomic_int_t *x);
+cairo_private cairo_atomic_int_t
+_cairo_atomic_int_get_relaxed (cairo_atomic_int_t *x);
+void
+_cairo_atomic_int_set_relaxed (cairo_atomic_int_t *x, cairo_atomic_int_t val);
# define _cairo_atomic_ptr_get(x) (void *) _cairo_atomic_int_get((cairo_atomic_int_t *) x)
#else
# define _cairo_atomic_int_get(x) (*x)
+# define _cairo_atomic_int_get_relaxed(x) (*x)
+# define _cairo_atomic_int_set_relaxed(x, val) (*x) = (val)
# define _cairo_atomic_ptr_get(x) (*x)
#endif
diff --git a/src/cairo-atomic.c b/src/cairo-atomic.c
index 909cfea..2af50cd 100644
--- a/src/cairo-atomic.c
+++ b/src/cairo-atomic.c
@@ -101,6 +101,20 @@ _cairo_atomic_int_get (cairo_atomic_intptr_t *x)
return ret;
}
+
+cairo_atomic_intptr_t
+_cairo_atomic_int_get_relaxed (cairo_atomic_intptr_t *x)
+{
+ return _cairo_atomic_int_get (x);
+}
+
+void
+_cairo_atomic_int_set_relaxed (cairo_atomic_intptr_t *x, cairo_atomic_intptr_t val)
+{
+ CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
+ *x = val;
+ CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
+}
#endif
#endif
diff --git a/src/cairo-freed-pool-private.h b/src/cairo-freed-pool-private.h
index 0ec6de3..8a7af52 100644
--- a/src/cairo-freed-pool-private.h
+++ b/src/cairo-freed-pool-private.h
@@ -51,7 +51,7 @@ CAIRO_BEGIN_DECLS
#define MAX_FREED_POOL_SIZE 16
typedef struct {
void *pool[MAX_FREED_POOL_SIZE];
- int top;
+ cairo_atomic_int_t top;
} freed_pool_t;
static cairo_always_inline void *
@@ -81,13 +81,13 @@ _freed_pool_get (freed_pool_t *pool)
void *ptr;
int i;
- i = pool->top - 1;
+ i = _cairo_atomic_int_get_relaxed (&pool->top) - 1;
if (i < 0)
i = 0;
ptr = _atomic_fetch (&pool->pool[i]);
if (likely (ptr != NULL)) {
- pool->top = i;
+ _cairo_atomic_int_set_relaxed (&pool->top, i);
return ptr;
}
@@ -103,11 +103,11 @@ _freed_pool_put (freed_pool_t *pool, void *ptr)
{
int i;
- i = pool->top;
+ i = _cairo_atomic_int_get_relaxed (&pool->top);
if (likely (i < ARRAY_LENGTH (pool->pool) &&
_atomic_store (&pool->pool[i], ptr)))
{
- pool->top = i + 1;
+ _cairo_atomic_int_set_relaxed (&pool->top, i + 1);
return;
}
diff --git a/src/cairo-freed-pool.c b/src/cairo-freed-pool.c
index cfdc8e9..5b1c4c0 100644
--- a/src/cairo-freed-pool.c
+++ b/src/cairo-freed-pool.c
@@ -50,13 +50,13 @@ _freed_pool_get_search (freed_pool_t *pool)
for (i = ARRAY_LENGTH (pool->pool); i--;) {
ptr = _atomic_fetch (&pool->pool[i]);
if (ptr != NULL) {
- pool->top = i;
+ _cairo_atomic_int_set_relaxed (&pool->top, i);
return ptr;
}
}
/* empty */
- pool->top = 0;
+ _cairo_atomic_int_set_relaxed (&pool->top, 0);
return NULL;
}
@@ -67,13 +67,13 @@ _freed_pool_put_search (freed_pool_t *pool, void *ptr)
for (i = 0; i < ARRAY_LENGTH (pool->pool); i++) {
if (_atomic_store (&pool->pool[i], ptr)) {
- pool->top = i + 1;
+ _cairo_atomic_int_set_relaxed (&pool->top, i + 1);
return;
}
}
/* full */
- pool->top = i;
+ _cairo_atomic_int_set_relaxed (&pool->top, i);
free (ptr);
}
@@ -87,7 +87,7 @@ _freed_pool_reset (freed_pool_t *pool)
pool->pool[i] = NULL;
}
- pool->top = 0;
+ _cairo_atomic_int_set_relaxed (&pool->top, 0);
}
#endif
More information about the cairo-commit
mailing list