[cairo-commit] 3 commits - configure.in src/cairo-atomic.c src/cairo-atomic-private.h src/cairo.c src/cairo-cache-private.h src/cairo-clip.c src/cairo-clip-private.h src/cairo-compiler-private.h src/cairo-font-face.c src/cairo-ft-font.c src/cairo-hash-private.h src/cairo-image-surface.c src/cairoint.h src/cairo-mutex-list-private.h src/cairo-mutex-private.h src/cairo-output-stream-private.h src/cairo-pattern.c src/cairo-private.h src/cairo-reference-count-private.h src/cairo-region-private.h src/cairo-scaled-font.c src/cairo-scaled-font-private.h src/cairo-surface.c src/cairo-surface-private.h src/cairo-wideint-private.h src/cairo-xlib-display.c src/cairo-xlib-private.h src/cairo-xlib-screen.c src/Makefile.am

Chris Wilson ickle at kemper.freedesktop.org
Tue Sep 25 08:32:46 PDT 2007


 configure.in                        |   16 +++++
 src/Makefile.am                     |    4 +
 src/cairo-atomic-private.h          |   81 +++++++++++++++++++++++++
 src/cairo-atomic.c                  |   79 ++++++++++++++++++++++++
 src/cairo-cache-private.h           |    1 
 src/cairo-clip-private.h            |   13 ++--
 src/cairo-clip.c                    |   11 ++-
 src/cairo-compiler-private.h        |  115 ++++++++++++++++++++++++++++++++++++
 src/cairo-font-face.c               |   49 +++++++--------
 src/cairo-ft-font.c                 |    2 
 src/cairo-hash-private.h            |    1 
 src/cairo-image-surface.c           |    2 
 src/cairo-mutex-list-private.h      |    3 
 src/cairo-mutex-private.h           |    1 
 src/cairo-output-stream-private.h   |    1 
 src/cairo-pattern.c                 |   50 ++++++++-------
 src/cairo-private.h                 |    3 
 src/cairo-reference-count-private.h |   66 ++++++++++++++++++++
 src/cairo-region-private.h          |    2 
 src/cairo-scaled-font-private.h     |    3 
 src/cairo-scaled-font.c             |   77 +++++++++++-------------
 src/cairo-surface-private.h         |    3 
 src/cairo-surface.c                 |   33 +++++-----
 src/cairo-wideint-private.h         |    2 
 src/cairo-xlib-display.c            |   42 +++++--------
 src/cairo-xlib-private.h            |   10 ++-
 src/cairo-xlib-screen.c             |   12 ++-
 src/cairo.c                         |   23 +++----
 src/cairoint.h                      |   98 ++++--------------------------
 29 files changed, 556 insertions(+), 247 deletions(-)

New commits:
diff-tree 03be41151d06d48d55bc1e172535829ec45a10cf (from 8b6c871c9084739460f1320cd36560a09477a83e)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Sep 23 21:08:09 2007 +0100

    [cairo-atomic] Rewrite reference counting using atomic ops.
    
    Introduce an opaque cairo_reference_count_t and define operations on it
    in terms of atomic ops. Update all users of reference counters to use
    the new opaque type.

diff --git a/src/Makefile.am b/src/Makefile.am
index 2e6d2c6..0564d99 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -209,6 +209,7 @@ libcairo_la_base_sources =			\
 	cairo-pen.c				\
 	cairo-polygon.c				\
 	cairo-rectangle.c			\
+	cairo-reference-count-private.h		\
 	cairo-region.c				\
 	cairo-scaled-font.c			\
 	cairo-scaled-font-private.h		\
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 7f880d8..c2fe494 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -42,12 +42,12 @@
 extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
 
 struct _cairo_clip_path {
-    unsigned int	ref_count;
-    cairo_path_fixed_t	path;
-    cairo_fill_rule_t	fill_rule;
-    double		tolerance;
-    cairo_antialias_t	antialias;
-    cairo_clip_path_t	*prev;
+    cairo_reference_count_t	 ref_count;
+    cairo_path_fixed_t		 path;
+    cairo_fill_rule_t		 fill_rule;
+    double			 tolerance;
+    cairo_antialias_t		 antialias;
+    cairo_clip_path_t		*prev;
 };
 
 struct _cairo_clip {
diff --git a/src/cairo-clip.c b/src/cairo-clip.c
index 214b408..c1667d2 100644
--- a/src/cairo-clip.c
+++ b/src/cairo-clip.c
@@ -285,7 +285,7 @@ _cairo_clip_intersect_path (cairo_clip_t
 	return status;
     }
 
-    clip_path->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&clip_path->ref_count, 1);
     clip_path->fill_rule = fill_rule;
     clip_path->tolerance = tolerance;
     clip_path->antialias = antialias;
@@ -301,7 +301,9 @@ _cairo_clip_path_reference (cairo_clip_p
     if (clip_path == NULL)
 	return NULL;
 
-    clip_path->ref_count++;
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
+
+    _cairo_reference_count_inc (&clip_path->ref_count);
 
     return clip_path;
 }
@@ -312,8 +314,9 @@ _cairo_clip_path_destroy (cairo_clip_pat
     if (clip_path == NULL)
 	return;
 
-    clip_path->ref_count--;
-    if (clip_path->ref_count)
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&clip_path->ref_count));
+
+    if (! _cairo_reference_count_dec_and_test (&clip_path->ref_count))
 	return;
 
     _cairo_path_fixed_fini (&clip_path->path);
diff --git a/src/cairo-font-face.c b/src/cairo-font-face.c
index 3b6dab3..c648020 100644
--- a/src/cairo-font-face.c
+++ b/src/cairo-font-face.c
@@ -50,7 +50,7 @@ static const cairo_font_face_backend_t _
 const cairo_font_face_t _cairo_font_face_nil = {
     { 0 },			/* hash_entry */
     CAIRO_STATUS_NO_MEMORY,	/* status */
-    CAIRO_REF_COUNT_INVALID,	/* ref_count */
+    CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
     { 0, 0, 0, NULL },		/* user_data */
     &_cairo_toy_font_face_backend
 };
@@ -62,7 +62,7 @@ _cairo_font_face_init (cairo_font_face_t
     CAIRO_MUTEX_INITIALIZE ();
 
     font_face->status = CAIRO_STATUS_SUCCESS;
-    font_face->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&font_face->ref_count, 1);
     font_face->backend = backend;
 
     _cairo_user_data_array_init (&font_face->user_data);
