1
/*
2
 * Copyright © 2005 Red Hat, Inc.
3
 *
4
 * Permission to use, copy, modify, distribute, and sell this software
5
 * and its documentation for any purpose is hereby granted without
6
 * fee, provided that the above copyright notice appear in all copies
7
 * and that both that copyright notice and this permission notice
8
 * appear in supporting documentation, and that the name of
9
 * Red Hat, Inc. not be used in advertising or publicity pertaining to
10
 * distribution of the software without specific, written prior
11
 * permission. Red Hat, Inc. makes no representations about the
12
 * suitability of this software for any purpose.  It is provided "as
13
 * is" without express or implied warranty.
14
 *
15
 * RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
16
 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17
 * FITNESS, IN NO EVENT SHALL RED HAT, INC. BE LIABLE FOR ANY SPECIAL,
18
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19
 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
21
 * IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 *
23
 * Author: Carl D. Worth <cworth@cworth.org>
24
 */
25

            
26
/* Test case for bug #4299:
27

            
28
   Assertion fails in "cairo-font.c" when using multithreads
29
   https://bugs.freedesktop.org/show_bug.cgi?id=4299
30
*/
31

            
32
#include "cairo-test.h"
33

            
34
#include <string.h>
35
#include <stdlib.h>
36
#include <pthread.h>
37

            
38
#define N_THREADS 8
39
#define NUM_ITERATIONS 40
40

            
41
#define WIDTH 400
42
#define HEIGHT 42
43

            
44
typedef struct {
45
  cairo_surface_t *target;
46
  int id;
47
} thread_data_t;
48

            
49
static void *
50
24
draw_thread (void *arg)
51
{
52
24
    const char *text = "Hello world. ";
53
24
    thread_data_t *thread_data = arg;
54
    cairo_surface_t *surface;
55
    cairo_font_extents_t extents;
56
    cairo_t *cr;
57
    int i;
58

            
59
24
    cr = cairo_create (thread_data->target);
60
24
    cairo_surface_destroy (thread_data->target);
61

            
62
24
    cairo_set_source_rgb (cr, 1, 1, 1);
63
24
    cairo_paint (cr);
64
24
    cairo_set_source_rgb (cr, 0, 0, 0);
65

            
66
24
    cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif",
67
			    CAIRO_FONT_SLANT_NORMAL,
68
			    CAIRO_FONT_WEIGHT_NORMAL);
69
24
    cairo_set_font_size (cr, NUM_ITERATIONS);
70
24
    cairo_font_extents (cr, &extents);
71

            
72
24
    cairo_move_to (cr, 1, HEIGHT - extents.descent - 1);
73

            
74
984
    for (i = 0; i < NUM_ITERATIONS; i++) {
75
	char buf[2];
76

            
77
960
	cairo_select_font_face (cr, CAIRO_TEST_FONT_FAMILY " Serif",
78
				CAIRO_FONT_SLANT_NORMAL,
79
				CAIRO_FONT_WEIGHT_NORMAL);
80
960
	cairo_set_font_size (cr, i);
81

            
82
960
	buf[0] = text[i%strlen(text)];
83
960
	buf[1] = '\0';
84
960
	cairo_show_text (cr, buf);
85
    }
86

            
87
24
    surface = cairo_surface_reference (cairo_get_target (cr));
88
24
    cairo_destroy (cr);
89

            
90
24
    return surface;
91
}
92

            
93
static cairo_test_status_t
94
3
draw (cairo_t *cr, int width, int height)
95
{
96
    pthread_t threads[N_THREADS];
97
    thread_data_t thread_data[N_THREADS];
98
3
    cairo_test_status_t test_status = CAIRO_TEST_SUCCESS;
99
    int i;
100

            
101
27
    for (i = 0; i < N_THREADS; i++) {
102
24
        thread_data[i].target = cairo_surface_create_similar (cairo_get_target (cr),
103
							      cairo_surface_get_content (cairo_get_target (cr)),
104
							      WIDTH, HEIGHT);
105
24
        thread_data[i].id = i;
106
24
        if (pthread_create (&threads[i], NULL, draw_thread, &thread_data[i]) != 0) {
107
	    threads[i] = pthread_self (); /* to indicate error */
108
            cairo_surface_destroy (thread_data[i].target);
109
            test_status = CAIRO_TEST_FAILURE;
110
	    break;
111
        }
112
    }
113

            
114
3
    cairo_set_source_rgb (cr, 0.5, 0.5, 0.5);
115
3
    cairo_paint (cr);
116

            
117
27
    for (i = 0; i < N_THREADS; i++) {
118
	void *surface;
119

            
120
24
        if (pthread_equal (threads[i], pthread_self ()))
121
            break;
122

            
123
24
        if (pthread_join (threads[i], &surface) == 0) {
124
24
	    cairo_set_source_surface (cr, surface, 0, 0);
125
24
	    cairo_surface_destroy (surface);
126
24
	    cairo_paint (cr);
127

            
128
24
	    cairo_translate (cr, 0, HEIGHT);
129
	} else {
130
            test_status = CAIRO_TEST_FAILURE;
131
	}
132
    }
133

            
134
3
    return test_status;
135
}
136

            
137
1
CAIRO_TEST (pthread_show_text,
138
	    "Concurrent stress test of the cairo_show_text().",
139
	    "thread, text", /* keywords */
140
	    NULL, /* requirements */
141
	    WIDTH, HEIGHT * N_THREADS,
142
	    NULL, draw)