/* memory.c -- Memory management for Khepera * Created: Thu Dec 22 09:58:38 1994 by faith@dict.org * Revised: Sat Mar 30 12:08:38 2002 by faith@dict.org * Copyright 1994-1996, 2002 Rickard E. Faith (faith@dict.org) * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: memory.c,v 1.9 2002/08/02 19:43:15 faith Exp $ * * \section{Memory Management Routines} * * \intro The memory management routines provide simple support for string * object storage. These routines are generally used as building blocks by * other parts of the \khepera library (e.g., string pools and abstract * syntax trees). * */ #include "maaP.h" #include "obstack.h" #ifdef DMALLOC_FUNC_CHECK /* Must be true functions */ #define obstack_chunk_alloc malloc #define obstack_chunk_free free #else #define obstack_chunk_alloc xmalloc #define obstack_chunk_free xfree #endif typedef struct stringInfo { #if MAA_MAGIC int magic; #endif int count; int bytes; struct obstack *obstack; } *stringInfo; typedef struct objectInfo { #if MAA_MAGIC int magic; #endif int total; int used; int reused; int size; stk_Stack stack; /* for free list */ struct obstack *obstack; } *objectInfo; #if !MAA_MAGIC #define _mem_magic_strings(i,function) \ do { \ if (!i) err_internal( function, "mem_String is null\n" ); \ } while (0); #else static void _mem_magic_strings( stringInfo i, const char *function ) { if (!i) err_internal( function, "mem_String is null\n" ); if (i->magic != MEM_STRINGS_MAGIC) err_internal( function, "Incorrect magic: 0x%08x (should be 0x%08x)\n", i->magic, MEM_STRINGS_MAGIC ); } #endif /* \doc |mem_create_strings| creates a memory object for storing strings. */ mem_String mem_create_strings( void ) { stringInfo info = xmalloc( sizeof( struct stringInfo ) ); #if MAA_MAGIC info->magic = MEM_STRINGS_MAGIC; #endif info->count = 0; info->bytes = 0; info->obstack = xmalloc( sizeof( struct obstack ) ); obstack_init( info->obstack ); obstack_alignment_mask( info->obstack ) = 0; /* no alignment for chars */ return info; } /* \doc |mem_destroy_strings| destroys the memory object returned from |mem_create_strings|. All memory if freed, including that used for the strings. Therefore, any pointers to strings in the table will be left dangling. */ void mem_destroy_strings( mem_String info ) { stringInfo i = (stringInfo)info; _mem_magic_strings( i, __FUNCTION__ ); #if MAA_MAGIC i->magic = MEM_STRINGS_MAGIC_FREED; #endif obstack_free( i->obstack, NULL ); xfree( i->obstack ); /* terminal */ xfree( i ); /* terminal */ } /* \doc |mem_strcpy| copies a |string| into the memory object pointed to by |info|. */ const char *mem_strcpy( mem_String info, const char *string ) { stringInfo i = (stringInfo)info; int len = strlen( string ); _mem_magic_strings( i, __FUNCTION__ ); ++i->count; i->bytes += len + 1; return obstack_copy0( i->obstack, string, len ); } /* \doc |mem_strncpy| copies |len| bytes of |string| into the memory object pointed to by |info|. A null is added to the end of the copied sequence. */ const char *mem_strncpy( mem_String info, const char *string, int len ) { stringInfo i = (stringInfo)info; _mem_magic_strings( i, __FUNCTION__ ); ++i->count; i->bytes += len + 1; return obstack_copy0( i->obstack, string, len ); } /* \doc |mem_grow| copies |len| of |string| onto the top of the memory object pointed to by |info|. Several calls to |mem_grow| should be followed by a single call to |mem_finish| without any intervening calls to other functions which modify |info|. */ void mem_grow( mem_String info, const char *string, int len ) { stringInfo i = (stringInfo)info; _mem_magic_strings( i, __FUNCTION__ ); i->bytes += len; obstack_grow( i->obstack, string, len ); } /* \doc |mem_finish| finishes the growth of the object performed by |mem_grow|. */ const char *mem_finish( mem_String info ) { stringInfo i = (stringInfo)info; _mem_magic_strings( i, __FUNCTION__ ); ++i->count; i->bytes += 1; obstack_grow0( i->obstack, "", 0 ); return obstack_finish( i->obstack ); } /* \doc |mem_get_string_stats| returns statistics about the memory object pointed to by |info|. The |mem_StringStats| structure is shown in \grind{mem_StringStats}. */ mem_StringStats mem_get_string_stats( mem_String info ) { stringInfo i = (stringInfo)info; mem_StringStats s = xmalloc( sizeof( struct mem_StringStats ) ); _mem_magic_strings( i, __FUNCTION__ ); s->count = i->count; s->bytes = i->bytes; return s; } /* \doc |mem_print_string_stats| prints the statistics for the memory object pointed to by |info| on the specified |stream|. If |stream| is "NULL", then "stdout" will be used. */ void mem_print_string_stats( mem_String info, FILE *stream ) { FILE *str = stream ? stream : stdout; mem_StringStats s = mem_get_string_stats( info ); _mem_magic_strings( info, __FUNCTION__ ); fprintf( str, "Statistics for string memory manager at %p:\n", info ); fprintf( str, " %d strings, using %d bytes\n", s->count, s->bytes ); xfree( s ); /* rare */ } #if !MAA_MAGIC #define _mem_magic_objects(i,function) /* */ #else static void _mem_magic_objects( objectInfo i, const char *function ) { if (!i) err_internal( function, "mem_Object is null\n" ); if (i->magic != MEM_OBJECTS_MAGIC) err_internal( function, "Incorrect magic: 0x%08x (should be 0x%08x)\n", i->magic, MEM_OBJECTS_MAGIC ); } #endif /* \doc |mem_create_objects| creates a memory storage object for object of |size| bytes. */ mem_Object mem_create_objects( int size ) { objectInfo info = xmalloc( sizeof ( struct objectInfo ) ); #if MAA_MAGIC info->magic = MEM_OBJECTS_MAGIC; #endif info->total = 0; info->used = 0; info->reused = 0; info->size = size; info->stack = stk_create(); info->obstack = xmalloc( sizeof( struct obstack ) ); obstack_init( info->obstack ); return info; } /* \doc |mem_destroy_objects| destroys the memory object returned from |mem_create_objects|. All memory if freed, including that used for the object. Therefore, any pointers to objects stored by |info| will be left dangling. */ void mem_destroy_objects( mem_Object info ) { objectInfo i = (objectInfo)info; _mem_magic_objects( i, __FUNCTION__ ); #if MAA_MAGIC i->magic = MEM_OBJECTS_MAGIC_FREED; #endif stk_destroy( i->stack ); obstack_free( i->obstack, NULL ); xfree( i->obstack ); /* terminal */ xfree( i ); /* terminal */ } /* \doc |mem_get_object| returns a pointer to a block of memory which is |size| bytes long (as specified in the call to |mem_create_objects|). This block is either newly allocated memory, or is memory which was previously allocated by |mem_get_object| and subsequently freed by |mem_free_object|. */ void *mem_get_object( mem_Object info ) { objectInfo i = (objectInfo)info; void *obj = stk_pop( i->stack ); _mem_magic_objects( i, __FUNCTION__ ); if (!obj) { obj = obstack_alloc( i->obstack, i->size ); ++i->total; } else ++i->reused; ++i->used; return obj; } /* \doc |mem_get_empty_object| is exactly like |mem_get_object|, except the memory associated with the object is set to all zeros. */ void *mem_get_empty_object( mem_Object info ) { objectInfo i = (objectInfo)info; void *obj = mem_get_object( info ); memset( obj, 0, i->size ); return obj; } /* \doc |mem_free_object| ``frees'' the object, |obj|, which was previously obtained from |mem_get_object|. The memory associated with the object is not actually freed, but the object pointer is stored on a stack, and is available for subsequent calls to |mem_get_object|. */ void mem_free_object( mem_Object info, void *obj ) { objectInfo i = (objectInfo)info; _mem_magic_objects( i, __FUNCTION__ ); stk_push( i->stack, obj ); --i->used; } /* \doc |mem_get_object_stats| returns statistics about the memory object pointed to by |info|. The |mem_ObjectStats| structure is shown in \grind{mem_ObjectStats}. */ mem_ObjectStats mem_get_object_stats( mem_Object info ) { objectInfo i = (objectInfo)info; mem_ObjectStats s = xmalloc( sizeof( struct mem_ObjectStats ) ); _mem_magic_objects( i, __FUNCTION__ ); if (info) { s->total = i->total; s->used = i->used; s->reused = i->reused; s->size = i->size; } else { s->total = 0; s->used = 0; s->reused = 0; s->size = 0; } return s; } /* \doc |mem_print_object_stats| prints the statistics for the memory object pointed to by |info| on the specified |stream|. If |stream| is "NULL", then "stdout" will be used. */ void mem_print_object_stats( mem_Object info, FILE *stream ) { FILE *str = stream ? stream : stdout; mem_ObjectStats s = mem_get_object_stats( info ); _mem_magic_objects( info, __FUNCTION__ ); fprintf( str, "Statistics for object memory manager at %p:\n", info ); fprintf( str, " %d objects allocated, of which %d are in use\n", s->total, s->used ); fprintf( str, " %d objects have been reused\n", s->reused ); xfree( s ); /* rare */ }