]>
jfr.im git - irc/rakaur/praxis.git/blob - src/core/balloc.c
1 /* praxis: services for TSora IRC networks.
2 * src/balloc.c: Block memory allocator.
4 * Copyright (c) 2004 Eric Will <rakaur@malkier.net>
5 * Copyright (c) 2003-2004 shrike development team.
6 * Copyright (c) 2002-2004 ircd-ratbox development team.
18 /* HP-UX apparently defines MAP_ANONYMOUS instead of MAP_ANON. */
22 #define MAP_ANON MAP_ANONYMOUS
27 /* If we have mmap() but we don't have MAP_ANON we'll have to improvise. */
30 static int zero_fd
= -1;
34 static void ballocGarbage(void *);
36 static DLinkList heap_lists
;
39 * Logs an error message and exits.
41 * inputs - message, file, line
45 _ballocFail(const char *reason
, const char *file
, int line
)
47 ilog(L_INFO
, "%s:%d: Block allocator failure: %s", file
, line
, reason
);
51 #define ballocFail(x) _ballocFail(x, __FILE__, __LINE__)
54 * Initialises the block allocator.
64 zero_fd
= open("/dev/zero", O_RDWR
);
67 ballocFail("couldn't open /dev/zero");
71 /* Garbage collection every five minutes. */
72 timerAdd("ballocGarbage", ballocGarbage
, NULL
, 300);
76 * Allocates a new block of memory.
78 * inputs - size to allocate
79 * outputs - pointer to new memory or NULL on failure.
88 memory
= mmap(NULL
, size
, (PROT_READ
| PROT_WRITE
),
89 (MAP_PRIVATE
| MAP_ANON
), -1, 0);
91 memory
= mmap(NULL
, size
, (PROT_READ
| PROT_WRITE
), MAP_PRIVATE
,
94 if (memory
== MAP_FAILED
)
97 memory
= malloc(size
);
103 * free()'s our memory.
105 * inputs - pointer to memory, size to free
109 ballocFree(void *memory
, size_t size
)
112 munmap(memory
, size
);
118 /* ballocBlockCreate()
119 * Allocates a new Block for addition to a Heap.
121 * inputs - Heap to add to
122 * outputs - 1 on success, 0 on failure
125 ballocBlockCreate(Heap
*heap_p
)
127 MemBlock
*memblock_p
;
132 iassert(heap_p
!= NULL
);
134 /* Set up initial data structure. */
135 block_p
= calloc(1, sizeof(Block
));
140 block_p
->next
= heap_p
->block_p
;
141 block_p
->alloc_size
= ((heap_p
->elems_per_block
+ 1) *
142 (heap_p
->elem_size
+ sizeof(MemBlock
)));
144 block_p
->elems
= balloc(block_p
->alloc_size
);
146 if (block_p
->elems
== NULL
)
149 offset
= block_p
->elems
;
151 /* Set up our MemBlocks now. */
152 for (i
= 0; i
< heap_p
->elems_per_block
; i
++)
157 memblock_p
->block_p
= block_p
;
159 memblock_p
->magic
= BALLOC_MAGIC
;
161 data
= (void *)((size_t) offset
+ sizeof(MemBlock
));
163 dlinkAdd(data
, &memblock_p
->self
, &block_p
->free_list
);
165 offset
= (uchar
*)((uchar
*)offset
+ heap_p
->elem_size
+
169 heap_p
->blocks_allocated
++;
170 heap_p
->elems_free
+= heap_p
->elems_per_block
;
171 heap_p
->block_p
= block_p
;
176 /* ballocHeapCreate()
177 * Creates a new Heap for Blocks.
179 * inputs - element size, elements per Block
180 * outputs - pointer to Heap or NULL on failure
183 ballocHeapCreate(size_t elem_size
, uint elems_per_block
)
187 iassert(elem_size
> 0);
188 iassert(elems_per_block
> 0);
190 /* Set up our initial data structure. */
191 heap_p
= calloc(1, sizeof(Heap
));
196 /* Some systems want pointers that are multiples of void *. */
197 if ((elem_size
% sizeof(void *)) != 0)
199 elem_size
+= sizeof(void *);
200 elem_size
&= ~(sizeof(void *) - 1);
203 heap_p
->elem_size
= elem_size
;
204 heap_p
->elems_per_block
= elems_per_block
;
206 /* Now get some Blocks for it. */
207 if (ballocBlockCreate(heap_p
) == 0)
212 ballocFail("ballocBlockCreate() failed.");
216 ballocFail("heap_p == NULL");
218 dlinkAdd(heap_p
, &heap_p
->hlist
, &heap_lists
);
223 /* ballocHeapDestroy()
224 * Completely frees a Heap.
226 * inputs - Heap to destroy
227 * outputs - 1 on success or 0 on failure
230 ballocHeapDestroy(Heap
*heap_p
)
232 Block
*walker
, *next
;
234 iassert(heap_p
!= NULL
);
236 for (walker
= heap_p
->block_p
; walker
!= NULL
; walker
= next
)
240 ballocFree(walker
->elems
, walker
->alloc_size
);
246 dlinkDelete(&heap_p
->hlist
, &heap_lists
);
254 * Finds a structure that's free for the taking.
256 * inputs - Heap to use for memory
257 * outputs - pointer to a structure or NULL on failure
260 ballocHeapAlloc(Heap
*heap_p
)
265 iassert(heap_p
!= NULL
);
267 /* Check to see if we have any free elements. */
268 if (heap_p
->elems_free
== 0)
270 /* We're out of free elements. Let's allocate a new Block. */
271 if (ballocBlockCreate(heap_p
) == 0)
273 /* We couldn't get a new Block. Let's try garbage collection. */
274 ballocHeapGarbage(heap_p
);
276 if (heap_p
->elems_free
== 0)
278 /* That didn't work either, so we're out of memory. */
279 ballocFail("couldn't allocate a new Block");
284 /* Find a free element. */
285 for (walker
= heap_p
->block_p
; walker
!= NULL
; walker
= walker
->next
)
287 if (dlinkLength(&walker
->free_list
) > 0)
289 /* We have a free element. */
290 heap_p
->elems_free
--;
292 node_p
= walker
->free_list
.head
;
293 dlinkNodeMove(node_p
, &walker
->free_list
, &walker
->used_list
);
295 iassert(node_p
->data
!= NULL
);
297 memset(node_p
->data
, 0, heap_p
->elem_size
);
303 /* If we get here then we couldn't get a free element. */
304 ballocFail("couldn't get a free element");
310 * Returns an element to the free pool.
312 * inputs - Heap containing element, element
313 * outputs - 1 on success, 0 on failure
316 ballocHeapFree(Heap
*heap_p
, void *element
)
319 MemBlock
*memblock_p
;
321 iassert(heap_p
!= NULL
);
322 iassert(element
!= NULL
);
324 memblock_p
= (void *)((size_t) element
- sizeof(MemBlock
));
327 if (memblock_p
->magic
!= BALLOC_MAGIC
)
328 ballocFail("magics do not match");
331 iassert(memblock_p
->block_p
!= NULL
);
333 block_p
= memblock_p
->block_p
;
334 heap_p
->elems_free
++;
336 dlinkNodeMove(&memblock_p
->self
, &block_p
->used_list
, &block_p
->free_list
);
342 * Performs garbage collection on all Heaps.
344 * inputs - Timer argument
348 ballocGarbage(void *arg
)
352 DLINK_FOREACH(node_p
, heap_lists
.head
) ballocHeapGarbage(node_p
->data
);
355 /* ballocHeapGarbage()
356 * Performs garbage collection on specified Heap.
358 * inputs - Heap to clean
362 ballocHeapGarbage(Heap
*heap_p
)
364 Block
*walker
, *last
;
366 iassert(heap_p
!= NULL
);
368 /* Check for entirely free Blocks. */
369 if ((heap_p
->elems_free
< heap_p
->elems_per_block
) ||
370 (heap_p
->blocks_allocated
== 1))
374 walker
= heap_p
->block_p
;
376 while (walker
!= NULL
)
378 if (dlinkLength(&walker
->free_list
) == heap_p
->elems_per_block
)
380 ballocFree(walker
->elems
, walker
->alloc_size
);
384 last
->next
= walker
->next
;
393 heap_p
->block_p
= walker
->next
;
398 walker
= heap_p
->block_p
;
401 heap_p
->blocks_allocated
--;
402 heap_p
->elems_free
-= heap_p
->elems_per_block
;
407 walker
= walker
->next
;