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
45 HASHTABLE pool__disturbed
= NULL
;
46 void *_pool__malloc(size_t size
)
51 void _pool__free(void *block
)
57 #define _pool__malloc malloc
58 #define _pool__free free
62 /* make an empty pool */
63 pool
_pool_new(char *zone
)
66 while((p
= _pool__malloc(sizeof(_pool
))) == NULL
) sleep(1);
75 sprintf(p
->name
,"%X",p
);
77 if(pool__disturbed
== NULL
)
78 pool__disturbed
= ghash_create(POOL_DEBUG
,(KEYHASHFUNC
)str_hash_code
,(KEYCOMPAREFUNC
)j_strcmp
);
79 ghash_put(pool__disturbed
,p
->name
,p
);
86 void _pool_heap_free(void *arg
)
88 struct pheap
*h
= (struct pheap
*)arg
;
90 _pool__free(h
->block
);
94 /* mem should always be freed last */
95 void _pool_cleanup_append(pool p
, struct pfree
*pf
)
99 if(p
->cleanup
== NULL
)
105 /* fast forward to end of list */
106 for(cur
= p
->cleanup
; cur
->next
!= NULL
; cur
= cur
->next
);
111 /* create a cleanup tracker */
112 struct pfree
*_pool_free(pool p
, pool_cleaner f
, void *arg
)
116 /* make the storage for the tracker */
117 while((ret
= _pool__malloc(sizeof(struct pfree
))) == NULL
) sleep(1);
125 /* create a heap and make sure it get's cleaned up */
126 struct pheap
*_pool_heap(pool p
, int size
)
131 /* make the return heap */
132 while((ret
= _pool__malloc(sizeof(struct pheap
))) == NULL
) sleep(1);
133 while((ret
->block
= _pool__malloc(size
)) == NULL
) sleep(1);
138 /* append to the cleanup list */
139 clean
= _pool_free(p
, _pool_heap_free
, (void *)ret
);
140 clean
->heap
= ret
; /* for future use in finding used mem for pstrdup */
141 _pool_cleanup_append(p
, clean
);
146 pool
_pool_new_heap(int size
, char *zone
)
150 p
->heap
= _pool_heap(p
,size
);
154 void *pmalloc(pool p
, int size
)
160 fprintf(stderr
,"Memory Leak! [pmalloc received NULL pool, unable to track allocation, exiting]\n");
164 /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
165 if(p
->heap
== NULL
|| size
> (p
->heap
->size
/ 2))
167 while((block
= _pool__malloc(size
)) == NULL
) sleep(1);
169 _pool_cleanup_append(p
, _pool_free(p
, _pool__free
, block
));
173 /* we have to preserve boundaries, long story :) */
175 while(p
->heap
->used
&7) p
->heap
->used
++;
177 /* if we don't fit in the old heap, replace it */
178 if(size
> (p
->heap
->size
- p
->heap
->used
))
179 p
->heap
= _pool_heap(p
, p
->heap
->size
);
181 /* the current heap has room */
182 block
= (char *)p
->heap
->block
+ p
->heap
->used
;
183 p
->heap
->used
+= size
;
187 void *pmalloc_x(pool p
, int size
, char c
)
189 void* result
= pmalloc(p
, size
);
191 memset(result
, c
, size
);
195 /* easy safety utility (for creating blank mem for structs, etc) */
196 void *pmalloco(pool p
, int size
)
198 void *block
= pmalloc(p
, size
);
199 memset(block
, 0, size
);
203 /* 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 */
204 char *pstrdup(pool p
, const char *src
)
211 ret
= pmalloc(p
,strlen(src
) + 1);
217 /* when move above, this one would actually return a new block */
218 char *pstrdupx(pool p
, const char *src
)
220 return pstrdup(p
, src
);
223 int pool_size(pool p
)
225 if(p
== NULL
) return 0;
230 void pool_free(pool p
)
232 struct pfree
*cur
, *stub
;
234 if(p
== NULL
) return;
246 ghash_remove(pool__disturbed
,p
->name
);
253 /* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
254 void pool_cleanup(pool p
, pool_cleaner f
, void *arg
)
258 clean
= _pool_free(p
, f
, arg
);
259 clean
->next
= p
->cleanup
;
264 void debug_log(char *zone
, const char *msgfmt
, ...);
265 int _pool_stat(void *arg
, const void *key
, void *data
)
270 debug_log("leak","%s: %X is a new pool",p
->zone
,p
->name
);
271 else if(p
->size
> p
->lsize
)
272 debug_log("leak","%s: %X grew %d",p
->zone
,p
->name
, p
->size
- p
->lsize
);
274 debug_log("leak","%s: %X exists %d",p
->zone
,p
->name
, p
->size
);
279 void pool_stat(int full
)
281 ghash_walk(pool__disturbed
,_pool_stat
,(void *)full
);
282 if(pool__total
!= pool__ltotal
)
283 debug_log("leak","%d\ttotal missed mallocs",pool__total
);
284 pool__ltotal
= pool__total
;
288 void pool_stat(int full
)