[cairo-commit] src/cairo.c src/cairo-debug.c src/cairoint.h src/cairo-mutex-list-private.h

Chris Wilson ickle at kemper.freedesktop.org
Sat Jun 12 02:47:20 PDT 2010


 src/cairo-debug.c              |    2 +
 src/cairo-mutex-list-private.h |    1 
 src/cairo.c                    |   76 +++++++++++++++++++++++++++++++++++------
 src/cairoint.h                 |    3 +
 4 files changed, 71 insertions(+), 11 deletions(-)

New commits:
commit 9b7cc7641b691a3b9e3d5edd51053c9a095d9c5a
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date:   Sat Jun 12 10:41:09 2010 +0100

    cairo: Create error objects for cairo_t
    
    Perform an early check for error status and prevent creation of a full
    object. This means that we do not pass down error objects to the
    initialisation routines and so can survive without paranoia inside the
    library. It also has brings consistency that like the other
    constructors, no object is created in error and we can skip the
    cairo_destroy() if we choose (and we don't waste one of the precious
    zero-alloc context slots.
    
    Fixes crash in test/a8-mask introduced by 1a544361e845.

diff --git a/src/cairo-debug.c b/src/cairo-debug.c
index 05ca16e..712ce93 100644
--- a/src/cairo-debug.c
+++ b/src/cairo-debug.c
@@ -81,6 +81,8 @@ cairo_debug_reset_static_data (void)
     _cairo_drm_device_reset_static_data ();
 #endif
 
+    _cairo_reset_static_data ();
+
     CAIRO_MUTEX_FINALIZE ();
 }
 
diff --git a/src/cairo-mutex-list-private.h b/src/cairo-mutex-list-private.h
index 29ffd04..5827667 100644
--- a/src/cairo-mutex-list-private.h
+++ b/src/cairo-mutex-list-private.h
@@ -40,6 +40,7 @@ CAIRO_MUTEX_DECLARE (_cairo_pattern_solid_surface_cache_lock)
 
 CAIRO_MUTEX_DECLARE (_cairo_image_solid_cache_mutex)
 
+CAIRO_MUTEX_DECLARE (_cairo_error_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_toy_font_face_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_intern_string_mutex)
 CAIRO_MUTEX_DECLARE (_cairo_scaled_font_map_mutex)
diff --git a/src/cairo.c b/src/cairo.c
index b2a3a7b..9d28aee 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -221,6 +221,61 @@ _context_put (cairo_t *cr)
 #define _context_put(cr) free (cr)
 #endif
 
+/* XXX This should disappear in favour of a common pool of error objects. */
+static cairo_t *_cairo_nil__objects[CAIRO_STATUS_LAST_STATUS + 1];
+
+static cairo_t *
+_cairo_create_in_error (cairo_status_t status)
+{
+    cairo_t *cr;
+
+    assert (status != CAIRO_STATUS_SUCCESS);
+
+    /* special case OOM in order to avoid another allocation */
+    switch ((int) status) {
+    case CAIRO_STATUS_NO_MEMORY:
+	return (cairo_t *) &_cairo_nil;
+    case CAIRO_STATUS_NULL_POINTER:
+	return (cairo_t *) &_cairo_nil__null_pointer;
+    }
+
+    CAIRO_MUTEX_LOCK (_cairo_error_mutex);
+    cr = _cairo_nil__objects[status];
+    if (cr == NULL) {
+	cr = malloc (sizeof (cairo_t));
+	if (unlikely (cr == NULL)) {
+	    CAIRO_MUTEX_UNLOCK (_cairo_error_mutex);
+	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
+	    return (cairo_t *) &_cairo_nil;
+	}
+
+	*cr = _cairo_nil;
+	cr->status = status;
+	_cairo_nil__objects[status] = cr;
+    }
+    CAIRO_MUTEX_UNLOCK (_cairo_error_mutex);
+
+    return cr;
+}
+
+void
+_cairo_reset_static_data (void)
+{
+    int status;
+
+    CAIRO_MUTEX_LOCK (_cairo_error_mutex);
+    for (status = CAIRO_STATUS_SUCCESS;
+	 status <= CAIRO_STATUS_LAST_STATUS;
+	 status++)
+    {
+	if (_cairo_nil__objects[status] != NULL) {
+	    free (_cairo_nil__objects[status]);
+	    _cairo_nil__objects[status] = NULL;
+	}
+    }
+    CAIRO_MUTEX_UNLOCK (_cairo_error_mutex);
+}
+
 /**
  * cairo_create:
  * @target: target surface for the context
@@ -250,17 +305,14 @@ cairo_create (cairo_surface_t *target)
     cairo_t *cr;
     cairo_status_t status;
 
-    /* special case OOM in order to avoid another allocation */
-    if (target == NULL)
-	return (cairo_t *) &_cairo_nil__null_pointer;
-    if (target->status == CAIRO_STATUS_NO_MEMORY)
-	return (cairo_t *) &_cairo_nil;
+    if (unlikely (target == NULL))
+	return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NULL_POINTER));
+    if (unlikely (target->status))
+	return _cairo_create_in_error (target->status);
 
     cr = _context_get ();
-    if (unlikely (cr == NULL)) {
-	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
-	return (cairo_t *) &_cairo_nil;
-    }
+    if (unlikely (cr == NULL))
+	return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
 
     CAIRO_REFERENCE_COUNT_INIT (&cr->ref_count, 1);
 
@@ -274,8 +326,10 @@ cairo_create (cairo_surface_t *target)
     cr->gstate_tail[1].next = NULL;
 
     status = _cairo_gstate_init (cr->gstate, target);
-    if (unlikely (status))
-	_cairo_set_error (cr, status);
+    if (unlikely (status)) {
+	_context_put (cr);
+	cr = _cairo_create_in_error (status);
+    }
 
     return cr;
 }
diff --git a/src/cairoint.h b/src/cairoint.h
index 014f0ba..b3deee9 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -389,6 +389,9 @@ struct _cairo_font_face {
 };
 
 cairo_private void
+_cairo_reset_static_data (void);
+
+cairo_private void
 _cairo_toy_font_face_reset_static_data (void);
 
 cairo_private void


More information about the cairo-commit mailing list