xmpp/xpool.c

Go to the documentation of this file.
00001 /*
00002  * $Id: xpool.c 4494 2008-07-22 13:43:48Z henningw $
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 /*! \file
00039  * \ingroup xmpp
00040  */
00041 
00042 
00043 #include "xode.h"
00044 //#include "config.h"
00045 
00046 #define _xode_pool__malloc malloc
00047 #define _xode_pool__free   free
00048 
00049 /* xode_pfree - a linked list node which stores an
00050    allocation chunk, plus a callback */
00051 struct xode_pool_free
00052 {
00053     xode_pool_cleaner f;
00054     void *arg;
00055     struct xode_pool_heap *heap;
00056     struct xode_pool_free *next;
00057 };
00058 
00059 /* make an empty pool */
00060 xode_pool _xode_pool_new(void)
00061 {
00062     xode_pool p;
00063     while((p = _xode_pool__malloc(sizeof(_xode_pool))) == NULL) sleep(1);
00064     p->cleanup = NULL;
00065     p->heap = NULL;
00066     p->size = 0;
00067 
00068     return p;
00069 }
00070 
00071 /* free a heap */
00072 void _xode_pool_heapfree(void *arg)
00073 {
00074     struct xode_pool_heap *h = (struct xode_pool_heap *)arg;
00075 
00076     _xode_pool__free(h->block);
00077     _xode_pool__free(h);
00078 }
00079 
00080 /* mem should always be freed last */
00081 void _xode_pool_cleanup_append(xode_pool p, struct xode_pool_free *pf)
00082 {
00083     struct xode_pool_free *cur;
00084 
00085     if(p->cleanup == NULL)
00086     {
00087         p->cleanup = pf;
00088         return;
00089     }
00090 
00091     /* fast forward to end of list */
00092     for(cur = p->cleanup; cur->next != NULL; cur = cur->next);
00093 
00094     cur->next = pf;
00095 }
00096 
00097 /* create a cleanup tracker */
00098 struct xode_pool_free *_xode_pool_free(xode_pool p, xode_pool_cleaner f, void *arg)
00099 {
00100     struct xode_pool_free *ret;
00101 
00102     /* make the storage for the tracker */
00103     while((ret = _xode_pool__malloc(sizeof(struct xode_pool_free))) == NULL) sleep(1);
00104     ret->f = f;
00105     ret->arg = arg;
00106     ret->next = NULL;
00107 
00108     return ret;
00109 }
00110 
00111 /* create a heap and make sure it get's cleaned up */
00112 struct xode_pool_heap *_xode_pool_heap(xode_pool p, int size)
00113 {
00114     struct xode_pool_heap *ret;
00115     struct xode_pool_free *clean;
00116 
00117     /* make the return heap */
00118     while((ret = _xode_pool__malloc(sizeof(struct xode_pool_heap))) == NULL) sleep(1);
00119     while((ret->block = _xode_pool__malloc(size)) == NULL) sleep(1);
00120     ret->size = size;
00121     p->size += size;
00122     ret->used = 0;
00123 
00124     /* append to the cleanup list */
00125     clean = _xode_pool_free(p, _xode_pool_heapfree, (void *)ret);
00126     clean->heap = ret; /* for future use in finding used mem for pstrdup */
00127     _xode_pool_cleanup_append(p, clean);
00128 
00129     return ret;
00130 }
00131 
00132 xode_pool _xode_pool_newheap(int bytes)
00133 {
00134     xode_pool p;
00135     p = _xode_pool_new();
00136     p->heap = _xode_pool_heap(p,bytes);
00137     return p;
00138 }
00139 
00140 void *xode_pool_malloc(xode_pool p, int size)
00141 {
00142     void *block;
00143 
00144     if(p == NULL)
00145     {
00146         fprintf(stderr,"Memory Leak! xode_pmalloc received NULL pool, unable to track allocation, exiting]\n");
00147         abort();
00148     }
00149 
00150     /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
00151     if(p->heap == NULL || size > (p->heap->size / 2))
00152     {
00153         while((block = _xode_pool__malloc(size)) == NULL) sleep(1);
00154         p->size += size;
00155         _xode_pool_cleanup_append(p, _xode_pool_free(p, _xode_pool__free, block));
00156         return block;
00157     }
00158 
00159     /* we have to preserve boundaries, long story :) */
00160     if(size >= 4)
00161         while(p->heap->used&7) p->heap->used++;
00162 
00163     /* if we don't fit in the old heap, replace it */
00164     if(size > (p->heap->size - p->heap->used))
00165         p->heap = _xode_pool_heap(p, p->heap->size);
00166 
00167     /* the current heap has room */
00168     block = (char *)p->heap->block + p->heap->used;
00169     p->heap->used += size;
00170     return block;
00171 }
00172 
00173 void *xode_pool_mallocx(xode_pool p, int size, char c)
00174 {
00175    void* result = xode_pool_malloc(p, size);
00176    if (result != NULL)
00177            memset(result, c, size);
00178    return result;
00179 }  
00180 
00181 /* easy safety utility (for creating blank mem for structs, etc) */
00182 void *xode_pool_malloco(xode_pool p, int size)
00183 {
00184     void *block = xode_pool_malloc(p, size);
00185     memset(block, 0, size);
00186     return block;
00187 }  
00188 
00189 /* 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 */
00190 char *xode_pool_strdup(xode_pool p, const char *src)
00191 {
00192     char *ret;
00193 
00194     if(src == NULL)
00195         return NULL;
00196 
00197     ret = xode_pool_malloc(p,strlen(src) + 1);
00198     strcpy(ret,src);
00199 
00200     return ret;
00201 }
00202 
00203 /* when move above, this one would actually return a new block */
00204 char *xode_pool_strdupx(xode_pool p, const char *src)
00205 {
00206     return xode_pool_strdup(p, src);
00207 }
00208 
00209 int xode_pool_size(xode_pool p)
00210 {
00211     if(p == NULL) return 0;
00212 
00213     return p->size;
00214 }
00215 
00216 void xode_pool_free(xode_pool p)
00217 {
00218     struct xode_pool_free *cur, *stub;
00219 
00220     if(p == NULL) return;
00221 
00222     cur = p->cleanup;
00223     while(cur != NULL)
00224     {
00225         (*cur->f)(cur->arg);
00226         stub = cur->next;
00227         _xode_pool__free(cur);
00228         cur = stub;
00229     }
00230 
00231     _xode_pool__free(p);
00232 }
00233 
00234 /* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
00235 void xode_pool_cleanup(xode_pool p, xode_pool_cleaner f, void *arg)
00236 {
00237     struct xode_pool_free *clean;
00238 
00239     clean = _xode_pool_free(p, f, arg);
00240     clean->next = p->cleanup;
00241     p->cleanup = clean;
00242 }
00243 
00244 xode_pool xode_pool_new(void)
00245 {
00246     return _xode_pool_new();
00247 }
00248 
00249 xode_pool xode_pool_heap(const int bytes)
00250 {
00251     return _xode_pool_newheap(bytes);
00252 }

Generated on Fri May 25 00:00:35 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6