1 /******************************************************************* 2 * 3 * hugemem.c 4 * 5 * Memory management component (body) 6 * for dealing with "huge" objects with 16-bit MS-DOS. 7 * 8 * Written by Dave Hoo and Antoine Leca. 9 * Copyright 1999 by Dave Hoo, Antoine Leca, 10 * David Turner, Robert Wilhelm, and Werner Lemberg. 11 * 12 * This file is part of the FreeType project, and may only be used 13 * modified and distributed under the terms of the FreeType project 14 * license, LICENSE.TXT. By continuing to use, modify, or distribute 15 * this file you indicate that you have read the license and 16 * understand and accept it fully. 17 * 18 ******************************************************************/ 19 20 #include <limits.h> 21 22 #include "ttdebug.h" 23 #include "ttmemory.h" 24 #include "ttengine.h" 25 26 #ifndef TT_HUGE_PTR 27 #error "This component needs TT_HUGE_PTR to be #defined." 28 #endif 29 30 /* ---- Microsoft C compilers support ------------------------------------ */ 31 32 #if defined( M_I86 ) || defined( _M_I86 ) 33 34 #include <malloc.h> 35 #define huge_alloc( size ) _halloc ( size, 1 ) 36 #define huge_free( block ) _hfree ( block ) 37 38 #endif /* Microsoft compilers */ 39 40 /* ---- Borland C compiler support --------------------------------------- */ 41 42 #ifdef __TURBOC__ 43 44 #include <alloc.h> 45 #define huge_alloc( size ) farmalloc ( size ) 46 #define huge_free( block ) farfree ( block ) 47 48 #endif 49 50 #if !defined( huge_alloc ) || !defined( huge_free ) 51 #error "Your compiler is not (yet) supported. Check the source file!" 52 #endif 53 54 #ifdef TT_CONFIG_OPTION_THREAD_SAFE 55 #error "This component needs static allocation and is not re-entrant." 56 #endif 57 58 /* required by the tracing mode */ 59 #undef TT_COMPONENT 60 #define TT_COMPONENT trace_memory 61 62 63 #ifdef DEBUG_MEMORY 64 65 #include <stdio.h> 66 67 #define MAX_TRACKED_BLOCKS 1024 68 69 struct TMemRec_ 70 { 71 void* base; 72 Long size; 73 }; 74 75 typedef struct TMemRec_ TMemRec; 76 77 static TMemRec pointers[MAX_TRACKED_BLOCKS + 1]; 78 79 static Int num_alloc; 80 static Int num_free; 81 static Int num_realloc; /* counts only `real' reallocations 82 (i.e., an existing buffer will be resized 83 to a value larger than zero */ 84 85 static Int fail_alloc; 86 static Int fail_realloc; 87 static Int fail_free; 88 89 #else 90 91 /* We need a tracing stack of the calls to big chunks of memory, */ 92 /* in order to call the matching version of free(). */ 93 94 #define MAX_TRACKED_BIGCHUNKS 16 95 96 struct TMemRec_ 97 { 98 void* base; 99 Long size; 100 }; 101 102 typedef struct TMemRec_ TMemRec; 103 104 static TMemRec pointers[MAX_TRACKED_BIGCHUNKS + 1]; 105 106 #endif /* DEBUG_MEMORY */ 107 108 109 #ifndef TT_CONFIG_OPTION_THREAD_SAFE 110 Long TTMemory_Allocated; 111 Long TTMemory_MaxAllocated; 112 #endif 113 114 115 /******************************************************************* 116 * 117 * Function : TT_Alloc 118 * 119 * Description : Allocates memory from the heap buffer. 120 * 121 * Input : Size size of the memory to be allocated 122 * P pointer to a buffer pointer 123 * 124 * Output : Error code. 125 * 126 * NOTE : The newly allocated block should _always_ be zeroed 127 * on return. Many parts of the engine rely on this to 128 * work properly. 129 * 130 ******************************************************************/ 131 132 EXPORT_FUNC TT_Alloc(ULong Size,void ** P)133 TT_Error TT_Alloc( ULong Size, void** P ) 134 { 135 Int i; 136 137 138 if ( !P ) 139 return TT_Err_Invalid_Argument; 140 /* Also see below for another case of "invalid argument". */ 141 142 if ( Size > 0 ) 143 { 144 if ( Size > ( UINT_MAX & ~0xFu ) ) 145 *P = (void*)huge_alloc( Size ); 146 else 147 *P = (void*)malloc( Size ); 148 if ( !*P ) 149 return TT_Err_Out_Of_Memory; 150 151 #ifndef TT_CONFIG_OPTION_THREAD_SAFE 152 TTMemory_Allocated += Size; 153 TTMemory_MaxAllocated += Size; 154 #endif 155 156 #ifdef DEBUG_MEMORY 157 158 num_alloc++; 159 160 i = 0; 161 while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != NULL ) 162 i++; 163 164 if ( i >= MAX_TRACKED_BLOCKS ) 165 fail_alloc++; 166 else 167 { 168 pointers[i].base = *P; 169 pointers[i].size = Size; 170 } 171 172 #else 173 174 if ( Size > ( UINT_MAX & ~0xFu ) ) 175 { 176 i = 0; 177 while ( i < MAX_TRACKED_BIGCHUNKS && pointers[i].base != NULL ) 178 i++; 179 180 if ( i >= MAX_TRACKED_BIGCHUNKS ) 181 /* We fail badly here. Increase MAX_TRACKED_BIGCHUNKS if needed. */ 182 return TT_Err_Invalid_Argument; 183 else 184 { 185 pointers[i].base = *P; 186 pointers[i].size = Size; 187 } 188 } 189 190 #endif /* DEBUG_MEMORY */ 191 192 if ( Size > ( UINT_MAX & ~0xFu ) ) 193 { 194 char TT_HUGE_PTR * p = (char TT_HUGE_PTR *) *P; 195 ULong left = (ULong)Size; 196 size_t toClear; 197 198 while ( left ) 199 { 200 toClear = (left > 0xFF00) ? 0xFF00 : left; 201 MEM_Set( p, 0, toClear ); 202 left -= (ULong) toClear; 203 p += toClear; 204 } 205 } 206 else 207 MEM_Set( *P, 0, Size ); 208 } 209 else 210 *P = NULL; 211 212 return TT_Err_Ok; 213 } 214 215 216 #ifdef TT_CONFIG_OPTION_EXTEND_ENGINE 217 218 219 /******************************************************************* 220 * 221 * Function : TT_Realloc 222 * 223 * Description : Reallocates memory from the heap buffer. 224 * 225 * Input : Size new size of the memory to be allocated; 226 * if zero, TT_Free() will be called 227 * P pointer to a buffer pointer; if *P == NULL, 228 * TT_Alloc() will be called 229 * 230 * Output : Error code. 231 * 232 * NOTES : It's not necessary to zero the memory in case the 233 * reallocated buffer is larger than before -- the 234 * application has to take care of this. 235 * 236 * If the memory request fails, TT_Free() will be 237 * called on *P, and TT_Err_Out_Of_Memory returned. 238 * 239 ******************************************************************/ 240 241 EXPORT_FUNC TT_Realloc(ULong Size,void ** P)242 TT_Error TT_Realloc( ULong Size, void** P ) 243 { 244 void* Q; 245 246 #ifdef DEBUG_MEMORY 247 Int i; 248 #endif 249 250 251 if ( !P ) 252 return TT_Err_Invalid_Argument; 253 254 if ( !*P ) 255 return TT_Alloc( Size, P ); 256 257 if ( Size == 0 ) 258 return TT_Free( P ); 259 260 if ( Size > ( UINT_MAX & ~0xFu ) ) 261 Q = NULL; /* Do not even try to deal with big chunks of memory. */ 262 else 263 Q = (void*)realloc( *P, Size ); 264 if ( !Q ) 265 { 266 TT_Free( *P ); 267 return TT_Err_Out_Of_Memory; 268 } 269 270 #ifdef DEBUG_MEMORY 271 272 num_realloc++; 273 274 i = 0; 275 while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P ) 276 i++; 277 278 if ( i >= MAX_TRACKED_BLOCKS ) 279 fail_realloc++; 280 else 281 { 282 #ifndef TT_CONFIG_OPTION_THREAD_SAFE 283 TTMemory_Allocated += Size - pointers[i].size; 284 if ( Size > pointers[i].size ) 285 TTMemory_MaxAllocated += Size - pointers[i].size; 286 #endif 287 288 pointers[i].base = Q; 289 pointers[i].size = Size; 290 } 291 #endif /* DEBUG_MEMORY */ 292 293 *P = Q; 294 295 return TT_Err_Ok; 296 } 297 298 299 #endif /* TT_CONFIG_OPTION_EXTEND_ENGINE */ 300 301 302 /******************************************************************* 303 * 304 * Function : TT_Free 305 * 306 * Description : Releases a previously allocated block of memory. 307 * 308 * Input : P pointer to memory block 309 * 310 * Output : Always SUCCESS. 311 * 312 * Note : The pointer must _always_ be set to NULL by this function. 313 * 314 ******************************************************************/ 315 316 EXPORT_FUNC TT_Free(void ** P)317 TT_Error TT_Free( void** P ) 318 { 319 Int i; 320 Long Size = 0; 321 322 323 if ( !P || !*P ) 324 return TT_Err_Ok; 325 326 #ifdef DEBUG_MEMORY 327 328 num_free++; 329 330 i = 0; 331 while ( i < MAX_TRACKED_BLOCKS && pointers[i].base != *P ) 332 i++; 333 334 if ( i >= MAX_TRACKED_BLOCKS ) 335 fail_free++; 336 else 337 { 338 #ifndef TT_CONFIG_OPTION_THREAD_SAFE 339 TTMemory_Allocated -= pointers[i].size; 340 #endif 341 342 Size = pointers[i].size; 343 pointers[i].base = NULL; 344 pointers[i].size = 0; 345 } 346 347 #else 348 349 i = 0; 350 while ( i < MAX_TRACKED_BIGCHUNKS && pointers[i].base != *P ) 351 i++; 352 353 /* If we did not found the pointer, then this is a "small" chunk. */ 354 355 if ( i < MAX_TRACKED_BIGCHUNKS ) 356 { 357 Size = pointers[i].size; 358 pointers[i].base = NULL; 359 pointers[i].base = NULL; 360 } 361 362 #endif /* DEBUG_MEMORY */ 363 364 if ( Size > ( UINT_MAX & ~0xFu ) ) 365 huge_free( *P ); 366 else 367 free( *P ); 368 369 *P = NULL; 370 371 return TT_Err_Ok; 372 } 373 374 375 /******************************************************************* 376 * 377 * Function : TTMemory_Init 378 * 379 * Description : Initializes the memory. 380 * 381 * Output : Always SUCCESS. 382 * 383 ******************************************************************/ 384 385 LOCAL_FUNC TTMemory_Init(void)386 TT_Error TTMemory_Init( void ) 387 { 388 #ifdef DEBUG_MEMORY 389 Int i; 390 391 392 for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ ) 393 { 394 pointers[i].base = NULL; 395 pointers[i].size = 0; 396 } 397 398 num_alloc = 0; 399 num_realloc = 0; 400 num_free = 0; 401 402 fail_alloc = 0; 403 fail_realloc = 0; 404 fail_free = 0; 405 #else 406 Int i; 407 408 for ( i = 0; i < MAX_TRACKED_BIGCHUNKS; i++ ) 409 { 410 pointers[i].base = NULL; 411 pointers[i].size = 0; 412 } 413 #endif 414 415 416 #ifndef TT_CONFIG_OPTION_THREAD_SAFE 417 TTMemory_Allocated = 0; 418 TTMemory_MaxAllocated = 0; 419 #endif 420 421 return TT_Err_Ok; 422 } 423 424 425 /******************************************************************* 426 * 427 * Function : TTMemory_Done 428 * 429 * Description : Finalizes memory usage. 430 * 431 * Output : Always SUCCESS. 432 * 433 ******************************************************************/ 434 435 LOCAL_FUNC TTMemory_Done(void)436 TT_Error TTMemory_Done( void ) 437 { 438 #ifdef DEBUG_MEMORY 439 Int i, num_leaked, tot_leaked; 440 441 442 num_leaked = 0; 443 tot_leaked = 0; 444 445 for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ ) 446 { 447 if ( pointers[i].base ) 448 { 449 num_leaked ++; 450 tot_leaked += pointers[i].size; 451 } 452 } 453 454 fprintf( stderr, 455 "%d memory allocations, of which %d failed\n", 456 num_alloc, 457 fail_alloc ); 458 459 fprintf( stderr, 460 "%d memory reallocations, of which %d failed\n", 461 num_realloc, 462 fail_realloc ); 463 464 fprintf( stderr, 465 "%d memory frees, of which %d failed\n", 466 num_free, 467 fail_free ); 468 469 if ( num_leaked > 0 ) 470 { 471 fprintf( stderr, 472 "There are %d leaked memory blocks, totalizing %d bytes\n", 473 num_leaked, tot_leaked ); 474 475 for ( i = 0; i < MAX_TRACKED_BLOCKS; i++ ) 476 { 477 if ( pointers[i].base ) 478 { 479 fprintf( stderr, 480 "index: %4d (base: $%08lx, size: %08ld)\n", 481 i, 482 (long)pointers[i].base, 483 pointers[i].size ); 484 } 485 } 486 } 487 else 488 fprintf( stderr, "No memory leaks !\n" ); 489 490 #endif /* DEBUG_MEMORY */ 491 492 return TT_Err_Ok; 493 } 494 495 496 /* END */ 497