[cairo-commit] 3 commits - src/cairo-surface.c src/test-meta-surface.c src/test-meta-surface.h test/cairo-test-trace.c test/Makefile.am
Chris Wilson
ickle at kemper.freedesktop.org
Fri Jul 3 04:58:13 PDT 2009
src/cairo-surface.c | 13 -
src/test-meta-surface.c | 115 +++++++++-----
src/test-meta-surface.h | 4
test/Makefile.am | 3
test/cairo-test-trace.c | 371 ++++++++++++++++++++++++++++++++++++++++++------
5 files changed, 412 insertions(+), 94 deletions(-)
New commits:
commit ac6c3dbbaed377273b73da6e9e03bb8380a78ec4
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jul 3 12:56:20 2009 +0100
[test-meta] Lazily allocate image
Only allocate the image on first use, as we may never actually need to
construct the image output.
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index 0075fbf..35bd0aa 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -56,6 +56,7 @@ typedef struct _test_meta_surface {
/* This is a cairo_meta_surface to record all operations. */
cairo_surface_t *meta;
+ int width, height;
/* And this is a cairo_image_surface to hold the final result. */
cairo_surface_t *image;
@@ -108,7 +109,7 @@ _test_meta_surface_acquire_source_image (void *abstract_surface,
static void
_test_meta_surface_release_source_image (void *abstract_surface,
cairo_image_surface_t *image,
- void *image_extra)
+ void *image_extra)
{
test_meta_surface_t *surface = abstract_surface;
@@ -125,6 +126,16 @@ _test_meta_surface_show_page (void *abstract_surface)
if (surface->image_reflects_meta)
return CAIRO_STATUS_SUCCESS;
+ if (surface->image == NULL) {
+ surface->image =
+ _cairo_image_surface_create_with_content (surface->base.content,
+ surface->width,
+ surface->height);
+ status = surface->image->status;
+ if (status)
+ return status;
+ }
+
status = _cairo_meta_surface_replay (surface->meta, surface->image);
if (status)
return status;
@@ -154,9 +165,12 @@ _test_meta_surface_get_extents (void *abstract_surface,
{
test_meta_surface_t *surface = abstract_surface;
- surface->image_reflects_meta = FALSE;
+ rectangle->x = 0;
+ rectangle->y = 0;
+ rectangle->width = surface->width;
+ rectangle->height = surface->height;
- return _cairo_surface_get_extents (surface->image, rectangle);
+ return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
@@ -196,7 +210,7 @@ _test_meta_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_rectangle_int_t *extents)
{
test_meta_surface_t *surface = abstract_surface;
@@ -318,10 +332,8 @@ _cairo_test_meta_surface_create (cairo_content_t content,
cairo_status_t status;
surface = malloc (sizeof (test_meta_surface_t));
- if (unlikely (surface == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto FAIL;
- }
+ if (unlikely (surface == NULL))
+ return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
_cairo_surface_init (&surface->base, &test_meta_surface_backend,
content);
@@ -329,23 +341,17 @@ _cairo_test_meta_surface_create (cairo_content_t content,
surface->meta = _cairo_meta_surface_create (content, width, height);
status = cairo_surface_status (surface->meta);
if (status)
- goto FAIL_CLEANUP_SURFACE;
+ goto FAIL;
- surface->image = _cairo_image_surface_create_with_content (content,
- width, height);
- status = cairo_surface_status (surface->image);
- if (status)
- goto FAIL_CLEANUP_META;
+ surface->width = width;
+ surface->height = height;
surface->image_reflects_meta = FALSE;
return &surface->base;
- FAIL_CLEANUP_META:
- cairo_surface_destroy (surface->meta);
- FAIL_CLEANUP_SURFACE:
- free (surface);
FAIL:
+ free (surface);
return _cairo_surface_create_in_error (status);
}
slim_hidden_def (_cairo_test_meta_surface_create);
commit fe73a9dd1413a851beeca7a0fc4ab7cb351ea9ea
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Fri Jul 3 11:24:42 2009 +0100
[test] Record trace to an in-memory meta-surface
Requires hooking into test-meta-surface currently. Export meta-surface!
The idea is that on detection of an error, we can reconstruct a minimal
trace from the meta-surface. The first step is to simply dump the trace
for the failing meta-surface. Later, we should automatically minimise
this further.
diff --git a/src/test-meta-surface.c b/src/test-meta-surface.c
index d5e14d7..0075fbf 100644
--- a/src/test-meta-surface.c
+++ b/src/test-meta-surface.c
@@ -63,49 +63,17 @@ typedef struct _test_meta_surface {
cairo_bool_t image_reflects_meta;
} test_meta_surface_t;
-static const cairo_surface_backend_t test_meta_surface_backend;
-
static cairo_int_status_t
_test_meta_surface_show_page (void *abstract_surface);
-cairo_surface_t *
-_cairo_test_meta_surface_create (cairo_content_t content,
- int width,
- int height)
-{
- test_meta_surface_t *surface;
- cairo_status_t status;
+slim_hidden_proto (_cairo_test_meta_surface_create);
- surface = malloc (sizeof (test_meta_surface_t));
- if (unlikely (surface == NULL)) {
- status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
- goto FAIL;
- }
-
- _cairo_surface_init (&surface->base, &test_meta_surface_backend,
- content);
-
- surface->meta = _cairo_meta_surface_create (content, width, height);
- status = cairo_surface_status (surface->meta);
- if (status)
- goto FAIL_CLEANUP_SURFACE;
-
- surface->image = _cairo_image_surface_create_with_content (content,
- width, height);
- status = cairo_surface_status (surface->image);
- if (status)
- goto FAIL_CLEANUP_META;
-
- surface->image_reflects_meta = FALSE;
-
- return &surface->base;
-
- FAIL_CLEANUP_META:
- cairo_surface_destroy (surface->meta);
- FAIL_CLEANUP_SURFACE:
- free (surface);
- FAIL:
- return _cairo_surface_create_in_error (status);
+static cairo_surface_t *
+_test_meta_surface_create_similar (void *abstract_surface,
+ cairo_content_t content,
+ int width, int height)
+{
+ return _cairo_test_meta_surface_create (content, width, height);
}
static cairo_status_t
@@ -303,7 +271,7 @@ _test_meta_surface_snapshot (void *abstract_other)
static const cairo_surface_backend_t test_meta_surface_backend = {
CAIRO_INTERNAL_SURFACE_TYPE_TEST_META,
- NULL, /* create_similar */
+ _test_meta_surface_create_similar,
_test_meta_surface_finish,
_test_meta_surface_acquire_source_image,
_test_meta_surface_release_source_image,
@@ -340,3 +308,56 @@ static const cairo_surface_backend_t test_meta_surface_backend = {
_test_meta_surface_has_show_text_glyphs,
_test_meta_surface_show_text_glyphs
};
+
+cairo_surface_t *
+_cairo_test_meta_surface_create (cairo_content_t content,
+ int width,
+ int height)
+{
+ test_meta_surface_t *surface;
+ cairo_status_t status;
+
+ surface = malloc (sizeof (test_meta_surface_t));
+ if (unlikely (surface == NULL)) {
+ status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
+ goto FAIL;
+ }
+
+ _cairo_surface_init (&surface->base, &test_meta_surface_backend,
+ content);
+
+ surface->meta = _cairo_meta_surface_create (content, width, height);
+ status = cairo_surface_status (surface->meta);
+ if (status)
+ goto FAIL_CLEANUP_SURFACE;
+
+ surface->image = _cairo_image_surface_create_with_content (content,
+ width, height);
+ status = cairo_surface_status (surface->image);
+ if (status)
+ goto FAIL_CLEANUP_META;
+
+ surface->image_reflects_meta = FALSE;
+
+ return &surface->base;
+
+ FAIL_CLEANUP_META:
+ cairo_surface_destroy (surface->meta);
+ FAIL_CLEANUP_SURFACE:
+ free (surface);
+ FAIL:
+ return _cairo_surface_create_in_error (status);
+}
+slim_hidden_def (_cairo_test_meta_surface_create);
+
+cairo_status_t
+_cairo_test_meta_surface_replay (cairo_surface_t *abstract_surface,
+ cairo_surface_t *target)
+{
+ test_meta_surface_t *surface = (test_meta_surface_t *) abstract_surface;
+
+ if (abstract_surface->backend != &test_meta_surface_backend)
+ return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
+
+ return _cairo_meta_surface_replay (surface->meta, target);
+}
diff --git a/src/test-meta-surface.h b/src/test-meta-surface.h
index c036bb9..a251fd4 100644
--- a/src/test-meta-surface.h
+++ b/src/test-meta-surface.h
@@ -45,6 +45,10 @@ _cairo_test_meta_surface_create (cairo_content_t content,
int width,
int height);
+cairo_status_t
+_cairo_test_meta_surface_replay (cairo_surface_t *abstract_surface,
+ cairo_surface_t *target);
+
CAIRO_END_DECLS
#endif /* TEST_META_SURFACE_H */
diff --git a/test/Makefile.am b/test/Makefile.am
index 1c2bf2a..25dd51a 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -110,6 +110,9 @@ cairo_test_trace_LDADD = \
$(top_builddir)/src/libcairo.la \
$(CAIRO_LDADD) \
$(SHM_LIBS)
+if HAVE_PTHREAD
+cairo_test_trace_LDADD += -lpthread
+endif
cairo_test_trace_DEPENDENCIES = \
$(top_builddir)/test/pdiff/libpdiff.la \
$(top_builddir)/util/cairo-script/libcairo-script-interpreter.la \
diff --git a/test/cairo-test-trace.c b/test/cairo-test-trace.c
index 4d415b8..18e1934 100644
--- a/test/cairo-test-trace.c
+++ b/test/cairo-test-trace.c
@@ -60,6 +60,13 @@
#include "cairo-boilerplate-getopt.h"
#include <cairo-script-interpreter.h>
+#if CAIRO_HAS_SCRIPT_SURFACE
+#include <cairo-script.h>
+#endif
+
+/* XXX give me a real meta surface! */
+#include <test-meta-surface.h>
+
/* For basename */
#ifdef HAVE_LIBGEN_H
#include <libgen.h>
@@ -78,11 +85,16 @@
#include <sys/un.h>
#include <errno.h>
#include <assert.h>
+#if HAVE_PTHREAD_H
+#include <pthread.h>
+#endif
#if HAVE_FCFINI
#include <fontconfig/fontconfig.h>
#endif
+#define DEBUG 0
+
#define DATA_SIZE (256 << 20)
#define SHM_PATH_XXX "/shmem-cairo-trace"
@@ -104,8 +116,10 @@ typedef struct _test_runner_thread {
cairo_surface_t *surface;
void *closure;
uint8_t *base;
+ const char *trace;
pid_t pid;
int sk;
+ cairo_bool_t is_meta;
cairo_script_interpreter_t *csi;
struct context_closure {
@@ -128,10 +142,12 @@ struct slave {
unsigned long start_line;
unsigned long end_line;
cairo_surface_t *image;
+ long width, height;
cairo_surface_t *difference;
buffer_diff_result_t result;
const cairo_boilerplate_target_t *target;
const struct slave *reference;
+ cairo_bool_t is_meta;
};
struct request_image {
@@ -139,16 +155,22 @@ struct request_image {
unsigned long start_line;
unsigned long end_line;
cairo_format_t format;
- int width;
- int height;
- int stride;
+ long width;
+ long height;
+ long stride;
};
struct surface_tag {
- int width, height;
+ long width, height;
};
static const cairo_user_data_key_t surface_tag;
+#if HAVE_PTHREAD_H
+#define thread_die(t) t->is_meta ? pthread_exit(NULL) : exit(1)
+#else
+#define thread_die(t) exit(1)
+#endif
+
static cairo_bool_t
writen (int fd, const void *ptr, int len)
{
@@ -221,6 +243,48 @@ format_for_content (cairo_content_t content)
}
}
+static void
+send_meta_surface (test_runner_thread_t *thread,
+ int width, int height,
+ struct context_closure *closure)
+{
+#if HAVE_PTHREAD_H
+ const struct request_image rq = {
+ closure->id,
+ closure->start_line,
+ closure->end_line,
+ -1,
+ width, height,
+ cairo_surface_get_type (closure->surface) == CAIRO_SURFACE_TYPE_IMAGE ? 0 : (long) closure->surface,
+ };
+ unsigned long offset;
+ unsigned long serial;
+
+ if (DEBUG > 1) {
+ printf ("send-meta-surface: %lu [%lu, %lu]\n",
+ closure->id,
+ closure->start_line,
+ closure->end_line);
+ }
+ writen (thread->sk, &rq, sizeof (rq));
+ readn (thread->sk, &offset, sizeof (offset));
+
+ /* signal completion */
+ writen (thread->sk, &closure->id, sizeof (closure->id));
+
+ /* wait for image check */
+ serial = 0;
+ readn (thread->sk, &serial, sizeof (serial));
+ if (DEBUG > 1) {
+ printf ("send-meta-surface: serial: %lu\n", serial);
+ }
+ if (serial != closure->id)
+ pthread_exit (NULL);
+#else
+ exit (1);
+#endif
+}
+
static void *
request_image (test_runner_thread_t *thread,
struct context_closure *closure,
@@ -233,18 +297,20 @@ request_image (test_runner_thread_t *thread,
closure->end_line,
format, width, height, stride
};
- size_t offset = -1;
+ unsigned long offset = -1;
+
+ assert (format != (cairo_format_t) -1);
writen (thread->sk, &rq, sizeof (rq));
readn (thread->sk, &offset, sizeof (offset));
- if (offset == (size_t) -1)
+ if (offset == (unsigned long) -1)
return NULL;
return thread->base + offset;
}
static void
-push_surface (test_runner_thread_t *thread,
+send_surface (test_runner_thread_t *thread,
struct context_closure *closure)
{
cairo_surface_t *source = closure->surface;
@@ -255,6 +321,10 @@ push_surface (test_runner_thread_t *thread,
void *data;
unsigned long serial;
+ if (DEBUG > 1) {
+ printf ("send-surface: '%s'\n", thread->target->name);
+ }
+
if (cairo_surface_get_type (source) == CAIRO_SURFACE_TYPE_IMAGE) {
width = cairo_image_surface_get_width (source);
height = cairo_image_surface_get_height (source);
@@ -279,9 +349,15 @@ push_surface (test_runner_thread_t *thread,
height = tag->height = y1 - y0;
if (cairo_surface_set_user_data (source, &surface_tag, tag, free))
- exit (-1);
+ thread_die (thread);
}
}
+
+ if (thread->is_meta) {
+ send_meta_surface (thread, width, height, closure);
+ return;
+ }
+
if (format == (cairo_format_t) -1)
format = format_for_content (cairo_surface_get_content (source));
@@ -289,7 +365,7 @@ push_surface (test_runner_thread_t *thread,
data = request_image (thread, closure, format, width, height, stride);
if (data == NULL)
- exit (-1);
+ thread_die (thread);
image = cairo_image_surface_create_for_data (data,
format,
@@ -310,7 +386,7 @@ push_surface (test_runner_thread_t *thread,
serial = 0;
readn (thread->sk, &serial, sizeof (serial));
if (serial != closure->id)
- exit (-1);
+ thread_die (thread);
}
static cairo_surface_t *
@@ -330,7 +406,7 @@ _surface_create (void *closure,
tag->width = width;
tag->height = height;
if (cairo_surface_set_user_data (surface, &surface_tag, tag, free))
- exit (-1);
+ thread_die (thread);
}
return surface;
@@ -367,13 +443,13 @@ _context_destroy (void *closure, void *ptr)
l->end_line =
cairo_script_interpreter_get_line_number (thread->csi);
if (cairo_surface_status (l->surface) == CAIRO_STATUS_SUCCESS) {
- push_surface (thread, l);
+ send_surface (thread, l);
} else {
fprintf (stderr, "%s: error during replay, line %lu: %s!\n",
thread->target->name,
l->end_line,
cairo_status_to_string (cairo_surface_status (l->surface)));
- exit (1);
+ thread_die (thread);
}
cairo_surface_destroy (l->surface);
@@ -386,8 +462,7 @@ _context_destroy (void *closure, void *ptr)
}
static void
-execute (test_runner_thread_t *thread,
- const char *trace)
+execute (test_runner_thread_t *thread)
{
const cairo_script_interpreter_hooks_t hooks = {
.closure = thread,
@@ -395,15 +470,21 @@ execute (test_runner_thread_t *thread,
.context_create = _context_create,
.context_destroy = _context_destroy,
};
+ pid_t ack;
thread->csi = cairo_script_interpreter_create ();
cairo_script_interpreter_install_hooks (thread->csi, &hooks);
- cairo_script_interpreter_run (thread->csi, trace);
+ ack = -1;
+ readn (thread->sk, &ack, sizeof (ack));
+ if (ack != thread->pid)
+ thread_die (thread);
+
+ cairo_script_interpreter_run (thread->csi, thread->trace);
cairo_script_interpreter_finish (thread->csi);
if (cairo_script_interpreter_destroy (thread->csi))
- exit (1);
+ thread_die (thread);
}
static int
@@ -457,10 +538,14 @@ spawn_target (const char *socket_path,
test_runner_thread_t thread;
pid_t pid;
+ if (DEBUG)
+ printf ("Spawning slave '%s' for %s\n", target->name, trace);
+
pid = fork ();
if (pid != 0)
return pid;
+ thread.is_meta = FALSE;
thread.pid = getpid ();
thread.sk = spawn_socket (socket_path, thread.pid);
@@ -480,6 +565,7 @@ spawn_target (const char *socket_path,
thread.target = target;
thread.contexts = NULL;
thread.context_id = 0;
+ thread.trace = trace;
thread.surface = target->create_surface (NULL,
target->content,
@@ -495,7 +581,7 @@ spawn_target (const char *socket_path,
exit (-1);
}
- execute (&thread, trace);
+ execute (&thread);
cairo_surface_destroy (thread.surface);
@@ -508,6 +594,95 @@ spawn_target (const char *socket_path,
exit (0);
}
+#if HAVE_PTHREAD_H
+static void
+cleanup_recorder (void *arg)
+{
+ test_runner_thread_t *thread = arg;
+
+ cairo_surface_finish (thread->surface);
+ cairo_surface_destroy (thread->surface);
+
+ if (thread->target->cleanup)
+ thread->target->cleanup (thread->closure);
+
+ close (thread->sk);
+ free (thread);
+}
+
+static void *
+record (void *arg)
+{
+ test_runner_thread_t *thread = arg;
+
+ pthread_cleanup_push (cleanup_recorder, thread);
+ execute (thread);
+ pthread_cleanup_pop (TRUE);
+
+ return NULL;
+}
+
+/* The recorder is special:
+ * 1. It doesn't generate an image, but keeps an in-memory trace to
+ * reconstruct any surface.
+ * 2. Runs in the same process, but separate thread.
+ */
+static pid_t
+spawn_recorder (const char *socket_path,
+ const cairo_boilerplate_target_t *target,
+ const char *trace)
+{
+ test_runner_thread_t *thread;
+ pthread_t id;
+ pthread_attr_t attr;
+ pid_t pid = getpid ();
+
+ if (DEBUG)
+ printf ("Spawning recorder for %s\n", trace);
+
+ thread = malloc (sizeof (*thread));
+ if (thread == NULL)
+ return -1;
+
+ thread->is_meta = TRUE;
+ thread->pid = pid;
+ thread->sk = spawn_socket (socket_path, thread->pid);
+ if (thread->sk == -1) {
+ free (thread);
+ return -1;
+ }
+
+ thread->base = NULL;
+ thread->target = target;
+ thread->contexts = NULL;
+ thread->context_id = 0;
+ thread->trace = trace;
+
+ thread->surface = target->create_surface (NULL,
+ target->content,
+ 1, 1,
+ 1, 1,
+ CAIRO_BOILERPLATE_MODE_TEST,
+ 0,
+ &thread->closure);
+ if (thread->surface == NULL) {
+ cleanup_recorder (thread);
+ return -1;
+ }
+
+ pthread_attr_init (&attr);
+ pthread_attr_setdetachstate (&attr, TRUE);
+ if (pthread_create (&id, &attr, record, thread) < 0) {
+ pthread_attr_destroy (&attr);
+ cleanup_recorder (thread);
+ return -1;
+ }
+ pthread_attr_destroy (&attr);
+
+ return pid;
+}
+#endif
+
/* XXX imagediff - is the extra expense worth it? */
static cairo_bool_t
matches_reference (struct slave *slave)
@@ -681,7 +856,7 @@ write_images (const char *trace, struct slave *slave, int num_slaves)
if (slave->image != NULL) {
char *filename;
- xasprintf (&filename, "%s-%s-out.png",
+ xasprintf (&filename, "%s-%s-fail.png",
trace, slave->target->name);
cairo_surface_write_to_png (slave->image, filename);
free (filename);
@@ -698,28 +873,69 @@ write_images (const char *trace, struct slave *slave, int num_slaves)
}
}
-static size_t
-allocate_image_for_slave (uint8_t *base, size_t offset, struct slave *slave)
+static void
+write_trace (const char *trace, struct slave *slave)
+{
+#if CAIRO_HAS_SCRIPT_SURFACE
+ cairo_surface_t *script;
+ char *filename;
+ cairo_status_t status;
+
+ xasprintf (&filename, "%s-fail.trace", trace);
+ script = cairo_script_surface_create (filename,
+ slave->width,
+ slave->height);
+ free (filename);
+
+ status = _cairo_test_meta_surface_replay (slave->image, script);
+ cairo_surface_destroy (script);
+#endif
+}
+
+static unsigned long
+allocate_image_for_slave (uint8_t *base,
+ unsigned long offset,
+ struct slave *slave)
{
struct request_image rq;
int size;
uint8_t *data;
+ assert (slave->image == NULL);
+
readn (slave->fd, &rq, sizeof (rq));
slave->image_serial = rq.id;
slave->start_line = rq.start_line;
slave->end_line = rq.end_line;
- size = rq.height * rq.stride;
- size = (size + 127) & -128;
- data = base + offset;
- offset += size;
- assert (offset <= DATA_SIZE);
+ slave->width = rq.width;
+ slave->height = rq.height;
+
+ if (DEBUG > 1) {
+ printf ("allocate-image-for-slave: %s %lu [%lu, %lu] %ldx%ld=> %lu\n",
+ slave->target->name,
+ slave->image_serial,
+ slave->start_line,
+ slave->end_line,
+ slave->width,
+ slave->height,
+ offset);
+ }
- assert (slave->image == NULL);
- slave->image = cairo_image_surface_create_for_data (data, rq.format,
- rq.width, rq.height,
- rq.stride);
+ if (slave->is_meta) {
+ /* special communication with meta-surface thread */
+ slave->image = cairo_surface_reference ((cairo_surface_t *) rq.stride);
+ } else {
+ size = rq.height * rq.stride;
+ size = (size + 4095) & -4096;
+ data = base + offset;
+ offset += size;
+ assert (offset <= DATA_SIZE);
+
+ slave->image = cairo_image_surface_create_for_data (data, rq.format,
+ rq.width, rq.height,
+ rq.stride);
+ }
return offset;
}
@@ -742,9 +958,14 @@ test_run (void *base,
int npfd, cnt, n, i;
int completion;
cairo_bool_t ret = FALSE;
- size_t image;
+ unsigned long image;
+
+ if (DEBUG) {
+ printf ("Running trace '%s' over %d slaves\n",
+ trace, num_slaves);
+ }
- pfd = xcalloc (num_slaves+2, sizeof (*pfd));
+ pfd = xcalloc (num_slaves+1, sizeof (*pfd));
pfd[0].fd = sk;
pfd[0].events = POLLIN;
@@ -761,13 +982,23 @@ test_run (void *base,
readn (fd, &pid, sizeof (pid));
for (n = 0; n < num_slaves; n++) {
- if (slaves[n].pid == pid)
+ if (slaves[n].pid == pid) {
slaves[n].fd = fd;
+ break;
+ }
+ }
+ if (n == num_slaves) {
+ if (DEBUG)
+ printf ("unknown slave pid\n");
+ goto out;
}
pfd[npfd].fd = fd;
pfd[npfd].events = POLLIN;
npfd++;
+
+ if (! writen (fd, &pid, sizeof (pid)))
+ goto out;
}
cnt--;
}
@@ -798,7 +1029,7 @@ test_run (void *base,
* if satisfied, send an acknowledgement to all slaves.
*/
if (slaves[i].image_serial == 0) {
- size_t offset;
+ unsigned long offset;
image =
allocate_image_for_slave (base,
@@ -810,11 +1041,18 @@ test_run (void *base,
readn (pfd[n].fd,
&slaves[i].image_ready,
sizeof (slaves[i].image_ready));
+ if (DEBUG) {
+ printf ("slave '%s' reports completion on %lu (expecting %lu)\n",
+ slaves[i].target->name,
+ slaves[i].image_ready,
+ slaves[i].image_serial);
+ }
if (slaves[i].image_ready != slaves[i].image_serial)
goto out;
/* Can anyone spell 'P·E·D·A·N·T'? */
- cairo_surface_mark_dirty (slaves[i].image);
+ if (! slaves[i].is_meta)
+ cairo_surface_mark_dirty (slaves[i].image);
completion++;
}
@@ -826,12 +1064,26 @@ test_run (void *base,
}
if (completion == num_slaves) {
+ if (DEBUG > 1) {
+ printf ("all saves report completion\n");
+ }
if (! check_images (slaves, num_slaves)) {
error->context_id = slaves[0].image_serial;
error->start_line = slaves[0].start_line;
error->end_line = slaves[0].end_line;
+ if (DEBUG) {
+ printf ("check_images failed: %lu, [%lu, %lu]\n",
+ slaves[0].image_serial,
+ slaves[0].start_line,
+ slaves[0].end_line);
+ }
+
write_images (trace, slaves, num_slaves);
+
+ if (slaves[0].is_meta)
+ write_trace (trace, &slaves[0]);
+
goto out;
}
@@ -840,6 +1092,10 @@ test_run (void *base,
cairo_surface_destroy (slaves[i].image);
slaves[i].image = NULL;
+ if (DEBUG > 1) {
+ printf ("sending continuation to '%s'\n",
+ slaves[i].target->name);
+ }
if (! writen (slaves[i].fd,
&slaves[i].image_serial,
sizeof (slaves[i].image_serial)))
@@ -859,6 +1115,10 @@ done:
ret = TRUE;
out:
+ if (DEBUG) {
+ printf ("run complete: %d\n", ret);
+ }
+
for (n = 0; n < num_slaves; n++) {
if (slaves[n].fd != -1)
close (slaves[n].fd);
@@ -983,7 +1243,7 @@ _test_trace (test_runner_t *test,
struct error_info *error)
{
const char *shm_path = SHM_PATH_XXX;
- const cairo_boilerplate_target_t *target, *image;
+ const cairo_boilerplate_target_t *target, *image, *meta;
struct slave *slaves, *s;
char socket_dir[] = "/tmp/cairo-test-trace.XXXXXX";
char *socket_path;
@@ -1016,8 +1276,31 @@ _test_trace (test_runner_t *test,
image = cairo_boilerplate_get_image_target (CAIRO_CONTENT_COLOR_ALPHA);
assert (image != NULL);
- /* spawn slave processes to run the trace */
s = slaves = xcalloc (2*test->num_targets + 1, sizeof (struct slave));
+
+#if HAVE_PTHREAD_H
+ /* set-up a meta-surface to reconstruct errors */
+ meta = cairo_boilerplate_get_target_by_name ("test-meta",
+ CAIRO_CONTENT_COLOR_ALPHA);
+ if (meta != NULL) {
+ pid_t slave;
+
+ slave = spawn_recorder (socket_path, meta, trace);
+ if (slave < 0) {
+ fprintf (stderr, "Unable to create meta surface\n");
+ goto cleanup_sk;
+ }
+
+ s->pid = slave;
+ s->is_meta = TRUE;
+ s->target = meta;
+ s->fd = -1;
+ s->reference = NULL;
+ s++;
+ }
+#endif
+
+ /* spawn slave processes to run the trace */
for (i = 0; i < test->num_targets; i++) {
pid_t slave;
const cairo_boilerplate_target_t *reference;
@@ -1082,12 +1365,15 @@ cleanup:
close (fd);
while (s-- > slaves) {
int status;
+
+ if (s->is_meta) /* in-process */
+ continue;
+
kill (s->pid, SIGKILL);
waitpid (s->pid, &status, 0);
ret &= WIFEXITED (status) && WEXITSTATUS (status) == 0;
- if (WIFSIGNALED (status) && WTERMSIG(status) != SIGKILL) {
+ if (WIFSIGNALED (status) && WTERMSIG(status) != SIGKILL)
fprintf (stderr, "%s crashed\n", s->target->name);
- }
}
free (slaves);
shm_unlink (shm_path);
@@ -1293,10 +1579,13 @@ parse_options (test_runner_t *test, int argc, char *argv[])
static void
test_reset (test_runner_t *test)
{
+ /* XXX leaking fonts again via meta-surface? */
+#if 0
cairo_debug_reset_static_data ();
#if HAVE_FCFINI
FcFini ();
#endif
+#endif
}
static void
@@ -1406,9 +1695,7 @@ main (int argc, char *argv[])
if (test_has_filenames (&test)) {
for (n = 0; n < test.num_names; n++) {
- if (test_can_run (&test, test.names[n]) &&
- access (test.names[n], R_OK) == 0)
- {
+ if (access (test.names[n], R_OK) == 0) {
test_trace (&test, test.names[n]);
test_reset (&test);
}
commit 633efe81873168506ec3594eae1f6ac38d71026c
Author: Chris Wilson <chris at chris-wilson.co.uk>
Date: Thu Jul 2 09:17:43 2009 +0100
[surface] Allocate temporary region on stack
Avoid a very short-lived temporary heap allocation of a region.
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 0b56b25..fd35c12 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2916,7 +2916,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
unsigned int height)
{
cairo_rectangle_int_t dst_rectangle;
- cairo_region_t *clear_region;
+ cairo_region_t clear_region;
cairo_status_t status;
/* The area that was drawn is the area in the destination rectangle but
@@ -2927,10 +2927,7 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
dst_rectangle.width = width;
dst_rectangle.height = height;
- clear_region = cairo_region_create_rectangle (&dst_rectangle);
- status = clear_region->status;
- if (unlikely (status))
- goto CLEANUP_REGIONS;
+ _cairo_region_init_rectangle (&clear_region, &dst_rectangle);
if (src_rectangle) {
if (! _cairo_rectangle_intersect (&dst_rectangle, src_rectangle))
@@ -2943,17 +2940,17 @@ _cairo_surface_composite_fixup_unbounded_internal (cairo_surface_t *dst,
}
/* Now compute the area that is in dst but not drawn */
- status = cairo_region_subtract_rectangle (clear_region, &dst_rectangle);
+ status = cairo_region_subtract_rectangle (&clear_region, &dst_rectangle);
if (unlikely (status))
goto CLEANUP_REGIONS;
EMPTY:
status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_SOURCE,
CAIRO_COLOR_TRANSPARENT,
- clear_region);
+ &clear_region);
CLEANUP_REGIONS:
- cairo_region_destroy (clear_region);
+ _cairo_region_fini (&clear_region);
return _cairo_surface_set_error (dst, status);
}
More information about the cairo-commit
mailing list