[PATCH] [cairo-atomic] Rewrite reference counting using atomic ops.
Chris Wilson
chris at chris-wilson.co.uk
Sun Sep 23 13:08:09 PDT 2007
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.
---
src/Makefile.am | 1 +
src/cairo-clip-private.h | 12 +++---
src/cairo-clip.c | 11 +++--
src/cairo-font-face.c | 49 ++++++++++------------
src/cairo-ft-font.c | 2 +-
src/cairo-image-surface.c | 2 +-
src/cairo-pattern.c | 50 ++++++++++++-----------
src/cairo-private.h | 3 +-
src/cairo-reference-count-private.h | 66 ++++++++++++++++++++++++++++++
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-xlib-display.c | 42 ++++++++-----------
src/cairo-xlib-private.h | 5 +-
src/cairo-xlib-screen.c | 12 +++--
src/cairo.c | 23 +++++-----
src/cairoint.h | 27 ++++++------
18 files changed, 244 insertions(+), 177 deletions(-)
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 *clip,
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_path_t *clip_path)
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_path_t *clip_path)
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 _cairo_toy_font_face_backend;
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 *font_face,
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 *font_face,
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_reference);
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_t *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_face_t *font_face)
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_font_face_t *font_face,
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 *family,
{
/* 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_unscaled_font_t *unscaled_font)
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_unscaled_font_t *unscaled_font)
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 *abstract_face)
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 _cairo_image_surface_nil_invalid_format = {
&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 *pattern, cairo_pattern_type_t type)
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_t *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, double cy0, double radius0,
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_pattern_t *pattern,
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 *abstract_glyph)
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_scaled_font_t *scaled_font,
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_font_t *scaled_font,
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_face_t *font_face,
* 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_face_t *font_face,
* 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_create);
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_font_t *scaled_font)
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_destroy);
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_scaled_font_t *scaled_font,
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,
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_surface_t *surface)
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 *surface)
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 *surface)
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_surface_t *surface,
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_xlib_display_t *display)
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_display_t *display)
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_xlib_screen_info_t *info)
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_xlib_screen_info_t *info)
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 *dpy, Screen *screen)
} 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_backend cairo_unscaled_font_backend_t;
* 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 {
--
1.4.4.2
--df+09Je9rNq3P+GE--
More information about the cairo
mailing list