home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1996 February / PCWK0296.iso / sharewar / dos / program / gs300sr1 / gs300sr1.exe / GSMEMORY.C < prev    next >
C/C++ Source or Header  |  1994-07-27  |  9KB  |  304 lines

  1. /* Copyright (C) 1993, 1994 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gsmemory.c */
  20. /* Generic allocator support for Ghostscript library */
  21. #include "gx.h"
  22. #include "malloc_.h"
  23. #include "memory_.h"
  24. #include "gsrefct.h"        /* to check prototype */
  25. #include "gsstruct.h"        /* ditto */
  26.  
  27. /* Define the fill patterns for unallocated memory. */
  28. byte gs_alloc_fill_alloc = 0xa1;
  29. byte gs_alloc_fill_collected = 0xc1;
  30. byte gs_alloc_fill_free = 0xf1;
  31.  
  32. /* The 'structure' type descriptor for bytes. */
  33. gs_public_st_simple(st_bytes, byte, "bytes");
  34.  
  35. /* ------ Heap allocator ------ */
  36.  
  37. /*
  38.  * An implementation of Ghostscript's memory manager interface
  39.  * that works directly with the C heap.  We keep track of all allocated
  40.  * blocks so we can free them at cleanup time.
  41.  */
  42. private gs_memory_proc_alloc_bytes(gs_heap_alloc_bytes);
  43. private gs_memory_proc_alloc_struct(gs_heap_alloc_struct);
  44. private gs_memory_proc_alloc_byte_array(gs_heap_alloc_byte_array);
  45. private gs_memory_proc_alloc_struct_array(gs_heap_alloc_struct_array);
  46. private gs_memory_proc_object_size(gs_heap_object_size);
  47. private gs_memory_proc_object_type(gs_heap_object_type);
  48. private gs_memory_proc_free_object(gs_heap_free_object);
  49. private gs_memory_proc_alloc_string(gs_heap_alloc_string);
  50. private gs_memory_proc_resize_string(gs_heap_resize_string);
  51. private gs_memory_proc_free_string(gs_heap_free_string);
  52. private gs_memory_proc_register_root(gs_heap_register_root);
  53. private gs_memory_proc_unregister_root(gs_heap_unregister_root);
  54. private gs_memory_proc_status(gs_heap_status);
  55. gs_memory_t gs_memory_default = {
  56.     {    gs_heap_alloc_bytes,
  57.         gs_heap_alloc_struct,
  58.         gs_heap_alloc_byte_array,
  59.         gs_heap_alloc_struct_array,
  60.         gs_heap_object_size,
  61.         gs_heap_object_type,
  62.         gs_heap_free_object,
  63.         gs_heap_alloc_string,
  64.         gs_heap_resize_string,
  65.         gs_heap_free_string,
  66.         gs_heap_register_root,
  67.         gs_heap_unregister_root,
  68.         gs_heap_status
  69.     }
  70. };
  71. /* We must make sure that malloc_blocks leave the block aligned. */
  72. typedef struct malloc_block_s malloc_block;
  73. #define malloc_block_data\
  74.     malloc_block *next;\
  75.     uint size;\
  76.     gs_memory_type_ptr_t type;\
  77.     client_name_t cname
  78. struct malloc_block_data_s { malloc_block_data; };
  79. struct malloc_block_s {
  80.     malloc_block_data;
  81. /* ANSI C does not allow zero-size arrays, so we need the following */
  82. /* unnecessary and wasteful workaround: */
  83. #define _npad (-sizeof(struct malloc_block_data_s) & 7)
  84.     byte _pad[(_npad == 0 ? 8 : _npad)];    /* pad to double */
  85. #undef _npad
  86. };
  87.  
  88. private malloc_block *malloc_list;
  89. private long malloc_used;
  90.  
  91. /* Initialize the malloc heap. */
  92. private long heap_available(P0());
  93. void
  94. gs_malloc_init(void)
  95. {    malloc_list = 0;
  96.     malloc_used = 0;
  97. }
  98. /* Estimate the amount of available memory by probing with mallocs. */
  99. /* We may under-estimate by a lot, but that's better than winding up with */
  100. /* a seriously inflated address space. */
  101. /* This is quite a hack! */
  102. #define max_malloc_probes 20
  103. #define malloc_probe_size 64000
  104. private long
  105. heap_available(void)
  106. {    long avail = 0;
  107.     void *probes[max_malloc_probes];
  108.     uint n;
  109.     for ( n = 0; n < max_malloc_probes; n++ )
  110.       { if ( (probes[n] = malloc(malloc_probe_size)) == 0 )
  111.           break;
  112.         avail += malloc_probe_size;
  113.       }
  114.     while ( n )
  115.       free(probes[--n]);
  116.     return avail;
  117. }
  118.  
  119. /* Allocate various kinds of blocks. */
  120. private byte *
  121. gs_heap_alloc_bytes(gs_memory_t *mem, uint size, client_name_t cname)
  122. {    byte *ptr;
  123.     const char *msg = "";
  124.     if ( size > max_uint - sizeof(malloc_block)
  125.        )
  126.        {    /* Can't represent the size in a uint! */
  127.         msg = "too large for size_t";
  128.         ptr = 0;
  129.        }
  130.     else
  131.        {    ptr = (byte *)malloc(size + sizeof(malloc_block));
  132.         if ( ptr == 0 )
  133.             msg = "failed";
  134.         else
  135.            {    malloc_block *bp = (malloc_block *)ptr;
  136.             bp->next = malloc_list;
  137.             bp->size = size;
  138.             bp->type = &st_bytes;
  139.             bp->cname = cname;
  140.             malloc_list = bp;
  141.             msg = "OK";
  142.             ptr = (byte *)(bp + 1);
  143.             if ( gs_alloc_debug )
  144.               { /* Clear the block in an attempt to track down */
  145.                 /* uninitialized data errors. */
  146.                 memset(ptr, gs_alloc_fill_alloc, size);
  147.               }
  148.             malloc_used += size + sizeof(malloc_block);
  149.            }
  150.        }
  151.     if ( gs_debug_c('a') || !*msg )
  152.         dprintf4("[a]gs_malloc(%s)(%u) = 0x%lx: %s\n",
  153.              client_name_string(cname),
  154.              size, (ulong)ptr, msg);
  155.     return ptr;
  156. }
  157. private void *
  158. gs_heap_alloc_struct(gs_memory_t *mem, gs_memory_type_ptr_t pstype,
  159.   client_name_t cname)
  160. {    void *ptr = gs_heap_alloc_bytes(mem, gs_struct_type_size(pstype), cname);
  161.     if ( ptr == 0 )
  162.       return 0;
  163.     ((malloc_block *)ptr)[-1].type = pstype;
  164.     return ptr;
  165. }
  166. private byte *
  167. gs_heap_alloc_byte_array(gs_memory_t *mem, uint num_elements, uint elt_size,
  168.   client_name_t cname)
  169. {    ulong lsize = (ulong)num_elements * elt_size;
  170.     if ( lsize != (uint)lsize )
  171.       return 0;
  172.     return gs_heap_alloc_bytes(mem, (uint)lsize, cname);
  173. }
  174. private void *
  175. gs_heap_alloc_struct_array(gs_memory_t *mem, uint num_elements,
  176.   gs_memory_type_ptr_t pstype, client_name_t cname)
  177. {    void *ptr = gs_heap_alloc_byte_array(mem, num_elements, gs_struct_type_size(pstype), cname);
  178.     if ( ptr == 0 )
  179.       return 0;
  180.     ((malloc_block *)ptr)[-1].type = pstype;
  181.     return ptr;
  182. }
  183. private uint
  184. gs_heap_object_size(gs_memory_t *mem, const void *ptr)
  185. {    return ((malloc_block *)ptr)[-1].size;
  186. }
  187. private gs_memory_type_ptr_t
  188. gs_heap_object_type(gs_memory_t *mem, const void *ptr)
  189. {    return ((malloc_block *)ptr)[-1].type;
  190. }
  191. private void
  192. gs_heap_free_object(gs_memory_t *mem, void *ptr, client_name_t cname)
  193. {    malloc_block *bp = malloc_list;
  194.     if_debug2('a', "[a]gs_free(%s)(0x%lx)\n",
  195.           client_name_string(cname), (ulong)ptr);
  196.     if ( ptr == 0 )
  197.         return;
  198.     if ( ptr == bp + 1 )
  199.       { malloc_list = bp->next;
  200.         malloc_used -= bp->size + sizeof(malloc_block);
  201.         if ( gs_alloc_debug )
  202.           memset((char *)(bp + 1), gs_alloc_fill_free, bp->size);
  203.         free(bp);
  204.       }
  205.     else
  206.       { malloc_block *np;
  207.         for ( ; (np = bp->next) != 0; bp = np )
  208.           { if ( ptr == np + 1 )
  209.           { bp->next = np->next;
  210.             malloc_used -= np->size + sizeof(malloc_block);
  211.             if ( gs_alloc_debug )
  212.               memset((char *)(np + 1), gs_alloc_fill_free, np->size);
  213.             free(np);
  214.             return;
  215.           }
  216.           }
  217.         lprintf2("%s: free 0x%lx not found!\n",
  218.              client_name_string(cname), (ulong)ptr);
  219.         free((char *)((malloc_block *)ptr - 1));
  220.       }
  221. }
  222. private byte *
  223. gs_heap_alloc_string(gs_memory_t *mem, uint nbytes, client_name_t cname)
  224. {    return gs_heap_alloc_bytes(mem, nbytes, cname);
  225. }
  226. private byte *
  227. gs_heap_resize_string(gs_memory_t *mem, byte *data, uint old_num, uint new_num,
  228.   client_name_t cname)
  229. {    byte *ptr = gs_heap_alloc_string(mem, new_num, cname);
  230.     if ( ptr == 0 )
  231.         return 0;
  232.     memcpy(ptr, data, min(old_num, new_num));
  233.     gs_heap_free_string(mem, data, old_num, cname);
  234.     return ptr;
  235. }
  236. private void
  237. gs_heap_free_string(gs_memory_t *mem, byte *data, uint nbytes,
  238.   client_name_t cname)
  239. {    /****** SHOULD CHECK SIZE IF DEBUGGING ******/
  240.     gs_heap_free_object(mem, (char *)data, cname);
  241. }
  242. private void
  243. gs_heap_register_root(gs_memory_t *mem, gs_gc_root_t *rp, gs_ptr_type_t ptype,
  244.   void **up, client_name_t cname)
  245. {
  246. }
  247. private void
  248. gs_heap_unregister_root(gs_memory_t *mem, gs_gc_root_t *rp,
  249.   client_name_t cname)
  250. {
  251. }
  252. private void
  253. gs_heap_status(gs_memory_t *mem, gs_memory_status_t *pstat)
  254. {    pstat->allocated = malloc_used + heap_available();
  255.     pstat->used = malloc_used;
  256. }
  257.  
  258. /* Release all malloc'ed blocks. */
  259. void
  260. gs_malloc_release(void)
  261. {    malloc_block *bp = malloc_list;
  262.     malloc_block *np;
  263.     for ( ; bp != 0; bp = np )
  264.        {    np = bp->next;
  265.         if ( gs_alloc_debug )
  266.           memset((char *)(bp + 1), gs_alloc_fill_free, bp->size);
  267.         free(bp);
  268.        }
  269.     malloc_list = 0;
  270.     malloc_used = 0;
  271. }
  272.  
  273. /* ------ Other memory management ------ */
  274.  
  275. /* No-op pointer enumeration procedure */
  276. gs_ptr_type_t
  277. gs_no_struct_enum_ptrs(void *vptr, uint size, uint index, void **pep)
  278. {    return 0;
  279. }
  280.  
  281. /* No-op pointer relocation procedure */
  282. void
  283. gs_no_struct_reloc_ptrs(void *vptr, uint size, gc_state_t *gcst)
  284. {
  285. }
  286.  
  287. /* Get the size of a structure from the descriptor. */
  288. uint
  289. gs_struct_type_size(gs_memory_type_ptr_t pstype)
  290. {    return pstype->ssize;
  291. }
  292.  
  293. /* Get the name of a structure from the descriptor. */
  294. struct_name_t
  295. gs_struct_type_name(gs_memory_type_ptr_t pstype)
  296. {    return pstype->sname;
  297. }
  298.  
  299. /* Normal freeing routine for reference-counted structures. */
  300. void
  301. rc_free_struct_only(gs_memory_t *mem, char *data, client_name_t cname)
  302. {    gs_free_object(mem, data, cname);
  303. }
  304.