-/* toolbox/memory.c -
+/* src/mm/memory.c - memory management
- Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
- R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
- M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
- P. Tomsich, J. Wenninger
+ 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
This file is part of CACAO.
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., 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA.
-
- Contact: cacao@complang.tuwien.ac.at
-
- Authors: Reinhard Grafl
-
- $Id: memory.c 1568 2004-11-23 16:02:31Z twisti $
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
*/
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
#if defined(__DARWIN__)
-/* If we compile with -ansi on darwin, <sys/types.h> is not included. So */
-/* let's do it here. */
+/* If we compile with -ansi on darwin, <sys/types.h> is not
+ included. So let's do it here. */
# include <sys/types.h>
#endif
-#include <sys/mman.h>
-#include <unistd.h>
+#include "vm/types.h"
+
+#include "arch.h"
+
+#include "mm/memory.h"
+
+#include "native/native.h"
+
+#include "threads/lock-common.h"
+#include "threads/threads-common.h"
-#include "config.h"
-#include "exceptions.h"
-#include "global.h"
-#include "native.h"
-#include "options.h"
-#include "statistics.h"
-#include "threads/nativethread.h"
#include "toolbox/logging.h"
-#include "toolbox/memory.h"
+#include "vm/exceptions.h"
+#include "vm/global.h"
+#include "vm/stringlocal.h"
+#include "vm/vm.h"
+
+#include "vmcore/options.h"
+
+#if defined(ENABLE_STATISTICS)
+# include "vmcore/statistics.h"
+#endif
-/********* general types, variables and auxiliary functions *********/
-static int mmapcodesize = 0;
-static void *mmapcodeptr = NULL;
+/* constants for ENABLE_MEMCHECK **********************************************/
+
+#if defined(ENABLE_MEMCHECK)
+#define MEMORY_CANARY_SIZE 16
+#define MEMORY_CANARY_FIRST_BYTE 0xca
+#define MEMORY_CLEAR_BYTE 0xa5
+#endif /* defined(ENABLE_MEMCHECK) */
/*******************************************************************************
- This structure is used for dump memory allocation if cacao runs without
- threads.
+ This structure is used for dump memory allocation if cacao
+ runs without threads.
*******************************************************************************/
-#if !defined(USE_THREADS)
-static dumpinfo nothreads_dumpinfo;
+#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
+
+
+/* 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.
+*******************************************************************************/
-void *mem_mmap(s4 size)
+bool memory_init(void)
{
- void *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();
- size = ALIGN(size, ALIGNSIZE);
+ /* everything's ok */
+
+ return true;
+}
- if (size > mmapcodesize) {
- mmapcodesize = 0x10000;
- if (size > mmapcodesize)
- mmapcodesize = size;
+/* memory_mmap_anon ************************************************************
- mmapcodesize = ALIGN(mmapcodesize, getpagesize());
- mmapcodeptr = mmap(NULL,
- (size_t) mmapcodesize,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE |
-#if defined(HAVE_MAP_ANONYMOUS)
- MAP_ANONYMOUS,
-#elif defined(HAVE_MAP_ANON)
- MAP_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
- 0,
-#endif
- -1,
- (off_t) 0);
+ int fd;
- if (mmapcodeptr == MAP_FAILED)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
- }
+ fd = open("/dev/zero", O_RDONLY, 0);
- m = mmapcodeptr;
- mmapcodeptr = (void *) ((char *) mmapcodeptr + size);
- mmapcodesize -= size;
+ if (fd == -1)
+ vm_abort("memory_mmap_anon: open failed: %s", strerror(errno));
- return m;
+ 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;
}
-static void *checked_alloc(s4 size)
+/* memory_checked_alloc ********************************************************
+
+ Allocated zeroed-out memory and does an OOM check.
+
+ ERROR HANDLING:
+ XXX If no memory could be allocated, this function justs *exists*.
+
+*******************************************************************************/
+
+static void *memory_checked_alloc(s4 size)
{
/* always allocate memory zeroed out */
- void *m = calloc(size, 1);
- if (!m)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
+ void *p = calloc(size, 1);
- return m;
+ if (p == NULL)
+ vm_abort("memory_checked_alloc: calloc failed: out of memory");
+
+ return p;
+}
+
+
+/* memory_cnew *****************************************************************
+
+ Allocates memory from the heap via mmap and make the memory read-,
+ write-, and executeable.
+
+*******************************************************************************/
+
+void *memory_cnew(s4 size)
+{
+ 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;
+ }
+#endif
+
+ /* allocate the memory */
+
+ p = memory_mmap_anon(NULL, code_memory_size,
+ PROT_READ | PROT_WRITE | PROT_EXEC,
+ MAP_PRIVATE);
+
+ /* set global code memory pointer */
+
+ code_memory = p;
+ }
+
+ /* get a memory chunk of the allocated memory */
+
+ p = code_memory;
+
+ code_memory = (void *) ((ptrint) code_memory + size);
+ code_memory_size -= size;
+
+ LOCK_MONITOR_EXIT(lock_code_memory);
+
+ return p;
+}
+
+
+/* memory_cfree ****************************************************************
+
+ Frees the code memory pointed to.
+
+ ATTENTION: This function currently does NOTHING! Because we don't
+ have a memory management for code memory.
+
+*******************************************************************************/
+
+void memory_cfree(void *p, s4 size)
+{
+ /* do nothing */
}
void *mem_alloc(s4 size)
{
+ void *m;
+
if (size == 0)
return NULL;
+#if defined(ENABLE_STATISTICS)
if (opt_stat) {
memoryusage += size;
if (memoryusage > maxmemusage)
maxmemusage = memoryusage;
}
-
- return checked_alloc(size);
+#endif
+
+ m = memory_checked_alloc(size);
+
+#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 m;
}
{
void *dst;
- if (!src) {
+ /* prevent compiler warnings */
+
+ dst = NULL;
+
+ if (src == NULL)
if (len1 != 0)
- panic("reallocating memoryblock with address NULL, length != 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)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Out of memory");
+ 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;
}
if (!m) {
if (size == 0)
return;
- panic("returned memoryblock with address NULL, length != 0");
+
+ log_text("returned memoryblock with address NULL, length != 0");
+ assert(0);
}
+#if defined(ENABLE_STATISTICS)
if (opt_stat)
memoryusage -= size;
+#endif
+
+#if defined(ENABLE_MEMCHECK)
+ /* destroy the contents */
+ memset(m, MEMORY_CLEAR_BYTE, size);
+#endif
free(m);
}
+/* memory_thread ***************************************************************
+
+ Prints regularly memory statistics.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+static void memory_thread(void)
+{
+ int32_t seconds;
+
+ /* 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 */
+
+ threads_sleep(seconds * 1000, 0);
+
+# if defined(ENABLE_STATISTICS)
+ /* Print current date and time (only when we print to the
+ stdout). */
+
+ if (!opt_ProfileMemoryUsageGNUPlot)
+ statistics_print_date();
+
+ /* print memory usage */
+
+ 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.
+
+*******************************************************************************/
+
+#if defined(ENABLE_THREADS) && !defined(NDEBUG)
+bool memory_start_thread(void)
+{
+ utf *name;
+
+ name = utf_new_char("Memory Profiler");
+
+ /* start the memory profiling thread */
+
+ if (!threads_thread_start_internal(name, memory_thread))
+ return false;
+
+ /* 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.
+
+*******************************************************************************/
+
+#if defined(ENABLE_MEMCHECK)
+void dump_check_canaries(dumpinfo_t *di, s4 bottomsize)
+{
+ 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; i<MEMORY_CANARY_SIZE; ++i)
+ if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
+ fprintf(stderr, "canary bytes:");
+ for (j=0; j<MEMORY_CANARY_SIZE; ++j)
+ fprintf(stderr, " %02x", pm[j]);
+ fprintf(stderr,"\n");
+ vm_abort("error: dump memory bottom canary killed: "
+ "%p (%d bytes allocated at %p)\n",
+ pm + i, da->size, da->mem);
+ }
+
+ pm = da->mem + da->size;
+ for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+ if (pm[i] != i + MEMORY_CANARY_FIRST_BYTE) {
+ fprintf(stderr, "canary bytes:");
+ for (j=0; j<MEMORY_CANARY_SIZE; ++j)
+ fprintf(stderr, " %02x", pm[j]);
+ fprintf(stderr,"\n");
+ vm_abort("error: dump memory top canary killed: "
+ "%p (%d bytes allocated at %p)\n",
+ pm + i, da->size, da->mem);
+ }
+
+ 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 *dump_alloc(s4 size)
{
- void *m;
- dumpinfo *di;
+#if defined(DISABLE_DUMP)
+
+ /* use malloc memory for dump memory (for debugging only!) */
+
+ 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. */
-#if defined(USE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
+
+ di = DUMPINFO;
if (size == 0)
return NULL;
- size = ALIGN(size, ALIGNSIZE);
+#if defined(ENABLE_MEMCHECK)
+ size += 2*MEMORY_CANARY_SIZE;
+#endif
+
+ size = MEMORY_ALIGN(size, ALIGNSIZE);
if (di->useddumpsize + size > di->allocateddumpsize) {
- dumpblock *newdumpblock;
- s4 newdumpblocksize;
+ dumpblock_t *newdumpblock;
+ s4 newdumpblocksize;
/* allocate a new dumplist structure */
- newdumpblock = checked_alloc(sizeof(dumpblock));
+
+ 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;
}
/* allocate dumpblock memory */
- /*printf("new dumpblock: %d\n", newdumpblocksize);*/
- newdumpblock->dumpmem = checked_alloc(newdumpblocksize);
+
+ newdumpblock->dumpmem = memory_checked_alloc(newdumpblocksize);
newdumpblock->prev = di->currentdumpblock;
newdumpblock->size = newdumpblocksize;
/* Used dump size is previously allocated dump size, because the */
/* remaining free memory of the previous dump block cannot be used. */
- /*printf("unused memory: %d\n", allocateddumpsize - useddumpsize);*/
+
di->useddumpsize = di->allocateddumpsize;
/* increase the allocated dump size by the size of the new dump block */
+
di->allocateddumpsize += newdumpblocksize;
- /* the amount of globally allocated dump memory (thread save) */
+#if defined(ENABLE_STATISTICS)
+ /* the amount of globally allocated dump memory (thread save) */
+
if (opt_stat)
globalallocateddumpsize += newdumpblocksize;
+#endif
}
/* 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);
- /* increase used dump size by the allocated memory size */
+#if defined(ENABLE_MEMCHECK)
+ {
+ dump_allocation_t *da = NEW(dump_allocation_t);
+ s4 i;
+ u1 *pm;
+
+ /* 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; i<MEMORY_CANARY_SIZE; ++i)
+ pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
+ pm = da->mem + da->size;
+ for (i=0; i<MEMORY_CANARY_SIZE; ++i)
+ pm[i] = i + MEMORY_CANARY_FIRST_BYTE;
+
+ /* make m point after the bottom canary */
+
+ m = (u1*)m + MEMORY_CANARY_SIZE;
+
+ /* clear the memory */
+
+ memset(m, MEMORY_CLEAR_BYTE, da->size);
+ }
+#endif /* defined(ENABLE_MEMCHECK) */
+
+ /* increase used dump size by the allocated memory size */
+
di->useddumpsize += size;
- if (opt_stat) {
- if (di->useddumpsize > maxdumpsize) {
+#if defined(ENABLE_STATISTICS)
+ if (opt_stat)
+ if (di->useddumpsize > maxdumpsize)
maxdumpsize = di->useddumpsize;
- }
- }
-
+#endif
+
return m;
-}
+#endif /* defined(DISABLE_DUMP) */
+}
+
+
+/* dump_realloc ****************************************************************
+
+ Stupid realloc implementation for dump memory. Avoid, if possible.
+
+*******************************************************************************/
void *dump_realloc(void *src, s4 len1, s4 len2)
{
+#if defined(DISABLE_DUMP)
+ /* use malloc memory for dump memory (for debugging only!) */
+
+ return mem_realloc(src, len1, len2);
+#else
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.
+
+ ERROR HANDLING:
+ XXX If the given size is invalid, this function *exits* with an
+ error message.
+
+ See `dump_alloc`.
+
+*******************************************************************************/
+
void dump_release(s4 size)
{
- dumpinfo *di;
+#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. */
-#if defined(USE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
- if (size < 0 || size > di->useddumpsize)
- throw_cacao_exception_exit(string_java_lang_InternalError,
- "Illegal dump release size %d", size);
+ 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 */
- /* reset the used dump size to the size specified */
di->useddumpsize = size;
while (di->currentdumpblock && di->allocateddumpsize - di->currentdumpblock->size >= di->useddumpsize) {
- dumpblock *tmp = di->currentdumpblock;
-
-#if 0
- /* XXX TWISTI: can someone explain this to me? */
-#ifdef TRACECALLARGS
- /* Keep the first dumpblock if we don't free memory. Otherwise
- * a new dumpblock is allocated each time and we run out of
- * memory.
- */
- if (!oldtop->prev) break;
-#endif
-#endif
+ dumpblock_t *tmp = di->currentdumpblock;
di->allocateddumpsize -= tmp->size;
di->currentdumpblock = tmp->prev;
- /* the amount of globally allocated dump memory (thread save) */
+#if defined(ENABLE_STATISTICS)
+ /* the amount of globally allocated dump memory (thread save) */
+
if (opt_stat)
globalallocateddumpsize -= tmp->size;
+#endif
+
+ /* release the dump memory and the dumpinfo structure */
- /* release the dump memory and the dumpinfo structure */
free(tmp->dumpmem);
free(tmp);
}
+
+#endif /* defined(DISABLE_DUMP) */
}
-s4 dump_size()
+/* dump_size *******************************************************************
+
+ Return the current size of the dump memory area. See `dump_alloc`.
+
+*******************************************************************************/
+
+s4 dump_size(void)
{
- dumpinfo *di;
+#if defined(DISABLE_DUMP)
+ /* use malloc memory for dump memory (for debugging only!) */
+
+ return 0;
+
+#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. */
-#if defined(USE_THREADS)
- di = &((threadobject *) THREADOBJECT)->dumpinfo;
-#else
- di = ¬hreads_dumpinfo;
-#endif
+
+ di = DUMPINFO;
+
+ if (di == NULL)
+ return 0;
return di->useddumpsize;
+
+#endif /* defined(DISABLE_DUMP) */
}
* c-basic-offset: 4
* tab-width: 4
* End:
+ * vim:noexpandtab:sw=4:ts=4:
*/