ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/ermyth/src/balloc.C
Revision: 1.4
Committed: Tue Aug 28 17:12:24 2007 UTC (16 years, 8 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +1 -1 lines
State: FILE REMOVED
Log Message:
removed old files

File Contents

# Content
1 /**
2 * balloc.C: Block allocation of memory segments
3 * Rights to this code are documented in doc/pod/license.pod.
4 *
5 * Copyright © 2005-2007 Atheme Project (http://www.atheme.org)
6 */
7
8 static char const rcsid[] = "$Id: balloc.C,v 1.3 2007-07-21 13:23:21 pippijn Exp $";
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 }