X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fmm%2Fmemory.c;h=9c3034491c051994ef2c9aeaf20061b81fb5308d;hb=9f859ad50d3d5d98c185d40b86b2179bc4dc9aeb;hp=d2617465b4194fa8490cbf326f6241308c2985bb;hpb=580f6f56e2fc5577675b8a6f90ab015e0c28b319;p=cacao.git diff --git a/src/mm/memory.c b/src/mm/memory.c index d2617465b..9c3034491 100644 --- a/src/mm/memory.c +++ b/src/mm/memory.c @@ -1,465 +1,812 @@ -/************************* toolbox/memory.c ************************************ +/* src/mm/memory.c - memory management - Copyright (c) 1997 A. Krall, R. Grafl, M. Gschwind, M. Probst + Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel, + C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring, + E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich, + J. Wenninger, Institut f. Computersprachen - TU Wien - See file COPYRIGHT for information on usage and disclaimer of warranties + This file is part of CACAO. - Not documented, see memory.h. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. - Authors: Reinhard Grafl EMAIL: cacao@complang.tuwien.ac.at + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. - Last Change: 1996/10/03 + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. + +*/ -*******************************************************************************/ +#include "config.h" + +#include +#include #include #include -#include #include -#include #include +#include + +#if defined(__DARWIN__) +/* If we compile with -ansi on darwin, is not + included. So let's do it here. */ +# include +#endif -#include "global.h" -#include "callargs.h" -#include "loging.h" -#include "memory.h" +#include "vm/types.h" +#include "arch.h" - /********* general types, variables and auxiliary functions *********/ +#include "mm/memory.h" -#define DUMPBLOCKSIZE (2<<21) -#define ALIGNSIZE 8 +#include "native/native.h" -typedef struct dumplist { - struct dumplist *prev; - char *dumpmem; -} dumplist; +#include "threads/lock-common.h" +#include "threads/threads-common.h" +#include "toolbox/logging.h" +#include "vm/exceptions.h" +#include "vm/global.h" +#include "vm/stringlocal.h" +#include "vm/vm.h" -long int memoryusage = 0; +#include "vmcore/options.h" -long int dumpsize = 0; -long int dumpspace = 0; -dumplist *topdumpblock = NULL; +#if defined(ENABLE_STATISTICS) +# include "vmcore/statistics.h" +#endif -long int maxmemusage = 0; -long int maxdumpsize = 0; -/* #define TRACECALLARGS */ +/* constants for ENABLE_MEMCHECK **********************************************/ -#ifdef TRACECALLARGS -static char *nomallocmem; -static char *nomalloctop; -static char *nomallocptr; +#if defined(ENABLE_MEMCHECK) +#define MEMORY_CANARY_SIZE 16 +#define MEMORY_CANARY_FIRST_BYTE 0xca +#define MEMORY_CLEAR_BYTE 0xa5 +#endif /* defined(ENABLE_MEMCHECK) */ -static void *lit_checked_alloc (int length) -{ - void *m; - if (!nomallocmem) { - nomallocmem = malloc(16777216); - nomalloctop = nomallocmem + 16777216; - nomallocptr = nomallocmem; - } +/******************************************************************************* - nomallocptr = (void*) ALIGN ((long) nomallocptr, ALIGNSIZE); - - m = nomallocptr; - nomallocptr += length; - if (nomallocptr > nomalloctop) panic ("Out of memory"); - return m; -} + This structure is used for dump memory allocation if cacao + runs without threads. +*******************************************************************************/ + +#if !defined(ENABLE_THREADS) +static dumpinfo_t _no_threads_dumpinfo; +#endif + +#if defined(ENABLE_THREADS) +#define DUMPINFO &((threadobject *) THREADOBJECT)->dumpinfo #else +#define DUMPINFO &_no_threads_dumpinfo +#endif -static void *lit_checked_alloc (int length) + +/* global code memory variables ***********************************************/ + +#define DEFAULT_CODE_MEMORY_SIZE 128 * 1024 /* defaulting to 128kB */ + +#if defined(ENABLE_THREADS) +static java_object_t *lock_code_memory = NULL; +#endif +static void *code_memory = NULL; +static int code_memory_size = 0; +static int pagesize = 0; + + +/* memory_init ***************************************************************** + + Initialize the memory subsystem. + +*******************************************************************************/ + +bool memory_init(void) { - void *m = malloc(length); - if (!m) panic ("Out of memory"); - return m; +#if defined(ENABLE_THREADS) + /* create lock for code memory */ + + lock_code_memory = NEW(java_object_t); + + lock_init_object_lock(lock_code_memory); +#endif + + /* get the pagesize of this architecture */ + + pagesize = getpagesize(); + + /* everything's ok */ + + return true; } + +/* memory_mmap_anon ************************************************************ + + Maps anonymous memory, even on systems not defining + MAP_ANON(YMOUS). + +*******************************************************************************/ + +void *memory_mmap_anon(void *addr, size_t len, int prot, int flags) +{ + void *p; + +#if defined(MAP_ANON) || defined(MAP_ANONYMOUS) + p = mmap(addr, len, prot, +# if defined(MAP_ANON) + MAP_ANON | flags, +# else + MAP_ANONYMOUS | flags, +# endif + -1, 0); +#else + int fd; + + fd = open("/dev/zero", O_RDONLY, 0); + + if (fd == -1) + vm_abort("memory_mmap_anon: open failed: %s", strerror(errno)); + + p = mmap(addr, len, prot, flags, fd, 0); +#endif + +#if defined(MAP_FAILED) + if (p == MAP_FAILED) +#else + if (p == (void *) -1) #endif + vm_abort("memory_mmap_anon: mmap failed: %s", strerror(errno)); + + return p; +} + + +/* memory_checked_alloc ******************************************************** + Allocated zeroed-out memory and does an OOM check. -static void *checked_alloc (int length) + ERROR HANDLING: + XXX If no memory could be allocated, this function justs *exists*. + +*******************************************************************************/ + +static void *memory_checked_alloc(s4 size) { - void *m = malloc(length); - if (!m) panic ("Out of memory"); - return m; + /* always allocate memory zeroed out */ + + void *p = calloc(size, 1); + + if (p == NULL) + vm_abort("memory_checked_alloc: calloc failed: out of memory"); + + return p; } -static int mmapcodesize = 0; -static void *mmapcodeptr = NULL; -void *mem_mmap(int length) +/* memory_cnew ***************************************************************** + + Allocates memory from the heap via mmap and make the memory read-, + write-, and executeable. + +*******************************************************************************/ + +void *memory_cnew(s4 size) { - void *retptr; - - length = (ALIGN(length,ALIGNSIZE)); - if (length > mmapcodesize) { - mmapcodesize = 0x10000; - if (length > mmapcodesize) - mmapcodesize = length; - mmapcodesize = (ALIGN(mmapcodesize, getpagesize())); - mmapcodeptr = mmap (NULL, (size_t) mmapcodesize, - PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANONYMOUS, -1, (off_t) 0); - if (mmapcodeptr == (void*) -1) - panic ("Out of memory"); + void *p; + + LOCK_MONITOR_ENTER(lock_code_memory); + + size = MEMORY_ALIGN(size, ALIGNSIZE); + + /* check if enough memory is available */ + + if (size > code_memory_size) { + /* set default code size */ + + code_memory_size = DEFAULT_CODE_MEMORY_SIZE; + + /* do we need more? */ + + if (size > code_memory_size) + code_memory_size = size; + + /* align the size of the memory to be allocated */ + + code_memory_size = MEMORY_ALIGN(code_memory_size, pagesize); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) { + codememusage += code_memory_size; + + if (codememusage > maxcodememusage) + maxcodememusage = codememusage; } - retptr = mmapcodeptr; - mmapcodeptr = (void*) ((char*) mmapcodeptr + length); - mmapcodesize -= length; - return retptr; -} +#endif + /* allocate the memory */ -#ifdef DEBUG + p = memory_mmap_anon(NULL, code_memory_size, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_PRIVATE); - /************ Memory manager, safe version **************/ + /* set global code memory pointer */ + code_memory = p; + } -typedef struct memblock { - struct memblock *prev,*next; - int length; -} memblock; + /* get a memory chunk of the allocated memory */ -#define BLOCKOFFSET (ALIGN(sizeof(memblock),ALIGNSIZE)) + p = code_memory; -struct memblock *firstmemblock; + code_memory = (void *) ((ptrint) code_memory + size); + code_memory_size -= size; + LOCK_MONITOR_EXIT(lock_code_memory); + return p; +} -void *mem_alloc(int length) -{ - memblock *mb; - if (length==0) return NULL; - mb = checked_alloc (length + BLOCKOFFSET); +/* memory_cfree **************************************************************** - mb -> prev = NULL; - mb -> next = firstmemblock; - mb -> length = length; + Frees the code memory pointed to. - if (firstmemblock) firstmemblock -> prev = mb; - firstmemblock = mb; + ATTENTION: This function currently does NOTHING! Because we don't + have a memory management for code memory. - memoryusage += length; - if (memoryusage > maxmemusage) maxmemusage = memoryusage; +*******************************************************************************/ - return ((char*) mb) + BLOCKOFFSET; +void memory_cfree(void *p, s4 size) +{ + /* do nothing */ } -void *lit_mem_alloc(int length) +void *mem_alloc(s4 size) { - memblock *mb; + void *m; - if (length==0) return NULL; - mb = lit_checked_alloc (length + BLOCKOFFSET); + if (size == 0) + return NULL; - mb -> prev = NULL; - mb -> next = firstmemblock; - mb -> length = length; +#if defined(ENABLE_STATISTICS) + if (opt_stat) { + memoryusage += size; - if (firstmemblock) firstmemblock -> prev = mb; - firstmemblock = mb; + if (memoryusage > maxmemusage) + maxmemusage = memoryusage; + } +#endif + + m = memory_checked_alloc(size); - memoryusage += length; - if (memoryusage > maxmemusage) maxmemusage = memoryusage; +#if defined(ENABLE_MEMCHECK) + /* XXX we would like to poison the memory, but callers rely on */ + /* the zeroing. This should change sooner or later. */ + /* memset(m, MEMORY_CLEAR_BYTE, size); */ +#endif - return ((char*) mb) + BLOCKOFFSET; + return m; } -void mem_free(void *m, int length) +void *mem_realloc(void *src, s4 len1, s4 len2) { - memblock *mb; - if (!m) { - if (length==0) return; - panic ("returned memoryblock with address NULL, length != 0"); - } + void *dst; - mb = (memblock*) (((char*) m) - BLOCKOFFSET); - - if (mb->length != length) { - sprintf (logtext, - "Memory block of size %d has been return as size %d", - mb->length, length); - error(); - } - - if (mb->prev) mb->prev->next = mb->next; - else firstmemblock = mb->next; - if (mb->next) mb->next->prev = mb->prev; + /* prevent compiler warnings */ - free (mb); + dst = NULL; - memoryusage -= length; + if (src == NULL) + if (len1 != 0) + vm_abort("mem_realloc: reallocating memoryblock with address NULL, length != 0"); + +#if defined(ENABLE_STATISTICS) + if (opt_stat) + memoryusage = (memoryusage - len1) + len2; +#endif + +#if defined(ENABLE_MEMCHECK) + if (len2 < len1) + memset((u1*)dst + len2, MEMORY_CLEAR_BYTE, len1 - len2); +#endif + + dst = realloc(src, len2); + + if (dst == NULL) + vm_abort("mem_realloc: realloc failed: out of memory"); + +#if defined(ENABLE_MEMCHECK) + if (len2 > len1) + memset((u1*)dst + len1, MEMORY_CLEAR_BYTE, len2 - len1); +#endif + + return dst; } -void lit_mem_free(void *m, int length) +void mem_free(void *m, s4 size) { - memblock *mb; if (!m) { - if (length==0) return; - panic ("returned memoryblock with address NULL, length != 0"); - } + if (size == 0) + return; - mb = (memblock*) (((char*) m) - BLOCKOFFSET); - - if (mb->length != length) { - sprintf (logtext, - "Memory block of size %d has been return as size %d", - mb->length, length); - error(); - } - - if (mb->prev) mb->prev->next = mb->next; - else firstmemblock = mb->next; - if (mb->next) mb->next->prev = mb->prev; + log_text("returned memoryblock with address NULL, length != 0"); + assert(0); + } -#ifdef TRACECALLARGS -#else - free (mb); +#if defined(ENABLE_STATISTICS) + if (opt_stat) + memoryusage -= size; +#endif + +#if defined(ENABLE_MEMCHECK) + /* destroy the contents */ + memset(m, MEMORY_CLEAR_BYTE, size); #endif - memoryusage -= length; + free(m); } -void *mem_realloc (void *m1, int len1, int len2) +/* memory_thread *************************************************************** + + Prints regularly memory statistics. + +*******************************************************************************/ + +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +static void memory_thread(void) { - void *m2; - - m2 = mem_alloc (len2); - memcpy (m2, m1, len1); - mem_free (m1, len1); + int32_t seconds; - return m2; -} + /* If both arguments are specified, use the value of + ProfileMemoryUsage. */ + if (opt_ProfileGCMemoryUsage) + seconds = opt_ProfileGCMemoryUsage; + if (opt_ProfileMemoryUsage) + seconds = opt_ProfileMemoryUsage; + while (true) { + /* sleep thread */ -static void mem_characterlog (unsigned char *m, int len) -{ -# define LINESIZE 16 - int z,i; - - for (z=0; z=' ' && m[i]<=127) ? m[i] : '.'); - } - - dolog(); - } -} + threads_sleep(seconds * 1000, 0); -#else - /******* Memory manager, fast version ******/ +# if defined(ENABLE_STATISTICS) + /* Print current date and time (only when we print to the + stdout). */ + if (!opt_ProfileMemoryUsageGNUPlot) + statistics_print_date(); -void *mem_alloc(int length) -{ - if (length==0) return NULL; + /* print memory usage */ - memoryusage += length; - if (memoryusage > maxmemusage) maxmemusage = memoryusage; - - return checked_alloc (length); + if (opt_ProfileMemoryUsage) + statistics_print_memory_usage(); + + /* print GC memory usage */ + + if (opt_ProfileGCMemoryUsage) + statistics_print_gc_memory_usage(); +# endif + } } +#endif + + +/* memory_start_thread ********************************************************* + + Starts the memory profiling thread. +*******************************************************************************/ -void *lit_mem_alloc(int length) +#if defined(ENABLE_THREADS) && !defined(NDEBUG) +bool memory_start_thread(void) { - if (length==0) return NULL; + utf *name; + + name = utf_new_char("Memory Profiler"); + + /* start the memory profiling thread */ + + if (!threads_thread_start_internal(name, memory_thread)) + return false; - memoryusage += length; - if (memoryusage > maxmemusage) maxmemusage = memoryusage; - - return lit_checked_alloc (length); + /* everything's ok */ + + return true; } +#endif + + +/* dump_check_canaries ********************************************************* + Check canaries in dump memory. + + IN: + di...........dumpinfo_t * of the dump area to check + bottomsize...dump size down to which the dump area should be checked + (specify 0 to check the whole dump area) + + ERROR HANDLING: + If any canary has been changed, this function aborts the VM with + an error message. + +*******************************************************************************/ -void mem_free(void *m, int length) +#if defined(ENABLE_MEMCHECK) +void dump_check_canaries(dumpinfo_t *di, s4 bottomsize) { - if (!m) { - if (length==0) return; - panic ("returned memoryblock with address NULL, length != 0"); - } + dump_allocation_t *da; + u1 *pm; + s4 i, j; + + /* iterate over all dump memory allocations above bottomsize */ + + da = di->allocations; + while (da && da->useddumpsize >= bottomsize) { + /* check canaries */ + + pm = da->mem - MEMORY_CANARY_SIZE; + for (i=0; isize, da->mem); + } - memoryusage -= length; + pm = da->mem + da->size; + for (i=0; isize, da->mem); + } - free (m); + da = da->next; + } } +#endif /* defined(ENABLE_MEMCHECK) */ + + +/* dump_alloc ****************************************************************** + + Allocate memory in the dump area. + IN: + size.........size of block to allocate, in bytes + may be zero, in which case NULL is returned + + RETURN VALUE: + pointer to allocated memory, or + NULL iff `size` was zero + + ERROR HANDLING: + XXX This function uses `memory_checked_alloc`, which *exits* if no + memory could be allocated. + + THREADS: + dump_alloc is thread safe. Each thread has its own dump memory area. + + dump_alloc is a fast allocator suitable for scratch memory that can be + collectively freed when the current activity (eg. compiling) is done. + + You cannot selectively free dump memory. Before you start allocating it, + you remember the current size returned by `dump_size`. Later, when you no + longer need the memory, call `dump_release` with the remembered size and + all dump memory allocated since the call to `dump_size` will be freed. + +*******************************************************************************/ -void lit_mem_free(void *m, int length) +void *dump_alloc(s4 size) { - if (!m) { - if (length==0) return; - panic ("returned memoryblock with address NULL, length != 0"); - } +#if defined(DISABLE_DUMP) - memoryusage -= length; + /* use malloc memory for dump memory (for debugging only!) */ -#ifdef TRACECALLARGS -#else - free (m); + return mem_alloc(size); + +#else /* !defined(DISABLE_DUMP) */ + + void *m; + dumpinfo_t *di; +#if defined(ENABLE_MEMCHECK) + s4 origsize = size; /* needed for the canary system */ #endif -} + /* If no threads are used, the dumpinfo structure is a static structure */ + /* defined at the top of this file. */ -void *mem_realloc (void *m1, int len1, int len2) -{ - void *m2; + di = DUMPINFO; + + if (size == 0) + return NULL; + +#if defined(ENABLE_MEMCHECK) + size += 2*MEMORY_CANARY_SIZE; +#endif + + size = MEMORY_ALIGN(size, ALIGNSIZE); + + if (di->useddumpsize + size > di->allocateddumpsize) { + dumpblock_t *newdumpblock; + s4 newdumpblocksize; + + /* allocate a new dumplist structure */ + + newdumpblock = memory_checked_alloc(sizeof(dumpblock_t)); + + /* If requested size is greater than the default, make the new dump */ + /* block as big as the size requested. Else use the default size. */ + + if (size > DUMPBLOCKSIZE) { + newdumpblocksize = size; - if (!m1) { - if (len1!=0) - panic ("reallocating memoryblock with address NULL, length != 0"); + } else { + newdumpblocksize = DUMPBLOCKSIZE; } - - memoryusage = (memoryusage - len1) + len2; - m2 = realloc (m1, len2); - if (!m2) panic ("Out of memory"); - return m2; -} + /* allocate dumpblock memory */ + + newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize); + + newdumpblock->prev = di->currentdumpblock; + newdumpblock->size = newdumpblocksize; + di->currentdumpblock = newdumpblock; + + /* Used dump size is previously allocated dump size, because the */ + /* remaining free memory of the previous dump block cannot be used. */ + di->useddumpsize = di->allocateddumpsize; + /* increase the allocated dump size by the size of the new dump block */ + + di->allocateddumpsize += newdumpblocksize; + +#if defined(ENABLE_STATISTICS) + /* the amount of globally allocated dump memory (thread save) */ + + if (opt_stat) + globalallocateddumpsize += newdumpblocksize; #endif + } - /******* common memory manager parts ******/ + /* current dump block base address + the size of the current dump block - */ + /* the size of the unused memory = new start address */ + m = di->currentdumpblock->dumpmem + di->currentdumpblock->size - + (di->allocateddumpsize - di->useddumpsize); +#if defined(ENABLE_MEMCHECK) + { + dump_allocation_t *da = NEW(dump_allocation_t); + s4 i; + u1 *pm; -long int mem_usage() -{ - return memoryusage; -} + /* add the allocation to our linked list of allocations */ + da->next = di->allocations; + da->mem = (u1*) m + MEMORY_CANARY_SIZE; + da->size = origsize; + da->useddumpsize = di->useddumpsize; + di->allocations = da; + /* write the canaries */ + pm = (u1*)m; + for (i=0; imem + da->size; + for (i=0; i 0); + /* clear the memory */ - if (dumpsize + length > dumpspace) { - dumplist *newdumpblock = checked_alloc (sizeof(dumplist)); + memset(m, MEMORY_CLEAR_BYTE, da->size); + } +#endif /* defined(ENABLE_MEMCHECK) */ - newdumpblock -> prev = topdumpblock; - topdumpblock = newdumpblock; + /* increase used dump size by the allocated memory size */ - newdumpblock -> dumpmem = checked_alloc (DUMPBLOCKSIZE); + di->useddumpsize += size; - dumpsize = dumpspace; - dumpspace += DUMPBLOCKSIZE; - } - - m = topdumpblock -> dumpmem + DUMPBLOCKSIZE - (dumpspace - dumpsize); - dumpsize += length; - - if (dumpsize > maxdumpsize) { - maxdumpsize = dumpsize; - } - - return m; -} +#if defined(ENABLE_STATISTICS) + if (opt_stat) + if (di->useddumpsize > maxdumpsize) + maxdumpsize = di->useddumpsize; +#endif + return m; -void *dump_realloc(void *ptr, int len1, int len2) -{ - void *p2 = dump_alloc (len2); - memcpy (p2, ptr, len1); - return p2; +#endif /* defined(DISABLE_DUMP) */ } -long int dump_size() -{ - return dumpsize; -} +/* dump_realloc **************************************************************** + Stupid realloc implementation for dump memory. Avoid, if possible. + +*******************************************************************************/ -void dump_release(long int size) +void *dump_realloc(void *src, s4 len1, s4 len2) { - assert (size >= 0 && size <= dumpsize); - - dumpsize = size; - - while (dumpspace > dumpsize + DUMPBLOCKSIZE) { - dumplist *oldtop = topdumpblock; - - topdumpblock = oldtop -> prev; - dumpspace -= DUMPBLOCKSIZE; - -#ifdef TRACECALLARGS +#if defined(DISABLE_DUMP) + /* use malloc memory for dump memory (for debugging only!) */ + + return mem_realloc(src, len1, len2); #else - free (oldtop -> dumpmem); - free (oldtop); + void *dst = dump_alloc(len2); + + memcpy(dst, src, len1); + +#if defined(ENABLE_MEMCHECK) + /* destroy the source */ + memset(src, MEMORY_CLEAR_BYTE, len1); +#endif + + return dst; #endif - } } +/* dump_release **************************************************************** + + Release dump memory above the given size. + IN: + size........All dump memory above this mark will be freed. Usually + `size` will be the return value of a `dump_size` call + made earlier. -void mem_usagelog (int givewarnings) + ERROR HANDLING: + XXX If the given size is invalid, this function *exits* with an + error message. + + See `dump_alloc`. + +*******************************************************************************/ + +void dump_release(s4 size) { - if ((memoryusage!=0) && givewarnings) { - sprintf (logtext, "Allocated memory not returned: %d", - (int)memoryusage); - dolog(); - -#ifdef DEBUG - { - memblock *mb = firstmemblock; - while (mb) { - sprintf (logtext, " Memory block size: %d", - (int)(mb->length) ); - dolog(); - mem_characterlog ( ((unsigned char*)mb) + BLOCKOFFSET, mb->length); - mb = mb->next; - } +#if defined(DISABLE_DUMP) + + /* use malloc memory for dump memory (for debugging only!) */ + + /* do nothing */ + +#else /* !defined(DISABLE_DUMP) */ + + dumpinfo_t *di; + + /* If no threads are used, the dumpinfo structure is a static structure */ + /* defined at the top of this file. */ + + di = DUMPINFO; + + if ((size < 0) || (size > di->useddumpsize)) + vm_abort("Illegal dump release size: %d", size); + +#if defined(ENABLE_MEMCHECK) + { + dump_allocation_t *da, *next; + + /* check canaries */ + + dump_check_canaries(di, size); + + /* iterate over all dump memory allocations about to be released */ + + da = di->allocations; + while (da && da->useddumpsize >= size) { + next = da->next; + + /* invalidate the freed memory */ + + memset(da->mem, MEMORY_CLEAR_BYTE, da->size); + + FREE(da, dump_allocation_t); + + da = next; } + di->allocations = da; + } +#endif /* defined(ENABLE_MEMCHECK) */ + + /* reset the used dump size to the size specified */ + + di->useddumpsize = size; + + while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) { + dumpblock_t *tmp = di->currentdumpblock; + + di->allocateddumpsize -= tmp->size; + di->currentdumpblock = tmp->prev; + +#if defined(ENABLE_STATISTICS) + /* the amount of globally allocated dump memory (thread save) */ + + if (opt_stat) + globalallocateddumpsize -= tmp->size; #endif - - } - if ((dumpsize!=0) && givewarnings) { - sprintf (logtext, "Dump memory not returned: %d",(int)dumpsize); - dolog(); - } + /* release the dump memory and the dumpinfo structure */ + + free(tmp->dumpmem); + free(tmp); + } + +#endif /* defined(DISABLE_DUMP) */ +} + + +/* dump_size ******************************************************************* + + Return the current size of the dump memory area. See `dump_alloc`. + +*******************************************************************************/ + +s4 dump_size(void) +{ +#if defined(DISABLE_DUMP) + /* use malloc memory for dump memory (for debugging only!) */ + return 0; - sprintf (logtext, "Random/Dump - memory usage: %dK/%dK", - (int)((maxmemusage+1023)/1024), - (int)((maxdumpsize+1023)/1024) ); - dolog(); - +#else /* !defined(DISABLE_DUMP) */ + + dumpinfo_t *di; + + /* If no threads are used, the dumpinfo structure is a static structure */ + /* defined at the top of this file. */ + + di = DUMPINFO; + + if (di == NULL) + return 0; + + return di->useddumpsize; + +#endif /* defined(DISABLE_DUMP) */ } + +/* + * These are local overrides for various environment variables in Emacs. + * Please do not remove this and leave it at the end of the file, where + * Emacs will automagically detect them. + * --------------------------------------------------------------------- + * Local variables: + * mode: c + * indent-tabs-mode: t + * c-basic-offset: 4 + * tab-width: 4 + * End: + * vim:noexpandtab:sw=4:ts=4: + */