398 lines
8.2 KiB
C
398 lines
8.2 KiB
C
/*******************************************************************
|
|
*
|
|
* ttmemory.c 1.2
|
|
*
|
|
* Memory management component (body).
|
|
*
|
|
* Copyright 1996-1999 by
|
|
* David Turner, Robert Wilhelm, and Werner Lemberg.
|
|
*
|
|
* This file is part of the FreeType project, and may only be used
|
|
* modified and distributed under the terms of the FreeType project
|
|
* license, LICENSE.TXT. By continuing to use, modify, or distribute
|
|
* this file you indicate that you have read the license and
|
|
* understand and accept it fully.
|
|
*
|
|
*
|
|
* Changes between 1.1 and 1.2:
|
|
*
|
|
* - the font pool is gone.
|
|
*
|
|
* - introduced the FREE macro and the Free function for
|
|
* future use in destructors.
|
|
*
|
|
* - Init_FontPool() is now a macro to allow the compilation of
|
|
* 'legacy' applications (all four test programs have been updated).
|
|
*
|
|
******************************************************************/
|
|
|
|
#include "ttdebug.h"
|
|
#include "ttmemory.h"
|
|
#include "ttengine.h"
|
|
|
|
/* required by the tracing mode */
|
|
#undef TT_COMPONENT
|
|
#define TT_COMPONENT trace_memory
|
|
|
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
#include <stdio.h>
|
|
|
|
#define MAX_TRACKED_BLOCKS 1024
|
|
|
|
struct TMemRec_
|
|
{
|
|
void* base;
|
|
Long size;
|
|
};
|
|
|
|
typedef struct TMemRec_ TMemRec;
|
|
|
|
static TMemRec pointers[MAX_TRACKED_BLOCKS + 1];
|
|
|
|
static Int num_alloc;
|
|
static Int num_free;
|
|
static Int num_realloc; /* counts only `real' reallocations
|
|
(i.e., an existing buffer will be resized
|
|
to a value larger than zero */
|
|
|
|
static Int fail_alloc;
|
|
static Int fail_realloc;
|
|
static Int fail_free;
|
|
|
|
#endif /* DEBUG_MEMORY */
|
|
|
|
|
|
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
|
|
Long TTMemory_Allocated;
|
|
Long TTMemory_MaxAllocated;
|
|
#endif
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TT_Alloc
|
|
*
|
|
* Description : Allocates memory from the heap buffer.
|
|
*
|
|
* Input : Size size of the memory to be allocated
|
|
* P pointer to a buffer pointer
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
* NOTE : The newly allocated block should _always_ be zeroed
|
|
* on return. Many parts of the engine rely on this to
|
|
* work properly.
|
|
*
|
|
******************************************************************/
|
|
|
|
EXPORT_FUNC
|
|
TT_Error TT_Alloc( ULong Size, void** P )
|
|
{
|
|
#ifdef DEBUG_MEMORY
|
|
Int i;
|
|
#endif
|
|
|
|
|
|
if ( !P )
|
|
return TT_Err_Invalid_Argument;
|
|
|
|
if ( Size > (size_t)-1 )
|
|
return TT_Err_Out_Of_Memory;
|
|
if ( Size > 0 )
|
|
{
|
|
*P = (void*)malloc( Size );
|
|
if ( !*P )
|
|
return TT_Err_Out_Of_Memory;
|
|
|
|
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
|
|
TTMemory_Allocated += Size;
|
|
TTMemory_MaxAllocated += Size;
|
|
#endif
|
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
num_alloc++;
|
|
|
|
i = 0;
|
|
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != NULL )
|
|
i++;
|
|
|
|
if ( i >= MAX_TRACKED_BLOCKS )
|
|
fail_alloc++;
|
|
else
|
|
{
|
|
pointers[i].base = *P;
|
|
pointers[i].size = Size;
|
|
}
|
|
|
|
#endif /* DEBUG_MEMORY */
|
|
|
|
MEM_Set( *P, 0, Size );
|
|
}
|
|
else
|
|
*P = NULL;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
#ifdef TT_CONFIG_OPTION_EXTEND_ENGINE
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TT_Realloc
|
|
*
|
|
* Description : Reallocates memory from the heap buffer.
|
|
*
|
|
* Input : Size new size of the memory to be allocated;
|
|
* if zero, TT_Free() will be called
|
|
* P pointer to a buffer pointer; if *P == NULL,
|
|
* TT_Alloc() will be called
|
|
*
|
|
* Output : Error code.
|
|
*
|
|
* NOTES : It's not necessary to zero the memory in case the
|
|
* reallocated buffer is larger than before -- the
|
|
* application has to take care of this.
|
|
*
|
|
* If the memory request fails, TT_Free() will be
|
|
* called on *P, and TT_Err_Out_Of_Memory returned.
|
|
*
|
|
******************************************************************/
|
|
|
|
EXPORT_FUNC
|
|
TT_Error TT_Realloc( ULong Size, void** P )
|
|
{
|
|
void* Q;
|
|
|
|
#ifdef DEBUG_MEMORY
|
|
Int i;
|
|
#endif
|
|
|
|
|
|
if ( !P )
|
|
return TT_Err_Invalid_Argument;
|
|
|
|
if ( !*P )
|
|
return TT_Alloc( Size, P );
|
|
|
|
if ( Size == 0 )
|
|
return TT_Free( P );
|
|
|
|
if ( Size > (size_t)-1 )
|
|
{
|
|
TT_Free( *P );
|
|
return TT_Err_Out_Of_Memory;
|
|
}
|
|
|
|
Q = (void*)realloc( *P, Size );
|
|
if ( !Q )
|
|
{
|
|
TT_Free( *P );
|
|
return TT_Err_Out_Of_Memory;
|
|
}
|
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
num_realloc++;
|
|
|
|
i = 0;
|
|
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
|
|
i++;
|
|
|
|
if ( i >= MAX_TRACKED_BLOCKS )
|
|
fail_realloc++;
|
|
else
|
|
{
|
|
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
|
|
TTMemory_Allocated += Size - pointers[i].size;
|
|
if ( Size > pointers[i].size )
|
|
TTMemory_MaxAllocated += Size - pointers[i].size;
|
|
#endif
|
|
|
|
pointers[i].base = Q;
|
|
pointers[i].size = size;
|
|
}
|
|
#endif /* DEBUG_MEMORY */
|
|
|
|
*P = Q;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
#endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TT_Free
|
|
*
|
|
* Description : Releases a previously allocated block of memory.
|
|
*
|
|
* Input : P pointer to memory block
|
|
*
|
|
* Output : Always SUCCESS.
|
|
*
|
|
* Note : The pointer must _always_ be set to NULL by this function.
|
|
*
|
|
******************************************************************/
|
|
|
|
EXPORT_FUNC
|
|
TT_Error TT_Free( void** P )
|
|
{
|
|
#ifdef DEBUG_MEMORY
|
|
Int i;
|
|
#endif /* DEBUG_MEMORY */
|
|
|
|
|
|
if ( !P || !*P )
|
|
return TT_Err_Ok;
|
|
|
|
#ifdef DEBUG_MEMORY
|
|
|
|
num_free++;
|
|
|
|
i = 0;
|
|
while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P )
|
|
i++;
|
|
|
|
if ( i >= MAX_TRACKED_BLOCKS )
|
|
fail_free++;
|
|
else
|
|
{
|
|
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
|
|
TTMemory_Allocated -= pointers[i].size;
|
|
#endif
|
|
|
|
pointers[i].base = NULL;
|
|
pointers[i].size = 0;
|
|
}
|
|
#endif /* DEBUG_MEMORY */
|
|
|
|
free( *P );
|
|
|
|
*P = NULL;
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TTMemory_Init
|
|
*
|
|
* Description : Initializes the memory.
|
|
*
|
|
* Output : Always SUCCESS.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error TTMemory_Init( void )
|
|
{
|
|
#ifdef DEBUG_MEMORY
|
|
Int i;
|
|
|
|
|
|
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
|
|
{
|
|
pointers[i].base = NULL;
|
|
pointers[i].size = 0;
|
|
}
|
|
|
|
num_alloc = 0;
|
|
num_realloc = 0;
|
|
num_free = 0;
|
|
|
|
fail_alloc = 0;
|
|
fail_realloc = 0;
|
|
fail_free = 0;
|
|
#endif
|
|
|
|
|
|
#ifndef TT_CONFIG_OPTION_THREAD_SAFE
|
|
TTMemory_Allocated = 0;
|
|
TTMemory_MaxAllocated = 0;
|
|
#endif
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
*
|
|
* Function : TTMemory_Done
|
|
*
|
|
* Description : Finalizes memory usage.
|
|
*
|
|
* Output : Always SUCCESS.
|
|
*
|
|
******************************************************************/
|
|
|
|
LOCAL_FUNC
|
|
TT_Error TTMemory_Done( void )
|
|
{
|
|
#ifdef DEBUG_MEMORY
|
|
Int i, num_leaked, tot_leaked;
|
|
|
|
|
|
num_leaked = 0;
|
|
tot_leaked = 0;
|
|
|
|
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
|
|
{
|
|
if ( pointers[i].base )
|
|
{
|
|
num_leaked ++;
|
|
tot_leaked += pointers[i].size;
|
|
}
|
|
}
|
|
|
|
fprintf( stderr,
|
|
"%d memory allocations, of which %d failed\n",
|
|
num_alloc,
|
|
fail_alloc );
|
|
|
|
fprintf( stderr,
|
|
"%d memory reallocations, of which %d failed\n",
|
|
num_realloc,
|
|
fail_realloc );
|
|
|
|
fprintf( stderr,
|
|
"%d memory frees, of which %d failed\n",
|
|
num_free,
|
|
fail_free );
|
|
|
|
if ( num_leaked > 0 )
|
|
{
|
|
fprintf( stderr,
|
|
"There are %d leaked memory blocks, totalizing %d bytes\n",
|
|
num_leaked, tot_leaked );
|
|
|
|
for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ )
|
|
{
|
|
if ( pointers[i].base )
|
|
{
|
|
fprintf( stderr,
|
|
"index: %4d (base: $%08lx, size: %08ld)\n",
|
|
i,
|
|
(long)pointers[i].base,
|
|
pointers[i].size );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
fprintf( stderr, "No memory leaks !\n" );
|
|
|
|
#endif /* DEBUG_MEMORY */
|
|
|
|
return TT_Err_Ok;
|
|
}
|
|
|
|
|
|
/* END */
|