ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/balloc.C
Revision: 1.2
Committed: Sat Jul 21 01:29:10 2007 UTC (16 years, 10 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.1: +1 -1 lines
Log Message:
- moved to new documentation system
- fixed small build error

File Contents

# User Rev Content
1 pippijn 1.1 /**
2     * balloc.C: Block allocation of memory segments
3 pippijn 1.2 * Rights to this code are documented in doc/pod/license.pod.
4 pippijn 1.1 *
5     * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6     */
7    
8     static char const rcsid[] = "$Id";
9    
10     #include "atheme.h"
11    
12     #ifdef HAVE_MMAP /* We've got mmap() that is good */
13     # include <sys/mman.h>
14     # ifdef MAP_ANONYMOUS
15     # ifndef MAP_ANON
16     # define MAP_ANON MAP_ANONYMOUS
17     # endif
18     # endif
19     #else
20     # define MAP_PRIVATE 0
21     # define MAP_ANON 0
22     # define MAP_FAILED 0
23     # define PROT_READ 0
24     # define PROT_WRITE 0
25     #endif
26    
27     static int newblock (BlockHeap *bh);
28     static int BlockHeapGarbageCollect (BlockHeap *);
29     static void block_heap_gc (void *unused);
30     static list_t heap_lists;
31    
32     #define blockheap_fail(x) _blockheap_fail(x, __FILE__, __LINE__)
33    
34     static void
35     _blockheap_fail (const char *reason, const char *file, int line)
36     {
37     slog (LG_INFO, "Blockheap failure: %s (%s:%d)", reason, file, line);
38     runflags |= RF_SHUTDOWN;
39     }
40    
41     #ifndef HAVE_MMAP
42     /*
43     * static void mmap(void *hint, size_t len, unsigned int prot,
44     * unsigned int flags, unsigned int fd, unsigned int off)
45     *
46     * Inputs - mmap style arguments.
47     * Output - None
48     * Side Effects - Memory is allocated to the block allocator.
49     */
50     static void *
51     mmap (void *hint, size_t len, unsigned int prot, unsigned int flags, unsigned int fd, unsigned int off)
52     {
53     void *ptr = smalloc (len);
54    
55     if (!ptr)
56     blockheap_fail ("smalloc() failed.");
57    
58     memset (ptr, 0, len);
59    
60     return ptr;
61     }
62    
63     /*
64     * static void munmap(void *addr, size_t len)
65     *
66     * Inputs - munmap style arguments.
67     * Output - None
68     * Side Effects - Memory is returned back to the OS.
69     */
70     static void
71     munmap (void *addr, size_t len)
72     {
73     if (!addr)
74     blockheap_fail ("no address to unmap.");
75    
76     free (addr);
77     }
78     #endif
79    
80     /*
81     * static void free_block(void *ptr, size_t size)
82     *
83     * Inputs: The block and its size
84     * Output: None
85     * Side Effects: Returns memory for the block back to the OS
86     */
87     static void
88     free_block (void *ptr, size_t size)
89     {
90     munmap (ptr, size);
91     }
92    
93    
94     /*
95     * void initBlockHeap(void)
96     *
97     * Inputs: None
98     * Outputs: None
99     * Side Effects: Initializes the block heap
100     */
101    
102     void
103     initBlockHeap (void)
104     {
105     #ifndef NOBALLOC
106     event_add ("block_heap_gc", block_heap_gc, NULL, 60);
107     #endif
108     }
109    
110     #ifndef NOBALLOC
111     /*
112     * static void *get_block(size_t size)
113     *
114     * Input: Size of block to allocate
115     * Output: Pointer to new block
116     * Side Effects: None
117     */
118     static void *
119     get_block (size_t size)
120     {
121     void *ptr;
122     ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
123    
124     if (ptr == MAP_FAILED)
125     ptr = NULL;
126    
127     return (ptr);
128     }
129    
130    
131     static void
132     block_heap_gc (void *unused)
133     {
134     node_t *ptr, *tptr;
135    
136     LIST_FOREACH_SAFE (ptr, tptr, heap_lists.head)
137     {
138     BlockHeapGarbageCollect (static_cast<BlockHeap *> (ptr->data));
139     }
140     }
141    
142     /* ************************************************************************ */
143     /* FUNCTION DOCUMENTATION: */
144     /* newblock */
145     /* Description: */
146     /* Allocates a new block for addition to a blockheap */
147     /* Parameters: */
148     /* bh (IN): Pointer to parent blockheap. */
149     /* Returns: */
150     /* 0 if successful, 1 if not */
151     /* ************************************************************************ */
152    
153     static int
154     newblock (BlockHeap *bh)
155     {
156     MemBlock *newblk;
157     Block *b;
158     unsigned long i;
159     void *offset;
160    
161     /* Setup the initial data structure. */
162     b = (Block *) scalloc (1, sizeof (Block));
163    
164     if (b == NULL)
165     return (1);
166    
167     b->free_list.head = b->free_list.tail = NULL;
168     b->used_list.head = b->used_list.tail = NULL;
169     b->next = bh->base;
170    
171     b->alloc_size = (bh->elemsPerBlock + 1) * (bh->elemSize + sizeof (MemBlock));
172    
173     b->elems = get_block (b->alloc_size);
174    
175     if (b->elems == NULL)
176     return (1);
177    
178     offset = b->elems;
179    
180     /* Setup our blocks now */
181     for (i = 0; i < bh->elemsPerBlock; i++)
182     {
183     void *data;
184     newblk = static_cast<MemBlock *> (offset);
185     newblk->block = b;
186     #ifdef DEBUG_BALLOC
187     newblk->magic = BALLOC_MAGIC;
188     #endif
189     data = (void *) ((size_t) offset + sizeof (MemBlock));
190     newblk->block = b;
191     node_add (data, &newblk->self, &b->free_list);
192     offset = (unsigned char *) ((unsigned char *) offset + bh->elemSize + sizeof (MemBlock));
193     }
194    
195     ++bh->blocksAllocated;
196     bh->freeElems += bh->elemsPerBlock;
197     bh->base = b;
198    
199     return (0);
200     }
201     #endif
202    
203     /* ************************************************************************ */
204     /* FUNCTION DOCUMENTATION: */
205     /* BlockHeapCreate */
206     /* Description: */
207     /* Creates a new blockheap from which smaller blocks can be allocated. */
208     /* Intended to be used instead of multiple calls to malloc() when */
209     /* performance is an issue. */
210     /* Parameters: */
211     /* elemsize (IN): Size of the basic element to be stored */
212     /* elemsperblock (IN): Number of elements to be stored in a single block */
213     /* of memory. When the blockheap runs out of free memory, it will */
214     /* allocate elemsize * elemsperblock more. */
215     /* Returns: */
216     /* Pointer to new BlockHeap, or NULL if unsuccessful */
217     /* ************************************************************************ */
218     BlockHeap *
219     BlockHeapCreate (size_t elemsize, int elemsperblock)
220     {
221     BlockHeap *bh;
222    
223     /* Catch idiotic requests up front */
224     if ((elemsize <= 0) || (elemsperblock <= 0))
225     {
226     blockheap_fail ("Attempting to BlockHeapCreate idiotic sizes");
227     }
228    
229     /* Allocate our new BlockHeap */
230     bh = (BlockHeap *) scalloc (1, sizeof (BlockHeap));
231    
232     if (bh == NULL)
233     {
234     slog (LG_INFO, "Attempt to calloc() failed: (%s:%d)", __FILE__, __LINE__);
235     runflags |= RF_SHUTDOWN;
236     }
237    
238     #ifndef NOBALLOC
239     if ((elemsize % sizeof (void *)) != 0)
240     {
241     /* Pad to even pointer boundary */
242     elemsize += sizeof (void *);
243     elemsize &= ~(sizeof (void *) - 1);
244     }
245     #endif
246    
247     bh->elemSize = elemsize;
248     bh->elemsPerBlock = elemsperblock;
249     bh->blocksAllocated = 0;
250     bh->freeElems = 0;
251     bh->base = NULL;
252    
253     #ifndef NOBALLOC
254     /* Be sure our malloc was successful */
255     if (newblock (bh))
256     {
257     if (bh != NULL)
258     free (bh);
259     slog (LG_INFO, "newblock() failed");
260     runflags |= RF_SHUTDOWN;
261     }
262     #endif
263    
264     if (bh == NULL)
265     {
266     blockheap_fail ("bh == NULL when it shouldn't be");
267     }
268     node_add (bh, &bh->hlist, &heap_lists);
269     return (bh);
270     }
271    
272     /* ************************************************************************ */
273     /* FUNCTION DOCUMENTATION: */
274     /* BlockHeapAlloc */
275     /* Description: */
276     /* Returns a pointer to a struct within our BlockHeap that's free for */
277     /* the taking. */
278     /* Parameters: */
279     /* bh (IN): Pointer to the Blockheap. */
280     /* Returns: */
281     /* Pointer to a structure (void *), or NULL if unsuccessful. */
282     /* ************************************************************************ */
283    
284     void *
285     BlockHeapAlloc (BlockHeap *bh)
286     {
287     Block *walker;
288     node_t *new_node;
289    
290     if (bh == NULL)
291     {
292     blockheap_fail ("Cannot allocate if bh == NULL");
293     }
294    
295     #ifdef NOBALLOC
296     return smalloc (bh->elemSize);
297     #else
298     if (bh->freeElems == 0)
299     {
300     /* Allocate new block and assign */
301     /* newblock returns 1 if unsuccessful, 0 if not */
302    
303     if (newblock (bh))
304     {
305     /* That didn't work..try to garbage collect */
306     BlockHeapGarbageCollect (bh);
307     if (bh->freeElems == 0)
308     {
309     slog (LG_INFO, "newblock() failed and garbage collection didn't help");
310     runflags |= RF_SHUTDOWN;
311     }
312     }
313     }
314    
315     for (walker = bh->base; walker != NULL; walker = walker->next)
316     {
317     if (LIST_LENGTH (&walker->free_list) > 0)
318     {
319     bh->freeElems--;
320     new_node = walker->free_list.head;
321     node_move (new_node, &walker->free_list, &walker->used_list);
322     if (new_node->data == NULL)
323     blockheap_fail ("new_node->data is NULL and that shouldn't happen!!!");
324     memset (new_node->data, 0, bh->elemSize);
325     return (new_node->data);
326     }
327     }
328     blockheap_fail ("BlockHeapAlloc failed, giving up");
329     return NULL;
330     #endif
331     }
332    
333    
334     /* ************************************************************************ */
335     /* FUNCTION DOCUMENTATION: */
336     /* BlockHeapFree */
337     /* Description: */
338     /* Returns an element to the free pool, does not free() */
339     /* Parameters: */
340     /* bh (IN): Pointer to BlockHeap containing element */
341     /* ptr (in): Pointer to element to be "freed" */
342     /* Returns: */
343     /* 0 if successful, 1 if element not contained within BlockHeap. */
344     /* ************************************************************************ */
345     int
346     BlockHeapFree (BlockHeap *bh, void *ptr)
347     {
348     Block *block;
349     struct MemBlock *memblock;
350    
351     if (bh == NULL)
352     {
353    
354     slog (LG_DEBUG, "balloc.c:BlockHeapFree() bh == NULL");
355     return (1);
356     }
357    
358     if (ptr == NULL)
359     {
360     slog (LG_DEBUG, "balloc.c:BlockHeapFree() ptr == NULL");
361     return (1);
362     }
363    
364     #ifdef NOBALLOC
365     free (ptr);
366     #else
367     memblock = static_cast<MemBlock *> ((void *) ((size_t) ptr - sizeof (MemBlock)));
368     #ifdef DEBUG_BALLOC
369     if (memblock->magic != BALLOC_MAGIC)
370     {
371     blockheap_fail ("memblock->magic != BALLOC_MAGIC");
372     runflags |= RF_SHUTDOWN;
373     }
374     #endif
375     if (memblock->block == NULL)
376     {
377     blockheap_fail ("memblock->block == NULL, not a valid block?");
378     runflags |= RF_SHUTDOWN;
379     }
380    
381     block = memblock->block;
382     bh->freeElems++;
383     node_move (&memblock->self, &block->used_list, &block->free_list);
384     #endif
385     return (0);
386     }
387    
388     /* ************************************************************************ */
389     /* FUNCTION DOCUMENTATION: */
390     /* BlockHeapGarbageCollect */
391     /* Description: */
392     /* Performs garbage collection on the block heap. Any blocks that are */
393     /* completely unallocated are removed from the heap. Garbage collection */
394     /* will never remove the root node of the heap. */
395     /* Parameters: */
396     /* bh (IN): Pointer to the BlockHeap to be cleaned up */
397     /* Returns: */
398     /* 0 if successful, 1 if bh == NULL */
399     /* ************************************************************************ */
400     static int
401     BlockHeapGarbageCollect (BlockHeap *bh)
402     {
403     #ifndef NOBALLOC
404     Block *walker, *last;
405     if (bh == NULL)
406     {
407     return (1);
408     }
409    
410     if (bh->freeElems < bh->elemsPerBlock || bh->blocksAllocated == 1)
411     {
412     /* There couldn't possibly be an entire free block. Return. */
413     return (0);
414     }
415    
416     last = NULL;
417     walker = bh->base;
418    
419     while (walker != NULL)
420     {
421     if ((LIST_LENGTH (&walker->free_list) == bh->elemsPerBlock) != 0)
422     {
423     free_block (walker->elems, walker->alloc_size);
424     if (last != NULL)
425     {
426     last->next = walker->next;
427     if (walker != NULL)
428     free (walker);
429     walker = last->next;
430     }
431     else
432     {
433     bh->base = walker->next;
434     if (walker != NULL)
435     free (walker);
436     walker = bh->base;
437     }
438     bh->blocksAllocated--;
439     bh->freeElems -= bh->elemsPerBlock;
440     }
441     else
442     {
443     last = walker;
444     walker = walker->next;
445     }
446     }
447     return (0);
448     #endif
449     }
450    
451     /* ************************************************************************ */
452     /* FUNCTION DOCUMENTATION: */
453     /* BlockHeapDestroy */
454     /* Description: */
455     /* Completely free()s a BlockHeap. Use for cleanup. */
456     /* Parameters: */
457     /* bh (IN): Pointer to the BlockHeap to be destroyed. */
458     /* Returns: */
459     /* 0 if successful, 1 if bh == NULL */
460     /* ************************************************************************ */
461     int
462     BlockHeapDestroy (BlockHeap *bh)
463     {
464     Block *walker, *next;
465    
466     if (bh == NULL)
467     {
468     return (1);
469     }
470    
471     #ifndef NOBALLOC
472     for (walker = bh->base; walker != NULL; walker = next)
473     {
474     next = walker->next;
475     free_block (walker->elems, walker->alloc_size);
476     if (walker != NULL)
477     free (walker);
478     }
479     #endif
480     node_del (&bh->hlist, &heap_lists);
481     free (bh);
482     return (0);
483     }
484    
485     void
486     BlockHeapUsage (BlockHeap *bh, size_t * bused, size_t * bfree, size_t * bmemusage)
487     {
488     size_t used;
489     size_t freem;
490     size_t memusage;
491     if (bh == NULL)
492     {
493     return;
494     }
495    
496     #ifdef NOBALLOC
497     freem = used = memusage = 0;
498     #else
499     freem = bh->freeElems;
500     used = (bh->blocksAllocated * bh->elemsPerBlock) - bh->freeElems;
501     memusage = used * (bh->elemSize + sizeof (MemBlock));
502     #endif
503    
504     if (bused != NULL)
505     *bused = used;
506     if (bfree != NULL)
507     *bfree = freem;
508     if (bmemusage != NULL)
509     *bmemusage = memusage;
510     }