@@ -85,18 +85,15 @@ _cairo_font_face_init (cairo_font_face_t
 cairo_font_face_t *
 cairo_font_face_reference (cairo_font_face_t *font_face)
 {
-    if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (font_face == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
 	return font_face;
 
-    CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
-
-    /* We would normally assert (font_face->ref_count >0) here but we
+    /* We would normally assert that we have a reference here but we
      * can't get away with that due to the zombie case as documented
      * in _cairo_ft_font_face_destroy. */
 
-    font_face->ref_count++;
-
-    CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
+    _cairo_reference_count_inc (&font_face->ref_count);
 
     return font_face;
 }
@@ -113,19 +110,14 @@ slim_hidden_def (cairo_font_face_referen
 void
 cairo_font_face_destroy (cairo_font_face_t *font_face)
 {
-    if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (font_face == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
 	return;
 
-    CAIRO_MUTEX_LOCK (_cairo_font_face_mutex);
-
-    assert (font_face->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count));
 
-    if (--(font_face->ref_count) > 0) {
-        CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
+    if (! _cairo_reference_count_dec_and_test (&font_face->ref_count))
 	return;
-    }
-
-    CAIRO_MUTEX_UNLOCK (_cairo_font_face_mutex);
 
     font_face->backend->destroy (font_face);
 
@@ -133,7 +125,7 @@ cairo_font_face_destroy (cairo_font_face
      * FreeType backend where cairo_ft_font_face_t and cairo_ft_unscaled_font_t
      * need to effectively mutually reference each other
      */
-    if (font_face->ref_count > 0)
+    if (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&font_face->ref_count))
 	return;
 
     _cairo_user_data_array_fini (&font_face->user_data);
@@ -173,10 +165,11 @@ cairo_font_face_get_type (cairo_font_fac
 unsigned int
 cairo_font_face_get_reference_count (cairo_font_face_t *font_face)
 {
-    if (font_face == NULL || font_face->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (font_face == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
 	return 0;
 
-    return font_face->ref_count;
+    return CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->ref_count);
 }
 
 /**
@@ -237,7 +230,7 @@ cairo_font_face_set_user_data (cairo_fon
 			       void			   *user_data,
 			       cairo_destroy_func_t	    destroy)
 {
-    if (font_face->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&font_face->ref_count))
 	return CAIRO_STATUS_NO_MEMORY;
 
     return _cairo_user_data_array_set_data (&font_face->user_data,
@@ -395,7 +388,7 @@ _cairo_toy_font_face_create (const char 
     {
 	/* We increment the reference count here manually to avoid
 	   double-locking. */
-	font_face->base.ref_count++;
+	_cairo_reference_count_inc (&font_face->base.ref_count);
 	_cairo_toy_font_face_hash_table_unlock ();
 	return &font_face->base;
     }
@@ -475,7 +468,7 @@ void
 _cairo_unscaled_font_init (cairo_unscaled_font_t               *unscaled_font,
 			   const cairo_unscaled_font_backend_t *backend)
 {
-    unscaled_font->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&unscaled_font->ref_count, 1);
     unscaled_font->backend = backend;
 }
 
@@ -485,7 +478,9 @@ _cairo_unscaled_font_reference (cairo_un
     if (unscaled_font == NULL)
 	return NULL;
 
-    unscaled_font->ref_count++;
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
+
+    _cairo_reference_count_inc (&unscaled_font->ref_count);
 
     return unscaled_font;
 }
@@ -496,7 +491,9 @@ _cairo_unscaled_font_destroy (cairo_unsc
     if (unscaled_font == NULL)
 	return;
 
-    if (--(unscaled_font->ref_count) > 0)
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&unscaled_font->ref_count));
+
+    if (! _cairo_reference_count_dec_and_test (&unscaled_font->ref_count))
 	return;
 
     unscaled_font->backend->destroy (unscaled_font);
diff --git a/src/cairo-ft-font.c b/src/cairo-ft-font.c
index 0161dae..3262163 100644
--- a/src/cairo-ft-font.c
+++ b/src/cairo-ft-font.c
@@ -2198,7 +2198,7 @@ _cairo_ft_font_face_destroy (void *abstr
 
     if (font_face->unscaled &&
 	font_face->unscaled->from_face &&
-	font_face->unscaled->base.ref_count > 1)
+	CAIRO_REFERENCE_COUNT_GET_VALUE (&font_face->unscaled->base.ref_count) > 1)
     {
 	cairo_font_face_reference (&font_face->base);
 
diff --git a/src/cairo-image-surface.c b/src/cairo-image-surface.c
index 04d8452..24c83ec 100644
--- a/src/cairo-image-surface.c
+++ b/src/cairo-image-surface.c
@@ -42,7 +42,7 @@ static const cairo_image_surface_t _cair
 	&cairo_image_surface_backend,	/* backend */
 	CAIRO_SURFACE_TYPE_IMAGE,
 	CAIRO_CONTENT_COLOR,
-	CAIRO_REF_COUNT_INVALID,	/* ref_count */
+	CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
 	CAIRO_STATUS_INVALID_FORMAT,	/* status */
 	FALSE,				/* finished */
 	{ 0,	/* size */
diff --git a/src/cairo-pattern.c b/src/cairo-pattern.c
index b75040b..231f5b2 100644
--- a/src/cairo-pattern.c
+++ b/src/cairo-pattern.c
@@ -32,31 +32,31 @@
 
 const cairo_solid_pattern_t _cairo_pattern_nil = {
     { CAIRO_PATTERN_TYPE_SOLID, 	/* type */
-      CAIRO_REF_COUNT_INVALID,		/* ref_count */
-      CAIRO_STATUS_NO_MEMORY,	/* status */
+      CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
+      CAIRO_STATUS_NO_MEMORY,		/* status */
       { 0, 0, 0, NULL },		/* user_data */
-      { 1., 0., 0., 1., 0., 0., }, /* matrix */
-      CAIRO_FILTER_DEFAULT,	/* filter */
+      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      CAIRO_FILTER_DEFAULT,		/* filter */
       CAIRO_EXTEND_GRADIENT_DEFAULT },	/* extend */
 };
 
 static const cairo_solid_pattern_t _cairo_pattern_nil_null_pointer = {
     { CAIRO_PATTERN_TYPE_SOLID, 	/* type */
-      CAIRO_REF_COUNT_INVALID,		/* ref_count */
-      CAIRO_STATUS_NULL_POINTER,/* status */
+      CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
+      CAIRO_STATUS_NULL_POINTER,	/* status */
       { 0, 0, 0, NULL },		/* user_data */
-      { 1., 0., 0., 1., 0., 0., }, /* matrix */
-      CAIRO_FILTER_DEFAULT,	/* filter */
+      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      CAIRO_FILTER_DEFAULT,		/* filter */
       CAIRO_EXTEND_GRADIENT_DEFAULT },	/* extend */
 };
 
 const cairo_solid_pattern_t cairo_pattern_none = {
     { CAIRO_PATTERN_TYPE_SOLID, 	/* type */
-      CAIRO_REF_COUNT_INVALID,		/* ref_count */
+      CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
       CAIRO_STATUS_SUCCESS,		/* status */
       { 0, 0, 0, NULL },		/* user_data */
-      { 1., 0., 0., 1., 0., 0., }, /* matrix */
-      CAIRO_FILTER_DEFAULT,	/* filter */
+      { 1., 0., 0., 1., 0., 0., },	/* matrix */
+      CAIRO_FILTER_DEFAULT,		/* filter */
       CAIRO_EXTEND_GRADIENT_DEFAULT },	/* extend */
 };
 
@@ -95,7 +95,7 @@ _cairo_pattern_init (cairo_pattern_t *pa
     CAIRO_MUTEX_INITIALIZE ();
 
     pattern->type      = type;
-    pattern->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
     pattern->status    = CAIRO_STATUS_SUCCESS;
 
     _cairo_user_data_array_init (&pattern->user_data);
@@ -186,7 +186,7 @@ _cairo_pattern_init_copy (cairo_pattern_
     }
 
     /* The reference count and user_data array are unique to the copy. */
-    pattern->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&pattern->ref_count, 1);
     _cairo_user_data_array_init (&pattern->user_data);
 
     return CAIRO_STATUS_SUCCESS;
@@ -577,12 +577,13 @@ cairo_pattern_create_radial (double cx0,
 cairo_pattern_t *
 cairo_pattern_reference (cairo_pattern_t *pattern)
 {
-    if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (pattern == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
 	return pattern;
 
-    assert (pattern->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
 
-    pattern->ref_count++;
+    _cairo_reference_count_inc (&pattern->ref_count);
 
     return pattern;
 }
@@ -634,13 +635,13 @@ slim_hidden_def (cairo_pattern_status);
 void
 cairo_pattern_destroy (cairo_pattern_t *pattern)
 {
-    if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (pattern == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
 	return;
 
-    assert (pattern->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&pattern->ref_count));
 
-    pattern->ref_count--;
-    if (pattern->ref_count)
+    if (! _cairo_reference_count_dec_and_test (&pattern->ref_count))
 	return;
 
     _cairo_pattern_fini (pattern);
@@ -680,10 +681,11 @@ slim_hidden_def (cairo_pattern_destroy);
 unsigned int
 cairo_pattern_get_reference_count (cairo_pattern_t *pattern)
 {
-    if (pattern == NULL || pattern->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (pattern == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
 	return 0;
 
-    return pattern->ref_count;
+    return CAIRO_REFERENCE_COUNT_GET_VALUE (&pattern->ref_count);
 }
 
 /**
@@ -732,7 +734,7 @@ cairo_pattern_set_user_data (cairo_patte
 			     void			 *user_data,
 			     cairo_destroy_func_t	  destroy)
 {
-    if (pattern->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&pattern->ref_count))
 	return CAIRO_STATUS_NO_MEMORY;
 
     return _cairo_user_data_array_set_data (&pattern->user_data,
@@ -1328,7 +1330,7 @@ _cairo_pattern_solid_surface_matches (
 	const cairo_solid_pattern_t			    *pattern,
 	cairo_surface_t					    *dst)
 {
-    if (cache->surface->ref_count != 1)
+    if (CAIRO_REFERENCE_COUNT_GET_VALUE (&cache->surface->ref_count) != 1)
 	return FALSE;
 
     if (! _cairo_color_equal (&cache->color, &pattern->color))
diff --git a/src/cairo-private.h b/src/cairo-private.h
index 14cc79a..a5faec8 100644
--- a/src/cairo-private.h
+++ b/src/cairo-private.h
@@ -36,11 +36,12 @@
 #ifndef CAIRO_PRIVATE_H
 #define CAIRO_PRIVATE_H
 
+#include "cairo-reference-count-private.h"
 #include "cairo-gstate-private.h"
 #include "cairo-path-fixed-private.h"
 
 struct _cairo {
-    unsigned int ref_count;
+    cairo_reference_count_t ref_count;
 
     cairo_status_t status;
 
diff --git a/src/cairo-reference-count-private.h b/src/cairo-reference-count-private.h
new file mode 100644
index 0000000..2d1d81b
--- /dev/null
+++ b/src/cairo-reference-count-private.h
@@ -0,0 +1,66 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_REFRENCE_COUNT_PRIVATE_H
+#define CAIRO_REFRENCE_COUNT_PRIVATE_H
+
+#include "cairo-atomic-private.h"
+
+CAIRO_BEGIN_DECLS
+
+/* Encapsulate operations on the object's reference count */
+typedef struct {
+    cairo_atomic_int_t ref_count;
+} cairo_reference_count_t;
+
+#define _cairo_reference_count_inc(RC) _cairo_atomic_int_inc (&(RC)->ref_count)
+#define _cairo_reference_count_dec_and_test(RC) _cairo_atomic_int_dec_and_test (&(RC)->ref_count)
+
+#define CAIRO_REFERENCE_COUNT_INIT(RC, VALUE) ((RC)->ref_count = (VALUE))
+
+#define CAIRO_REFERENCE_COUNT_GET_VALUE(RC) _cairo_atomic_int_get (&(RC)->ref_count)
+#define CAIRO_REFERENCE_COUNT_SET_VALUE(RC, VALUE) _cairo_atomic_int_set (&(RC)->ref_count, (VALUE))
+
+#define CAIRO_REFERENCE_COUNT_INVALID_VALUE ((cairo_atomic_int_t) -1)
+#define CAIRO_REFERENCE_COUNT_INVALID ((cairo_reference_count_t) {CAIRO_REFERENCE_COUNT_INVALID_VALUE})
+
+#define CAIRO_REFERENCE_COUNT_IS_INVALID(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) == CAIRO_REFERENCE_COUNT_INVALID_VALUE)
+
+#define CAIRO_REFERENCE_COUNT_HAS_REFERENCE(RC) (CAIRO_REFERENCE_COUNT_GET_VALUE (RC) > 0)
+
+CAIRO_END_DECLS
+
+#endif
diff --git a/src/cairo-scaled-font-private.h b/src/cairo-scaled-font-private.h
index fa71644..f16487c 100644
--- a/src/cairo-scaled-font-private.h
+++ b/src/cairo-scaled-font-private.h
@@ -42,6 +42,7 @@
 
 #include "cairo-types-private.h"
 #include "cairo-mutex-type-private.h"
+#include "cairo-reference-count-private.h"
 
 struct _cairo_scaled_font {
     /* For most cairo objects, the rule for multiple threads is that
@@ -79,7 +80,7 @@ struct _cairo_scaled_font {
 
     /* useful bits for _cairo_scaled_font_nil */
     cairo_status_t status;
-    unsigned int ref_count;
+    cairo_reference_count_t ref_count;
     cairo_user_data_array_t user_data;
 
     /* hash key members */
diff --git a/src/cairo-scaled-font.c b/src/cairo-scaled-font.c
index cb3af9f..f3808c9 100644
--- a/src/cairo-scaled-font.c
+++ b/src/cairo-scaled-font.c
@@ -180,7 +180,7 @@ _cairo_scaled_glyph_destroy (void *abstr
 const cairo_scaled_font_t _cairo_scaled_font_nil = {
     { 0 },			/* hash_entry */
     CAIRO_STATUS_NO_MEMORY,	/* status */
-    CAIRO_REF_COUNT_INVALID,	/* ref_count */
+    CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
     { 0, 0, 0, NULL },		/* user_data */
     NULL,			/* font_face */
     { 1., 0., 0., 1., 0, 0},	/* font_matrix */
@@ -241,7 +241,7 @@ _cairo_scaled_font_set_error (cairo_scal
 cairo_font_type_t
 cairo_scaled_font_get_type (cairo_scaled_font_t *scaled_font)
 {
-    if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return CAIRO_FONT_TYPE_TOY;
 
     return scaled_font->backend->type;
@@ -352,7 +352,7 @@ _cairo_scaled_font_map_destroy (void)
 	/* We should only get here through the reset_static_data path
 	 * and there had better not be any active references at that
 	 * point. */
-	assert (scaled_font->ref_count == 0);
+	assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 	_cairo_hash_table_remove (font_map->hash_table,
 				  &scaled_font->hash_entry);
 	_cairo_scaled_font_fini (scaled_font);
@@ -483,7 +483,7 @@ _cairo_scaled_font_init (cairo_scaled_fo
     if (scaled_font->glyphs == NULL)
 	return CAIRO_STATUS_NO_MEMORY;
 
-    scaled_font->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&scaled_font->ref_count, 1);
 
     _cairo_user_data_array_init (&scaled_font->user_data);
 
@@ -613,7 +613,7 @@ cairo_scaled_font_create (cairo_font_fac
 	 * been found in font_map->holdovers, (which means this caching is
 	 * actually working). So now we remove it from the holdovers
 	 * array. */
-	if (scaled_font->ref_count == 0) {
+	if (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count)) {
 	    int i;
 
 	    for (i = 0; i < font_map->num_holdovers; i++)
@@ -635,7 +635,7 @@ cairo_scaled_font_create (cairo_font_fac
 	     * than calling into cairo_scaled_font_reference), since we
 	     * must modify the reference count while our lock is still
 	     * held. */
-	    scaled_font->ref_count++;
+	    _cairo_reference_count_inc (&scaled_font->ref_count);
 	    _cairo_scaled_font_map_unlock ();
 	    return scaled_font;
 	}
@@ -686,16 +686,13 @@ slim_hidden_def (cairo_scaled_font_creat
 cairo_scaled_font_t *
 cairo_scaled_font_reference (cairo_scaled_font_t *scaled_font)
 {
-    if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (scaled_font == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return scaled_font;
 
-    _cairo_scaled_font_map_lock ();
-    {
-	assert (scaled_font->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 
-	scaled_font->ref_count++;
-    }
-    _cairo_scaled_font_map_unlock ();
+    _cairo_reference_count_inc (&scaled_font->ref_count);
 
     return scaled_font;
 }
@@ -715,38 +712,37 @@ cairo_scaled_font_destroy (cairo_scaled_
     cairo_scaled_font_map_t *font_map;
     cairo_scaled_font_t *lru = NULL;
 
-    if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (scaled_font == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return;
 
     font_map = _cairo_scaled_font_map_lock ();
-    {
-	assert (font_map != NULL);
+    assert (font_map != NULL);
 
-	assert (scaled_font->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&scaled_font->ref_count));
 
-	if (--(scaled_font->ref_count) == 0)
+    if (_cairo_reference_count_dec_and_test (&scaled_font->ref_count)) {
+	/* Rather than immediately destroying this object, we put it into
+	 * the font_map->holdovers array in case it will get used again
+	 * soon (and is why we must hold the lock over the atomic op on
+	 * the reference count). To make room for it, we do actually
+	 * destroy the least-recently-used holdover.
+	 */
+	if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS)
 	{
-	    /* Rather than immediately destroying this object, we put it into
-	     * the font_map->holdovers array in case it will get used again
-	     * soon. To make room for it, we do actually destroy the
-	     * least-recently-used holdover.
-	     */
-	    if (font_map->num_holdovers == CAIRO_SCALED_FONT_MAX_HOLDOVERS)
-	    {
-		lru = font_map->holdovers[0];
-		assert (lru->ref_count == 0);
-
-		_cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
-
-		font_map->num_holdovers--;
-		memmove (&font_map->holdovers[0],
-			 &font_map->holdovers[1],
-			 font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
-	    }
+	    lru = font_map->holdovers[0];
+	    assert (! CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&lru->ref_count));
+
+	    _cairo_hash_table_remove (font_map->hash_table, &lru->hash_entry);
 
-	    font_map->holdovers[font_map->num_holdovers] = scaled_font;
-	    font_map->num_holdovers++;
+	    font_map->num_holdovers--;
+	    memmove (&font_map->holdovers[0],
+		     &font_map->holdovers[1],
+		     font_map->num_holdovers * sizeof (cairo_scaled_font_t*));
 	}
+
+	font_map->holdovers[font_map->num_holdovers] = scaled_font;
+	font_map->num_holdovers++;
     }
     _cairo_scaled_font_map_unlock ();
 
@@ -777,10 +773,11 @@ slim_hidden_def (cairo_scaled_font_destr
 unsigned int
 cairo_scaled_font_get_reference_count (cairo_scaled_font_t *scaled_font)
 {
-    if (scaled_font == NULL || scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (scaled_font == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return 0;
 
-    return scaled_font->ref_count;
+    return CAIRO_REFERENCE_COUNT_GET_VALUE (&scaled_font->ref_count);
 }
 
 /**
@@ -829,7 +826,7 @@ cairo_scaled_font_set_user_data (cairo_s
 				 void			     *user_data,
 				 cairo_destroy_func_t	      destroy)
 {
-    if (scaled_font->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&scaled_font->ref_count))
 	return CAIRO_STATUS_NO_MEMORY;
 
     return _cairo_user_data_array_set_data (&scaled_font->user_data,
diff --git a/src/cairo-surface-private.h b/src/cairo-surface-private.h
index a0b50c5..efd4365 100644
--- a/src/cairo-surface-private.h
+++ b/src/cairo-surface-private.h
@@ -41,6 +41,7 @@
 #include "cairo.h"
 
 #include "cairo-types-private.h"
+#include "cairo-reference-count-private.h"
 
 struct _cairo_surface {
     const cairo_surface_backend_t *backend;
@@ -52,7 +53,7 @@ struct _cairo_surface {
 
     cairo_content_t content;
 
-    unsigned int ref_count;
+    cairo_reference_count_t ref_count;
     cairo_status_t status;
     cairo_bool_t finished;
     cairo_user_data_array_t user_data;
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 612d8cf..05dc906 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -46,7 +46,7 @@ const cairo_surface_t name = {					\
     &cairo_image_surface_backend,	/* backend */		\
     CAIRO_SURFACE_TYPE_IMAGE,					\
     CAIRO_CONTENT_COLOR,					\
-    CAIRO_REF_COUNT_INVALID,		/* ref_count */		\
+    CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */		\
     status,				/* status */		\
     FALSE,				/* finished */		\
     { 0,	/* size */					\
@@ -188,7 +188,7 @@ _cairo_surface_init (cairo_surface_t			*
     surface->content = content;
     surface->type = backend->type;
 
-    surface->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&surface->ref_count, 1);
     surface->status = CAIRO_STATUS_SUCCESS;
     surface->finished = FALSE;
 
@@ -372,12 +372,13 @@ _cairo_surface_get_clip_mode (cairo_surf
 cairo_surface_t *
 cairo_surface_reference (cairo_surface_t *surface)
 {
-    if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (surface == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return surface;
 
-    assert (surface->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
 
-    surface->ref_count++;
+    _cairo_reference_count_inc (&surface->ref_count);
 
     return surface;
 }
@@ -394,13 +395,13 @@ slim_hidden_def (cairo_surface_reference
 void
 cairo_surface_destroy (cairo_surface_t *surface)
 {
-    if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (surface == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return;
 
-    assert (surface->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&surface->ref_count));
 
-    surface->ref_count--;
-    if (surface->ref_count)
+    if (! _cairo_reference_count_dec_and_test (&surface->ref_count))
 	return;
 
     if (! surface->finished)
@@ -422,10 +423,11 @@ slim_hidden_def(cairo_surface_destroy);
 cairo_status_t
 _cairo_surface_reset (cairo_surface_t *surface)
 {
-    if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (surface == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return CAIRO_STATUS_SUCCESS;
 
-    assert (surface->ref_count == 1);
+    assert (CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count) == 1);
 
     _cairo_user_data_array_fini (&surface->user_data);
 
@@ -454,10 +456,11 @@ _cairo_surface_reset (cairo_surface_t *s
 unsigned int
 cairo_surface_get_reference_count (cairo_surface_t *surface)
 {
-    if (surface == NULL || surface->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (surface == NULL ||
+	    CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return 0;
 
-    return surface->ref_count;
+    return CAIRO_REFERENCE_COUNT_GET_VALUE (&surface->ref_count);
 }
 
 /**
@@ -486,7 +489,7 @@ cairo_surface_finish (cairo_surface_t *s
     if (surface == NULL)
 	return;
 
-    if (surface->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return;
 
     if (surface->finished) {
@@ -557,7 +560,7 @@ cairo_surface_set_user_data (cairo_surfa
 			     void			 *user_data,
 			     cairo_destroy_func_t	 destroy)
 {
-    if (surface->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&surface->ref_count))
 	return CAIRO_STATUS_NO_MEMORY;
 
     return _cairo_user_data_array_set_data (&surface->user_data,
diff --git a/src/cairo-xlib-display.c b/src/cairo-xlib-display.c
index 5d4f339..673c546 100644
--- a/src/cairo-xlib-display.c
+++ b/src/cairo-xlib-display.c
@@ -127,13 +127,9 @@ _cairo_xlib_display_reference (cairo_xli
     if (display == NULL)
 	return NULL;
 
-    /* use our mutex until we get a real atomic inc */
-    CAIRO_MUTEX_LOCK (display->mutex);
-
-    assert (display->ref_count > 0);
-    display->ref_count++;
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&display->ref_count));
 
-    CAIRO_MUTEX_UNLOCK (display->mutex);
+    _cairo_reference_count_inc (&display->ref_count);
 
     return display;
 }
@@ -144,27 +140,25 @@ _cairo_xlib_display_destroy (cairo_xlib_
     if (display == NULL)
 	return;
 
-    CAIRO_MUTEX_LOCK (display->mutex);
-    assert (display->ref_count > 0);
-    if (--display->ref_count == 0) {
-	/* destroy all outstanding notifies */
-	while (display->workqueue != NULL) {
-	    cairo_xlib_job_t *job = display->workqueue;
-	    display->workqueue = job->next;
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&display->ref_count));
 
-	    if (job->type == WORK && job->func.work.destroy != NULL)
-		job->func.work.destroy (job->func.work.data);
+    if (! _cairo_reference_count_dec_and_test (&display->ref_count))
+	return;
 
-	    _cairo_freelist_free (&display->wq_freelist, job);
-	}
-	_cairo_freelist_fini (&display->wq_freelist);
-	_cairo_freelist_fini (&display->hook_freelist);
+    /* destroy all outstanding notifies */
+    while (display->workqueue != NULL) {
+	cairo_xlib_job_t *job = display->workqueue;
+	display->workqueue = job->next;
 
-	CAIRO_MUTEX_UNLOCK (display->mutex);
+	if (job->type == WORK && job->func.work.destroy != NULL)
+	    job->func.work.destroy (job->func.work.data);
 
-	free (display);
-    } else
-	CAIRO_MUTEX_UNLOCK (display->mutex);
+	_cairo_freelist_free (&display->wq_freelist, job);
+    }
+    _cairo_freelist_fini (&display->wq_freelist);
+    _cairo_freelist_fini (&display->hook_freelist);
+
+    free (display);
 }
 
 static int
@@ -280,7 +274,7 @@ _cairo_xlib_display_get (Display *dpy)
     _cairo_freelist_init (&display->wq_freelist, sizeof (cairo_xlib_job_t));
     _cairo_freelist_init (&display->hook_freelist, sizeof (cairo_xlib_hook_t));
 
-    display->ref_count = 2; /* add one for the CloseDisplay */
+    CAIRO_REFERENCE_COUNT_INIT (&display->ref_count, 2); /* add one for the CloseDisplay */
     CAIRO_MUTEX_INIT (display->mutex);
     display->display = dpy;
     display->screens = NULL;
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 28ab1d3..ce2e5ae 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -39,6 +39,7 @@
 
 #include "cairo-compiler-private.h"
 #include "cairo-freelist-private.h"
+#include "cairo-reference-count-private.h"
 #include "cairo-xlib-xrender-private.h"
 
 #include <X11/Xutil.h> /* for XDestroyImage */
@@ -58,7 +59,7 @@ struct _cairo_xlib_hook {
 
 struct _cairo_xlib_display {
     cairo_xlib_display_t *next;
-    unsigned int ref_count;
+    cairo_reference_count_t ref_count;
     cairo_mutex_t mutex;
 
     Display *display;
@@ -74,7 +75,7 @@ struct _cairo_xlib_display {
 
 struct _cairo_xlib_screen_info {
     cairo_xlib_screen_info_t *next;
-    unsigned int ref_count;
+    cairo_reference_count_t ref_count;
 
     cairo_xlib_display_t *display;
     Screen *screen;
diff --git a/src/cairo-xlib-screen.c b/src/cairo-xlib-screen.c
index 88f0899..578a33a 100644
--- a/src/cairo-xlib-screen.c
+++ b/src/cairo-xlib-screen.c
@@ -246,8 +246,9 @@ _cairo_xlib_screen_info_reference (cairo
     if (info == NULL)
 	return NULL;
 
-    assert (info->ref_count > 0);
-    info->ref_count++;
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count));
+
+    _cairo_reference_count_inc (&info->ref_count);
 
     return info;
 }
@@ -274,8 +275,9 @@ _cairo_xlib_screen_info_destroy (cairo_x
     if (info == NULL)
 	return;
 
-    assert (info->ref_count > 0);
-    if (--info->ref_count)
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&info->ref_count));
+
+    if (! _cairo_reference_count_dec_and_test (&info->ref_count))
 	return;
 
     CAIRO_MUTEX_LOCK (info->display->mutex);
@@ -330,7 +332,7 @@ _cairo_xlib_screen_info_get (Display *dp
     } else {
 	info = malloc (sizeof (cairo_xlib_screen_info_t));
 	if (info != NULL) {
-	    info->ref_count = 2; /* Add one for display cache */
+	    CAIRO_REFERENCE_COUNT_INIT (&info->ref_count, 2); /* Add one for display cache */
 	    info->display = _cairo_xlib_display_reference (display);
 	    info->screen = screen;
 	    info->has_render = FALSE;
diff --git a/src/cairo.c b/src/cairo.c
index ff052b5..8652b28 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -45,7 +45,7 @@
 #define CAIRO_TOLERANCE_MINIMUM	0.0002 /* We're limited by 16 bits of sub-pixel precision */
 
 static const cairo_t _cairo_nil = {
-  CAIRO_REF_COUNT_INVALID,	/* ref_count */
+  CAIRO_REFERENCE_COUNT_INVALID,	/* ref_count */
   CAIRO_STATUS_NO_MEMORY,	/* status */
   { 0, 0, 0, NULL },		/* user_data */
   NULL,				/* gstate */
@@ -199,7 +199,7 @@ cairo_create (cairo_surface_t *target)
     if (cr == NULL)
 	return (cairo_t *) &_cairo_nil;
 
-    cr->ref_count = 1;
+    CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1);
 
     cr->status = CAIRO_STATUS_SUCCESS;
 
@@ -232,12 +232,12 @@ slim_hidden_def (cairo_create);
 cairo_t *
 cairo_reference (cairo_t *cr)
 {
-    if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
 	return cr;
 
-    assert (cr->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count));
 
-    cr->ref_count++;
+    _cairo_reference_count_inc (&cr->ref_count);
 
     return cr;
 }
@@ -253,13 +253,12 @@ cairo_reference (cairo_t *cr)
 void
 cairo_destroy (cairo_t *cr)
 {
-    if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
 	return;
 
-    assert (cr->ref_count > 0);
+    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&cr->ref_count));
 
-    cr->ref_count--;
-    if (cr->ref_count)
+    if (! _cairo_reference_count_dec_and_test (&cr->ref_count))
 	return;
 
     while (cr->gstate != cr->gstate_tail) {
@@ -323,7 +322,7 @@ cairo_set_user_data (cairo_t			 *cr,
 		     void			 *user_data,
 		     cairo_destroy_func_t	 destroy)
 {
-    if (cr->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
 	return CAIRO_STATUS_NO_MEMORY;
 
     return _cairo_user_data_array_set_data (&cr->user_data,
@@ -344,10 +343,10 @@ cairo_set_user_data (cairo_t			 *cr,
 unsigned int
 cairo_get_reference_count (cairo_t *cr)
 {
-    if (cr == NULL || cr->ref_count == CAIRO_REF_COUNT_INVALID)
+    if (cr == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (&cr->ref_count))
 	return 0;
 
-    return cr->ref_count;
+    return CAIRO_REFERENCE_COUNT_GET_VALUE (&cr->ref_count);
 }
 
 /**
diff --git a/src/cairoint.h b/src/cairoint.h
index 695cb8f..be7079c 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -110,8 +110,6 @@ do {					\
     assert (NOT_REACHED);		\
 } while (0)
 
-#define CAIRO_REF_COUNT_INVALID ((unsigned int) -1)
-
 #define CAIRO_ALPHA_IS_OPAQUE(alpha) ((alpha) >= ((double)0xff00 / (double)0xffff))
 #define CAIRO_ALPHA_SHORT_IS_OPAQUE(alpha) ((alpha) >= 0xff00)
 #define CAIRO_ALPHA_IS_ZERO(alpha) ((alpha) <= 0.0)
@@ -168,6 +166,7 @@ be32_to_cpu(uint32_t v)
 #include "cairo-types-private.h"
 #include "cairo-cache-private.h"
 #include "cairo-fixed-private.h"
+#include "cairo-reference-count-private.h"
 
 typedef struct _cairo_region cairo_region_t;
 
@@ -384,9 +383,9 @@ typedef struct _cairo_unscaled_font_back
  * glyph cache.
  */
 typedef struct _cairo_unscaled_font {
-    cairo_hash_entry_t hash_entry;
-    unsigned int ref_count;
-    const cairo_unscaled_font_backend_t *backend;
+    cairo_hash_entry_t			 hash_entry;
+    cairo_reference_count_t		 ref_count;
+    const cairo_unscaled_font_backend_t	*backend;
 } cairo_unscaled_font_t;
 
 typedef struct _cairo_scaled_glyph {
@@ -410,7 +409,7 @@ struct _cairo_font_face {
     /* hash_entry must be first */
     cairo_hash_entry_t hash_entry;
     cairo_status_t status;
-    unsigned int ref_count;
+    cairo_reference_count_t ref_count;
     cairo_user_data_array_t user_data;
     const cairo_font_face_backend_t *backend;
 };
@@ -883,14 +882,14 @@ typedef enum {
 #define CAIRO_FILTER_DEFAULT CAIRO_FILTER_BEST
 
 struct _cairo_pattern {
-    cairo_pattern_type_t    type;
-    unsigned int	    ref_count;
-    cairo_status_t          status;
-    cairo_user_data_array_t user_data;
-
-    cairo_matrix_t	    matrix;
-    cairo_filter_t	    filter;
-    cairo_extend_t	    extend;
+    cairo_pattern_type_t	type;
+    cairo_reference_count_t	ref_count;
+    cairo_status_t		status;
+    cairo_user_data_array_t	user_data;
+
+    cairo_matrix_t		matrix;
+    cairo_filter_t		filter;
+    cairo_extend_t		extend;
 };
 
 typedef struct _cairo_solid_pattern {
diff-tree 8b6c871c9084739460f1320cd36560a09477a83e (from 42de1a0a7f5cc10c2bad98ef69da302ed2a1ca84)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Fri Sep 21 10:45:55 2007 +0100

    [cairo-atomic] Introduce atomic ops.
    
    Test for the availability of the Intel __sync_* atomic primitives and
    use them to define a few operations useful for reference counting -
    providing a generic interface that may be targeted at more architectures
    in the future. If no atomic primitives are available, use a mutex based
    variant. If the contention on that mutex is too high, we can consider
    using an array of mutexes using the address of the atomic variable as
    the hash.

diff --git a/configure.in b/configure.in
index aa7c1e7..5f7f613 100644
--- a/configure.in
+++ b/configure.in
@@ -89,6 +89,22 @@ dnl ====================================
 
 AC_CHECK_FUNCS(vasnprintf)
 	
+dnl ===========================================================================
+dnl
+dnl Test for native atomic operations.
+dnl
+AC_MSG_CHECKING([for native atomic primitives])
+cairo_atomic_primitives="none"
+
+AC_TRY_COMPILE([int atomic_add(int i) { return __sync_fetch_and_add (&i, 1); }], [],
+  AC_DEFINE(CAIRO_HAS_INTEL_ATOMIC_PRIMITIVES, 1, [Enable if your compiler supports the Intel __sync_* atomic primitives])
+  cairo_atomic_primitives="Intel"
+  )
+
+AC_MSG_RESULT([$cairo_atomic_primitives])
+
+dnl ===========================================================================
+
 AC_CHECK_LIBM
 LIBS="$LIBS $LIBM"
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 85964e3..2e6d2c6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -172,6 +172,8 @@ libcairo_la_base_sources =			\
 	cairo-arc.c				\
 	cairo-arc-private.h			\
 	cairo-array.c				\
+	cairo-atomic.c				\
+	cairo-atomic-private.h			\
 	cairo-base85-stream.c			\
 	cairo-bentley-ottmann.c			\
 	cairo-cache.c				\
diff --git a/src/cairo-atomic-private.h b/src/cairo-atomic-private.h
new file mode 100644
index 0000000..3577e0d
--- /dev/null
+++ b/src/cairo-atomic-private.h
@@ -0,0 +1,81 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#ifndef CAIRO_ATOMIC_PRIVATE_H
+#define CAIRO_ATOMIC_PRIVATE_H
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+CAIRO_BEGIN_DECLS
+
+#define CAIRO_HAS_ATOMIC_OPS 1
+
+#if CAIRO_HAS_INTEL_ATOMIC_PRIMITIVES
+
+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_get(x) (*x)
+# define _cairo_atomic_int_set(x, value) ((*x) = value)
+
+#else
+
+# include "cairo-compiler-private.h"
+
+# undef CAIRO_HAS_ATOMIC_OPS
+
+typedef int cairo_atomic_int_t;
+
+cairo_private void
+_cairo_atomic_int_inc (int *x);
+
+cairo_private cairo_bool_t
+_cairo_atomic_int_dec_and_test (int *x);
+
+cairo_private int
+_cairo_atomic_int_get (int *x);
+
+cairo_private void
+_cairo_atomic_int_set (int *x, int value);
+
+#endif
+
+CAIRO_END_DECLS
+
+#endif
diff --git a/src/cairo-atomic.c b/src/cairo-atomic.c
new file mode 100644
index 0000000..9941548
--- /dev/null
+++ b/src/cairo-atomic.c
@@ -0,0 +1,79 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2007 Chris Wilson
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * Contributor(s):
+ *	Chris Wilson <chris at chris-wilson.co.uk>
+ */
+
+#include "cairoint.h"
+
+#include "cairo-atomic-private.h"
+#include "cairo-mutex-private.h"
+
+#ifndef CAIRO_HAS_ATOMIC_OPS
+void
+_cairo_atomic_int_inc (int *x)
+{
+    CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
+    *x += 1;
+    CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
+}
+
+cairo_bool_t
+_cairo_atomic_int_dec_and_test (int *x)
+{
+    cairo_bool_t ret;
+
+    CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
+    ret = --*x == 0;
+    CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
+
+    return ret;
+}
+
+int
+_cairo_atomic_int_get (int *x)
+{
+    int ret;
+
+    CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
+    ret = *x;
+    CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
+
+    return ret;
+}
+
+void
+_cairo_atomic_int_set (int *x, int value)
+{
+    CAIRO_MUTEX_LOCK (_cairo_atomic_mutex);
+    *x = value;
+    CAIRO_MUTEX_UNLOCK (_cairo_atomic_mutex);
+}
+#endif
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index abb4a9a..9960797 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -46,6 +46,9 @@ CAIRO_MUTEX_DECLARE (_cairo_ft_unscaled_
 CAIRO_MUTEX_DECLARE (_cairo_xlib_display_mutex);
 #endif
 
+#ifndef CAIRO_HAS_ATOMIC_OPS
+CAIRO_MUTEX_DECLARE (_cairo_atomic_mutex);
+#endif
 
 /* Undefine, to err on unintended inclusion */
 #undef   CAIRO_MUTEX_DECLARE
diff-tree 42de1a0a7f5cc10c2bad98ef69da302ed2a1ca84 (from be327a7b49a62c684e133aad5d5d6adec30b60e6)
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sun Sep 23 21:00:23 2007 +0100

    Move GCC attributes wrapping into a separate header.
    
    The wrapping of GCC attributes (such as cairo_private) needs to be
    visible to any header file, including those that avoid cairoint.h such
    as cairo-boilerplate. To achieve this we move the pre-processor magic to
    its own header file and include it as required.

diff --git a/src/Makefile.am b/src/Makefile.am
index ae7cb63..85964e3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -178,6 +178,7 @@ libcairo_la_base_sources =			\
 	cairo-clip.c				\
 	cairo-clip-private.h			\
 	cairo-color.c				\
+	cairo-compiler-private.h		\
 	cairo-debug.c				\
 	cairo-fixed.c				\
 	cairo-font-face.c			\
diff --git a/src/cairo-cache-private.h b/src/cairo-cache-private.h
index 7ab14e2..4b3164a 100644
--- a/src/cairo-cache-private.h
+++ b/src/cairo-cache-private.h
@@ -39,6 +39,7 @@
 #ifndef CAIRO_CACHE_PRIVATE_H
 #define CAIRO_CACHE_PRIVATE_H
 
+#include "cairo-compiler-private.h"
 #include "cairo-types-private.h"
 
 /**
diff --git a/src/cairo-clip-private.h b/src/cairo-clip-private.h
index 61559ce..7f880d8 100644
--- a/src/cairo-clip-private.h
+++ b/src/cairo-clip-private.h
@@ -36,6 +36,7 @@
 #ifndef CAIRO_CLIP_PRIVATE_H
 #define CAIRO_CLIP_PRIVATE_H
 
+#include "cairo-compiler-private.h"
 #include "cairo-path-fixed-private.h"
 
 extern const cairo_private cairo_rectangle_list_t _cairo_rectangles_nil;
diff --git a/src/cairo-compiler-private.h b/src/cairo-compiler-private.h
new file mode 100644
index 0000000..da80b89
--- /dev/null
+++ b/src/cairo-compiler-private.h
@@ -0,0 +1,115 @@
+/* cairo - a vector graphics library with display and print output
+ *
+ * Copyright © 2002 University of Southern California
+ * Copyright © 2005 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ * The Original Code is the cairo graphics library.
+ *
+ * The Initial Developer of the Original Code is University of Southern
+ * California.
+ *
+ * Contributor(s):
+ *	Carl D. Worth <cworth at cworth.org>
+ */
+
+#ifndef CAIRO_COMPILER_PRIVATE_H
+#define CAIRO_COMPILER_PRIVATE_H
+
+CAIRO_BEGIN_DECLS
+
+#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
+# define slim_hidden_proto(name)		slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
+# define slim_hidden_proto_no_warn(name)	slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
+# define slim_hidden_def(name)			slim_hidden_def1(name, slim_hidden_int_name(name))
+# define slim_hidden_int_name(name) INT_##name
+# define slim_hidden_proto1(name, internal)				\
+  extern __typeof (name) name						\
+	__asm__ (slim_hidden_asmname (internal))
+# define slim_hidden_def1(name, internal)				\
+  extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name))	\
+	__attribute__((__alias__(slim_hidden_asmname(internal))))
+# define slim_hidden_ulp		slim_hidden_ulp1(__USER_LABEL_PREFIX__)
+# define slim_hidden_ulp1(x)		slim_hidden_ulp2(x)
+# define slim_hidden_ulp2(x)		#x
+# define slim_hidden_asmname(name)	slim_hidden_asmname1(name)
+# define slim_hidden_asmname1(name)	slim_hidden_ulp #name
+#else
+# define slim_hidden_proto(name)		int _cairo_dummy_prototype(void)
+# define slim_hidden_proto_no_warn(name)	int _cairo_dummy_prototype(void)
+# define slim_hidden_def(name)			int _cairo_dummy_prototype(void)
+#endif
+
+#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
+	__attribute__((__format__(__printf__, fmt_index, va_index)))
+#else
+#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
+#endif
+
+/* slim_internal.h */
+#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
+#define cairo_private_no_warn	__attribute__((__visibility__("hidden")))
+#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
+#define cairo_private_no_warn	__hidden
+#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
+#define cairo_private_no_warn
+#endif
+
+#ifndef WARN_UNUSED_RESULT
+#define WARN_UNUSED_RESULT
+#endif
+/* Add attribute(warn_unused_result) if supported */
+#define cairo_warn	    WARN_UNUSED_RESULT
+#define cairo_private	    cairo_private_no_warn cairo_warn
+
+/* This macro allow us to deprecate a function by providing an alias
+   for the old function name to the new function name. With this
+   macro, binary compatibility is preserved. The macro only works on
+   some platforms --- tough.
+
+   Meanwhile, new definitions in the public header file break the
+   source code so that it will no longer link against the old
+   symbols. Instead it will give a descriptive error message
+   indicating that the old function has been deprecated by the new
+   function.
+*/
+#if __GNUC__ >= 2 && defined(__ELF__)
+# define CAIRO_FUNCTION_ALIAS(old, new)		\
+	extern __typeof (new) old		\
+	__asm__ ("" #old)			\
+	__attribute__((__alias__("" #new)))
+#else
+# define CAIRO_FUNCTION_ALIAS(old, new)
+#endif
+
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
+
+CAIRO_END_DECLS
+
+#endif
diff --git a/src/cairo-hash-private.h b/src/cairo-hash-private.h
index 8ed3ba8..9101f2e 100644
--- a/src/cairo-hash-private.h
+++ b/src/cairo-hash-private.h
@@ -39,6 +39,7 @@
 #ifndef CAIRO_HASH_PRIVATE_H
 #define CAIRO_HASH_PRIVATE_H
 
+#include "cairo-compiler-private.h"
 #include "cairo-types-private.h"
 
 /* XXX: I'd like this file to be self-contained in terms of
diff --git a/src/cairo-mutex-private.h b/src/cairo-mutex-private.h
index 88e88bb..ac803c8 100644
--- a/src/cairo-mutex-private.h
+++ b/src/cairo-mutex-private.h
@@ -47,6 +47,7 @@
 
 #include <cairo-features.h>
 
+#include "cairo-compiler-private.h"
 #include "cairo-mutex-type-private.h"
 
 /* Only the following three are mandatory at this point */
diff --git a/src/cairo-output-stream-private.h b/src/cairo-output-stream-private.h
index 0600431..0e7d4db 100644
--- a/src/cairo-output-stream-private.h
+++ b/src/cairo-output-stream-private.h
@@ -37,6 +37,7 @@
 #ifndef CAIRO_OUTPUT_STREAM_PRIVATE_H
 #define CAIRO_OUTPUT_STREAM_PRIVATE_H
 
+#include "cairo-compiler-private.h"
 #include "cairo-types-private.h"
 
 typedef cairo_status_t (*cairo_output_stream_write_func_t) (cairo_output_stream_t *output_stream,
diff --git a/src/cairo-region-private.h b/src/cairo-region-private.h
index 7f92f9c..8fc6567 100644
--- a/src/cairo-region-private.h
+++ b/src/cairo-region-private.h
@@ -39,6 +39,8 @@
 
 #include <pixman.h>
 
+#include "cairo-compiler-private.h"
+
 /* cairo_region_t is defined in cairoint.h */
 
 struct _cairo_region {
diff --git a/src/cairo-wideint-private.h b/src/cairo-wideint-private.h
index 636d8a6..69fa156 100644
--- a/src/cairo-wideint-private.h
+++ b/src/cairo-wideint-private.h
@@ -74,6 +74,8 @@
 #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
 #endif
 
+#include "cairo-compiler-private.h"
+
 /*
  * 64-bit datatypes.  Two separate implementations, one using
  * built-in 64-bit signed/unsigned types another implemented
diff --git a/src/cairo-xlib-private.h b/src/cairo-xlib-private.h
index 9b806ee..28ab1d3 100644
--- a/src/cairo-xlib-private.h
+++ b/src/cairo-xlib-private.h
@@ -34,9 +34,12 @@
 #define CAIRO_XLIB_PRIVATE_H
 
 #include "cairoint.h"
+
 #include "cairo-xlib.h"
-#include "cairo-xlib-xrender-private.h"
+
+#include "cairo-compiler-private.h"
 #include "cairo-freelist-private.h"
+#include "cairo-xlib-xrender-private.h"
 
 #include <X11/Xutil.h> /* for XDestroyImage */
 
diff --git a/src/cairoint.h b/src/cairoint.h
index 22eb165..695cb8f 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -66,6 +66,8 @@
 #include "cairo.h"
 #include <pixman.h>
 
+#include "cairo-compiler-private.h"
+
 #ifdef _MSC_VER
 #define snprintf _snprintf
 #undef inline
@@ -74,75 +76,6 @@
 
 CAIRO_BEGIN_DECLS
 
-#if __GNUC__ >= 3 && defined(__ELF__) && !defined(__sun)
-# define slim_hidden_proto(name)		slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private
-# define slim_hidden_proto_no_warn(name)	slim_hidden_proto1(name, slim_hidden_int_name(name)) cairo_private_no_warn
-# define slim_hidden_def(name)			slim_hidden_def1(name, slim_hidden_int_name(name))
-# define slim_hidden_int_name(name) INT_##name
-# define slim_hidden_proto1(name, internal)				\
-  extern __typeof (name) name						\
-	__asm__ (slim_hidden_asmname (internal))
-# define slim_hidden_def1(name, internal)				\
-  extern __typeof (name) EXT_##name __asm__(slim_hidden_asmname(name))	\
-	__attribute__((__alias__(slim_hidden_asmname(internal))))
-# define slim_hidden_ulp		slim_hidden_ulp1(__USER_LABEL_PREFIX__)
-# define slim_hidden_ulp1(x)		slim_hidden_ulp2(x)
-# define slim_hidden_ulp2(x)		#x
-# define slim_hidden_asmname(name)	slim_hidden_asmname1(name)
-# define slim_hidden_asmname1(name)	slim_hidden_ulp #name
-#else
-# define slim_hidden_proto(name)		int _cairo_dummy_prototype(void)
-# define slim_hidden_proto_no_warn(name)	int _cairo_dummy_prototype(void)
-# define slim_hidden_def(name)			int _cairo_dummy_prototype(void)
-#endif
-
-#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
-#define CAIRO_PRINTF_FORMAT(fmt_index, va_index) \
-	__attribute__((__format__(__printf__, fmt_index, va_index)))
-#else
-#define CAIRO_PRINTF_FORMAT(fmt_index, va_index)
-#endif
-
-/* slim_internal.h */
-#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3)) && defined(__ELF__) && !defined(__sun)
-#define cairo_private_no_warn	__attribute__((__visibility__("hidden")))
-#elif defined(__SUNPRO_C) && (__SUNPRO_C >= 0x550)
-#define cairo_private_no_warn	__hidden
-#else /* not gcc >= 3.3 and not Sun Studio >= 8 */
-#define cairo_private_no_warn
-#endif
-
-#ifndef WARN_UNUSED_RESULT
-#define WARN_UNUSED_RESULT
-#endif
-/* Add attribute(warn_unused_result) if supported */
-#define cairo_warn	    WARN_UNUSED_RESULT
-#define cairo_private	    cairo_private_no_warn cairo_warn
-
-/* This macro allow us to deprecate a function by providing an alias
-   for the old function name to the new function name. With this
-   macro, binary compatibility is preserved. The macro only works on
-   some platforms --- tough.
-
-   Meanwhile, new definitions in the public header file break the
-   source code so that it will no longer link against the old
-   symbols. Instead it will give a descriptive error message
-   indicating that the old function has been deprecated by the new
-   function.
-*/
-#if __GNUC__ >= 2 && defined(__ELF__)
-# define CAIRO_FUNCTION_ALIAS(old, new)		\
-	extern __typeof (new) old		\
-	__asm__ ("" #old)			\
-	__attribute__((__alias__("" #new)))
-#else
-# define CAIRO_FUNCTION_ALIAS(old, new)
-#endif
-
-#ifndef __GNUC__
-#define __attribute__(x)
-#endif
-
 #undef MIN
 #define MIN(a, b) ((a) < (b) ? (a) : (b))
 


More information about the cairo-commit mailing list