1 /* Cairo - a vector graphics library with display and print output
3 * Copyright © 2007 Chris Wilson
4 * Copyright © 2009 Intel Corporation
6 * This library is free software; you can redistribute it and/or
7 * modify it either under the terms of the GNU Lesser General Public
8 * License version 2.1 as published by the Free Software Foundation
9 * (the "LGPL") or, at your option, under the terms of the Mozilla
10 * Public License Version 1.1 (the "MPL"). If you do not alter this
11 * notice, a recipoolent may use your version of this file under either
12 * the MPL or the LGPL.
14 * You should have received a copy of the LGPL along with this library
15 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17 * You should have received a copy of the MPL along with this library
18 * in the file COPYING-MPL-1.1
20 * The contents of this file are subject to the Mozilla Public License
21 * Version 1.1 (the "License"); you may not use this file except in
22 * compliance with the License. You may obtain a copy of the License at
23 * http://www.mozilla.org/MPL/
25 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27 * the specific language governing rights and limitations.
29 * The Original Code is the cairo graphics library.
31 * The Initial Developer of the Original Code is Red Hat, Inc.
34 * Chris Wilson <chris@chris-wilson.co.uk>
39 #include "cairo-mempool-private.h"
40 #include "cairo-list-inline.h"
42 /* a simple buddy allocator for memory pools
43 * XXX fragmentation? use Doug Lea's malloc?
46 #define BITTEST(p, n) ((p)->map[(n) >> 3] & (128 >> ((n) & 7)))
47 #define BITSET(p, n) ((p)->map[(n) >> 3] |= (128 >> ((n) & 7)))
48 #define BITCLEAR(p, n) ((p)->map[(n) >> 3] &= ~(128 >> ((n) & 7)))
51 clear_bits (cairo_mempool_t
*pool
, size_t first
, size_t last
)
54 size_t first_full
= (first
+ 7) & ~7;
55 size_t past_full
= last
& ~7;
60 for (i
= first
; i
< n
; i
++)
63 if (past_full
> first_full
) {
64 bytes
= past_full
- first_full
;
66 memset (pool
->map
+ (first_full
>> 3), 0, bytes
);
71 for (i
= past_full
; i
< last
; i
++)
76 free_bits (cairo_mempool_t
*pool
, size_t start
, int bits
, cairo_bool_t clear
)
78 struct _cairo_memblock
*block
;
81 clear_bits (pool
, start
, start
+ (1 << bits
));
83 block
= pool
->blocks
+ start
;
86 cairo_list_add (&block
->link
, &pool
->free
[bits
]);
88 pool
->free_bytes
+= 1 << (bits
+ pool
->min_bits
);
89 if (bits
> pool
->max_free_bits
)
90 pool
->max_free_bits
= bits
;
93 /* Add a chunk to the free list */
95 free_blocks (cairo_mempool_t
*pool
,
103 for (i
= first
, len
= 1; i
< last
; i
+= len
) {
104 /* To avoid cost quadratic in the number of different
105 * blocks produced from this chunk of store, we have to
106 * use the size of the previous block produced from this
107 * chunk as the starting point to work out the size of the
108 * next block we can produce. If you look at the binary
109 * representation of the starting points of the blocks
110 * produced, you can see that you first of all increase the
111 * size of the blocks produced up to some maximum as the
112 * address dealt with gets offsets added on which zap out
113 * low order bits, then decrease as the low order bits of the
114 * final block produced get added in. E.g. as you go from
115 * 001 to 0111 you generate blocks
116 * of size 001 at 001 taking you to 010
117 * of size 010 at 010 taking you to 100
118 * of size 010 at 100 taking you to 110
119 * of size 001 at 110 taking you to 111
120 * So the maximum total cost of the loops below this comment
121 * is one trip from the lowest blocksize to the highest and
124 while (bits
< pool
->num_sizes
- 1) {
125 size_t next_bits
= bits
+ 1;
126 size_t next_len
= len
<< 1;
128 if (i
+ next_bits
> last
) {
129 /* off end of chunk to be freed */
133 if (i
& (next_len
- 1)) /* block would not be on boundary */
141 if (i
+ len
<= last
&& /* off end of chunk to be freed */
142 (i
& (len
- 1)) == 0) /* block would not be on boundary */
151 free_bits (pool
, i
, bits
, clear
);
155 static struct _cairo_memblock
*
156 get_buddy (cairo_mempool_t
*pool
, size_t offset
, int bits
)
158 struct _cairo_memblock
*block
;
160 if (offset
+ (1 << bits
) >= pool
->num_blocks
)
161 return NULL
; /* invalid */
163 if (BITTEST (pool
, offset
+ (1 << bits
) - 1))
164 return NULL
; /* buddy is allocated */
166 block
= pool
->blocks
+ offset
;
167 if (block
->bits
!= bits
)
168 return NULL
; /* buddy is partially allocated */
174 merge_buddies (cairo_mempool_t
*pool
,
175 struct _cairo_memblock
*block
,
178 size_t block_offset
= block
- pool
->blocks
;
179 int bits
= block
->bits
;
181 while (bits
< max_bits
- 1) {
182 /* while you can, merge two blocks and get a legal block size */
183 size_t buddy_offset
= block_offset
^ (1 << bits
);
185 block
= get_buddy (pool
, buddy_offset
, bits
);
189 cairo_list_del (&block
->link
);
191 /* Merged block starts at buddy */
192 if (buddy_offset
< block_offset
)
193 block_offset
= buddy_offset
;
198 block
= pool
->blocks
+ block_offset
;
200 cairo_list_add (&block
->link
, &pool
->free
[bits
]);
202 if (bits
> pool
->max_free_bits
)
203 pool
->max_free_bits
= bits
;
206 /* attempt to merge all available buddies up to a particular size */
208 merge_bits (cairo_mempool_t
*pool
, int max_bits
)
210 struct _cairo_memblock
*block
, *buddy
, *next
;
213 for (bits
= 0; bits
< max_bits
- 1; bits
++) {
214 cairo_list_foreach_entry_safe (block
, next
,
215 struct _cairo_memblock
,
219 size_t buddy_offset
= (block
- pool
->blocks
) ^ (1 << bits
);
221 buddy
= get_buddy (pool
, buddy_offset
, bits
);
226 next
= cairo_container_of (buddy
->link
.next
,
227 struct _cairo_memblock
,
231 cairo_list_del (&block
->link
);
232 merge_buddies (pool
, block
, max_bits
);
236 return pool
->max_free_bits
;
239 /* find store for 1 << bits blocks */
241 buddy_malloc (cairo_mempool_t
*pool
, int bits
)
244 struct _cairo_memblock
*block
;
247 if (bits
> pool
->max_free_bits
&& bits
> merge_bits (pool
, bits
))
250 /* Find a list with blocks big enough on it */
252 for (b
= bits
; b
<= pool
->max_free_bits
; b
++) {
253 if (! cairo_list_is_empty (&pool
->free
[b
])) {
254 block
= cairo_list_first_entry (&pool
->free
[b
],
255 struct _cairo_memblock
,
260 assert (block
!= NULL
);
262 cairo_list_del (&block
->link
);
264 while (cairo_list_is_empty (&pool
->free
[pool
->max_free_bits
])) {
265 if (--pool
->max_free_bits
== -1)
269 /* Mark end of allocated area */
270 offset
= block
- pool
->blocks
;
271 past
= offset
+ (1 << bits
);
272 BITSET (pool
, past
- 1);
275 /* If we used a larger free block than we needed, free the rest */
276 pool
->free_bytes
-= 1 << (b
+ pool
->min_bits
);
277 free_blocks (pool
, past
, offset
+ (1 << b
), 0);
279 return pool
->base
+ ((block
- pool
->blocks
) << pool
->min_bits
);
283 _cairo_mempool_init (cairo_mempool_t
*pool
,
284 void *base
, size_t bytes
,
285 int min_bits
, int num_sizes
)
291 /* Align the start to an integral chunk */
292 tmp
= ((unsigned long) base
) & ((1 << min_bits
) - 1);
294 tmp
= (1 << min_bits
) - tmp
;
295 base
= (char *)base
+ tmp
;
299 assert ((((unsigned long) base
) & ((1 << min_bits
) - 1)) == 0);
300 assert (num_sizes
< ARRAY_LENGTH (pool
->free
));
303 pool
->free_bytes
= 0;
304 pool
->max_bytes
= bytes
;
305 pool
->max_free_bits
= -1;
307 num_blocks
= bytes
>> min_bits
;
308 pool
->blocks
= calloc (num_blocks
, sizeof (struct _cairo_memblock
));
309 if (pool
->blocks
== NULL
)
310 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
312 pool
->num_blocks
= num_blocks
;
313 pool
->min_bits
= min_bits
;
314 pool
->num_sizes
= num_sizes
;
316 for (i
= 0; i
< ARRAY_LENGTH (pool
->free
); i
++)
317 cairo_list_init (&pool
->free
[i
]);
319 pool
->map
= malloc ((num_blocks
+ 7) >> 3);
320 if (pool
->map
== NULL
) {
322 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
325 memset (pool
->map
, -1, (num_blocks
+ 7) >> 3);
326 clear_bits (pool
, 0, num_blocks
);
328 /* Now add all blocks to the free list */
329 free_blocks (pool
, 0, num_blocks
, 1);
331 return CAIRO_STATUS_SUCCESS
;
335 _cairo_mempool_alloc (cairo_mempool_t
*pool
, size_t bytes
)
340 size
= 1 << pool
->min_bits
;
341 for (bits
= 0; size
< bytes
; bits
++)
343 if (bits
>= pool
->num_sizes
)
346 return buddy_malloc (pool
, bits
);
350 _cairo_mempool_free (cairo_mempool_t
*pool
, void *storage
)
353 struct _cairo_memblock
*block
;
355 block_offset
= ((char *)storage
- pool
->base
) >> pool
->min_bits
;
356 block
= pool
->blocks
+ block_offset
;
358 BITCLEAR (pool
, block_offset
+ ((1 << block
->bits
) - 1));
359 pool
->free_bytes
+= 1 << (block
->bits
+ pool
->min_bits
);
361 merge_buddies (pool
, block
, pool
->num_sizes
);
365 _cairo_mempool_fini (cairo_mempool_t
*pool
)