[cairo-commit] src/cairo-atomic-private.h src/cairo-gl-msaa-compositor.c src/cairo-gl-spans-compositor.c src/cairo-gl-traps-compositor.c src/cairo-image-compositor.c src/cairo-image-mask-compositor.c src/cairo-xlib-core-compositor.c src/cairo-xlib-render-compositor.c src/test-null-compositor-surface.c src/win32

Adrian Johnson ajohnson at kemper.freedesktop.org
Sun Oct 15 08:26:25 UTC 2017


 src/cairo-atomic-private.h             |   33 +++++++++++++++++++++++++++++++++
 src/cairo-gl-msaa-compositor.c         |    5 ++++-
 src/cairo-gl-spans-compositor.c        |    5 ++++-
 src/cairo-gl-traps-compositor.c        |    5 ++++-
 src/cairo-image-compositor.c           |   19 ++++++++++++++-----
 src/cairo-image-mask-compositor.c      |    5 ++++-
 src/cairo-xlib-core-compositor.c       |    5 ++++-
 src/cairo-xlib-render-compositor.c     |   10 ++++++++--
 src/test-null-compositor-surface.c     |   10 ++++++++--
 src/win32/cairo-win32-gdi-compositor.c |    5 ++++-
 10 files changed, 87 insertions(+), 15 deletions(-)

New commits:
commit 90104809b0e03d28ac1152034fd4f05fc8e97b9a
Author: Mikhail Fludkov <misha at pexip.com>
Date:   Fri Oct 6 13:47:51 2017 +0200

    Surround initialisations with atomic critical section
    
    Fixes the race condition when one thread uses cairo_mask_compositor_t
    pointer returned by _cairo_image_mask_compositor_get, while another one
    started but has not finished it's initialisation yet
    
    Usage:
    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
    if (_cairo_atomic_init_once_enter(&once)) {
        /* Initialization code */
        _cairo_atomic_init_once_leave(&once);
    }
    
    https://bugs.freedesktop.org/show_bug.cgi?id=103037

diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
index 50012903..723a326c 100644
--- a/src/cairo-atomic-private.h
+++ b/src/cairo-atomic-private.h
@@ -45,6 +45,8 @@
 #include "config.h"
 #endif
 
+#include <assert.h>
+
 /* The autoconf on OpenBSD 4.5 produces the malformed constant name
  * SIZEOF_VOID__ rather than SIZEOF_VOID_P.  Work around that here. */
 #if !defined(SIZEOF_VOID_P) && defined(SIZEOF_VOID__)
@@ -393,6 +395,37 @@ _cairo_atomic_ptr_cmpxchg_return_old_fallback(void **x, void *oldv, void *newv)
     (void) ret__; \
 } while (0)
 
+typedef cairo_atomic_int_t cairo_atomic_once_t;
+
+#define CAIRO_ATOMIC_ONCE_UNINITIALIZED (0)
+#define CAIRO_ATOMIC_ONCE_INITIALIZING  (1)
+#define CAIRO_ATOMIC_ONCE_INITIALIZED   (2)
+#define CAIRO_ATOMIC_ONCE_INIT          CAIRO_ATOMIC_ONCE_UNINITIALIZED
+
+static cairo_always_inline cairo_bool_t
+_cairo_atomic_init_once_enter(cairo_atomic_once_t *once)
+{
+    if (likely(_cairo_atomic_int_get(once) == CAIRO_ATOMIC_ONCE_INITIALIZED))
+	return 0;
+
+    if (_cairo_atomic_int_cmpxchg(once,
+				  CAIRO_ATOMIC_ONCE_UNINITIALIZED,
+				  CAIRO_ATOMIC_ONCE_INITIALIZING))
+	return 1;
+
+    while (_cairo_atomic_int_get(once) != CAIRO_ATOMIC_ONCE_INITIALIZED) {}
+    return 0;
+}
+
+static cairo_always_inline void
+_cairo_atomic_init_once_leave(cairo_atomic_once_t *once)
+{
+    if (unlikely(!_cairo_atomic_int_cmpxchg(once,
+					    CAIRO_ATOMIC_ONCE_INITIALIZING,
+					    CAIRO_ATOMIC_ONCE_INITIALIZED)))
+	assert (0 && "incorrect use of _cairo_atomic_init_once API (once != CAIRO_ATOMIC_ONCE_INITIALIZING)");
+}
+
 CAIRO_END_DECLS
 
 #endif
diff --git a/src/cairo-gl-msaa-compositor.c b/src/cairo-gl-msaa-compositor.c
index f9cd7c29..00150df0 100644
--- a/src/cairo-gl-msaa-compositor.c
+++ b/src/cairo-gl-msaa-compositor.c
@@ -944,10 +944,13 @@ _cairo_gl_msaa_compositor_init (cairo_compositor_t	 *compositor,
 const cairo_compositor_t *
 _cairo_gl_msaa_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_compositor_t compositor;
-    if (compositor.delegate == NULL)
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_gl_msaa_compositor_init (&compositor,
 					_cairo_gl_span_compositor_get ());
+	_cairo_atomic_init_once_leave(&once);
+    }
 
     return &compositor;
 }
