1 /*
2 * Copyright © 2006 Joonas Pihlaja
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
23 #include "cairoint.h"
24
25 #include "cairo-error-private.h"
26 #include "cairo-freelist-private.h"
27
28 void
_cairo_freelist_init(cairo_freelist_t * freelist,unsigned nodesize)29 _cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize)
30 {
31 memset (freelist, 0, sizeof (cairo_freelist_t));
32 freelist->nodesize = nodesize;
33 }
34
35 void
_cairo_freelist_fini(cairo_freelist_t * freelist)36 _cairo_freelist_fini (cairo_freelist_t *freelist)
37 {
38 cairo_freelist_node_t *node = freelist->first_free_node;
39 while (node) {
40 cairo_freelist_node_t *next;
41
42 VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
43 next = node->next;
44
45 free (node);
46 node = next;
47 }
48 }
49
50 void *
_cairo_freelist_alloc(cairo_freelist_t * freelist)51 _cairo_freelist_alloc (cairo_freelist_t *freelist)
52 {
53 if (freelist->first_free_node) {
54 cairo_freelist_node_t *node;
55
56 node = freelist->first_free_node;
57 VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
58 freelist->first_free_node = node->next;
59 VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize));
60
61 return node;
62 }
63
64 return malloc (freelist->nodesize);
65 }
66
67 void *
_cairo_freelist_calloc(cairo_freelist_t * freelist)68 _cairo_freelist_calloc (cairo_freelist_t *freelist)
69 {
70 void *node = _cairo_freelist_alloc (freelist);
71 if (node)
72 memset (node, 0, freelist->nodesize);
73 return node;
74 }
75
76 void
_cairo_freelist_free(cairo_freelist_t * freelist,void * voidnode)77 _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode)
78 {
79 cairo_freelist_node_t *node = voidnode;
80 if (node) {
81 node->next = freelist->first_free_node;
82 freelist->first_free_node = node;
83 VG (VALGRIND_MAKE_MEM_NOACCESS (node, freelist->nodesize));
84 }
85 }
86
87 void
_cairo_freepool_init(cairo_freepool_t * freepool,unsigned nodesize)88 _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize)
89 {
90 freepool->first_free_node = NULL;
91 freepool->pools = &freepool->embedded_pool;
92 freepool->freepools = NULL;
93 freepool->nodesize = nodesize;
94
95 freepool->embedded_pool.next = NULL;
96 freepool->embedded_pool.size = sizeof (freepool->embedded_data);
97 freepool->embedded_pool.rem = sizeof (freepool->embedded_data);
98 freepool->embedded_pool.data = freepool->embedded_data;
99
100 VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data)));
101 }
102
103 void
_cairo_freepool_fini(cairo_freepool_t * freepool)104 _cairo_freepool_fini (cairo_freepool_t *freepool)
105 {
106 cairo_freelist_pool_t *pool;
107
108 pool = freepool->pools;
109 while (pool != &freepool->embedded_pool) {
110 cairo_freelist_pool_t *next = pool->next;
111 free (pool);
112 pool = next;
113 }
114
115 pool = freepool->freepools;
116 while (pool != NULL) {
117 cairo_freelist_pool_t *next = pool->next;
118 free (pool);
119 pool = next;
120 }
121
122 VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool)));
123 }
124
125 void *
_cairo_freepool_alloc_from_new_pool(cairo_freepool_t * freepool)126 _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool)
127 {
128 cairo_freelist_pool_t *pool;
129 int poolsize;
130
131 if (freepool->freepools != NULL) {
132 pool = freepool->freepools;
133 freepool->freepools = pool->next;
134
135 poolsize = pool->size;
136 } else {
137 if (freepool->pools != &freepool->embedded_pool)
138 poolsize = 2 * freepool->pools->size;
139 else
140 poolsize = (128 * freepool->nodesize + 8191) & -8192;
141
142 pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize);
143 if (unlikely (pool == NULL))
144 return pool;
145
146 pool->size = poolsize;
147 }
148
149 pool->next = freepool->pools;
150 freepool->pools = pool;
151
152 pool->rem = poolsize - freepool->nodesize;
153 pool->data = (uint8_t *) (pool + 1) + freepool->nodesize;
154
155 VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem));
156
157 return pool + 1;
158 }
159
160 cairo_status_t
_cairo_freepool_alloc_array(cairo_freepool_t * freepool,int count,void ** array)161 _cairo_freepool_alloc_array (cairo_freepool_t *freepool,
162 int count,
163 void **array)
164 {
165 int i;
166
167 for (i = 0; i < count; i++) {
168 cairo_freelist_node_t *node;
169
170 node = freepool->first_free_node;
171 if (likely (node != NULL)) {
172 VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next)));
173 freepool->first_free_node = node->next;
174 VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize));
175 } else {
176 node = _cairo_freepool_alloc_from_pool (freepool);
177 if (unlikely (node == NULL))
178 goto CLEANUP;
179 }
180
181 array[i] = node;
182 }
183
184 return CAIRO_STATUS_SUCCESS;
185
186 CLEANUP:
187 while (i--)
188 _cairo_freepool_free (freepool, array[i]);
189
190 return _cairo_error (CAIRO_STATUS_NO_MEMORY);
191 }
192