jabberd2
2.2.16
|
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