home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 10 / 10.iso / l / l430 / 1.ddi / SOURCE.ZIP / WINHEAP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-09  |  9.5 KB  |  363 lines

  1. /*
  2.     WINHEAP.C -- C heap functions for Windows:
  3.     _amblksiz
  4.     _fmalloc, _fcalloc, _fexpand, _frealloc, _ffree, _fmsize
  5.     _nmalloc, _ncalloc, _nexpand, _nrealloc, _nfree, _nmsize
  6.     _malloc,  _calloc,  _expand,  _realloc,  _free,  _msize
  7.         
  8.     See also BASED.C
  9.         
  10.     Copyright (c) Andrew Schulman, 1990-1992.
  11.     All Rights Reserved.
  12.         
  13.     Contact:  Andrew Schulman (CompuServe 76320,302)
  14.     
  15.     From "Undocumented Windows" (Addison-Wesley 1992)
  16.     by Andrew Schulman, Dave Maxey and Matt Pietrek
  17.         
  18.     NOTE:  This is for Microsoft C only.  Would require some
  19.     tweaking to make work with Borland.
  20. */
  21.  
  22. #include <windows.h>
  23. #include <memory.h>
  24. #include <stdlib.h>
  25. #ifdef __BORLANDC__
  26. #include "based.h"
  27. #else
  28. #include <malloc.h>
  29. #endif
  30. #include "winio.h"
  31.  
  32. #ifdef __BORLANDC__
  33. void _ffree(void _far *fp);
  34. size_t _fmsize(void _far *memblock);
  35. void _nfree(void _near *memblock);
  36. size_t _nmsize(void _near *memblock);
  37. #endif
  38.  
  39. #define MAKEP(seg,ofs)  \
  40.     ((void _far *)(((DWORD)(seg) << 16) | (unsigned) (ofs)))
  41.  
  42. #define SELECTOROF(fp)      ((WORD)(((DWORD)(fp)) >> 16))
  43.  
  44. #define OFFSETOF(fp)        ((WORD)(DWORD)(fp))
  45.     
  46. #define MAX_SEL             1024    /* enough for 64 megabytes */
  47.  
  48. typedef struct {
  49.     WORD sel;
  50.     WORD items;
  51.     WORD capacity;
  52.     } MEMHEAP;
  53.     
  54. static MEMHEAP _near *memheap = 0;
  55. static int numheaps = 0;
  56.  
  57. /* for stats */
  58. static unsigned long num_try_allocs = 0L;
  59. static unsigned long num_try_frees = 0L;
  60. static unsigned long num_fmalloc = 0L;
  61. static unsigned long num_frealloc = 0L;
  62. static unsigned long num_ffree = 0L;
  63. static unsigned long num_get_pheap_loops = 0L;
  64.  
  65. static MEMHEAP _near *add_heap(void);
  66. static BOOL memheap_init(void);
  67. static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size);
  68. static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs);
  69. static MEMHEAP _near *get_pheap(unsigned sel);
  70.  
  71. /**********************************************************************/
  72.  
  73. unsigned _near _cdecl _amblksiz = 4096;
  74.  
  75. void _far *_fmalloc(unsigned size)
  76. {
  77.     void _far *ret;
  78.     static MEMHEAP _near *pheap = 0;
  79.     MEMHEAP _near *skip;
  80.     int i;
  81.     
  82.     num_fmalloc++;
  83.     
  84.     if (! memheap)     /* one-time initialization */
  85.         if (! memheap_init())
  86.             return NULL;
  87.         
  88.     /* special case for large (32k+) blocks */
  89.     if (size > (WORD) (32 << 10))
  90.     {
  91.         HANDLE h;
  92.         h = GlobalAlloc(GMEM_FIXED | GMEM_NODISCARD | GMEM_ZEROINIT, size);
  93.         return h? GlobalLock(h) : NULL;
  94.     }
  95.     
  96.     /* try most recently used pheap first: not surprisingly, this
  97.        dramatically improves performance */
  98.     if (! pheap) pheap = memheap;
  99.     if ((ret = try_alloc(pheap, size)) != NULL)
  100.         return ret;
  101.     else
  102.         skip = pheap;   /* don't check this one again */
  103.  
  104.     /* try to find a heap from which to allocate block */
  105.     for (i=numheaps, pheap=memheap; i--; pheap++)
  106.         if (pheap != skip)  /* don't retry one we tried already */
  107.             if ((ret = try_alloc(pheap, size)) != NULL)  /* first fit */
  108.                 return ret;
  109.         
  110.     /* still here: need to allocate a new heap and try once more */
  111.     if ((pheap = add_heap()) != NULL)
  112.         if ((ret = try_alloc(pheap, size)) != NULL)
  113.             return ret;
  114.  
  115.     /* still here: memory totally exhausted */
  116.     return NULL;
  117. }
  118.  
  119. void _far *_fcalloc(unsigned num, unsigned size)
  120. {
  121.     return _fmalloc(num * size);
  122. }
  123.  
  124. void _far *_fexpand(void _far *memblock, size_t size)
  125. {
  126.     NPSTR np;
  127.     WORD old_size;
  128.     WORD sel = SELECTOROF(memblock);
  129.     WORD ofs = OFFSETOF(memblock);
  130.     
  131.     if (ofs == 0)
  132.     {
  133.         GlobalReAlloc(sel, GMEM_FIXED | GMEM_NODISCARD | GMEM_ZEROINIT, size);
  134.         return memblock;
  135.     }
  136.     
  137.     old_size = _bmsize(sel, ofs);
  138.     if (np = (NPSTR) _bexpand(sel, ofs, size))
  139.     {
  140.         MEMHEAP _near *pheap = get_pheap(sel);
  141.         pheap->capacity -= old_size;
  142.         pheap->capacity += size;
  143.         return MAKEP(sel, np);
  144.     }
  145.     else
  146.         return NULL;
  147. }
  148.  
  149. void _far *_frealloc(void _far *memblock, unsigned size)
  150. {
  151.     void _far *fp;
  152.     
  153.     num_frealloc++;
  154.     
  155.     if (OFFSETOF(memblock) == 0)
  156.     {
  157.         WORD sel = SELECTOROF(memblock);
  158.         HANDLE h;
  159.         h = GlobalReAlloc(sel, GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT,
  160.             size);
  161.         return h? GlobalLock(h) : NULL;
  162.     }
  163.     
  164.     /* first try to expand the block in place */
  165.     if ((fp = _fexpand(memblock, size)) != NULL)
  166.         return fp;
  167.     else if (fp = _fmalloc(size))
  168.     {
  169.         WORD old_size = _fmsize(memblock);
  170.         _fmemcpy(fp, memblock, min(old_size, size));
  171.         _ffree(memblock);
  172.         return fp;
  173.     }
  174.     else
  175.         return NULL;
  176. }
  177.  
  178. void _ffree(void _far *fp)
  179. {
  180.     WORD sel, ofs;
  181.     MEMHEAP _near *pheap;
  182.     
  183.     num_ffree++;
  184.     
  185.     if (fp == NULL)
  186.         return;
  187.  
  188.     sel = SELECTOROF(fp);
  189.     ofs = OFFSETOF(fp);
  190.     
  191.     /* special case for (large) global blocks */
  192.     if (ofs == 0)
  193.     {
  194.         GlobalUnlock(sel);
  195.         GlobalFree(sel);
  196.         return;
  197.     }
  198.     
  199.     if ((pheap = get_pheap(sel)) != NULL)
  200.         try_free(pheap, sel, ofs);
  201. }
  202.  
  203. size_t _fmsize(void _far *memblock)
  204. {
  205.     unsigned sel = SELECTOROF(memblock);
  206.     unsigned ofs = OFFSETOF(memblock);
  207.     return ofs? _bmsize(sel, ofs) : GlobalSize(sel);
  208. }
  209.  
  210. /**********************************************************************/
  211.  
  212. static BOOL memheap_init(void)
  213. {
  214.     HANDLE h;
  215.     
  216.     h = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, MAX_SEL * sizeof(MEMHEAP));
  217.     if (h == NULL)
  218.         return FALSE;
  219.     if ((memheap = (MEMHEAP _near *) LocalLock(h)) == NULL)
  220.         return FALSE;
  221.     if (add_heap() == NULL)
  222.         return FALSE;
  223.     return TRUE;
  224. }
  225.  
  226. static MEMHEAP _near *get_pheap(unsigned sel)
  227. {
  228.     static MEMHEAP _near *pheap = (MEMHEAP _near *) 0;
  229.     int i;
  230.     if (! pheap) 
  231.         pheap = memheap;
  232.     if (pheap->sel == sel) 
  233.         return pheap;
  234.     num_get_pheap_loops++;
  235.     for (i=numheaps, pheap=memheap; i--; pheap++)
  236.         if (pheap->sel == sel)
  237.             return pheap;
  238.     /* still here */
  239.     return NULL;
  240. }
  241.     
  242. static MEMHEAP _near *add_heap(void)
  243. {
  244.     WORD sel;
  245.     MEMHEAP _near *pheap;
  246.     int i;
  247.     
  248.     if ((sel = _bheapseg(_amblksiz)) == (WORD) -1)
  249.         return NULL;
  250.     
  251.     /* find first free space in memheap array */
  252.     for (i=0, pheap=memheap; i<numheaps; i++, pheap++)
  253.         if (pheap->sel == 0)
  254.             break;
  255.     if (i==numheaps) 
  256.         numheaps++;
  257.         
  258.     pheap->sel = sel;
  259.     pheap->items = 0;
  260.     pheap->capacity = 0xFF00U;  /* approximate */
  261.     
  262.     return pheap;
  263. }
  264.  
  265. static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size)
  266. {
  267.     NPSTR np;
  268.     num_try_allocs++;
  269.     if (pheap->sel && (pheap->capacity >= size))
  270.         if ((np = (NPSTR) _bmalloc(pheap->sel, size)) != NULL)
  271.         {
  272.             pheap->items++;
  273.             pheap->capacity -= size;
  274.             return MAKEP(pheap->sel, np);
  275.         }
  276.     return NULL;
  277. }
  278.         
  279. static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs)
  280. {
  281.     WORD size;
  282.     
  283.     num_try_frees++;
  284.     
  285.     if (pheap->sel != sel)
  286.         return FALSE;
  287.  
  288.     size = _bmsize(sel, ofs);
  289.     _bfree(sel, (NPSTR) ofs);
  290.     pheap->capacity += size;
  291.     pheap->items--;
  292.     if (pheap->items == 0) // return empties to Windows
  293.     {
  294.         if (_bfreeseg(pheap->sel) == 0)
  295.         {
  296.             pheap->sel = 0;
  297.             return TRUE;
  298.         }
  299.         else
  300.             return FALSE;
  301.     }
  302.     return TRUE;
  303. }
  304.  
  305. winheap_stats()
  306. {
  307.     MEMHEAP _near *pheap;
  308.     int i;
  309.     unsigned num_live_heaps=0;
  310.     for (i=numheaps, pheap=memheap; i--; pheap++)
  311.         if (pheap->sel) num_live_heaps++;
  312.  
  313.     printf("Calls to _fmalloc: %lu\n", num_fmalloc);
  314.     printf("Calls to _frealloc: %lu\n", num_frealloc);
  315.     printf("Calls to _ffree: %lu\n", num_ffree);
  316.     printf("Heaps: %u\n", num_live_heaps);
  317.     printf("Freed heaps: %u\n", numheaps - num_live_heaps);
  318.     printf("Calls to try_alloc: %lu\n", num_try_allocs);
  319.     printf("Calls to try_free: %lu\n", num_try_frees);
  320.     printf("Get heap loops: %lu\n", num_get_pheap_loops);
  321. }
  322.  
  323. /**********************************************************************/
  324.  
  325. /* 0 as first argument to _bxxxx functions: use default data seg */
  326.  
  327. typedef void _near *NPTR;
  328.  
  329. NPTR _nmalloc(size_t size)                 { return _bmalloc(0, size); }
  330.  
  331. NPTR _ncalloc(unsigned num, unsigned size) { return _bcalloc(0, num, size); }
  332.  
  333. NPTR _nexpand(NPTR blk, size_t size)       { return _bexpand(0, blk, size); }
  334.  
  335. NPTR _nrealloc(NPTR blk, size_t size)      { return _brealloc(0, blk, size); }
  336.  
  337. void _nfree(NPTR memblock)                 { return _bfree(0, memblock); }
  338.  
  339. size_t _nmsize(NPTR memblock)              { return _bmsize(0, memblock); }
  340.  
  341. /**********************************************************************/
  342.  
  343. #if defined(M_I86SM) || defined(M_I86MM)    
  344. /* small or medium model */
  345. #define _FN(x)  _n ## x
  346. #else
  347. /* large or compact model */
  348. #define _FN(x)  _f ## x
  349. #endif
  350.  
  351. void *malloc(size_t size)             { return _FN(malloc(size)); }
  352.  
  353. void *calloc(size_t num, size_t size) { return _FN(calloc(num, size)); }
  354.  
  355. void *realloc(void *blk, size_t size) { return _FN(realloc(blk, size)); }
  356.  
  357. void *_expand(void *blk, size_t size) { return _FN(expand(blk, size)); }
  358.  
  359. void free(void *blk)                  { return _FN(free(blk)); }
  360.  
  361. size_t _msize(void *blk)              { return _FN(msize(blk)); }
  362.  
  363.