Created
March 5, 2013 22:45
-
-
Save splbio/5095049 to your computer and use it in GitHub Desktop.
lame arena allocator for libz during kernel crashes. allows memory allocation from a hunk of DATA and does minimal "best fit" management of a freelist. This is quick and dirty because the system is about to go down anyhow so any complexity is likely to be wasted time here.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stddef.h> | |
#include <sys/types.h> | |
#include <sys/queue.h> | |
#ifndef roundup | |
#define roundup(x, y) ((((x)+((y)-1))/(y))*(y) | |
#endif | |
/* | |
* This arena allocator is very bad, but its only used during a | |
* crash so it should suffice. | |
*/ | |
/* | |
* In practice it seems like 281kb is typical usage for large core | |
* dumps, so over allocate to 1MB to avoid losing a dump. | |
*/ | |
#define GZ_STATIC_ALLOC_BYTES (1024*1024) | |
static char gz_arena[GZ_STATIC_ALLOC_BYTES]; | |
struct gz_arena_item { | |
int fi_size; | |
TAILQ_ENTRY(gz_arena_item) fi_lnk; | |
uintptr_t fi_data; | |
}; | |
static int gz_arena_sbrk = 0; /* pointer to end of heap */ | |
static TAILQ_HEAD(, gz_arena_item) gz_arena_freelist = | |
TAILQ_HEAD_INITIALIZER(gz_arena_freelist); | |
static TAILQ_HEAD(, gz_arena_item) gz_arena_alloclist = | |
TAILQ_HEAD_INITIALIZER(gz_arena_alloclist); | |
static void * | |
gz_arena_alloc(void *notused __unused, u_int items, u_int size) | |
{ | |
struct gz_arena_item *fi, *fi_bestfit; | |
size_t actual_alloc; | |
size_t realsize = size*items; | |
/* | |
* Walk the freelist and try to find the smallest | |
* piece that will fit "size" | |
*/ | |
fi_bestfit = NULL; | |
TAILQ_FOREACH(fi, &gz_arena_freelist, fi_lnk) { | |
/* exact fit */ | |
if (fi->fi_size == realsize) { | |
fi_bestfit = fi; | |
break; | |
} | |
if (fi->fi_size < realsize) | |
continue; | |
if (fi_bestfit == NULL) | |
fi_bestfit = fi; | |
else if (fi_bestfit->fi_size < fi->fi_size) | |
fi_bestfit = fi; | |
} | |
if (fi_bestfit != NULL) { | |
fprintf(stderr, "found @%p\n", fi_bestfit); | |
TAILQ_REMOVE(&gz_arena_freelist, fi_bestfit, fi_lnk); | |
TAILQ_INSERT_HEAD(&gz_arena_alloclist, fi_bestfit, fi_lnk); | |
return (&fi_bestfit->fi_data); | |
} | |
/* | |
* Ok we couldn't find a chunk to reuse, expand the heap.. if we can. | |
*/ | |
actual_alloc = 0; | |
actual_alloc = roundup(realsize + sizeof(struct gz_arena_item), | |
sizeof(uintptr_t))); | |
if (gz_arena_sbrk + actual_alloc >= GZ_STATIC_ALLOC_BYTES) { | |
printf("out of memory in gz_arena_alloc!\n"); | |
return NULL; | |
} | |
fi = (struct gz_arena_item *)&(gz_arena[gz_arena_sbrk]); | |
fi->fi_size = realsize; | |
TAILQ_INSERT_HEAD(&gz_arena_alloclist, fi, fi_lnk); | |
fprintf(stderr, "created @%p size %d, actualalloc %d\n", fi, | |
(int)realsize, (int)actual_alloc); | |
gz_arena_sbrk += actual_alloc; | |
return (&fi->fi_data); | |
} | |
static void | |
gz_arena_free(void *opaque __unused, void *ptr) | |
{ | |
struct gz_arena_item *fi, *fi_guess; | |
fprintf(stderr, "free: ptr = @%p\n", ptr); | |
fi_guess = (struct gz_arena_item *)(((char *)ptr) - | |
offsetof(struct gz_arena_item, fi_data)); | |
fprintf(stderr, "free: guess = @%p\n", fi_guess); | |
TAILQ_FOREACH(fi, &gz_arena_alloclist, fi_lnk) { | |
if (fi == fi_guess) | |
break; | |
} | |
if (fi == NULL) { | |
printf("free of non-allocated memory\n"); | |
return; | |
} | |
TAILQ_REMOVE(&gz_arena_alloclist, fi, fi_lnk); | |
TAILQ_INSERT_HEAD(&gz_arena_freelist, fi, fi_lnk); | |
} | |
int | |
main(void) | |
{ | |
void *p1, *p2, *p3, *p4; | |
p1 = gz_arena_alloc(NULL, 10, 5); | |
p2 = gz_arena_alloc(NULL, 10, 5); | |
p3 = gz_arena_alloc(NULL, 10, 5); | |
p4 = gz_arena_alloc(NULL, 10, 5); | |
printf("%p %p %p %p\n", p1, p2, p3, p4); | |
gz_arena_free(NULL, p1); | |
gz_arena_free(NULL, p2); | |
gz_arena_free(NULL, p3); | |
gz_arena_free(NULL, p4); | |
p1 = gz_arena_alloc(NULL, 10, 5); | |
p2 = gz_arena_alloc(NULL, 10, 5); | |
p3 = gz_arena_alloc(NULL, 10, 5); | |
p4 = gz_arena_alloc(NULL, 10, 5); | |
printf("%p %p %p %p\n", p1, p2, p3, p4); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment