2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 * Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
19 * 2/27/00:3am, random plans by jer
21 * ok based on gprof, we really need some innovation here... my thoughs are this:
23 * most things are strings, so have a string-based true-blue garbage collector
24 * one big global hash containing all the strings created by any pstrdup, returning const char *
25 * a refcount on each string block
26 * when a pool is freed, it moves down the refcount
27 * garbage collector collects pools on the free stack, and runs through the hash for unused strings
28 * j_strcmp can check for == (if they are both from a pstrdup)
30 * let's see... this would change:
31 * pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put
47 HASHTABLE pool__disturbed
= NULL
;
48 void *_pool__malloc(size_t size
)
53 void _pool__free(void *block
)
59 #define _pool__malloc malloc
60 #define _pool__free free
64 /* make an empty pool */
65 pool
_pool_new(char *zone
)
68 while((p
= _pool__malloc(sizeof(_pool
))) == NULL
) sleep(1);
77 sprintf(p
->name
,"%X",p
);
79 if(pool__disturbed
== NULL
)
80 pool__disturbed
= ghash_create(POOL_DEBUG
,(KEYHASHFUNC
)str_hash_code
,(KEYCOMPAREFUNC
)j_strcmp
);
81 ghash_put(pool__disturbed
,p
->name
,p
);
88 void _pool_heap_free(void *arg
)
90 struct pheap
*h
= (struct pheap
*)arg
;
92 _pool__free(h
->block
);
96 /* mem should always be freed last */
97 void _pool_cleanup_append(pool p
, struct pfree
*pf
)
101 if(p
->cleanup
== NULL
)
107 /* fast forward to end of list */
108 for(cur
= p
->cleanup
; cur
->next
!= NULL
; cur
= cur
->next
);
113 /* create a cleanup tracker */
114 struct pfree
*_pool_free(pool p
, pool_cleaner f
, void *arg
)
118 /* make the storage for the tracker */
119 while((ret
= _pool__malloc(sizeof(struct pfree
))) == NULL
) sleep(1);
127 /* create a heap and make sure it get's cleaned up */
128 struct pheap
*_pool_heap(pool p
, int size
)
133 /* make the return heap */
134 while((ret
= _pool__malloc(sizeof(struct pheap
))) == NULL
) sleep(1);
135 while((ret
->block
= _pool__malloc(size
)) == NULL
) sleep(1);
140 /* append to the cleanup list */
141 clean
= _pool_free(p
, _pool_heap_free
, (void *)ret
);
142 clean
->heap
= ret
; /* for future use in finding used mem for pstrdup */
143 _pool_cleanup_append(p
, clean
);
148 pool
_pool_new_heap(int size
, char *zone
)
152 p
->heap
= _pool_heap(p
,size
);
156 void *pmalloc(pool p
, int size
)
162 fprintf(stderr
,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
166 /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
167 if(p
->heap
== NULL
|| size
> (p
->heap
->size
/ 2))
169 while((block
= _pool__malloc(size
)) == NULL
) sleep(1);
171 _pool_cleanup_append(p
, _pool_free(p
, _pool__free
, block
));
175 /* we have to preserve boundaries, long story :) */
177 while(p
->heap
->used
&7) p
->heap
->used
++;
179 /* if we don't fit in the old heap, replace it */
180 if(size
> (p
->heap
->size
- p
->heap
->used
))
181 p
->heap
= _pool_heap(p
, p
->heap
->size
);
183 /* the current heap has room */
184 block
= (char *)p
->heap
->block
+ p
->heap
->used
;
185 p
->heap
->used
+= size
;
189 void *pmalloc_x(pool p
, int size
, char c
)
191 void* result
= pmalloc(p
, size
);
193 memset(result
, c
, size
);
197 /* easy safety utility (for creating blank mem for structs, etc) */
198 void *pmalloco(pool p
, int size
)
200 void *block
= pmalloc(p
, size
);
201 memset(block
, 0, size
);
205 /* XXX efficient: move this to const char * and then loop throug the existing heaps to see if src is within a block in this pool */
206 char *pstrdup(pool p
, const char *src
)
213 ret
= pmalloc(p
,strlen(src
) + 1);
219 /* when move above, this one would actually return a new block */
220 char *pstrdupx(pool p
, const char *src
)
222 return pstrdup(p
, src
);
225 int pool_size(pool p
)
227 if(p
== NULL
) return 0;
232 void pool_free(pool p
)
234 struct pfree
*cur
, *stub
;
236 if(p
== NULL
) return;
248 ghash_remove(pool__disturbed
,p
->name
);
255 /* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
256 void pool_cleanup(pool p
, pool_cleaner f
, void *arg
)
260 clean
= _pool_free(p
, f
, arg
);
261 clean
->next
= p
->cleanup
;
266 void debug_log(char *zone
, const char *msgfmt
, ...);
267 int _pool_stat(void *arg
, const void *key
, void *data
)
272 debug_log("leak","%s: %X is a new pool",p
->zone
,p
->name
);
273 else if(p
->size
> p
->lsize
)
274 debug_log("leak","%s: %X grew %d",p
->zone
,p
->name
, p
->size
- p
->lsize
);
276 debug_log("leak","%s: %X exists %d",p
->zone
,p
->name
, p
->size
);
281 void pool_stat(int full
)
283 ghash_walk(pool__disturbed
,_pool_stat
,(void *)full
);
284 if(pool__total
!= pool__ltotal
)
285 debug_log("leak","%d\ttotal missed mallocs",pool__total
);
286 pool__ltotal
= pool__total
;
290 void pool_stat(int full
)