psyclpc/src/xptmalloc.c

259 lines
7.7 KiB
C

/*---------------------------------------------------------------------------
* xalloc stubs for the ptmalloc2 Memory Manager
*
* ptmalloc2 was written by Wolfram Glober (www.malloc.de).
* ptmalloc2 is based on work of Doug Lea (gee.cs.oswego.edu).
* ptmalloc2 was adapted to ldmud by Christian Welzel (www.camlann.de)
*---------------------------------------------------------------------------
* This allocator supports REPLACE_MALLOC.
* Note: when using pthreads and GC_SUPPORT under *BSD, malloc()
* is called before the synchronisation data structures are available.
* This would cause a deadlock in the call to gc_lock(), therefore
* under *BSD the REPLACE_MALLOC feature is disabled.
* This allocator is threadsafe.
*/
#include "mstrings.h"
#include "stdstrings.h"
#include "svalue.h"
#include "ptmalloc/malloc.h"
#include "../mudlib/sys/debug_info.h"
/* Functions defined by ptmalloc */
extern POINTER dlmalloc(size_t);
extern POINTER dlrealloc(POINTER, size_t);
extern void dlfree(POINTER);
extern int dlmalloc_usable_size(POINTER);
extern void dlmalloc_mark_collectable(POINTER);
extern void dlmalloc_mark_permanent(POINTER);
extern void dlmalloc_clear_ref(POINTER);
extern void dlmalloc_mark_ref(POINTER);
extern int dlmalloc_test_ref(POINTER);
extern void dlmalloc_clear_ref_flags();
extern void dlmalloc_free_unrefed_memory();
extern int dlmalloc_is_freed(POINTER, size_t);
extern struct mallinfo dlmallinfo();
static word_t *heap_end = NULL;
static word_t *heap_start = NULL;
/* Start and end address of the heap - currently always set to NULL,
* which disables the assert_stack_gap() logic. Considering that
* ptmalloc uses mmap, the logic wouldn't really work anyway.
*/
#define PT_OVERHEAD (2*sizeof(size_t))
/* to allocate a memory block */
static POINTER mem_alloc(size_t size) {
return dlmalloc(size);
}
/* to deallocate a memory block */
static void mem_free(POINTER p) {
return dlfree(p);
}
/* reallocate a block. */
static POINTER mem_realloc (POINTER p, size_t size) {
return dlrealloc(p, size);
}
/* Increase a block size in place. If not possible, return NULL. */
static void * mem_increment_size (void *vp, size_t size) {
return NULL;
}
/* Return the size of an allocated block.
* If this value is not available, implement this function as a dummy,
* but also #define NO_MEM_BLOCK_SIZE.
* For Garbage Collection or replacing malloc() this function must be
* valid!
* Returns the blocksize excl. overhead.
*/
static size_t mem_block_size (POINTER p) {
return dlmalloc_usable_size(p);
}
/* Return the size of the allocators internal overhead. */
static size_t mem_overhead () {
return PT_OVERHEAD;
}
/* Mark a block as permanent */
static void mem_mark_permanent (POINTER p) {
dlmalloc_mark_permanent(p);
}
/* Mark a block as collectable */
static void mem_mark_collectable (POINTER p) {
dlmalloc_mark_collectable(p);
}
/* Do whatever consolidation is useful. */
void mem_consolidate (Bool force UNUSED)
{
# ifdef __MWERKS__
# pragma unused(force)
# endif
/* nothing to do here... malloc does it automagically */
}
#ifdef MALLOC_EXT_STATISTICS
/* Update whatever extended statistics the allocator has. Called every
* backend cycle or so to allow for the calculation of averages over time.
*/
void
mem_update_stats (void)
{
/* Nothing */
} /* mem_update_stats() */
#endif /* MALLOC_EXT_STATISTICS */
/* For the status commands and functions: add the ptmalloc statistic
* to the buffer <sbuf>.
*/
void mem_dump_data (strbuf_t *sbuf) {
struct mallinfo stats;
/* Get a snapshot of the statistics - strbuf_add() might do further
* allocations while we're reading them.
*/
stats = dlmallinfo();
# define dump_stat(str,member) strbuf_addf(sbuf, str, stats.member)
strbuf_add(sbuf, "Type Amount\n");
dump_stat("total non-mmaped: %8d bytes\n", arena);
dump_stat("number of free chunks: %8d\n", ordblks);
dump_stat("number of fastbins: %8d\n", smblks);
dump_stat("number of mmap: %8d\n", hblks);
dump_stat("bytes in mmap: %8d bytes\n", hblkhd);
dump_stat("max alloced ever: %8d bytes\n", usmblks);
dump_stat("total in fastbin: %8d bytes\n", fsmblks);
dump_stat("total alloced: %8d bytes \n", uordblks);
dump_stat("total free: %8d bytes\n", fordblks);
dump_stat("freeable bytes: %8d bytes\n", keepcost);
#undef dump_stat
} /* mem_dump_data() */
void mem_dump_extdata (strbuf_t *sbuf) {
strbuf_add(sbuf, "ptmalloc doesn't have extended statistics.\n");
} /* mem_dump_extdata() */
/* Fill in the data for debug_info(DINFO_DATA, DID_MEMORY) into the
* svalue-block svp.
*/
void mem_dinfo_data (svalue_t *svp, int value) {
struct mallinfo stats;
#define ST_NUMBER(which,code) \
if (value == -1) svp[which].u.number = code; \
else if (value == which) svp->u.number = code
stats = dlmallinfo();
if (value == -1)
put_ref_string(svp+DID_MEM_NAME, STR_PTMALLOC);
else if (value == DID_MEM_NAME)
put_ref_string(svp, STR_PTMALLOC);
ST_NUMBER(DID_MEM_SBRK_SIZE, stats.arena);
ST_NUMBER(DID_MEM_FREE_CHUNKS, stats.ordblks);
ST_NUMBER(DID_MEM_FFREE, stats.smblks);
ST_NUMBER(DID_MEM_FFREE_SIZE, stats.fsmblks);
ST_NUMBER(DID_MEM_MMAP, stats.hblks);
ST_NUMBER(DID_MEM_MMAP_SIZE, stats.hblkhd);
ST_NUMBER(DID_MEM_MAX_ALLOCATED, stats.usmblks);
ST_NUMBER(DID_MEM_OVERHEAD, PT_OVERHEAD);
ST_NUMBER(DID_MEM_ALLOCATED, stats.uordblks);
ST_NUMBER(DID_MEM_USED, stats.uordblks - stats.fordblks);
ST_NUMBER(DID_MEM_TOTAL_UNUSED, stats.fordblks);
ST_NUMBER(DID_MEM_KEEP_COST, stats.keepcost);
#undef ST_NUMBER
} /* mem_dinfo_data() */
#ifdef GC_SUPPORT
/* Clear, set, test the 'referenced' marker. */
static void mem_clear_ref (POINTER p) {
dlmalloc_clear_ref(p);
}
static void mem_mark_ref (POINTER p) {
dlmalloc_mark_ref(p);
}
static Bool mem_test_ref (POINTER p) {
return !dlmalloc_test_ref(p);
}
/* Clear all 'referenced' markers. */
void mem_clear_ref_flags() {
dlmalloc_clear_ref_flags();
}
/* Free all memory marked as 'unreferenced'. */
void mem_free_unrefed_memory() {
dlmalloc_free_unrefed_memory();
}
/*-------------------------------------------------------------------------*/
Bool
mem_dump_memory (int fd)
/* Print the location, size, and (if available) the TRACE information
* of all memory blocks to file <fd>, and return TRUE.
* If the allocator doesn't support this operation, print nothing
* and return FALSE.
*
* If <fd> is -1, just return TRUE or FALSE (this is used to check if
* the allocator supports memory dumps).
*/
{
return MY_FALSE;
} /* mem_dump_memory() */
#ifdef MALLOC_TRACE
/* Return true if <p> is a free block. */
static Bool mem_is_freed (POINTER p, size_t minsize) {
return dlmalloc_is_freed(p, minsize);
}
#endif
#endif /* GC_SUPPORT */
/* the alignment guaranteed by the allocator */
//#define MEM_ALIGN (2*(sizeof(size_t)))
#define MEM_ALIGN (2*SIZEOF_INT)
/* If the allocator can replace the libc allocation routines.
* See above for the *BSD situation.
*/
#if defined(SBRK_OK) && \
!defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__)
#define REPLACE_MALLOC
#endif
/* The allocator is threadsafe */
#define MEM_THREADSAFE
/* Reference a couple of unused variables and functions to avoid
* unnecessary warning.
*/
void ptmalloc_ref_unused(void)
{
in_malloc = 0;
print_block(0, 0);
#ifdef REPLACE_MALLOC
count_up(&clib_alloc_stat, 0);
#endif
}
/***************************************************************************/