source: trunk/third/jwgc/lib/libxode/pool.c @ 22406

Revision 22406, 6.4 KB checked in by ghudson, 19 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r22405, which included commits to RCS files with non-trunk default branches.
Line 
1/*
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.
6 *
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.
11 *
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.
15 *
16 *  Jabber
17 *  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
18 * 
19 *  2/27/00:3am, random plans by jer
20 * 
21 *  ok based on gprof, we really need some innovation here... my thoughs are this:
22 * 
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)
29 * 
30 *  let's see... this would change:
31 *  pstrdup: do a hash lookup, success=return, fail=pmalloc & hash put
32 *  pool_free:
33 * 
34 * 
35 * 
36 * 
37 * 
38 */
39
40#include "libxode.h"
41#include "config.h"
42
43#define _xode_pool__malloc malloc
44#define _xode_pool__free   free
45
46/* xode_pfree - a linked list node which stores an
47   allocation chunk, plus a callback */
48struct xode_pool_free
49{
50    xode_pool_cleaner f;
51    void *arg;
52    struct xode_pool_heap *heap;
53    struct xode_pool_free *next;
54};
55
56/* make an empty pool */
57xode_pool _xode_pool_new(void)
58{
59    xode_pool p;
60    while((p = _xode_pool__malloc(sizeof(_xode_pool))) == NULL) sleep(1);
61    p->cleanup = NULL;
62    p->heap = NULL;
63    p->size = 0;
64
65    return p;
66}
67
68/* free a heap */
69void _xode_pool_heapfree(void *arg)
70{
71    struct xode_pool_heap *h = (struct xode_pool_heap *)arg;
72
73    _xode_pool__free(h->block);
74    _xode_pool__free(h);
75}
76
77/* mem should always be freed last */
78void _xode_pool_cleanup_append(xode_pool p, struct xode_pool_free *pf)
79{
80    struct xode_pool_free *cur;
81
82    if(p->cleanup == NULL)
83    {
84        p->cleanup = pf;
85        return;
86    }
87
88    /* fast forward to end of list */
89    for(cur = p->cleanup; cur->next != NULL; cur = cur->next);
90
91    cur->next = pf;
92}
93
94/* create a cleanup tracker */
95struct xode_pool_free *_xode_pool_free(xode_pool p, xode_pool_cleaner f, void *arg)
96{
97    struct xode_pool_free *ret;
98
99    /* make the storage for the tracker */
100    while((ret = _xode_pool__malloc(sizeof(struct xode_pool_free))) == NULL) sleep(1);
101    ret->f = f;
102    ret->arg = arg;
103    ret->next = NULL;
104
105    return ret;
106}
107
108/* create a heap and make sure it get's cleaned up */
109struct xode_pool_heap *_xode_pool_heap(xode_pool p, int size)
110{
111    struct xode_pool_heap *ret;
112    struct xode_pool_free *clean;
113
114    /* make the return heap */
115    while((ret = _xode_pool__malloc(sizeof(struct xode_pool_heap))) == NULL) sleep(1);
116    while((ret->block = _xode_pool__malloc(size)) == NULL) sleep(1);
117    ret->size = size;
118    p->size += size;
119    ret->used = 0;
120
121    /* append to the cleanup list */
122    clean = _xode_pool_free(p, _xode_pool_heapfree, (void *)ret);
123    clean->heap = ret; /* for future use in finding used mem for pstrdup */
124    _xode_pool_cleanup_append(p, clean);
125
126    return ret;
127}
128
129xode_pool _xode_pool_newheap(int bytes)
130{
131    xode_pool p;
132    p = _xode_pool_new();
133    p->heap = _xode_pool_heap(p,bytes);
134    return p;
135}
136
137void *xode_pool_malloc(xode_pool p, int size)
138{
139    void *block;
140
141    if(p == NULL)
142    {
143        fprintf(stderr,"Memory Leak! xode_pmalloc received NULL pool, unable to track allocation, exiting]\n");
144        abort();
145    }
146
147    /* if there is no heap for this pool or it's a big request, just raw, I like how we clean this :) */
148    if(p->heap == NULL || size > (p->heap->size / 2))
149    {
150        while((block = _xode_pool__malloc(size)) == NULL) sleep(1);
151        p->size += size;
152        _xode_pool_cleanup_append(p, _xode_pool_free(p, _xode_pool__free, block));
153        return block;
154    }
155
156    /* we have to preserve boundaries, long story :) */
157    if(size >= 4)
158        while(p->heap->used&7) p->heap->used++;
159
160    /* if we don't fit in the old heap, replace it */
161    if(size > (p->heap->size - p->heap->used))
162        p->heap = _xode_pool_heap(p, p->heap->size);
163
164    /* the current heap has room */
165    block = (char *)p->heap->block + p->heap->used;
166    p->heap->used += size;
167    return block;
168}
169
170void *xode_pool_mallocx(xode_pool p, int size, char c)
171{
172   void* result = xode_pool_malloc(p, size);
173   if (result != NULL)
174           memset(result, c, size);
175   return result;
176
177
178/* easy safety utility (for creating blank mem for structs, etc) */
179void *xode_pool_malloco(xode_pool p, int size)
180{
181    void *block = xode_pool_malloc(p, size);
182    memset(block, 0, size);
183    return block;
184
185
186/* 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 */
187char *xode_pool_strdup(xode_pool p, const char *src)
188{
189    char *ret;
190
191    if(src == NULL)
192        return NULL;
193
194    ret = xode_pool_malloc(p,strlen(src) + 1);
195    strcpy(ret,src);
196
197    return ret;
198}
199
200/* when move above, this one would actually return a new block */
201char *xode_pool_strdupx(xode_pool p, const char *src)
202{
203    return xode_pool_strdup(p, src);
204}
205
206int xode_pool_size(xode_pool p)
207{
208    if(p == NULL) return 0;
209
210    return p->size;
211}
212
213void xode_pool_free(xode_pool p)
214{
215    struct xode_pool_free *cur, *stub;
216
217    if(p == NULL) return;
218
219    cur = p->cleanup;
220    while(cur != NULL)
221    {
222        (*cur->f)(cur->arg);
223        stub = cur->next;
224        _xode_pool__free(cur);
225        cur = stub;
226    }
227
228    _xode_pool__free(p);
229}
230
231/* public cleanup utils, insert in a way that they are run FIFO, before mem frees */
232void xode_pool_cleanup(xode_pool p, xode_pool_cleaner f, void *arg)
233{
234    struct xode_pool_free *clean;
235
236    clean = _xode_pool_free(p, f, arg);
237    clean->next = p->cleanup;
238    p->cleanup = clean;
239}
240
241xode_pool xode_pool_new(void)
242{
243    return _xode_pool_new();
244}
245
246xode_pool xode_pool_heap(const int bytes)
247{
248    return _xode_pool_newheap(bytes);
249}
Note: See TracBrowser for help on using the repository browser.