1ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
2ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
3ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  ftdbgmem.c                                                             */
4ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
5ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*    Memory debugger (body).                                              */
6ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
7ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann/*  Copyright 2001-2015 by                                                 */
8ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  David Turner, Robert Wilhelm, and Werner Lemberg.                      */
9ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
10ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  This file is part of the FreeType project, and may only be used,       */
11ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  modified, and distributed under the terms of the FreeType project      */
12ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  license, LICENSE.TXT.  By continuing to use, modify, or distribute     */
13ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  this file you indicate that you have read the license and              */
14ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*  understand and accept it fully.                                        */
15ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/*                                                                         */
16ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/***************************************************************************/
17ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
18ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
19e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include <ft2build.h>
20e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_CONFIG_CONFIG_H
21e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_DEBUG_H
22e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_INTERNAL_MEMORY_H
23e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_SYSTEM_H
24e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_ERRORS_H
25e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_TYPES_H
26ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
27ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
28ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef FT_DEBUG_MEMORY
29ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
30ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define  KEEPALIVE /* `Keep alive' means that freed blocks aren't released
31ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    * to the heap.  This is useful to detect double-frees
32ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    * or weird heap corruption, but it uses large amounts of
33ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    * memory, however.
34ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    */
35ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
36e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov#include FT_CONFIG_STANDARD_LIBRARY_H
37ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
38ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  FT_BASE_DEF( const char* )  _ft_debug_file   = NULL;
39ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_BASE_DEF( long )         _ft_debug_lineno = 0;
40ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
41ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  extern void
42ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DumpMemory( FT_Memory  memory );
43ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
44ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
45ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct FT_MemSourceRec_*  FT_MemSource;
46ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct FT_MemNodeRec_*    FT_MemNode;
47ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct FT_MemTableRec_*   FT_MemTable;
48ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
49ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
50ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#define FT_MEM_VAL( addr )  ( (FT_PtrDist)(FT_Pointer)( addr ) )
51ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
52ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*
53ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  This structure holds statistics for a single allocation/release
54ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  site.  This is useful to know where memory operations happen the
55ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  most.
56ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   */
57ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  FT_MemSourceRec_
58ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
59ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char*   file_name;
60ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    long          line_no;
61ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
62ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       cur_blocks;   /* current number of allocated blocks */
63ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       max_blocks;   /* max. number of allocated blocks    */
64ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       all_blocks;   /* total number of blocks allocated   */
65ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
66ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       cur_size;     /* current cumulative allocated size */
67ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       max_size;     /* maximum cumulative allocated size */
68ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       all_size;     /* total cumulative allocated size   */
69ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
70ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       cur_max;      /* current maximum allocated size */
71ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
72ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32     hash;
73ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemSource  link;
74ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
75ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } FT_MemSourceRec;
76ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
77ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
78ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*
79ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann   *  We don't need a resizable array for the memory sources because
80ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  their number is pretty limited within FreeType.
81ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   */
82ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_MEM_SOURCE_BUCKETS  128
83ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
84ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*
85ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  This structure holds information related to a single allocated
86ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  memory block.  If KEEPALIVE is defined, blocks that are freed by
87ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  FreeType are never released to the system.  Instead, their `size'
88ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann   *  field is set to `-size'.  This is mainly useful to detect double
89ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann   *  frees, at the price of a large memory footprint during execution.
90ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   */
91ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  FT_MemNodeRec_
92ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
93ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*      address;
94ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       size;     /* < 0 if the block was freed */
95ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
96ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemSource  source;
97ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
98ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#ifdef KEEPALIVE
99ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char*   free_file_name;
100ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long       free_line_no;
101ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
102ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
103ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemNode    link;
104ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
105ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } FT_MemNodeRec;
106ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
107ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
108ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*
109ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  The global structure, containing compound statistics and all hash
110ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  tables.
111ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   */
112ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef struct  FT_MemTableRec_
113ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
114ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          size;
115ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          nodes;
116ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemNode*      buckets;
117ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
118ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          alloc_total;
119ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          alloc_current;
120ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          alloc_max;
121ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          alloc_count;
122ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
123ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Bool          bound_total;
124ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          alloc_total_max;
125ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
126ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Bool          bound_count;
127ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long          alloc_count_max;
128ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
129ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemSource     sources[FT_MEM_SOURCE_BUCKETS];
130ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
131ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Bool          keep_alive;
132ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
133ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory        memory;
134ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Pointer       memory_user;
135ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Alloc_Func    alloc;
136ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Free_Func     free;
137ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Realloc_Func  realloc;
138ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
139ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  } FT_MemTableRec;
140ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
141ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
142ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_MEM_SIZE_MIN  7
143ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#define FT_MEM_SIZE_MAX  13845163
144ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
145ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann#define FT_FILENAME( x )  ( (x) ? (x) : "unknown file" )
146ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
147ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
148ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /*
149ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  Prime numbers are ugly to handle.  It would be better to implement
150ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   *  L-Hashing, which is 10% faster and doesn't require divisions.
151ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov   */
152ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  static const FT_Int  ft_mem_primes[] =
153ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
154ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    7,
155ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    11,
156ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    19,
157ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    37,
158ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    73,
159ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    109,
160ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    163,
161ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    251,
162ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    367,
163ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    557,
164ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    823,
165ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1237,
166ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1861,
167ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2777,
168ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4177,
169ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    6247,
170ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    9371,
171ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    14057,
172ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    21089,
173ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    31627,
174ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    47431,
175ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    71143,
176ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    106721,
177ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    160073,
178ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    240101,
179ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    360163,
180ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    540217,
181ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    810343,
182ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1215497,
183ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    1823231,
184ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    2734867,
185ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    4102283,
186ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    6153409,
187ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    9230113,
188ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    13845163,
189ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  };
190ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
191ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
192ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  static FT_Long
193ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  ft_mem_closest_prime( FT_Long  num )
194ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
195ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    size_t  i;
196ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
197ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
198ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( i = 0;
199ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ )
200ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( ft_mem_primes[i] > num )
201ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return ft_mem_primes[i];
202ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
203ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return FT_MEM_SIZE_MAX;
204ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
205ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
206ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
207ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  static void
208ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_debug_panic( const char*  fmt,
209ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      ... )
210ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
211ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    va_list  ap;
212ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
213ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
214ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    printf( "FreeType.Debug: " );
215ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
216ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    va_start( ap, fmt );
217ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    vprintf( fmt, ap );
218ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    va_end( ap );
219ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
220ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    printf( "\n" );
221ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    exit( EXIT_FAILURE );
222ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
223ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
224ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
225ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_Pointer
226ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_alloc( FT_MemTable  table,
227ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Long      size )
228ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
229ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory   memory = table->memory;
230ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Pointer  block;
231ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
232ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
233ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memory->user = table->memory_user;
234ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    block = table->alloc( memory, size );
235ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memory->user = table;
236ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
237ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return block;
238ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
239ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
240ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
241ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
242ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_free( FT_MemTable  table,
243ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Pointer   block )
244ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
245ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Memory  memory = table->memory;
246ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
247ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
248ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memory->user = table->memory_user;
249ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->free( memory, block );
250ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    memory->user = table;
251ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
252ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
253ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
254ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
255ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_resize( FT_MemTable  table )
256ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
257ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long  new_size;
258ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
259ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
260ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    new_size = ft_mem_closest_prime( table->nodes );
261ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( new_size != table->size )
262ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
263ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemNode*  new_buckets;
264ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      FT_Long      i;
265ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
266ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
267ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      new_buckets = (FT_MemNode *)
268ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                      ft_mem_table_alloc(
269ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                        table,
270ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                        new_size * (FT_Long)sizeof ( FT_MemNode ) );
271ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( new_buckets == NULL )
272ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        return;
273ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
274ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ARRAY_ZERO( new_buckets, new_size );
275ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
276ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( i = 0; i < table->size; i++ )
277ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
278ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MemNode  node, next, *pnode;
279ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_PtrDist  hash;
280ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
281ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
282ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        node = table->buckets[i];
283ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        while ( node )
284ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
285ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          next  = node->link;
286ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann          hash  = FT_MEM_VAL( node->address ) % (FT_PtrDist)new_size;
287ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pnode = new_buckets + hash;
288ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
289ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node->link = pnode[0];
290ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          pnode[0]   = node;
291ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
292ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node = next;
293ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
294ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
295ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
296ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( table->buckets )
297ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ft_mem_table_free( table, table->buckets );
298ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
299ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table->buckets = new_buckets;
300ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table->size    = new_size;
301ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
302ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
303ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
304ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
305ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_MemTable
306ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_new( FT_Memory  memory )
307ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
308ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table;
309ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
310ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
311ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) );
312ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table == NULL )
313ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      goto Exit;
314ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
315ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_ZERO( table );
316ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
317ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->size  = FT_MEM_SIZE_MIN;
318ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->nodes = 0;
319ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
320ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->memory = memory;
321ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
322ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->memory_user = memory->user;
323ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
324ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->alloc   = memory->alloc;
325ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->realloc = memory->realloc;
326ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->free    = memory->free;
327ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
328ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->buckets = (FT_MemNode *)
329ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                       memory->alloc(
330ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                         memory,
331ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                         table->size * (FT_Long)sizeof ( FT_MemNode ) );
332ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table->buckets )
333ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_ARRAY_ZERO( table->buckets, table->size );
334ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
335ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
336ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      memory->free( memory, table );
337ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table = NULL;
338ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
339ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
340ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
341ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return table;
342ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
343ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
344ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
345ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
346ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_destroy( FT_MemTable  table )
347ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
348ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long  i;
349ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long  leak_count = 0;
350ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    FT_Long  leaks      = 0;
351ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
352ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
353ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_DumpMemory( table->memory );
354ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
355ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* remove all blocks from the table, revealing leaked ones */
356ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( i = 0; i < table->size; i++ )
357ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
358ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemNode  *pnode = table->buckets + i, next, node = *pnode;
359ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
360ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
361ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      while ( node )
362ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
363ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        next       = node->link;
364ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann        node->link = NULL;
365ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
366ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( node->size > 0 )
367ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
368ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          printf(
369ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "leaked memory block at address %p, size %8ld in (%s:%ld)\n",
370ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            node->address, node->size,
371ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_FILENAME( node->source->file_name ),
372ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            node->source->line_no );
373ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
374ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          leak_count++;
375ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          leaks += node->size;
376ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
377ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ft_mem_table_free( table, node->address );
378ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
379ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
380ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        node->address = NULL;
381ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        node->size    = 0;
382ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
383ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ft_mem_table_free( table, node );
384ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        node = next;
385ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
386ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      table->buckets[i] = NULL;
387ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
388ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
389ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ft_mem_table_free( table, table->buckets );
390ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->buckets = NULL;
391ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
392ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->size  = 0;
393ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->nodes = 0;
394ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
395ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* remove all sources */
396ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ )
397ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
398ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemSource  source, next;
399ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
400ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
401ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( source = table->sources[i]; source != NULL; source = next )
402ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
403ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        next = source->link;
404ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ft_mem_table_free( table, source );
405ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
406ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
407ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table->sources[i] = NULL;
408ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
409ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
410ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    printf( "FreeType: total memory allocations = %ld\n",
411ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            table->alloc_total );
412ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    printf( "FreeType: maximum memory footprint = %ld\n",
413ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            table->alloc_max );
414ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
415ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ft_mem_table_free( table, table );
416ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
417ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( leak_count > 0 )
418ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic(
419ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        "FreeType: %ld bytes of memory leaked in %ld blocks\n",
420ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        leaks, leak_count );
421ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
422ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    printf( "FreeType: no memory leaks detected\n" );
423ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
424ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
425ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
426ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_MemNode*
427ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_get_nodep( FT_MemTable  table,
428ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          FT_Byte*     address )
429ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
430ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_PtrDist   hash;
431ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemNode  *pnode, node;
432ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
433ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
434ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hash  = FT_MEM_VAL( address );
435ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    pnode = table->buckets + ( hash % (FT_PtrDist)table->size );
436ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
437ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for (;;)
438ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
439ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node = pnode[0];
440ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( !node )
441ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
442ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
443ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( node->address == address )
444ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
445ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
446ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      pnode = &node->link;
447ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
448ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return pnode;
449ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
450ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
451ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
452ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static FT_MemSource
453ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_get_source( FT_MemTable  table )
454ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
455ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_UInt32     hash;
456ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemSource  node, *pnode;
457ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
458ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
459ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* cast to FT_PtrDist first since void* can be larger */
460ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* than FT_UInt32 and GCC 4.1.1 emits a warning       */
461ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    hash  = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file +
462ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              (FT_UInt32)( 5 * _ft_debug_lineno );
463ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS];
464ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
465ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    for ( ;; )
466ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
467ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node = *pnode;
468ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( node == NULL )
469ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        break;
470ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
471ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( node->file_name == _ft_debug_file   &&
472ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann           node->line_no   == _ft_debug_lineno )
473ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        goto Exit;
474ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
475ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      pnode = &node->link;
476ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
477ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
478ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) );
479ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( node == NULL )
480ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic(
481ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        "not enough memory to perform memory debugging\n" );
482ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
483ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->file_name = _ft_debug_file;
484ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->line_no   = _ft_debug_lineno;
485ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
486ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->cur_blocks = 0;
487ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->max_blocks = 0;
488ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->all_blocks = 0;
489ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
490ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    node->cur_size = 0;
491ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    node->max_size = 0;
492ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    node->all_size = 0;
493ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
494ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    node->cur_max = 0;
495ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
496ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->link = NULL;
497ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node->hash = hash;
498ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    *pnode     = node;
499ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
500ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  Exit:
501ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return node;
502ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
503ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
504ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
505ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
506ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_set( FT_MemTable  table,
507ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Byte*     address,
508ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                    FT_Long      size,
509ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                    FT_Long      delta )
510ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
511ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemNode  *pnode, node;
512ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
513ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
514ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table )
515ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
516ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemSource  source;
517ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
518ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
519ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      pnode = ft_mem_table_get_nodep( table, address );
520ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node  = *pnode;
521ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( node )
522ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
523ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( node->size < 0 )
524ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
525ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* This block was already freed.  Our memory is now completely */
526ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* corrupted!                                                  */
527ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* This can only happen in keep-alive mode.                    */
528ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ft_mem_debug_panic(
529ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "memory heap corrupted (allocating freed block)" );
530ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
531ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
532ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
533ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* This block was already allocated.  This means that our memory */
534ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* is also corrupted!                                            */
535ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ft_mem_debug_panic(
536ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "memory heap corrupted (re-allocating allocated block at"
537ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            " %p, of size %ld)\n"
538ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "org=%s:%d new=%s:%d\n",
539ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            node->address, node->size,
540ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_FILENAME( node->source->file_name ), node->source->line_no,
541ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
542ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
543ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
544ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
545ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      /* we need to create a new node in this table */
546ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) );
547ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( node == NULL )
548ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ft_mem_debug_panic( "not enough memory to run memory tests" );
549ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
550ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node->address = address;
551ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node->size    = size;
552ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node->source  = source = ft_mem_table_get_source( table );
553ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
554ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( delta == 0 )
555ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
556ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* this is an allocation */
557ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        source->all_blocks++;
558ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        source->cur_blocks++;
559ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( source->cur_blocks > source->max_blocks )
560ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          source->max_blocks = source->cur_blocks;
561ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
562ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
563ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      if ( size > source->cur_max )
564ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        source->cur_max = size;
565ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
566ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( delta != 0 )
567ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
568ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* we are growing or shrinking a reallocated block */
569ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        source->cur_size     += delta;
570ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        table->alloc_current += delta;
571ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
572ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
573ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
574ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* we are allocating a new block */
575ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        source->cur_size     += size;
576ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        table->alloc_current += size;
577ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
578ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
579ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      source->all_size += size;
580ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
581ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( source->cur_size > source->max_size )
582ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        source->max_size = source->cur_size;
583ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
584ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node->free_file_name = NULL;
585ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node->free_line_no   = 0;
586ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
587ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node->link = pnode[0];
588ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
589ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      pnode[0] = node;
590ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table->nodes++;
591ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
592ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table->alloc_total += size;
593ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
594ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( table->alloc_current > table->alloc_max )
595ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        table->alloc_max = table->alloc_current;
596ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
597ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( table->nodes * 3 < table->size  ||
598ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov           table->size  * 3 < table->nodes )
599ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ft_mem_table_resize( table );
600ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
601ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
602ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
603ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
604ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static void
605ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_table_remove( FT_MemTable  table,
606ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_Byte*     address,
607ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                       FT_Long      delta )
608ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
609ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table )
610ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
611ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemNode  *pnode, node;
612ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
613ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
614ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      pnode = ft_mem_table_get_nodep( table, address );
615ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      node  = *pnode;
616ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( node )
617ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
618ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MemSource  source;
619ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
620ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
621ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( node->size < 0 )
622ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ft_mem_debug_panic(
623ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "freeing memory block at %p more than once at (%s:%ld)\n"
624ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            "block allocated at (%s:%ld) and released at (%s:%ld)",
625ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            address,
626ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_FILENAME( _ft_debug_file ), _ft_debug_lineno,
627ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_FILENAME( node->source->file_name ), node->source->line_no,
628ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            FT_FILENAME( node->free_file_name ), node->free_line_no );
629ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
630ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        /* scramble the node's content for additional safety */
631ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MEM_SET( address, 0xF3, node->size );
632ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
633ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( delta == 0 )
634ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
635ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          source = node->source;
636ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
637ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          source->cur_blocks--;
638ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          source->cur_size -= node->size;
639ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
640ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          table->alloc_current -= node->size;
641ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
642ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
643ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( table->keep_alive )
644ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
645ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* we simply invert the node's size to indicate that the node */
646ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          /* was freed.                                                 */
647ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node->size           = -node->size;
648ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node->free_file_name = _ft_debug_file;
649ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node->free_line_no   = _ft_debug_lineno;
650ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
651ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        else
652ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
653ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          table->nodes--;
654ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
655ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          *pnode = node->link;
656ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
657ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node->size   = 0;
658ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          node->source = NULL;
659ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
660ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          ft_mem_table_free( table, node );
661ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
662ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( table->nodes * 3 < table->size  ||
663ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov               table->size  * 3 < table->nodes )
664ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            ft_mem_table_resize( table );
665ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
666ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
667ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      else
668ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        ft_mem_debug_panic(
669ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          "trying to free unknown block at %p in (%s:%ld)\n",
670ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          address,
671ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_FILENAME( _ft_debug_file ), _ft_debug_lineno );
672ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
673ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
674ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
675ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
676ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  static FT_Pointer
677ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_debug_alloc( FT_Memory  memory,
678ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                      FT_Long    size )
679ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
680ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table = (FT_MemTable)memory->user;
681ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Byte*     block;
682ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
683ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
684ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( size <= 0 )
685ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic( "negative block size allocation (%ld)", size );
686ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
687ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return NULL if the maximum number of allocations was reached */
688ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table->bound_count                           &&
689ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         table->alloc_count >= table->alloc_count_max )
690ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
691ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
692ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return NULL if this allocation would overflow the maximum heap size */
693ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( table->bound_total                                   &&
694ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann         table->alloc_total_max - table->alloc_current > size )
695ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
696ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
697ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    block = (FT_Byte *)ft_mem_table_alloc( table, size );
698ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( block )
699ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
700ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      ft_mem_table_set( table, block, size, 0 );
701ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
702ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table->alloc_count++;
703ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
704ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
705ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _ft_debug_file   = "<unknown>";
706ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _ft_debug_lineno = 0;
707ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
708ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return (FT_Pointer)block;
709ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
710ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
711ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
712ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  static void
713ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_debug_free( FT_Memory   memory,
714ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                     FT_Pointer  block )
715ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
716ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table = (FT_MemTable)memory->user;
717ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
718ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
719ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( block == NULL )
720ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic( "trying to free NULL in (%s:%ld)",
721ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          FT_FILENAME( _ft_debug_file ),
722ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          _ft_debug_lineno );
723ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
724ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ft_mem_table_remove( table, (FT_Byte*)block, 0 );
725ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
726ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !table->keep_alive )
727ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_table_free( table, block );
728ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
729ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    table->alloc_count--;
730ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
731ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _ft_debug_file   = "<unknown>";
732ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _ft_debug_lineno = 0;
733ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
734ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
735ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
736ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann  static FT_Pointer
737ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_debug_realloc( FT_Memory   memory,
738ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_Long     cur_size,
739ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_Long     new_size,
740ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                        FT_Pointer  block )
741ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
742ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table = (FT_MemTable)memory->user;
743ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemNode   node, *pnode;
744ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Pointer   new_block;
745ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long      delta;
746ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
747ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    const char*  file_name = FT_FILENAME( _ft_debug_file );
748ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Long      line_no   = _ft_debug_lineno;
749ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
750ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
751ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* unlikely, but possible */
752ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( new_size == cur_size )
753ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return block;
754ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
755ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* the following is valid according to ANSI C */
756ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#if 0
757ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( block == NULL || cur_size == 0 )
758ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)",
759ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          file_name, line_no );
760ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif
761ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
762ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* while the following is allowed in ANSI C also, we abort since */
763ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* such case should be handled by FreeType.                      */
764ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( new_size <= 0 )
765ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic(
766ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)",
767ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        block, cur_size, file_name, line_no );
768ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
769ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* check `cur_size' value */
770ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block );
771ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    node  = *pnode;
772ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !node )
773ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic(
774ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        "trying to reallocate unknown block at %p in (%s:%ld)",
775ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        block, file_name, line_no );
776ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
777ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( node->size <= 0 )
778ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic(
779ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        "trying to reallocate freed block at %p in (%s:%ld)",
780ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        block, file_name, line_no );
781ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
782ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( node->size != cur_size )
783ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is "
784ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          "%ld instead of %ld in (%s:%ld)",
785ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                          block, cur_size, node->size, file_name, line_no );
786ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
787ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return NULL if the maximum number of allocations was reached */
788ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table->bound_count                           &&
789ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov         table->alloc_count >= table->alloc_count_max )
790ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
791ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
792ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    delta = new_size - cur_size;
793ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
794ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    /* return NULL if this allocation would overflow the maximum heap size */
795ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    if ( delta > 0                                             &&
796ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann         table->bound_total                                    &&
797ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann         table->alloc_current + delta > table->alloc_total_max )
798ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
799ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
800ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    new_block = (FT_Pointer)ft_mem_table_alloc( table, new_size );
801ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( new_block == NULL )
802ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return NULL;
803ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
804ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta );
805ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
806ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann    ft_memcpy( new_block, block, cur_size < new_size ? (size_t)cur_size
807ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                                                     : (size_t)new_size );
808ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
809ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    ft_mem_table_remove( table, (FT_Byte*)block, delta );
810ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
811ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _ft_debug_file   = "<unknown>";
812ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    _ft_debug_lineno = 0;
813ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
814ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( !table->keep_alive )
815ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_table_free( table, block );
816ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
817ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return new_block;
818ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
819ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
820ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
821ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  extern FT_Int
822ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_debug_init( FT_Memory  memory )
823ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
824ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table;
825ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_Int       result = 0;
826ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
827ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
828e6986e1e8d4a57987f47c215490cb080a65ee29aSvet Ganov    if ( getenv( "FT2_DEBUG_MEMORY" ) )
829ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
830ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      table = ft_mem_table_new( memory );
831ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      if ( table )
832ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
833ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        const char*  p;
834ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
835ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
836ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memory->user    = table;
837ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memory->alloc   = ft_mem_debug_alloc;
838ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memory->realloc = ft_mem_debug_realloc;
839ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        memory->free    = ft_mem_debug_free;
840ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
841ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p = getenv( "FT2_ALLOC_TOTAL_MAX" );
842ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( p != NULL )
843ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
844ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Long   total_max = ft_atol( p );
845ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
846ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
847ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( total_max > 0 )
848ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
849ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            table->bound_total     = 1;
850ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            table->alloc_total_max = total_max;
851ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
852ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
853ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
854ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p = getenv( "FT2_ALLOC_COUNT_MAX" );
855ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( p != NULL )
856ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
857ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Long  total_count = ft_atol( p );
858ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
859ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
860ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( total_count > 0 )
861ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          {
862ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            table->bound_count     = 1;
863ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann            table->alloc_count_max = total_count;
864ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          }
865ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
866ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
867ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        p = getenv( "FT2_KEEP_ALIVE" );
868ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        if ( p != NULL )
869ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        {
870ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          FT_Long  keep_alive = ft_atol( p );
871ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
872ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
873ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          if ( keep_alive > 0 )
874ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov            table->keep_alive = 1;
875ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        }
876ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
877ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        result = 1;
878ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
879ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
880ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    return result;
881ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
882ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
883ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
884ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  extern void
885ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_debug_done( FT_Memory  memory )
886ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
887ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table = (FT_MemTable)memory->user;
888ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
889ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
890ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table )
891ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
892ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      memory->free    = table->free;
893ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      memory->realloc = table->realloc;
894ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      memory->alloc   = table->alloc;
895ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
896ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_table_destroy( table );
897ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      memory->user = NULL;
898ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
899ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
900ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
901ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
902ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  static int
903ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  ft_mem_source_compare( const void*  p1,
904ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                         const void*  p2 )
905ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
906ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemSource  s1 = *(FT_MemSource*)p1;
907ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemSource  s2 = *(FT_MemSource*)p2;
908ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
909ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
910ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( s2->max_size > s1->max_size )
911ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 1;
912ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else if ( s2->max_size < s1->max_size )
913ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return -1;
914ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    else
915ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      return 0;
916ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
917ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
918ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
919ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  extern void
920ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  FT_DumpMemory( FT_Memory  memory )
921ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  {
922ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    FT_MemTable  table = (FT_MemTable)memory->user;
923ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
924ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
925ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    if ( table )
926ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    {
927ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemSource*  bucket = table->sources;
928ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemSource*  limit  = bucket + FT_MEM_SOURCE_BUCKETS;
929ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      FT_MemSource*  sources;
930ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      FT_Int         nn, count;
931ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      const char*    fmt;
932ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
933ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
934ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      count = 0;
935ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( ; bucket < limit; bucket++ )
936ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
937ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MemSource  source = *bucket;
938ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
939ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
940ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( ; source; source = source->link )
941ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          count++;
942ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
943ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
944ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      sources = (FT_MemSource*)
945ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                  ft_mem_table_alloc(
946ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                    table, count * (FT_Long)sizeof ( *sources ) );
947ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
948ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      count = 0;
949ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( bucket = table->sources; bucket < limit; bucket++ )
950ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
951ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MemSource  source = *bucket;
952ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
953ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
954ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        for ( ; source; source = source->link )
955ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov          sources[count++] = source;
956ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
957ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
958ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann      ft_qsort( sources,
959ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                (size_t)count,
960ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                sizeof ( *sources ),
961ac3d58cff7c80b0ef56bf55130d91da17cbaa3c4Philip P. Moltmann                ft_mem_source_compare );
962ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
963ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      printf( "FreeType Memory Dump: "
964ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              "current=%ld max=%ld total=%ld count=%ld\n",
965ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              table->alloc_current, table->alloc_max,
966ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov              table->alloc_total, table->alloc_count );
967ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      printf( " block  block    sizes    sizes    sizes   source\n" );
968ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      printf( " count   high      sum  highsum      max   location\n" );
969ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      printf( "-------------------------------------------------\n" );
970ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
971ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n";
972ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
973ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      for ( nn = 0; nn < count; nn++ )
974ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      {
975ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        FT_MemSource  source = sources[nn];
976ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
977ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
978ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov        printf( fmt,
979ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                source->cur_blocks, source->max_blocks,
980ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                source->cur_size, source->max_size, source->cur_max,
981ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                FT_FILENAME( source->file_name ),
982ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov                source->line_no );
983ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      }
984ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      printf( "------------------------------------------------\n" );
985ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
986ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov      ft_mem_table_free( table, sources );
987ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov    }
988ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  }
989ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
990ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#else  /* !FT_DEBUG_MEMORY */
991ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
992ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  /* ANSI C doesn't like empty source files */
993ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov  typedef int  _debug_mem_dummy;
994ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
995ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov#endif /* !FT_DEBUG_MEMORY */
996ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
997ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov
998ee451cb395940862dad63c85adfe8f2fd55e864cSvet Ganov/* END */
999