| /* |
| * Copyright © 2006 Joonas Pihlaja |
| * |
| * Permission to use, copy, modify, distribute, and sell this software and its |
| * documentation for any purpose is hereby granted without fee, provided that |
| * the above copyright notice appear in all copies and that both that copyright |
| * notice and this permission notice appear in supporting documentation, and |
| * that the name of the copyright holders not be used in advertising or |
| * publicity pertaining to distribution of the software without specific, |
| * written prior permission. The copyright holders make no representations |
| * about the suitability of this software for any purpose. It is provided "as |
| * is" without express or implied warranty. |
| * |
| * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, |
| * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO |
| * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR |
| * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, |
| * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| * OF THIS SOFTWARE. |
| */ |
| |
| #include "cairoint.h" |
| |
| #include "cairo-error-private.h" |
| #include "cairo-freelist-private.h" |
| |
| void |
| _cairo_freelist_init (cairo_freelist_t *freelist, unsigned nodesize) |
| { |
| memset (freelist, 0, sizeof (cairo_freelist_t)); |
| freelist->nodesize = nodesize; |
| } |
| |
| void |
| _cairo_freelist_fini (cairo_freelist_t *freelist) |
| { |
| cairo_freelist_node_t *node = freelist->first_free_node; |
| while (node) { |
| cairo_freelist_node_t *next; |
| |
| VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); |
| next = node->next; |
| |
| free (node); |
| node = next; |
| } |
| } |
| |
| void * |
| _cairo_freelist_alloc (cairo_freelist_t *freelist) |
| { |
| if (freelist->first_free_node) { |
| cairo_freelist_node_t *node; |
| |
| node = freelist->first_free_node; |
| VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); |
| freelist->first_free_node = node->next; |
| VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freelist->nodesize)); |
| |
| return node; |
| } |
| |
| return malloc (freelist->nodesize); |
| } |
| |
| void * |
| _cairo_freelist_calloc (cairo_freelist_t *freelist) |
| { |
| void *node = _cairo_freelist_alloc (freelist); |
| if (node) |
| memset (node, 0, freelist->nodesize); |
| return node; |
| } |
| |
| void |
| _cairo_freelist_free (cairo_freelist_t *freelist, void *voidnode) |
| { |
| cairo_freelist_node_t *node = voidnode; |
| if (node) { |
| node->next = freelist->first_free_node; |
| freelist->first_free_node = node; |
| VG (VALGRIND_MAKE_MEM_NOACCESS (node, freelist->nodesize)); |
| } |
| } |
| |
| void |
| _cairo_freepool_init (cairo_freepool_t *freepool, unsigned nodesize) |
| { |
| freepool->first_free_node = NULL; |
| freepool->pools = &freepool->embedded_pool; |
| freepool->freepools = NULL; |
| freepool->nodesize = nodesize; |
| |
| freepool->embedded_pool.next = NULL; |
| freepool->embedded_pool.size = sizeof (freepool->embedded_data); |
| freepool->embedded_pool.rem = sizeof (freepool->embedded_data); |
| freepool->embedded_pool.data = freepool->embedded_data; |
| |
| VG (VALGRIND_MAKE_MEM_NOACCESS (freepool->embedded_data, sizeof (freepool->embedded_data))); |
| } |
| |
| void |
| _cairo_freepool_fini (cairo_freepool_t *freepool) |
| { |
| cairo_freelist_pool_t *pool; |
| |
| pool = freepool->pools; |
| while (pool != &freepool->embedded_pool) { |
| cairo_freelist_pool_t *next = pool->next; |
| free (pool); |
| pool = next; |
| } |
| |
| pool = freepool->freepools; |
| while (pool != NULL) { |
| cairo_freelist_pool_t *next = pool->next; |
| free (pool); |
| pool = next; |
| } |
| |
| VG (VALGRIND_MAKE_MEM_NOACCESS (freepool, sizeof (freepool))); |
| } |
| |
| void * |
| _cairo_freepool_alloc_from_new_pool (cairo_freepool_t *freepool) |
| { |
| cairo_freelist_pool_t *pool; |
| int poolsize; |
| |
| if (freepool->freepools != NULL) { |
| pool = freepool->freepools; |
| freepool->freepools = pool->next; |
| |
| poolsize = pool->size; |
| } else { |
| if (freepool->pools != &freepool->embedded_pool) |
| poolsize = 2 * freepool->pools->size; |
| else |
| poolsize = (128 * freepool->nodesize + 8191) & -8192; |
| |
| pool = malloc (sizeof (cairo_freelist_pool_t) + poolsize); |
| if (unlikely (pool == NULL)) |
| return pool; |
| |
| pool->size = poolsize; |
| } |
| |
| pool->next = freepool->pools; |
| freepool->pools = pool; |
| |
| pool->rem = poolsize - freepool->nodesize; |
| pool->data = (uint8_t *) (pool + 1) + freepool->nodesize; |
| |
| VG (VALGRIND_MAKE_MEM_NOACCESS (pool->data, pool->rem)); |
| |
| return pool + 1; |
| } |
| |
| cairo_status_t |
| _cairo_freepool_alloc_array (cairo_freepool_t *freepool, |
| int count, |
| void **array) |
| { |
| int i; |
| |
| for (i = 0; i < count; i++) { |
| cairo_freelist_node_t *node; |
| |
| node = freepool->first_free_node; |
| if (likely (node != NULL)) { |
| VG (VALGRIND_MAKE_MEM_DEFINED (node, sizeof (node->next))); |
| freepool->first_free_node = node->next; |
| VG (VALGRIND_MAKE_MEM_UNDEFINED (node, freepool->nodesize)); |
| } else { |
| node = _cairo_freepool_alloc_from_pool (freepool); |
| if (unlikely (node == NULL)) |
| goto CLEANUP; |
| } |
| |
| array[i] = node; |
| } |
| |
| return CAIRO_STATUS_SUCCESS; |
| |
| CLEANUP: |
| while (i--) |
| _cairo_freepool_free (freepool, array[i]); |
| |
| return _cairo_error (CAIRO_STATUS_NO_MEMORY); |
| } |