123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /*
- * $Id$
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * Jabber
- * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
- *
- * 2/27/00:3am, random plans by jer
- *
- * ok based on gprof, we really need some innovation here... my thoughs are this:
- *
- * most things are strings, so have a string-based true-blue garbage collector
- * one big global hash containing all the strings created by any pstrdup, returning const char *
- * a refcount on each string block
- * when a pool is freed, it moves down the refcount
- * garbage collector collects pools on the free stack, and runs through the hash for unused strings
- * j_strcmp can check for == (if they are both from a pstrdup)
- *
- * let's see... this would change:
- * pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put
- * pool_free:
- *
- */
- /*! \file
- * \ingroup xmpp
- */
- #include "xode.h"
- //#include "config.h"
- #define _xode_pool__malloc malloc
- #define _xode_pool__free free
- /* xode_pfree - a linked list node which stores an
- allocation chunk, plus a callback */
- struct xode_pool_free
- {
- xode_pool_cleaner f;
- void *arg;
- struct xode_pool_heap *heap;
- struct xode_pool_free *next;
- };
- /* make an empty pool */
- xode_pool _xode_pool_new(void)
- {
- xode_pool p;
- while((p = _xode_pool__malloc(sizeof(_xode_pool))) == NULL) sleep(1);
- p->cleanup = NULL;
- p->heap = NULL;
- p->size = 0;
- return p;
- }
- /* free a heap */
- void _xode_pool_heapfree(void *arg)
- {
- struct xode_pool_heap *h = (struct xode_pool_heap *)arg;
- _xode_pool__free(h->block);
- _xode_pool__free(h);
- }
- /* mem should always be freed last */
- void _xode_pool_cleanup_append(xode_pool p, struct xode_pool_free *pf)
- {
- struct xode_pool_free *cur;
- if(p->cleanup == NULL)
- {
- p->cleanup = pf;
- return;
- }
- /* fast forward to end of list */
- for(cur = p->cleanup; cur->next != NULL; cur = cur->next);
- cur->next = pf;
- }
- /* create a cleanup tracker */
- struct xode_pool_free *_xode_pool_free(xode_pool p, xode_pool_cleaner f, void *arg)
- {
- struct xode_pool_free *ret;
- /* make the storage for the tracker */
- while((ret = _xode_pool__malloc(sizeof(struct xode_pool_free))) == NULL) sleep(1);
- ret->f = f;
- ret->arg = arg;
- ret->next = NULL;
- return ret;
- }
- /* create a heap and make sure it get's cleaned up */
- struct xode_pool_heap *_xode_pool_heap(xode_pool p, int size)
- {
- struct xode_pool_heap *ret;
- struct xode_pool_free *clean;
- /* make the return heap */
- while((ret = _xode_pool__malloc(sizeof(struct xode_pool_heap))) == NULL) sleep(1);
- while((ret->block = _xode_pool__malloc(size)) == NULL) sleep(1);
- ret->size = size;
- p->size += size;
- ret->used = 0;
- /* append to the cleanup list */
- clean = _xode_pool_free(p, _xode_pool_heapfree, (void *)ret);
- clean->heap = ret; /* for future use in finding used mem for pstrdup */
- _xode_pool_cleanup_append(p, clean);
- return ret;
- }
- xode_pool _xode_pool_newheap(int bytes)
- {
- xode_pool p;
- p = _xode_pool_new();
- p->heap = _xode_pool_heap(p,bytes);
- return p;
- }
- void *xode_pool_malloc(xode_pool p, int size)
- {
- void *block;
- if(p == NULL)
- {
- fprintf(stderr,"Memory Leak! xode_pmalloc received NULL pool, unable to track allocation, exiting]\n");
- abort();
- }
- /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
- if(p->heap == NULL || size > (p->heap->size / 2))
- {
- while((block = _xode_pool__malloc(size)) == NULL) sleep(1);
- p->size += size;
- _xode_pool_cleanup_append(p, _xode_pool_free(p, _xode_pool__free, block));
- return block;
- }
- /* we have to preserve boundaries, long story :) */
- if(size >= 4)
- while(p->heap->used&7) p->heap->used++;
- /* if we don't fit in the old heap, replace it */
- if(size > (p->heap->size - p->heap->used))
- p->heap = _xode_pool_heap(p, p->heap->size);
- /* the current heap has room */
- block = (char *)p->heap->block + p->heap->used;
- p->heap->used += size;
- return block;
- }
- void *xode_pool_mallocx(xode_pool p, int size, char c)
- {
- void* result = xode_pool_malloc(p, size);
- if (result != NULL)
- memset(result, c, size);
- return result;
- }
- /* easy safety utility (for creating blank mem for structs, etc) */
- void *xode_pool_malloco(xode_pool p, int size)
- {
- void *block = xode_pool_malloc(p, size);
- memset(block, 0, size);
- return block;
- }
- /* XXX efficient: move this to const char * and then loop through the existing heaps to see if src is within a block in this pool */
- char *xode_pool_strdup(xode_pool p, const char *src)
- {
- char *ret;
- if(src == NULL)
- return NULL;
- ret = xode_pool_malloc(p,strlen(src) + 1);
- strcpy(ret,src);
- return ret;
- }
- /* when move above, this one would actually return a new block */
- char *xode_pool_strdupx(xode_pool p, const char *src)
- {
- return xode_pool_strdup(p, src);
- }
- int xode_pool_size(xode_pool p)
- {
- if(p == NULL) return 0;
- return p->size;
- }
- void xode_pool_free(xode_pool p)
- {
- struct xode_pool_free *cur, *stub;
- if(p == NULL) return;
- cur = p->cleanup;
- while(cur != NULL)
- {
- (*cur->f)(cur->arg);
- stub = cur->next;
- _xode_pool__free(cur);
- cur = stub;
- }
- _xode_pool__free(p);
- }
- /* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
- void xode_pool_cleanup(xode_pool p, xode_pool_cleaner f, void *arg)
- {
- struct xode_pool_free *clean;
- clean = _xode_pool_free(p, f, arg);
- clean->next = p->cleanup;
- p->cleanup = clean;
- }
- xode_pool xode_pool_new(void)
- {
- return _xode_pool_new();
- }
- xode_pool xode_pool_heap(const int bytes)
- {
- return _xode_pool_newheap(bytes);
- }
|