jabberd2  2.2.16
util/pool.c
Go to the documentation of this file.
00001 /*
00002  * jabberd - Jabber Open Source Server
00003  * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
00004  *                    Ryan Eatmon, Robert Norris
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
00019  */
00020 
00021 #include "util.h"
00022 #include "pool.h"
00023 
00024 #ifdef POOL_DEBUG
00025 int pool__total = 0;
00026 int pool__ltotal = 0;
00027 xht pool__disturbed = NULL;
00028 void *_pool__malloc(size_t size)
00029 {
00030     pool__total++;
00031     return malloc(size);
00032 }
00033 void _pool__free(void *block)
00034 {
00035     pool__total--;
00036     free(block);
00037 }
00038 #else
00039 #define _pool__malloc malloc
00040 #define _pool__free free
00041 #endif
00042 
00043 
00045 pool_t _pool_new(char *zone, int line)
00046 {
00047     pool_t p;
00048     while((p = _pool__malloc(sizeof(_pool))) == NULL) sleep(1);
00049     p->cleanup = NULL;
00050     p->heap = NULL;
00051     p->size = 0;
00052 
00053 #ifdef POOL_DEBUG
00054     p->lsize = -1;
00055     p->zone[0] = '\0';
00056     snprintf(p->zone, sizeof(p->zone), "%s:%i", zone, line);
00057     sprintf(p->name,"%X",(int)p);
00058 
00059     if(pool__disturbed == NULL)
00060     {
00061         pool__disturbed = (xht)1; /* reentrancy flag! */
00062     pool__disturbed = xhash_new(POOL_NUM);
00063     }
00064     if(pool__disturbed != (xht)1)
00065         xhash_put(pool__disturbed,p->name,p);
00066 #endif
00067 
00068     return p;
00069 }
00070 
00072 static void _pool_heap_free(void *arg)
00073 {
00074     struct pheap *h = (struct pheap *)arg;
00075 
00076     _pool__free(h->block);
00077     _pool__free(h);
00078 }
00079 
00081 static void _pool_cleanup_append(pool_t p, struct pfree *pf)
00082 {
00083     struct pfree *cur;
00084 
00085     if(p->cleanup == NULL)
00086     {
00087         p->cleanup = pf;
00088         p->cleanup_tail = pf;
00089         return;
00090     }
00091 
00092     /* append at end of list */
00093     cur = p->cleanup_tail; 
00094     cur->next = pf;
00095     p->cleanup_tail = pf;
00096 }
00097 
00099 static struct pfree *_pool_free(pool_t p, pool_cleanup_t f, void *arg)
00100 {
00101     struct pfree *ret;
00102 
00103     /* make the storage for the tracker */
00104     while((ret = _pool__malloc(sizeof(struct pfree))) == NULL) sleep(1);
00105     ret->f = f;
00106     ret->arg = arg;
00107     ret->next = NULL;
00108 
00109     return ret;
00110 }
00111 
00113 static struct pheap *_pool_heap(pool_t p, int size)
00114 {
00115     struct pheap *ret;
00116     struct pfree *clean;
00117 
00118     /* make the return heap */
00119     while((ret = _pool__malloc(sizeof(struct pheap))) == NULL) sleep(1);
00120     while((ret->block = _pool__malloc(size)) == NULL) sleep(1);
00121     ret->size = size;
00122     p->size += size;
00123     ret->used = 0;
00124 
00125     /* append to the cleanup list */
00126     clean = _pool_free(p, _pool_heap_free, (void *)ret);
00127     clean->heap = ret; /* for future use in finding used mem for pstrdup */
00128     _pool_cleanup_append(p, clean);
00129 
00130     return ret;
00131 }
00132 
00133 pool_t _pool_new_heap(int size, char *zone, int line)
00134 {
00135     pool_t p;
00136     p = _pool_new(zone, line);
00137     p->heap = _pool_heap(p,size);
00138     return p;
00139 }
00140 
00141 void *pmalloc(pool_t p, int size)
00142 {
00143     void *block;
00144 
00145     if(p == NULL)
00146     {
00147         fprintf(stderr,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
00148         abort();
00149     }
00150 
00151     /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
00152     if(p->heap == NULL || size > (p->heap->size / 2))
00153     {
00154         while((block = _pool__malloc(size)) == NULL) sleep(1);
00155         p->size += size;
00156         _pool_cleanup_append(p, _pool_free(p, _pool__free, block));
00157         return block;
00158     }
00159 
00160     /* we have to preserve boundaries, long story :) */
00161     if(size >= 4)
00162         while(p->heap->used&7) p->heap->used++;
00163 
00164     /* if we don't fit in the old heap, replace it */
00165     if(size > (p->heap->size - p->heap->used))
00166         p->heap = _pool_heap(p, p->heap->size);
00167 
00168     /* the current heap has room */
00169     block = (char *)p->heap->block + p->heap->used;
00170     p->heap->used += size;
00171     return block;
00172 }
00173 
00174 void *pmalloc_x(pool_t p, int size, char c)
00175 {
00176    void* result = pmalloc(p, size);
00177    if (result != NULL)
00178            memset(result, c, size);
00179    return result;
00180 }  
00181 
00183 void *pmalloco(pool_t p, int size)
00184 {
00185     void *block = pmalloc(p, size);
00186     memset(block, 0, size);
00187     return block;
00188 }  
00189 
00191 char *pstrdup(pool_t p, const char *src)
00192 {
00193     char *ret;
00194 
00195     if(src == NULL)
00196         return NULL;
00197 
00198     ret = pmalloc(p,strlen(src) + 1);
00199     strcpy(ret,src);
00200 
00201     return ret;
00202 }
00203 
00205 char *pstrdupx(pool_t p, const char *src, int len)
00206 {
00207     char *ret;
00208 
00209     if(src == NULL || len <= 0)
00210         return NULL;
00211 
00212     ret = pmalloc(p,len + 1);
00213     memcpy(ret,src,len);
00214     ret[len] = '\0';
00215 
00216     return ret;
00217 }
00218 
00219 int pool_size(pool_t p)
00220 {
00221     if(p == NULL) return 0;
00222 
00223     return p->size;
00224 }
00225 
00226 void pool_free(pool_t p)
00227 {
00228     struct pfree *cur, *stub;
00229 
00230     if(p == NULL) return;
00231 
00232     cur = p->cleanup;
00233     while(cur != NULL)
00234     {
00235         (*cur->f)(cur->arg);
00236         stub = cur->next;
00237         _pool__free(cur);
00238         cur = stub;
00239     }
00240 
00241 #ifdef POOL_DEBUG
00242     if (pool__disturbed != NULL && pool__disturbed != (xht)1)
00243     xhash_zap(pool__disturbed,p->name);
00244 #endif
00245 
00246     _pool__free(p);
00247 
00248 }
00249 
00251 void pool_cleanup(pool_t p, pool_cleanup_t f, void *arg)
00252 {
00253     struct pfree *clean;
00254 
00255     clean = _pool_free(p, f, arg);
00256     clean->next = p->cleanup;
00257     p->cleanup = clean;
00258 }
00259 
00260 #ifdef POOL_DEBUG
00261 void _pool_stat(const char *key, int keylen, void *val, void *arg)
00262 {
00263     pool_t p = (pool_t)val;
00264 
00265     if(p->lsize == -1)
00266         fprintf(stderr, "POOL: %s: %s is a new pool\n",p->zone,p->name);
00267     else if(p->size > p->lsize)
00268         fprintf(stderr, "POOL: %s: %s grew %d\n",p->zone,p->name, p->size - p->lsize);
00269     else if((int)arg)
00270         fprintf(stderr, "POOL: %s: %s exists %d\n",p->zone,p->name, p->size);
00271     p->lsize = p->size;
00272 }
00273 
00274 void pool_stat(int full)
00275 {
00276     if (pool__disturbed == NULL || pool__disturbed == (xht)1)
00277     return;
00278     xhash_walk(pool__disturbed,_pool_stat,(void *)full);
00279     if(pool__total != pool__ltotal)
00280         fprintf(stderr, "POOL: %d total missed mallocs\n",pool__total);
00281     pool__ltotal = pool__total;
00282     return;
00283 }
00284 #else
00285 void pool_stat(int full)
00286 {
00287     return;
00288 }
00289 #endif