diff --git a/src/cairo-gl-spans-compositor.c b/src/cairo-gl-spans-compositor.c
index 4317ccd0..46ddc982 100644
--- a/src/cairo-gl-spans-compositor.c
+++ b/src/cairo-gl-spans-compositor.c
@@ -528,10 +528,11 @@ _cairo_gl_span_renderer_fini (cairo_abstract_span_renderer_t *_r,
 const cairo_compositor_t *
 _cairo_gl_span_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_spans_compositor_t spans;
     static cairo_compositor_t shape;
 
-    if (spans.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	/* The fallback to traps here is essentially just for glyphs... */
 	_cairo_shape_mask_compositor_init (&shape,
 					   _cairo_gl_traps_compositor_get());
@@ -547,6 +548,8 @@ _cairo_gl_span_compositor_get (void)
 	//spans.check_span_renderer = check_span_renderer;
 	spans.renderer_init = _cairo_gl_span_renderer_init;
 	spans.renderer_fini = _cairo_gl_span_renderer_fini;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &spans.base;
diff --git a/src/cairo-gl-traps-compositor.c b/src/cairo-gl-traps-compositor.c
index 1e11006e..928f0189 100644
--- a/src/cairo-gl-traps-compositor.c
+++ b/src/cairo-gl-traps-compositor.c
@@ -500,9 +500,10 @@ check_composite (const cairo_composite_rectangles_t *extents)
 const cairo_compositor_t *
 _cairo_gl_traps_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_traps_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_traps_compositor_init (&compositor, &_cairo_fallback_compositor);
 	compositor.acquire = acquire;
 	compositor.release = release;
@@ -522,6 +523,8 @@ _cairo_gl_traps_compositor_get (void)
 	compositor.composite_tristrip = composite_tristrip;
 	compositor.check_composite_glyphs = _cairo_gl_check_composite_glyphs;
 	compositor.composite_glyphs = _cairo_gl_composite_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
diff --git a/src/cairo-image-compositor.c b/src/cairo-image-compositor.c
index bfa1e92d..2d25a31b 100644
--- a/src/cairo-image-compositor.c
+++ b/src/cairo-image-compositor.c
@@ -1244,11 +1244,12 @@ check_composite (const cairo_composite_rectangles_t *extents)
 const cairo_compositor_t *
 _cairo_image_traps_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_traps_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
-	_cairo_traps_compositor_init (&compositor,
-				      &__cairo_no_compositor);
+    if (_cairo_atomic_init_once_enter(&once)) {
+	_cairo_traps_compositor_init(&compositor,
+				     &__cairo_no_compositor);
 	compositor.acquire = acquire;
 	compositor.release = release;
 	compositor.set_clip_region = set_clip_region;
@@ -1269,6 +1270,8 @@ _cairo_image_traps_compositor_get (void)
 #endif
 	compositor.check_composite_glyphs = check_composite_glyphs;
 	compositor.composite_glyphs = composite_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
@@ -1277,9 +1280,10 @@ _cairo_image_traps_compositor_get (void)
 const cairo_compositor_t *
 _cairo_image_mask_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_mask_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_mask_compositor_init (&compositor,
 				     _cairo_image_traps_compositor_get ());
 	compositor.acquire = acquire;
@@ -1296,6 +1300,8 @@ _cairo_image_mask_compositor_get (void)
 	compositor.composite_boxes = composite_boxes;
 	compositor.check_composite_glyphs = check_composite_glyphs;
 	compositor.composite_glyphs = composite_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
@@ -3105,10 +3111,11 @@ span_renderer_fini (cairo_abstract_span_renderer_t *_r,
 const cairo_compositor_t *
 _cairo_image_spans_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_spans_compositor_t spans;
     static cairo_compositor_t shape;
 
-    if (spans.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_shape_mask_compositor_init (&shape,
 					   _cairo_image_traps_compositor_get());
 	shape.glyphs = NULL;
@@ -3131,6 +3138,8 @@ _cairo_image_spans_compositor_get (void)
 	//spans.check_span_renderer = check_span_renderer;
 	spans.renderer_init = span_renderer_init;
 	spans.renderer_fini = span_renderer_fini;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &spans.base;
diff --git a/src/cairo-image-mask-compositor.c b/src/cairo-image-mask-compositor.c
index bb990dd6..feb7c622 100644
--- a/src/cairo-image-mask-compositor.c
+++ b/src/cairo-image-mask-compositor.c
@@ -387,9 +387,10 @@ composite_boxes (void			*_dst,
 const cairo_compositor_t *
 _cairo_image_mask_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_mask_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_mask_compositor_init (&compositor,
 				     _cairo_image_traps_compositor_get ());
 	compositor.acquire = acquire;
@@ -405,6 +406,8 @@ _cairo_image_mask_compositor_get (void)
 	compositor.composite = composite;
 	//compositor.check_composite_boxes = check_composite_boxes;
 	compositor.composite_boxes = composite_boxes;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
diff --git a/src/cairo-xlib-core-compositor.c b/src/cairo-xlib-core-compositor.c
index 5babcc81..13929996 100644
--- a/src/cairo-xlib-core-compositor.c
+++ b/src/cairo-xlib-core-compositor.c
@@ -632,9 +632,10 @@ _cairo_xlib_core_compositor_fill (const cairo_compositor_t	*compositor,
 const cairo_compositor_t *
 _cairo_xlib_core_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_compositor_t compositor;
 
-    if (compositor.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	compositor.delegate = _cairo_xlib_fallback_compositor_get ();
 
 	compositor.paint = _cairo_xlib_core_compositor_paint;
@@ -642,6 +643,8 @@ _cairo_xlib_core_compositor_get (void)
 	compositor.fill  = _cairo_xlib_core_compositor_fill;
 	compositor.stroke = _cairo_xlib_core_compositor_stroke;
 	compositor.glyphs = NULL; /* XXX PolyGlyph? */
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor;
diff --git a/src/cairo-xlib-render-compositor.c b/src/cairo-xlib-render-compositor.c
index 861ebe63..4352b44c 100644
--- a/src/cairo-xlib-render-compositor.c
+++ b/src/cairo-xlib-render-compositor.c
@@ -1725,9 +1725,10 @@ composite_glyphs (void				*surface,
 const cairo_compositor_t *
 _cairo_xlib_mask_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_mask_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_mask_compositor_init (&compositor,
 				     _cairo_xlib_fallback_compositor_get ());
 
@@ -1745,6 +1746,8 @@ _cairo_xlib_mask_compositor_get (void)
 	compositor.composite_boxes = composite_boxes;
 	compositor.check_composite_glyphs = check_composite_glyphs;
 	compositor.composite_glyphs = composite_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
@@ -1973,9 +1976,10 @@ composite_tristrip (void		*abstract_dst,
 const cairo_compositor_t *
 _cairo_xlib_traps_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_traps_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_traps_compositor_init (&compositor,
 				      _cairo_xlib_mask_compositor_get ());
 
@@ -1997,6 +2001,8 @@ _cairo_xlib_traps_compositor_get (void)
 	compositor.composite_tristrip = composite_tristrip;
 	compositor.check_composite_glyphs = check_composite_glyphs;
 	compositor.composite_glyphs = composite_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
diff --git a/src/test-null-compositor-surface.c b/src/test-null-compositor-surface.c
index d5d98c88..6b8d4eeb 100644
--- a/src/test-null-compositor-surface.c
+++ b/src/test-null-compositor-surface.c
@@ -404,9 +404,10 @@ check_composite (const cairo_composite_rectangles_t *extents)
 static const cairo_compositor_t *
 no_traps_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_traps_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_traps_compositor_init (&compositor,
 				      no_fallback_compositor_get ());
 
@@ -426,6 +427,8 @@ no_traps_compositor_get (void)
 	compositor.composite_traps = composite_traps;
 	compositor.check_composite_glyphs = check_composite_glyphs;
 	compositor.composite_glyphs = composite_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
@@ -434,9 +437,10 @@ no_traps_compositor_get (void)
 static const cairo_compositor_t *
 no_spans_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_spans_compositor_t compositor;
 
-    if (compositor.base.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	_cairo_spans_compositor_init (&compositor,
 				      no_traps_compositor_get());
 
@@ -448,6 +452,8 @@ no_spans_compositor_get (void)
 	//compositor.check_span_renderer = check_span_renderer;
 	compositor.renderer_init = span_renderer_init;
 	compositor.renderer_fini = span_renderer_fini;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor.base;
diff --git a/src/win32/cairo-win32-gdi-compositor.c b/src/win32/cairo-win32-gdi-compositor.c
index 073e889a..2858affc 100644
--- a/src/win32/cairo-win32-gdi-compositor.c
+++ b/src/win32/cairo-win32-gdi-compositor.c
@@ -634,9 +634,10 @@ _cairo_win32_gdi_compositor_glyphs (const cairo_compositor_t	*compositor,
 const cairo_compositor_t *
 _cairo_win32_gdi_compositor_get (void)
 {
+    static cairo_atomic_once_t once = CAIRO_ATOMIC_ONCE_INIT;
     static cairo_compositor_t compositor;
 
-    if (compositor.delegate == NULL) {
+    if (_cairo_atomic_init_once_enter(&once)) {
 	compositor.delegate = &_cairo_fallback_compositor;
 
 	compositor.paint  = _cairo_win32_gdi_compositor_paint;
@@ -644,6 +645,8 @@ _cairo_win32_gdi_compositor_get (void)
 	compositor.fill   = _cairo_win32_gdi_compositor_fill;
 	compositor.stroke = _cairo_win32_gdi_compositor_stroke;
 	compositor.glyphs = _cairo_win32_gdi_compositor_glyphs;
+
+	_cairo_atomic_init_once_leave(&once);
     }
 
     return &compositor;


More information about the cairo-commit mailing list