| /**************************************************************/ |
| /* ********************************************************** */ |
| /* * * */ |
| /* * DYNAMIC MEMORY MANAGEMENT MODULE * */ |
| /* * * */ |
| /* * $Module: MEMORY * */ |
| /* * * */ |
| /* * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 * */ |
| /* * MPI fuer Informatik * */ |
| /* * * */ |
| /* * 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 of the License, * */ |
| /* * or (at your option) any later version. * */ |
| /* * * */ |
| /* * 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. * */ |
| /* * * */ |
| /* * 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 * */ |
| /* * * */ |
| /* * * */ |
| /* $Revision$ * */ |
| /* $State$ * */ |
| /* $Date$ * */ |
| /* $Author$ * */ |
| /* * * */ |
| /* * Contact: * */ |
| /* * Christoph Weidenbach * */ |
| /* * MPI fuer Informatik * */ |
| /* * Stuhlsatzenhausweg 85 * */ |
| /* * 66123 Saarbruecken * */ |
| /* * Email: weidenb@mpi-sb.mpg.de * */ |
| /* * Germany * */ |
| /* * * */ |
| /* ********************************************************** */ |
| /**************************************************************/ |
| |
| |
| /* $RCSfile$ */ |
| |
| |
| #ifndef _MEMORY_ |
| #define _MEMORY_ |
| |
| /**************************************************************/ |
| /* Includes */ |
| /**************************************************************/ |
| |
| #include "misc.h" |
| |
| /**************************************************************/ |
| /* Data structures and constants */ |
| /**************************************************************/ |
| |
| #ifndef memory__DYNMAXSIZE |
| #define memory__DYNMAXSIZE 1024 /* At most blocks of size memory__DYNMAXSIZE |
| bytes are administrated by the |
| module, larger requests are |
| directly mapped to system calls */ |
| #endif |
| |
| #ifndef memory__SHAREDPAGES |
| #define memory__SHAREDPAGES 1 /* Number of block sizes sharing an allocated |
| page. By setting memory__SHAREDPAGES to 4, |
| the module would administrate requests |
| for 1, 2, 3 and 4 bytes on the same set of |
| pages, requests for 5, 6, 7 and 8 on another |
| one, etc. By default every block size has |
| its own set of pages */ |
| #endif |
| |
| #ifndef memory__FREESHREDDER |
| #define memory__FREESHREDDER 'S' /* The decimal number 83, which can also be |
| read as 53 hexadecimal, or the character |
| 'S' in ASCII code */ |
| #endif |
| |
| #define memory__KILOBYTE 1024 |
| |
| #ifndef memory__DEFAULTPAGESIZE |
| #define memory__DEFAULTPAGESIZE (8 * memory__KILOBYTE) |
| /* Used to set the default size of a page. |
| If the default page size is too small to |
| contain two objects of size memory__DYNMAXSIZE |
| the default page size is automatically |
| increased by the function memory_Init */ |
| #endif |
| |
| #ifndef memory__UNLIMITED |
| #define memory__UNLIMITED (-1) |
| /* Used to set the maximal amount of memory |
| available for the memory module to |
| "unlimited" when calling memory_Init. */ |
| #endif |
| |
| typedef struct MEMORY_RESOURCEHELP { |
| POINTER free; /* pointer to the next free block in list */ |
| POINTER next; /* pointer to the next fresh block */ |
| POINTER page; /* pointer to head of page list */ |
| POINTER end_of_page; /* pointer to the end of current page */ |
| int total_size; /* total block size inc. debug marks */ |
| int aligned_size; /* block size without debug marks */ |
| int offset; /* offset of last usable block on page */ |
| } MEMORY_RESOURCE; |
| |
| extern MEMORY_RESOURCE * memory_ARRAY[]; |
| |
| #if defined(CHECK) |
| typedef struct MEMORY_INFOHELP { |
| const char * mallocInFile; /* origin of allocation request: file */ |
| const char * freeInFile; /* origin of deallocation request: file */ |
| unsigned short int mallocAtLine; /* origin of allocation request: line */ |
| unsigned short int freeAtLine; /* origin of deallocation request: line */ |
| } MEMORY_INFONODE, * MEMORY_INFO; |
| |
| #endif |
| |
| typedef struct MEMORY_BIGBLOCKHEADERHELP { |
| struct MEMORY_BIGBLOCKHEADERHELP * previous, * next; |
| } MEMORY_BIGBLOCKHEADERNODE, * MEMORY_BIGBLOCKHEADER; |
| |
| extern long memory_MAXMEM; |
| |
| extern unsigned long memory_NEWBYTES; |
| extern unsigned long memory_FREEDBYTES; |
| |
| extern const unsigned int memory_MAGICMALLOC; |
| extern const unsigned int memory_MAGICFREE; |
| |
| extern const unsigned int memory_ALIGN; |
| |
| extern MEMORY_BIGBLOCKHEADER memory_BIGBLOCKS; |
| |
| /**************************************************************/ |
| /* Debug Information */ |
| /**************************************************************/ |
| |
| extern unsigned int memory_MARKSIZE; |
| extern unsigned int memory_OFFSET; |
| |
| /**************************************************************/ |
| /* Check Functions */ |
| /**************************************************************/ |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| |
| #ifdef CHECK |
| void memory_CheckFree(POINTER Freepointer, unsigned int Size, unsigned int RealBlockSize, const char * File, unsigned short int Line); |
| #endif /* CHECK */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| /**************************************************************/ |
| /* Inline Functions */ |
| /**************************************************************/ |
| |
| |
| static __inline__ unsigned int memory_CalculateRealBlockSize(unsigned int |
| BlockSize) |
| /********************************************************** |
| INPUT : Size of a block of memory. |
| RETURNS: its real size. |
| SUMMARY: Calculates the size of a memory block, |
| including padding due to memory alignment and |
| page sharing |
| **********************************************************/ |
| { |
| unsigned int RealSize; |
| |
| RealSize = BlockSize; |
| |
| if (RealSize % memory__SHAREDPAGES) { |
| RealSize += memory__SHAREDPAGES - (RealSize % memory__SHAREDPAGES); |
| } |
| |
| if (RealSize % memory_ALIGN) { |
| RealSize += memory_ALIGN - (RealSize % memory_ALIGN); |
| } |
| |
| return RealSize; |
| |
| } |
| |
| static __inline__ unsigned int memory_LookupRealBlockSize(unsigned int |
| BlockSize) |
| /********************************************************** |
| INPUT : Size of a block of memory. |
| RETURNS: its real size. |
| SUMMARY: Returns the size of a memory block, |
| including padding due to memory alignment and |
| page sharing. |
| **********************************************************/ |
| { |
| |
| unsigned int RealSize; |
| |
| if (BlockSize < memory__DYNMAXSIZE) { |
| RealSize = memory_ARRAY[BlockSize]->aligned_size; |
| } |
| else { |
| RealSize = memory_CalculateRealBlockSize(BlockSize); |
| } |
| |
| return RealSize; |
| |
| } |
| |
| #ifdef CHECK |
| static __inline__ void memory_SetBlockStatusAndSize(POINTER Mem, |
| unsigned int Status, |
| unsigned int Size) |
| /********************************************************** |
| INPUT : a pointer to a block of memory, its status |
| (memory_MAGICMALLOC or memory_MAGICFREE), and |
| size. |
| RETURNS: None. |
| SUMMARY: Sets a status flag (memory_MAGICMALLOC or |
| memory_MAGICFREE) and block size. |
| **********************************************************/ |
| { |
| *((int *)Mem - 1) = Size; |
| *((int *)((char *)Mem + memory_LookupRealBlockSize(Size))) = Status; |
| } |
| |
| static __inline__ unsigned int memory_GetBlockSize(POINTER Mem) |
| /********************************************************** |
| INPUT : A pointer to a block of memory. |
| RETURNS: its size. |
| SUMMARY: Returns the size of a memory block. |
| **********************************************************/ |
| { |
| return *((int *)Mem - 1); |
| } |
| |
| static __inline__ unsigned int memory_GetRealBlockSize(POINTER Mem) |
| /********************************************************** |
| INPUT : A pointer to a block of memory. |
| RETURNS: its real size. |
| SUMMARY: Returns the real size of a memory block, |
| including padding bytes. |
| **********************************************************/ |
| { |
| return memory_LookupRealBlockSize(memory_GetBlockSize(Mem)); |
| } |
| |
| static __inline__ unsigned int memory_GetBlockStatus(POINTER Mem) |
| /********************************************************** |
| INPUT : A pointer to a block of memory. |
| RETURNS: its status. |
| SUMMARY: Returns the status of a memory block. |
| **********************************************************/ |
| { |
| unsigned int Size; |
| |
| Size = memory_GetBlockSize(Mem); |
| |
| return *((int *)((char *)Mem + memory_LookupRealBlockSize(Size))); |
| } |
| |
| static __inline__ void memory_SetInfo(MEMORY_INFO Info, |
| const char * MallocInFile, |
| unsigned short int MallocAtLine, |
| const char * FreeInFile, |
| unsigned short int FreeAtLine) |
| /********************************************************** |
| INPUT : a memory info structure, strings for files where |
| the block was allocated and freed, and short |
| integers for the corresponding lines. |
| RETURNS: None. |
| SUMMARY: Sets the debugging information for a memory block |
| **********************************************************/ |
| { |
| if (!Info) { |
| misc_StartErrorReport(); |
| misc_ErrorReport("\n In memory_SetInfo:"); |
| misc_ErrorReport("\n Memory Error. Info is a NULL pointer.\n"); |
| misc_FinishErrorReport(); |
| } |
| |
| Info->mallocAtLine = MallocAtLine; |
| Info->mallocInFile = MallocInFile; |
| Info->freeAtLine = FreeAtLine; |
| Info->freeInFile = FreeInFile; |
| } |
| #endif |
| |
| static __inline__ unsigned long memory_DemandedBytes(void) |
| /********************************************************** |
| INPUT : Nothing. |
| RETURNS: Maximum number of bytes allocated at the same |
| time by the module. |
| SUMMARY: Returns maximum number of allocated bytes at the |
| same time. |
| **********************************************************/ |
| { |
| return memory_NEWBYTES; |
| } |
| |
| |
| static __inline__ unsigned long memory_UsedBytes(void) |
| /********************************************************** |
| INPUT : Nothing. |
| RETURNS: Number of bytes currently in use by your program. |
| SUMMARY: Returns number of bytes currently allocated. |
| **********************************************************/ |
| { |
| return memory_NEWBYTES-memory_FREEDBYTES; |
| } |
| |
| #ifdef NO_MEMORY_MANAGEMENT |
| |
| static __inline__ void memory_Free(POINTER Freepointer, unsigned int Size) |
| { |
| free((char*)Freepointer); |
| } |
| |
| #else |
| |
| #ifdef CHECK |
| static __inline__ void memory_FreeIntern(POINTER Freepointer, |
| unsigned int Size, |
| const char * File, |
| unsigned short int Line) |
| #else |
| static __inline__ void memory_Free(POINTER Freepointer, unsigned int Size) |
| #endif |
| /********************************************************** |
| INPUT : Pointer to the block of memory to be freed, |
| and the block's size |
| RETURNS: Nothing. |
| SUMMARY: Frees a block of memory for reallocation. |
| This function performs correctness checks |
| in debugging mode. |
| **********************************************************/ |
| { |
| unsigned int RealBlockSize; /* block´s alignment correct size */ |
| |
| RealBlockSize = memory_LookupRealBlockSize(Size); |
| |
| #ifdef CHECK |
| memory_CheckFree(Freepointer, Size, RealBlockSize, File, Line); |
| #endif |
| |
| |
| /* Check if current block is a big block */ |
| if (Size >= memory__DYNMAXSIZE) { |
| /* if that´s true, remove it from the double linked big block list */ |
| MEMORY_BIGBLOCKHEADER BigBlockHeader; |
| |
| BigBlockHeader = |
| (MEMORY_BIGBLOCKHEADER) ((char *) Freepointer - memory_OFFSET |
| - sizeof(MEMORY_BIGBLOCKHEADERNODE)); |
| |
| /* Check if current big block is the first block in the list */ |
| if (BigBlockHeader->previous != NULL) { |
| /* if that´s not true, set previous block´s successor |
| to current block´s successor |
| */ |
| BigBlockHeader->previous->next = BigBlockHeader->next; |
| } |
| else { |
| /* otherwise set the first block in the big blocks list |
| to current block´s successor |
| */ |
| memory_BIGBLOCKS = BigBlockHeader->next; |
| } |
| |
| /* Check if current block is the last block in the list */ |
| if (BigBlockHeader->next != NULL) { |
| /* if that´s not true, set next block´ predecessor to |
| current block´s predecessor |
| */ |
| BigBlockHeader->next->previous = BigBlockHeader->previous; |
| } |
| |
| /* Adapt total number of freed bytes |
| and number of bytes available for allocation |
| accordingly |
| */ |
| memory_FREEDBYTES += RealBlockSize + memory_MARKSIZE + |
| sizeof(MEMORY_BIGBLOCKHEADERNODE); |
| |
| if (memory_MAXMEM >= 0) { |
| memory_MAXMEM += RealBlockSize + memory_MARKSIZE + |
| sizeof(MEMORY_BIGBLOCKHEADERNODE); |
| } |
| |
| /* pass the call though to free() with correct pointer value */ |
| #ifdef CHECK |
| free((char *)Freepointer - memory_OFFSET |
| - sizeof(MEMORY_BIGBLOCKHEADERNODE)); |
| #else |
| free((char*) Freepointer - sizeof(MEMORY_BIGBLOCKHEADERNODE)); |
| #endif |
| } |
| else { |
| /* current block is not a big block */ |
| /* Adapt number of allocated bytes |
| and the freed blocks list accordingly |
| */ |
| memory_FREEDBYTES += memory_ARRAY[Size]->total_size; |
| *(POINTER *)Freepointer = memory_ARRAY[Size]->free; |
| memory_ARRAY[Size]->free = Freepointer; |
| } |
| |
| } |
| |
| #endif |
| |
| /**************************************************************/ |
| /* Functions */ |
| /**************************************************************/ |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| |
| void memory_Init(long); |
| void memory_Restrict(long); |
| |
| void memory_Print(void); |
| void memory_FPrint(FILE*); |
| |
| void memory_PrintLeaks(void); |
| void memory_PrintDetailed(void); |
| void memory_PrintAllocatedBlocks(unsigned int Size); |
| void memory_PrintFreedBlocks(unsigned int Size); |
| void memory_PrintAllocatedBigBlocks(void); |
| |
| void memory_FreeAllMem(void); |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #if defined(CHECK) && !defined(NO_MEMORY_MANAGEMENT) |
| /* declare drop-in debug versions memory functions */ |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| POINTER memory_MallocIntern(unsigned int, const char *, unsigned short int); |
| POINTER memory_CallocIntern(unsigned int, |
| unsigned int, |
| const char *, |
| unsigned short int); |
| #ifdef __cplusplus |
| } |
| #endif |
| #define memory_Malloc(Size) memory_MallocIntern((Size), __FILE__, __LINE__) |
| #define memory_Calloc(Elements, Size) \ |
| memory_CallocIntern((Elements), (Size), __FILE__, __LINE__) |
| #define memory_Free(Pointer, Size) \ |
| memory_FreeIntern((Pointer), (Size), __FILE__, __LINE__) |
| #else |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| POINTER memory_Malloc(unsigned int); |
| POINTER memory_Calloc(unsigned int, unsigned int); |
| #ifdef __cplusplus |
| } |
| #endif |
| #endif |
| |
| #endif |