From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 19072 invoked by alias); 27 Apr 2009 18:03:08 -0000 Received: (qmail 18957 invoked by alias); 27 Apr 2009 18:03:07 -0000 X-SWARE-Spam-Status: No, hits=1.0 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_44,J_CHICKENPOX_46,J_CHICKENPOX_52,J_CHICKENPOX_55,J_CHICKENPOX_61,J_CHICKENPOX_64,J_CHICKENPOX_66,J_CHICKENPOX_73,J_CHICKENPOX_83,J_CHICKENPOX_84,SPF_HELO_PASS X-Spam-Status: No, hits=1.0 required=5.0 tests=AWL,BAYES_00,J_CHICKENPOX_44,J_CHICKENPOX_46,J_CHICKENPOX_52,J_CHICKENPOX_55,J_CHICKENPOX_61,J_CHICKENPOX_64,J_CHICKENPOX_66,J_CHICKENPOX_73,J_CHICKENPOX_83,J_CHICKENPOX_84,SPF_HELO_PASS X-Spam-Check-By: sourceware.org X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on bastion2.fedora.phx.redhat.com Subject: rgmanager: master - rgmanager: Remove local slab allocator To: cluster-cvs-relay@redhat.com X-Project: Cluster Project X-Git-Module: rgmanager.git X-Git-Refname: refs/heads/master X-Git-Reftype: branch X-Git-Oldrev: 5fd2833fbe401c324c8298ec0e48a9c4f565bc1b X-Git-Newrev: fc140034274a86d88ee9c2669d1792fa22109dec From: Lon Hohberger Message-Id: <20090427180236.0FB441202FF@lists.fedorahosted.org> Date: Mon, 27 Apr 2009 18:03:00 -0000 X-Scanned-By: MIMEDefang 2.58 on 172.16.52.254 Mailing-List: contact cluster-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Post: List-Help: , Sender: cluster-cvs-owner@sourceware.org X-SW-Source: 2009-q2/txt/msg00127.txt.bz2 Gitweb: http://git.fedorahosted.org/git/rgmanager.git?p=rgmanager.git;a=commitdiff;h=fc140034274a86d88ee9c2669d1792fa22109dec Commit: fc140034274a86d88ee9c2669d1792fa22109dec Parent: 5fd2833fbe401c324c8298ec0e48a9c4f565bc1b Author: Lon Hohberger AuthorDate: Mon Apr 27 13:56:50 2009 -0400 Committer: Lon Hohberger CommitterDate: Mon Apr 27 14:02:23 2009 -0400 rgmanager: Remove local slab allocator It was unused code anyway. Signed-off-by: Lon Hohberger --- 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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< -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 - -#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; xmb_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; xmb_next) { - metadata += HDR_SIZE; - fcount += b->mb_size; - ++fb; - } - } - -#ifdef PARANOID - for (x=0; xmb_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 -