obsolete/jabber_k/xpool.c

00001 /*
00002  * $Id$
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  *
00018  *  Jabber
00019  *  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
00020  *  
00021  *  2/27/00:3am, random plans by jer
00022  *  
00023  *  ok based on gprof, we really need some innovation here... my thoughs are this:
00024  *  
00025  *  most things are strings, so have a string-based true-blue garbage collector
00026  *  one big global hash containing all the strings created by any pstrdup, returning const char *
00027  *  a refcount on each string block
00028  *  when a pool is freed, it moves down the refcount
00029  *  garbage collector collects pools on the free stack, and runs through the hash for unused strings
00030  *  j_strcmp can check for == (if they are both from a pstrdup)
00031  *  
00032  *  let's see... this would change:
00033  *  pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put
00034  *  pool_free: 
00035  *  
00036  *  
00037  *  
00038  *  
00039  *  
00040  */
00041 
00042 #include "xode.h"
00043 //#include "config.h"
00044 
00045 #define _xode_pool__malloc malloc
00046 #define _xode_pool__free   free
00047 
00048 /* xode_pfree - a linked list node which stores an
00049    allocation chunk, plus a callback */
00050 struct xode_pool_free
00051 {
00052     xode_pool_cleaner f;
00053     void *arg;
00054     struct xode_pool_heap *heap;
00055     struct xode_pool_free *next;
00056 };
00057 
00058 /* make an empty pool */
00059 xode_pool _xode_pool_new(void)
00060 {
00061     xode_pool p;
00062     while((p = _xode_pool__malloc(sizeof(_xode_pool))) == NULL) sleep(1);
00063     p->cleanup = NULL;
00064     p->heap = NULL;
00065     p->size = 0;
00066 
00067     return p;
00068 }
00069 
00070 /* free a heap */
00071 void _xode_pool_heapfree(void *arg)
00072 {
00073     struct xode_pool_heap *h = (struct xode_pool_heap *)arg;
00074 
00075     _xode_pool__free(h->block);
00076     _xode_pool__free(h);
00077 }
00078 
00079 /* mem should always be freed last */
00080 void _xode_pool_cleanup_append(xode_pool p, struct xode_pool_free *pf)
00081 {
00082     struct xode_pool_free *cur;
00083 
00084     if(p->cleanup == NULL)
00085     {
00086         p->cleanup = pf;
00087         return;
00088     }
00089 
00090     /* fast forward to end of list */
00091     for(cur = p->cleanup; cur->next != NULL; cur = cur->next);
00092 
00093     cur->next = pf;
00094 }
00095 
00096 /* create a cleanup tracker */
00097 struct xode_pool_free *_xode_pool_free(xode_pool p, xode_pool_cleaner f, void *arg)
00098 {
00099     struct xode_pool_free *ret;
00100 
00101     /* make the storage for the tracker */
00102     while((ret = _xode_pool__malloc(sizeof(struct xode_pool_free))) == NULL) sleep(1);
00103     ret->f = f;
00104     ret->arg = arg;
00105     ret->next = NULL;
00106 
00107     return ret;
00108 }
00109 
00110 /* create a heap and make sure it get's cleaned up */
00111 struct xode_pool_heap *_xode_pool_heap(xode_pool p, int size)
00112 {
00113     struct xode_pool_heap *ret;
00114     struct xode_pool_free *clean;
00115 
00116     /* make the return heap */
00117     while((ret = _xode_pool__malloc(sizeof(struct xode_pool_heap))) == NULL) sleep(1);
00118     while((ret->block = _xode_pool__malloc(size)) == NULL) sleep(1);
00119     ret->size = size;
00120     p->size += size;
00121     ret->used = 0;
00122 
00123     /* append to the cleanup list */
00124     clean = _xode_pool_free(p, _xode_pool_heapfree, (void *)ret);
00125     clean->heap = ret; /* for future use in finding used mem for pstrdup */
00126     _xode_pool_cleanup_append(p, clean);
00127 
00128     return ret;
00129 }
00130 
00131 xode_pool _xode_pool_newheap(int bytes)
00132 {
00133     xode_pool p;
00134     p = _xode_pool_new();
00135     p->heap = _xode_pool_heap(p,bytes);
00136     return p;
00137 }
00138 
00139 void *xode_pool_malloc(xode_pool p, int size)
00140 {
00141     void *block;
00142 
00143     if(p == NULL)
00144     {
00145         fprintf(stderr,"Memory Leak! xode_pmalloc received NULL pool, unable to track allocation, exiting]\n");
00146         abort();
00147     }
00148 
00149     /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
00150     if(p->heap == NULL || size > (p->heap->size / 2))
00151     {
00152         while((block = _xode_pool__malloc(size)) == NULL) sleep(1);
00153         p->size += size;
00154         _xode_pool_cleanup_append(p, _xode_pool_free(p, _xode_pool__free, block));
00155         return block;
00156     }
00157 
00158     /* we have to preserve boundaries, long story :) */
00159     if(size >= 4)
00160         while(p->heap->used&7) p->heap->used++;
00161 
00162     /* if we don't fit in the old heap, replace it */
00163     if(size > (p->heap->size - p->heap->used))
00164         p->heap = _xode_pool_heap(p, p->heap->size);
00165 
00166     /* the current heap has room */
00167     block = (char *)p->heap->block + p->heap->used;
00168     p->heap->used += size;
00169     return block;
00170 }
00171 
00172 void *xode_pool_mallocx(xode_pool p, int size, char c)
00173 {
00174    void* result = xode_pool_malloc(p, size);
00175    if (result != NULL)
00176            memset(result, c, size);
00177    return result;
00178 }  
00179 
00180 /* easy safety utility (for creating blank mem for structs, etc) */
00181 void *xode_pool_malloco(xode_pool p, int size)
00182 {
00183     void *block = xode_pool_malloc(p, size);
00184     memset(block, 0, size);
00185     return block;
00186 }  
00187 
00188 /* 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 */
00189 char *xode_pool_strdup(xode_pool p, const char *src)
00190 {
00191     char *ret;
00192 
00193     if(src == NULL)
00194         return NULL;
00195 
00196     ret = xode_pool_malloc(p,strlen(src) + 1);
00197     strcpy(ret,src);
00198 
00199     return ret;
00200 }
00201 
00202 /* when move above, this one would actually return a new block */
00203 char *xode_pool_strdupx(xode_pool p, const char *src)
00204 {
00205     return xode_pool_strdup(p, src);
00206 }
00207 
00208 int xode_pool_size(xode_pool p)
00209 {
00210     if(p == NULL) return 0;
00211 
00212     return p->size;
00213 }
00214 
00215 void xode_pool_free(xode_pool p)
00216 {
00217     struct xode_pool_free *cur, *stub;
00218 
00219     if(p == NULL) return;
00220 
00221     cur = p->cleanup;
00222     while(cur != NULL)
00223     {
00224         (*cur->f)(cur->arg);
00225         stub = cur->next;
00226         _xode_pool__free(cur);
00227         cur = stub;
00228     }
00229 
00230     _xode_pool__free(p);
00231 }
00232 
00233 /* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
00234 void xode_pool_cleanup(xode_pool p, xode_pool_cleaner f, void *arg)
00235 {
00236     struct xode_pool_free *clean;
00237 
00238     clean = _xode_pool_free(p, f, arg);
00239     clean->next = p->cleanup;
00240     p->cleanup = clean;
00241 }
00242 
00243 xode_pool xode_pool_new(void)
00244 {
00245     return _xode_pool_new();
00246 }
00247 
00248 xode_pool xode_pool_heap(const int bytes)
00249 {
00250     return _xode_pool_newheap(bytes);
00251 }