This is the mail archive of the
cluster-cvs@sourceware.org
mailing list for the cluster.
cluster: STABLE3 - rgmanager: Remove local slab allocator
- From: Lon Hohberger <lon at fedoraproject dot org>
- To: cluster-cvs-relay at redhat dot com
- Date: Mon, 27 Apr 2009 18:00:12 +0000 (UTC)
- Subject: cluster: STABLE3 - rgmanager: Remove local slab allocator
Gitweb: http://git.fedorahosted.org/git/cluster.git?p=cluster.git;a=commitdiff;h=6384601982d87ecc756876af334abde86f952ff7
Commit: 6384601982d87ecc756876af334abde86f952ff7
Parent: a7071ccf17acf270adcd6f647ac894447bbd66bd
Author: Lon Hohberger <lhh@redhat.com>
AuthorDate: Mon Apr 27 13:56:50 2009 -0400
Committer: Lon Hohberger <lhh@redhat.com>
CommitterDate: Mon Apr 27 13:56:50 2009 -0400
rgmanager: Remove local slab allocator
It was unused code anyway.
Signed-off-by: Lon Hohberger <lhh@redhat.com>
---
rgmanager/src/clulib/Makefile | 16 +-
rgmanager/src/clulib/alloc.c | 1233 -----------------------------------------
2 files changed, 4 insertions(+), 1245 deletions(-)
diff --git a/rgmanager/src/clulib/Makefile b/rgmanager/src/clulib/Makefile
index 0dc7a2e..6595953 100644
--- a/rgmanager/src/clulib/Makefile
+++ b/rgmanager/src/clulib/Makefile
@@ -1,8 +1,7 @@
TARGET1= libclulib.a
-TARGET2= liblalloc.a
-TARGET3= msgtest
+TARGET2= msgtest
-all: ${TARGET1} ${TARGET2} ${TARGET3}
+all: ${TARGET1} ${TARGET2}
include ../../../make/defines.mk
include $(OBJDIR)/make/cobj.mk
@@ -15,9 +14,7 @@ OBJS1= logging.o daemon_init.o signals.o msgsimple.o \
lock.o cman.o vft.o msg_cluster.o msg_socket.o \
wrap_lock.o sets.o
-OBJS2= alloc.o
-
-OBJS3= msgtest.o
+OBJS2= msgtest.o
CFLAGS += -Werror -Wstrict-prototypes -Wshadow -fPIC -D_GNU_SOURCE
CFLAGS += -I${ccsincdir} -I${cmanincdir} -I${dlmincdir}
@@ -35,15 +32,10 @@ ${TARGET1}: ${OBJS1}
${AR} cru $@ $^
${RANLIB} $@
-${TARGET2}: ${OBJS2}
- ${AR} cru $@ $^
- ${RANLIB} $@
-
-${TARGET3}: ${OBJS3} ${TARGET1}
+${TARGET2}: ${OBJS2} ${TARGET1}
$(CC) -o $@ $^ $(LDFLAGS)
clean: generalclean
-include $(OBJS1:.o=.d)
-include $(OBJS2:.o=.d)
--include $(OBJS3:.o=.d)
diff --git a/rgmanager/src/clulib/alloc.c b/rgmanager/src/clulib/alloc.c
deleted file mode 100644
index 55ee632..0000000
--- a/rgmanager/src/clulib/alloc.c
+++ /dev/null
@@ -1,1233 +0,0 @@
-/**
- @file
-
- Bounded memory allocator. This is designed for applications which require
- bounded memory allocation and which ought not be swapped out to disk.
-
- What it is:
- - Replacement for malloc, calloc, free, and realloc which allocates
- memory from a fixed-size heap, which is either allocated at the time
- of the first allocation or during program initialization with a call
- to 'malloc_init(size_t count)'.
-
- - Designed for applications requiring small amounts of RAM. Note
- that though we use size_t arguments, the maximum supported in the
- header structure is a 32-bit integer.
-
- - Fairly fast.
-
-
- What it's _not_:
- - General purpose. The heap is allocated either at the first call to
- malloc() or the call to malloc_init(), and is a fixed size. There is no
- memalign/valloc/pvalloc currently.
-
- - Super-efficient. It's reasonably fast in many situations compared to
- glibc's malloc, but records states in the memory blocks to help prevent
- accidental double-frees and such (it's still possible, mind you). In
- general, your program will consume MORE memory when using this allocator,
- because it preallocates a huge block. However, your program should run
- faster. It's also probably not terribly efficient in a threaded
- program, but it does work (and properly zap its mutex on fork()).
-
-
- malloc algorithm in detail:
-
- (1) Init the pool as necessary. After the pool is initialized, we have
- one large free block which is the size of the memory pool less the header.
-
- (2) Whenever we get a call to malloc, we look for a free block. If the
- size of a free block matches within 25% of the requested size (bounded at
- MIN_SAVE), we immediately return that chunk to the user. If no blocks are
- found matching this criteria, we look for chunks which are large enough
- to split (i.e. with a size >= requested_size + MIN_EXTRA).
-
- (3) If we find one, we split the block, create a new (smaller) free block,
- and return the block to the user.
-
- [ Note: Steps 4 and 5 only if AGGR_RECLAIM is 0 ]
- (4) If none are found, we perform an aggressive consolidation which searches
- the entire memory pool for free blocks next to each other and combines
- them into one larger block.
-
- (5) Repeat steps (2) and (3).
-
- (6) If no blocks are found again, we're done. Return NULL/ENOMEM.
-
-
- free algorithm in detail:
-
- (1) Sanity check the pointer and block structure it would point to.
-
- (2) [ If AGGR_RECLAIM = 0 ] Consolidate this block with all free blocks
- with a higher address than it in the pool.
-
- (2) [ If AGGR_RECLAIM = 1 ] Aggressively consolidate all free blocks
- in the pool which are next to one another.
-
-
- realloc:
-
- ... Just an obvious wrapper around malloc. Potentially could resize if
- the next block was free and has enough space. I.e. Join-blocks,
- resize, and split again if necessary. For now, it works, so we'll
- leave it alone. This would be both an increase in speed and memory
- efficiency (while performing the operation), but otherwise isn't necessary.
-
-
- calloc:
-
- ... Really obvious wrapper. Uses memset to clear the memory.
-
- TODO: Use futex, perhaps, instead of pthread stuff.
- */
-#include <stdint.h>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/mman.h>
-#include <string.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <malloc.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/wait.h>
-
-#ifndef DEBUG
-#define DEBUG /* Record program counter of malloc/calloc */
-#endif /* or realloc call; print misc stuff out */
-
-#if defined(__ia64__) || defined(__hppa__)
-#undef DEBUG
-#endif
-
-/* Tunable stuff XXX This should be external */
-#define PARANOID /* Trade off a bit of space and speed for
- extra sanity checks */
-#define DIE_ON_FAULT /* Kill program if we do something bad
- (double free, free after overrun, etc.
- for instance) */
-#undef AGGR_RECLAIM /* consolidate_all on free (*slow*) */
-
-//#undef STACKSIZE /*4 backtrace to store if DEBUG is set */
-#define STACKSIZE 1 /* at least 1 gets you free addr */
-
-#undef GDB_HOOK /* Dump program addresses in malloc_table
- using a fork/exec of gdb (SLOW but fun)
- building this defeats the purpose of
- a bounded memory allocator, and is only
- useful for debugging memory leaks.
- This does not harm anything except code
- size until "malloc_dump_table" is called.
- Given that this is not a normal malloc
- API, this should not matter. */
-
-#define DEFAULT_SIZE (1<<23) /* 8MB default giant block size */
-#define BUCKET_COUNT (13) /* 2^BUCKET_COUNT = max. interesting size */
-#define MIN_POWER (3) /* 2^MIN_POWER = minimum size */
-#define MIN_SIZE (1<<MIN_POWER)
-#define ALIGN (sizeof(void *))
-#define NOBUCKET ((uint16_t)(~0))
-#define MIN_EXTRA (1<<5) /* 64 bytes to split a block */
-
-/* Misc stuff */
-#define ST_FREE 0xfec3 /* Block is free */
-#define ST_ALLOC 0x08f7 /* Block is in use */
-
-
-#ifndef NOPTHREADS
-#include <pthread.h>
-static pthread_mutex_t _alloc_mutex = PTHREAD_MUTEX_INITIALIZER;
-#else
-#define pthread_mutex_trylock(x) (0)
-#define pthread_mutex_lock(x)
-#define pthread_mutex_unlock(x)
-#endif
-
-#ifdef DIE_ON_FAULT
-
-#include <signal.h>
-
-#define die_or_return(val)\
-do { \
- raise(SIGSEGV); \
- return val; \
-} while (0)
-
-#else
-
-#define die_or_return(val)\
-do { \
- return val; \
-} while (0)
-
-#endif
-
-
-typedef struct _memblock {
- /*
- Need to align for 64-bit arches, so for now, we'll keep
- the header size to 8 bytes.
- */
- uint32_t mb_size;
- uint16_t mb_bucket;
- uint16_t mb_state;
-#ifdef DEBUG
-#ifdef STACKSIZE
- void *mb_pc[STACKSIZE];
-#endif
-#endif
- /* If PARANOID isn't defined, we use the following pointer for
- more space. */
- struct _memblock *mb_next;
-} memblock_t;
-
-
-/**
- mmap(2)ed memory pool.
- */
-static void *_pool = NULL;
-
-/**
- Pool size
- */
-static size_t _poolsize = 0;
-
-/**
- Free buckets
- */
-static memblock_t *free_buckets[BUCKET_COUNT];
-
-
-#ifdef PARANOID
-
-/**
- Allocated buckets
- */
-static memblock_t *alloc_buckets[BUCKET_COUNT];
-
-/*
- We use the next pointer for the alloc_bucket list if we're PARANOID, as
- we record the allocated block list in that mode.
- */
-#define HDR_SIZE (sizeof(memblock_t))
-
-#else /* ... not PARANOID */
-
-/*
- We use the next pointer for extra data space if we're secure. Makes the
- allocator slightly more memory efficient.
- */
-#define HDR_SIZE (sizeof(memblock_t) - sizeof(memblock_t *))
-
-#endif /* PARANOID */
-
-/* Return the user pointer for a given memblock_t structure. */
-#define pointer(block) (void *)((void *)block + HDR_SIZE)
-
-/* Return the memblock_t structure given a pointer */
-#define block(pointer) (memblock_t *)((void *)pointer - HDR_SIZE)
-
-/* Calculate and return the next memblock_t pointer in the memory pool
- given a memblock_t pointer. */
-#define nextblock(pointer) \
- (memblock_t *)((void *)pointer + pointer->mb_size + HDR_SIZE)
-
-/* Doesn't *ensure* a block is free, but is a pretty good heuristic */
-#define is_valid_free(block) \
- (block->mb_bucket < BUCKET_COUNT && block->mb_state == ST_FREE)
-
-/* Doesn't *ensure* a block is allocated, but is a pretty good heuristic */
-#define is_valid_alloc(block) \
- (block->mb_bucket == NOBUCKET && block->mb_state == ST_ALLOC && \
- block->mb_size != 0)
-
-
-/**
- Find the proper bucket index, given a size
- */
-static inline int
-find_bucket(size_t size)
-{
- int rv = 0;
- size_t s = size;
-
- s >>= MIN_POWER;
- while (s && (rv < (BUCKET_COUNT-1))) {
- s >>= 1;
- rv++;
- }
-
- return rv;
-}
-
-
-#ifdef PARANOID
-/**
- Check for and remove a block from its free list.
- */
-static inline int
-remove_alloc_block(memblock_t *b)
-{
- memblock_t *block, **prev;
- uint16_t bucket;
-
- /* Could improve performance if NOBUCKET wasn't used
- as an indicator of an allocated block */
- bucket = find_bucket(b->mb_size);
- prev = &(alloc_buckets[bucket]);
-
- if (!(block = alloc_buckets[bucket]))
- return 0;
-
- do {
- if (b == block) {
- *prev = b->mb_next;
- b->mb_next = NULL;
- return 1;
- }
-
- prev = &(*prev)->mb_next;
- block = block->mb_next;
- } while (block);
-
- /* Couldn't find in its appropriate bucket */
- return 0;
-}
-#endif
-
-
-/**
- Check for and remove a block from its free list.
- */
-static inline int
-remove_free_block(memblock_t *b)
-{
- memblock_t *block, **prev;
- uint16_t bucket;
-
- bucket = b->mb_bucket;
- prev = &(free_buckets[bucket]);
-
- if (!(block = free_buckets[bucket]))
- return 0;
-
- do {
- if (b == block) {
- *prev = b->mb_next;
- b->mb_next = NULL;
- return 1;
- }
-
- prev = &(*prev)->mb_next;
- block = block->mb_next;
- } while (block);
-
- /* Couldn't find in its appropriate bucket */
- return 0;
-}
-
-
-#ifdef PARANOID
-/**
- Insert a block on to the allocated bucket list
- */
-static inline memblock_t *
-insert_alloc_block(memblock_t *b)
-{
- uint16_t bucket = find_bucket(b->mb_size);
-
- b->mb_bucket = NOBUCKET;
- b->mb_state = ST_ALLOC;
- b->mb_next = NULL;
-
- if (alloc_buckets[bucket] != NULL)
- b->mb_next = alloc_buckets[bucket];
-
- alloc_buckets[bucket] = b;
-
- return b;
-}
-#endif
-
-
-/**
- Insert a block on to the free bucket list
- */
-static inline memblock_t *
-insert_free_block(memblock_t *b)
-{
- uint16_t bucket = find_bucket(b->mb_size);
-
- b->mb_bucket = bucket;
- b->mb_state = ST_FREE;
- b->mb_next = NULL;
-
- if (free_buckets[bucket] != NULL)
- b->mb_next = free_buckets[bucket];
-
- free_buckets[bucket] = b;
-
- return b;
-}
-
-
-/**
- Consolidate a block with all free blocks to the right of it in the
- pool.
-
- @param left Left block
- @return Number of blocks consolidated.
- */
-static inline int
-consolidate(memblock_t *left)
-{
- memblock_t *right;
- int merged = 0;
-
- while (1) {
- right = nextblock(left);
- if ((void *)right >= (_pool + _poolsize))
- return merged;
-
- if (!is_valid_free(right)) {
- if (is_valid_alloc(right))
- return merged;
-
- /* Not valid free and not valid allocated. BAD. */
- fprintf(stderr, "consolidate: Block %p corrupt. "
- "(Overflow from block %p?)\n", right, left);
- die_or_return(-1);
- }
- if (!remove_free_block(right))
- return merged;
-
- left->mb_size += (right->mb_size + HDR_SIZE);
- right->mb_state = 0;
-
- ++merged;
- }
- /* Not reached */
- return merged;
-}
-
-
-/**
- Consolidate all free blocks next to each-other in the pool in to larger
- blocks. This algorithm is slow...
- */
-static inline void
-consolidate_all(void)
-{
- memblock_t *b, *p;
- int total = 0;
-
- p = NULL;
- b = _pool;
-
- while ((void *)b < (void *)(_pool + _poolsize)) {
-
- if (is_valid_free(b)) {
- if (!remove_free_block(b)) {
- fprintf(stderr, "consolidate: Free block %p "
- "was not in our free list.\n", b);
- }
-
- total += consolidate(b);
- insert_free_block(b);
- } else if (!is_valid_alloc(b)) {
- /* Not valid free and not valid allocated. BAD. */
- fprintf(stderr, "consolidate_all: Block %p corrupt. "
- "(Overflow from block %p?)\n", b, p);
- die_or_return();
- }
-
- /* Consolidated or we're a valid allocated block */
- p = b;
- b = nextblock(b);
- }
-
-#ifdef DEBUG
- if (total)
- fprintf(stderr, "%s: consolidated %d\n", __FUNCTION__, total);
-#endif
-
-}
-
-
-#ifndef NOTHREADS
-/**
- After a fork, we need to kill the mutex so the child can still call malloc
- without getting stuck.
- */
-void
-malloc_zap_mutex(void)
-{
- pthread_mutex_init(&_alloc_mutex, NULL);
-}
-#endif
-
-
-/**
- Initialize the giant mmap pool storage.
- */
-#ifndef NOTHREADS
-static inline int
-_malloc_init(size_t poolsize)
-#else
-int
-malloc_init(size_t poolsize)
-#endif
-{
- int e;
- memblock_t *first = NULL;
-
- if (_pool)
- return -1;
-
- if (poolsize % 32)
- poolsize += (32 - (poolsize % 32));
-
- _pool = mmap(NULL, poolsize, PROT_READ | PROT_WRITE, MAP_LOCKED |
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
-
- if ((_pool == MAP_FAILED) && (errno == EAGAIN)) {
- /* Try again without MAP_LOCKED */
- _pool = mmap(NULL, poolsize, PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
- if (_pool != MAP_FAILED)
- fprintf(stderr, "malloc_init: Warning: using unlocked"
- " memory pages (got root?)\n");
- }
-
- if (_pool == MAP_FAILED) {
- return -1;
- }
-
- _poolsize = poolsize;
-
- for (e = 0; e < BUCKET_COUNT; e++)
- free_buckets[e] = NULL;
-
- first = _pool;
- first->mb_size = (_poolsize - HDR_SIZE);
- first->mb_state = ST_FREE;
- first->mb_next = NULL;
- first->mb_bucket = NOBUCKET;
-
-#ifdef PARANOID
- for (e = 0; e < BUCKET_COUNT; e++)
- alloc_buckets[e] = NULL;
-#endif
-#if 0
-#ifdef DEBUG
- fprintf(stderr, "malloc_init: %lu/%lu available\n",
- (long unsigned)first->mb_size, (long unsigned)_poolsize);
-#endif
-#endif
-
- insert_free_block(first);
- return 0;
-}
-
-
-#ifndef NOTHREADS
-/* Same as above, but lock first! */
-int
-malloc_init(size_t poolsize)
-{
- int e = 0, ret = -1;
- pthread_mutex_lock(&_alloc_mutex);
- if (!_pool) {
- ret = _malloc_init(poolsize);
- e = errno;
- }
- pthread_atfork(NULL, NULL, malloc_zap_mutex);
- pthread_mutex_unlock(&_alloc_mutex);
- errno = e;
- return ret;
-}
-#endif
-
-
-static inline memblock_t *
-split(memblock_t *block, size_t size)
-{
- memblock_t *nb;
- size_t oldsz;
-
- oldsz = block->mb_size;
-
- /* Ok, we got it. */
- block->mb_size = size;
- block->mb_next = NULL;
- block->mb_state = ST_ALLOC;
- block->mb_bucket = NOBUCKET;
-
- nb = nextblock(block);
- nb->mb_state = ST_FREE;
- nb->mb_bucket = NOBUCKET;
- nb->mb_size = (size_t)(oldsz - (HDR_SIZE + size));
- insert_free_block(nb);
-
- /* Created a new next-block. */
-
- return block;
-}
-
-
-/**
- Search the freestore and return an available block which accomodates the
- requested size, splitting up a free block if necessary.
- */
-static inline memblock_t *
-search_freestore(size_t size)
-{
- uint16_t bucket;
- memblock_t *block, **prev;
-
- for (bucket = find_bucket(size); bucket < BUCKET_COUNT; bucket++) {
- block = free_buckets[bucket];
- if (!block)
- continue;
-
- prev = &(free_buckets[bucket]);
-
- do {
- /*
- Look for block with size within 25%
- */
- if (block->mb_size >= size) {
-
- /*
- Split if size >= size + MIN_EXTRA.
-
- 25% of 1MB = 256kb -- which is way too much
- unused space to leave hanging around when
- we're tuned for small bits.
- */
- if (block->mb_size >= (size + MIN_EXTRA)) {
- *prev = block->mb_next;
- block->mb_state = ST_ALLOC;
- block->mb_bucket = NOBUCKET;
- return split(block, size);
- }
-
- /*
- Otherwise, return if the size matches
- within 25%
-
- So, the max unused bytes from a malloc
- operation for a given size is 56 (since
- 64 == MIN_EXTRA). So the following is
- very inefficient:
-
- p = malloc(280);
- free(p);
- p = malloc(224);
- */
- if (block->mb_size < (size + size / 4)) {
- *prev = block->mb_next;
- block->mb_state = ST_ALLOC;
- block->mb_bucket = NOBUCKET;
- return block;
- }
- }
-
- prev = &(*prev)->mb_next;
- block = block->mb_next;
- } while (block);
- }
-
- /* Ok, nothing big enough in the free store */
- return NULL;
-}
-
-
-#ifdef DEBUG
-
-#define stack_pointer(n) \
- (__builtin_frame_address(n)?__builtin_return_address(n):NULL)
-
-#define assign_address(_ptr, _cnt) \
-{ \
- switch(_cnt) { \
- case 0: \
- (_ptr)[_cnt] = stack_pointer(0); \
- break; \
- case 1: \
- (_ptr)[_cnt] = stack_pointer(1); \
- break; \
- case 2: \
- (_ptr)[_cnt] = stack_pointer(2); \
- break; \
- case 3: \
- (_ptr)[_cnt] = stack_pointer(3); \
- break; \
- case 4: \
- (_ptr)[_cnt] = stack_pointer(4); \
- break; \
- case 5: \
- (_ptr)[_cnt] = stack_pointer(5); \
- break; \
- case 6: \
- (_ptr)[_cnt] = stack_pointer(6); \
- break; \
- case 7: \
- (_ptr)[_cnt] = stack_pointer(7); \
- break; \
- case 8: \
- raise(SIGKILL); \
- break; \
- }\
-}
-#endif
-
-
-
-
-/**
- Memory allocation
- */
-void *
-malloc(size_t size)
-{
-#ifndef NOROUND
- size_t r;
-#endif
- memblock_t *block;
-#ifdef DEBUG
-#ifdef STACKSIZE
- int sp;
-#endif
-#endif
-
- if (size < MIN_SIZE)
- size = MIN_SIZE;
-#ifndef NOROUND
- else {
- r = size % MIN_SIZE;
- size += (r ? (MIN_SIZE - r) : 0);
- }
-#endif /* NOROUND */
-
-#ifndef NOTHREADS
- while (pthread_mutex_trylock(&_alloc_mutex) != 0);
-#endif
- if (!_pool) {
-#if 0
-#ifdef DEBUG
- fprintf(stderr,
- "malloc: Initializing region default size %lu\n",
- (long unsigned)DEFAULT_SIZE);
-#endif
-#endif
-#ifndef NOTHREADS
- if (_malloc_init(DEFAULT_SIZE) < 0)
-#else
- if (malloc_init(DEFAULT_SIZE) < 0)
-#endif
- return NULL;
- }
-
- block = search_freestore(size);
- if (block) {
-#ifdef DEBUG
-#ifdef STACKSIZE
- for (sp = 0; sp < STACKSIZE; sp++) {
- assign_address(block->mb_pc, sp);
- if (!block->mb_pc[sp])
- break;
- }
-#endif
-#endif
-#ifdef PARANOID
- insert_alloc_block(block);
-#endif
-#ifndef NOTHREADS
- pthread_mutex_unlock(&_alloc_mutex);
-#endif
- return pointer(block);
- }
-
-#ifdef AGGR_RECLAIM
- consolidate_all();
- block = search_freestore(size);
- if (block) {
-#ifdef DEBUG
-#ifdef STACKSIZE
- for (sp = 0; sp < STACKSIZE; sp++) {
- assign_address(block->mb_pc, sp);
- if (!block->mb_pc[sp])
- break;
- }
-#endif
-#endif
-#ifdef PARANOID
- insert_alloc_block(block);
-#endif
- pthread_mutex_unlock(&_alloc_mutex);
- return pointer(block);
- }
-#endif /* AGGR_RECLAIM */
-
-#ifdef DEBUG
- fprintf(stderr, "Out of memory malloc(%lu) @ %p\n",
- (long unsigned)size, __builtin_return_address(0));
-#endif
- errno = ENOMEM;
- return NULL;
-}
-
-
-/**
- Memory free
- */
-void
-free(void *p)
-{
- memblock_t *b;
-#ifdef DEBUG
-#ifdef STACKSIZE
- void *pc = __builtin_return_address(0);
- int x;
-#endif
-#endif
-
- if (!p) {
-#if 0
- fprintf(stderr, "free(NULL) @ %p\n",
- __builtin_return_address(0));
-#endif
- /* POSIX allows for free(NULL) */
- return;
- }
-
- b = ((void *)p - HDR_SIZE);
-
- pthread_mutex_lock(&_alloc_mutex);
- if (((void *)b < _pool) || ((void *)b >= (_pool + _poolsize))) {
- fprintf(stderr, "free(%p) @ %p - Out of bounds\n",
- p, __builtin_return_address(0));
- pthread_mutex_unlock(&_alloc_mutex);
- die_or_return();
- }
-
- if (!is_valid_alloc(b)) {
-#ifdef DEBUG
- if (!is_valid_free(b))
- fprintf(stderr,
- "free(%p) @ %p - Invalid address\n",
- p, __builtin_return_address(0));
- else
-#ifdef STACKSIZE
- fprintf(stderr,
- "free(%p) @ %p - Already free @ %p\n",
- p, __builtin_return_address(0), b->mb_pc[0]);
-#else
- fprintf(stderr,
- "free(%p) @ %p - Already free\n",
- p, __builtin_return_address(0));
-#endif
-
-#endif
- pthread_mutex_unlock(&_alloc_mutex);
- die_or_return();
- }
-
-#ifdef PARANOID
- /* Remove from the allocated list if we're tracking it. */
- if (!remove_alloc_block(b)) {
- fprintf(stderr, "free(%p) @ %p - Not allocated\n",
- p, __builtin_return_address(0));
- pthread_mutex_unlock(&_alloc_mutex);
- die_or_return();
- }
-#endif
-
-#ifdef DEBUG
-#ifdef STACKSIZE
- for (x = 0; x < STACKSIZE; x++)
- b->mb_pc[x] = NULL;
- b->mb_pc[0] = pc;
-#endif
-#endif
-
- b->mb_state = ST_FREE;
- b->mb_next = NULL;
-
-#ifdef AGGR_RECLAIM
- /* Aggressively search the whole pool and combine all side-by-side
- free blocks */
- insert_free_block(b);
- consolidate_all();
-#else
- /* Combine with all blocks to the right in the pool */
- b->mb_bucket = find_bucket(b->mb_size);
- consolidate(b);
- insert_free_block(b);
-#endif
- pthread_mutex_unlock(&_alloc_mutex);
-}
-
-
-/**
- Slow realloc. It *should* resize the memory, but since we're dealing
- with a static heap, it doesn't.
- */
-void *
-realloc(void *oldp, size_t newsize)
-{
- memblock_t *oldb;
-#ifdef DEBUG
- memblock_t *newb;
-#ifdef STACKSIZE
- int sp;
-#endif
-#endif
- void *newp;
-
- if (oldp) {
- oldb = block(oldp);
- if (newsize <= oldb->mb_size)
- return oldp;
- }
-
- newp = malloc(newsize);
-
- if (!newp) {
- return NULL;
- }
-
- if (oldp) {
- oldb = block(oldp);
- memcpy(newp, oldp, (newsize > oldb->mb_size) ?
- oldb->mb_size : newsize);
- free(oldp);
- }
-#ifdef DEBUG
- newb = block(newp);
-#ifdef STACKSIZE
- for (sp = 0; sp < STACKSIZE; sp++) {
- assign_address(newb->mb_pc, sp);
- if (!newb->mb_pc[sp])
- break;
- }
-#endif
-#endif
- return newp;
-}
-
-
-/**
- simple calloc.
- */
-void *
-calloc(size_t sz, size_t nmemb)
-{
- void *p;
-#ifdef DEBUG
- memblock_t *newb;
-#ifdef STACKSIZE
- int sp;
-#endif
-#endif
-
- sz *= nmemb;
- p = malloc(sz);
- if (!p)
- return NULL;
-
-#ifdef DEBUG
- newb = block(p);
-#ifdef STACKSIZE
- for (sp = 0; sp < STACKSIZE; sp++) {
- assign_address(newb->mb_pc, sp);
- if (!newb->mb_pc[sp])
- break;
- }
-#endif
-#endif
- memset(p, 0, sz);
- return p;
-}
-
-
-void resolve_stack_gdb(void **, size_t);
-
-
-/**
- Dump the allocated memory table. Only does anything useful if PARANOID
- is set.
- */
-void
-malloc_dump_table(size_t minsize, size_t maxsize)
-{
-#ifdef PARANOID
- int any = 0;
- int x;
-#ifdef DEBUG
-#ifdef STACKSIZE
-#ifndef GDB_HOOK
- int sp;
-#endif
-#endif
-#endif
- memblock_t *b;
-
- fflush(stdout);
- pthread_mutex_lock(&_alloc_mutex);
- for (x=0; x<BUCKET_COUNT; x++) {
- for (b = alloc_buckets[x]; b; b = b->mb_next) {
-
- if (b->mb_size < minsize || b->mb_size > maxsize)
- continue;
-
- if (!any)
- fprintf(stderr,
- "+++ Memory table dump +++\n");
- any++;
-#ifndef DEBUG
- fprintf(stderr, " %p (%lu bytes)\n", pointer(b),
- (unsigned long)b->mb_size);
-#else /* DEBUG */
- fprintf(stderr,
- " %p (%lu bytes) allocation trace:\n",
- pointer(b), (unsigned long)b->mb_size);
-#ifdef STACKSIZE
-#ifdef GDB_HOOK
- resolve_stack_gdb(b->mb_pc, STACKSIZE);
- fprintf(stderr,"\n");
-#else
- for (sp = 0; sp < STACKSIZE; sp++)
- fprintf(stderr,"\t%p\n",b->mb_pc[sp]);
-#endif
-#endif /* STACKSIZE */
-#endif /* DEBUG */
- }
- }
- pthread_mutex_unlock(&_alloc_mutex);
- if (any)
- fprintf(stderr, "--- End Memory table dump ---\n");
-
-#else /* PARANOID */
- fprintf(stderr, "malloc_dump_table: Unimplemented\n");
-#endif /* PARANOID */
-}
-
-
-/**
- Print general stats about how we're doing with memory.
- */
-void
-malloc_stats(void)
-{
- int fb = 0, ub = 0, x;
- size_t metadata = 0, ucount = 0, fcount = 0, ps = 0;
- memblock_t *b;
- void *p;
-
- pthread_mutex_lock(&_alloc_mutex);
- if (!_pool) {
- pthread_mutex_unlock(&_alloc_mutex);
- fprintf(stderr,"malloc_stats: No information\n");
- return;
- }
-
-
- for (x=0; x<BUCKET_COUNT; x++) {
- for (b = free_buckets[x]; b; b = b->mb_next) {
- metadata += HDR_SIZE;
- fcount += b->mb_size;
- ++fb;
- }
- }
-
-#ifdef PARANOID
- for (x=0; x<BUCKET_COUNT; x++) {
- for (b = alloc_buckets[x]; b; b = b->mb_next) {
- metadata += HDR_SIZE;
- ucount += b->mb_size;
- ++ub;
- }
- }
-#else
- /* Estimate only... :( */
- ucount = fcount - metadata;
- ub = 0;
-#endif
- p = _pool;
- ps = _poolsize;
-
- pthread_mutex_unlock(&_alloc_mutex);
-
- fprintf(stderr, "malloc_stats:\n");
- fprintf(stderr, " Total: %lu bytes\n", (unsigned long)ps);
- fprintf(stderr, " Base address: %p\n", p);
- fprintf(stderr, " Free: %lu bytes in %d blocks\n",
- (unsigned long)fcount, fb);
-#ifdef PARANOID
- fprintf(stderr, " Used: %lu bytes in %d blocks\n",
- (unsigned long)ucount, ub);
- fprintf(stderr, " Metadata Usage: %lu bytes\n",
- (unsigned long)metadata);
-#else
- fprintf(stderr,
- " Used: %lu bytes (debugging off, block count unknown)\n",
- (unsigned long)ucount);
- fprintf(stderr,
- " Metadata Usage: %lu bytes (debugging off, estimate)\n",
- (unsigned long)metadata);
-#endif
-}
-
-
-#ifdef DEBUG
-#ifdef STACKSIZE
-#ifdef GDB_HOOK
-void
-show_gdb_address(char *buf, size_t buflen, void *address)
-{
- char *line;
- char *end = buf + buflen;
- char foo[32];
-
- snprintf(foo, sizeof(foo), "%p", address);
-
- line = buf;
- while ((line = strchr(line, '\n'))) {
-
- if ((line + strlen(foo) + 1) > end)
- return;
- ++line;
-
- if (!strncmp(line, foo, strlen(foo))) {
- end = strchr(line, ':');
- if (end)
- *end = 0;
- fprintf(stderr,"\t%s\n", line);
- if (end)
- *end = ':';
- return;
- }
- }
-}
-
-
-int
-my_system(char *foo, char *outbuf, size_t buflen)
-{
- char cmd[4096];
- char *args[128];
- int x = 0, y;
- int pid, arg;
- int p[2];
-
- strncpy(cmd, foo, sizeof(cmd));
- foo = NULL;
- do {
- if (!x)
- args[x] = strtok_r(cmd, " ", &foo);
- else
- args[x] = strtok_r(NULL, " ", &foo);
-
- } while (args[x++]);
-
- pipe(p);
- pid = fork();
- if (!pid) {
- close(STDOUT_FILENO);
- dup2(p[1], STDOUT_FILENO);
- execv(args[0], args);
- exit(1);
- }
-
- close(p[1]);
-
- y = 0;
- arg = WNOHANG;
- memset(outbuf, 0, buflen);
- while (waitpid(pid, NULL, arg) != pid) {
-
- /* Interrupt after we decided to block for child */
- if (!arg)
- continue;
-
- if (y >= buflen) {
- /* Out of space. Wait for child without
- the WNOHANG flag now... */
- arg = 0;
- continue;
- }
- x = read(p[0], outbuf + y, 1);
- ++y;
- }
-
- return 0;
-}
-
-
-/*
- Yes, it's slow. Painfully slow.
- */
-void
-resolve_stack_gdb(void **stack, size_t stacksize)
-{
- int pid, fd;
- char fname[1024];
- char programname[1024];
- char commandline[4096];
- char tmp[4096];
- int s;
-
- pid = fork();
- if (pid < 0) {
- return;
- }
-
- if (pid) {
- while (waitpid(pid, &s, 0) != pid);
- return;
- }
-
- /* Child */
-
- pid = getppid();
-
- snprintf(fname, sizeof(fname), "/proc/%d/exe", pid);
- memset(programname, 0, sizeof(programname));
- readlink(fname, programname, sizeof(programname));
-
- snprintf(fname, sizeof(fname), "/tmp/alloc.gdb.XXXXXX");
-
- fd = mkstemp(fname);
- for (s = 0; s < stacksize; s++) {
- if (!stack[s])
- break;
- snprintf(tmp, sizeof(tmp), "x/i %p\n", stack[s]);
- write(fd, tmp, strlen(tmp));
- }
- snprintf(tmp, sizeof(tmp), "quit\n");
- write(fd, tmp, strlen(tmp));
- fsync(fd);
- fdatasync(fd);
-
- snprintf(commandline, sizeof(commandline),
- "/usr/bin/gdb %s %d -batch -x %s",
- programname, pid, fname);
- my_system(commandline, tmp, sizeof(tmp));
- for (s = 0; s < stacksize; s++) {
- if (!stack[s])
- break;
- show_gdb_address(tmp, sizeof(tmp), stack[s]);
- }
-
- unlink(fname);
- close(fd);
- exit(0);
-}
-#endif
-#endif
-#endif
-