home *** CD-ROM | disk | FTP | other *** search
- /*
- WINHEAP.C -- C heap functions for Windows:
- _amblksiz
- _fmalloc, _fcalloc, _fexpand, _frealloc, _ffree, _fmsize
- _nmalloc, _ncalloc, _nexpand, _nrealloc, _nfree, _nmsize
- _malloc, _calloc, _expand, _realloc, _free, _msize
-
- See also BASED.C
-
- Copyright (c) Andrew Schulman, 1990-1992.
- All Rights Reserved.
-
- Contact: Andrew Schulman (CompuServe 76320,302)
-
- From "Undocumented Windows" (Addison-Wesley 1992)
- by Andrew Schulman, Dave Maxey and Matt Pietrek
-
- NOTE: This is for Microsoft C only. Would require some
- tweaking to make work with Borland.
- */
-
- #include <windows.h>
- #include <memory.h>
- #include <stdlib.h>
- #ifdef __BORLANDC__
- #include "based.h"
- #else
- #include <malloc.h>
- #endif
- #include "winio.h"
-
- #ifdef __BORLANDC__
- void _ffree(void _far *fp);
- size_t _fmsize(void _far *memblock);
- void _nfree(void _near *memblock);
- size_t _nmsize(void _near *memblock);
- #endif
-
- #define MAKEP(seg,ofs) \
- ((void _far *)(((DWORD)(seg) << 16) | (unsigned) (ofs)))
-
- #define SELECTOROF(fp) ((WORD)(((DWORD)(fp)) >> 16))
-
- #define OFFSETOF(fp) ((WORD)(DWORD)(fp))
-
- #define MAX_SEL 1024 /* enough for 64 megabytes */
-
- typedef struct {
- WORD sel;
- WORD items;
- WORD capacity;
- } MEMHEAP;
-
- static MEMHEAP _near *memheap = 0;
- static int numheaps = 0;
-
- /* for stats */
- static unsigned long num_try_allocs = 0L;
- static unsigned long num_try_frees = 0L;
- static unsigned long num_fmalloc = 0L;
- static unsigned long num_frealloc = 0L;
- static unsigned long num_ffree = 0L;
- static unsigned long num_get_pheap_loops = 0L;
-
- static MEMHEAP _near *add_heap(void);
- static BOOL memheap_init(void);
- static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size);
- static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs);
- static MEMHEAP _near *get_pheap(unsigned sel);
-
- /**********************************************************************/
-
- unsigned _near _cdecl _amblksiz = 4096;
-
- void _far *_fmalloc(unsigned size)
- {
- void _far *ret;
- static MEMHEAP _near *pheap = 0;
- MEMHEAP _near *skip;
- int i;
-
- num_fmalloc++;
-
- if (! memheap) /* one-time initialization */
- if (! memheap_init())
- return NULL;
-
- /* special case for large (32k+) blocks */
- if (size > (WORD) (32 << 10))
- {
- HANDLE h;
- h = GlobalAlloc(GMEM_FIXED | GMEM_NODISCARD | GMEM_ZEROINIT, size);
- return h? GlobalLock(h) : NULL;
- }
-
- /* try most recently used pheap first: not surprisingly, this
- dramatically improves performance */
- if (! pheap) pheap = memheap;
- if ((ret = try_alloc(pheap, size)) != NULL)
- return ret;
- else
- skip = pheap; /* don't check this one again */
-
- /* try to find a heap from which to allocate block */
- for (i=numheaps, pheap=memheap; i--; pheap++)
- if (pheap != skip) /* don't retry one we tried already */
- if ((ret = try_alloc(pheap, size)) != NULL) /* first fit */
- return ret;
-
- /* still here: need to allocate a new heap and try once more */
- if ((pheap = add_heap()) != NULL)
- if ((ret = try_alloc(pheap, size)) != NULL)
- return ret;
-
- /* still here: memory totally exhausted */
- return NULL;
- }
-
- void _far *_fcalloc(unsigned num, unsigned size)
- {
- return _fmalloc(num * size);
- }
-
- void _far *_fexpand(void _far *memblock, size_t size)
- {
- NPSTR np;
- WORD old_size;
- WORD sel = SELECTOROF(memblock);
- WORD ofs = OFFSETOF(memblock);
-
- if (ofs == 0)
- {
- GlobalReAlloc(sel, GMEM_FIXED | GMEM_NODISCARD | GMEM_ZEROINIT, size);
- return memblock;
- }
-
- old_size = _bmsize(sel, ofs);
- if (np = (NPSTR) _bexpand(sel, ofs, size))
- {
- MEMHEAP _near *pheap = get_pheap(sel);
- pheap->capacity -= old_size;
- pheap->capacity += size;
- return MAKEP(sel, np);
- }
- else
- return NULL;
- }
-
- void _far *_frealloc(void _far *memblock, unsigned size)
- {
- void _far *fp;
-
- num_frealloc++;
-
- if (OFFSETOF(memblock) == 0)
- {
- WORD sel = SELECTOROF(memblock);
- HANDLE h;
- h = GlobalReAlloc(sel, GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_ZEROINIT,
- size);
- return h? GlobalLock(h) : NULL;
- }
-
- /* first try to expand the block in place */
- if ((fp = _fexpand(memblock, size)) != NULL)
- return fp;
- else if (fp = _fmalloc(size))
- {
- WORD old_size = _fmsize(memblock);
- _fmemcpy(fp, memblock, min(old_size, size));
- _ffree(memblock);
- return fp;
- }
- else
- return NULL;
- }
-
- void _ffree(void _far *fp)
- {
- WORD sel, ofs;
- MEMHEAP _near *pheap;
-
- num_ffree++;
-
- if (fp == NULL)
- return;
-
- sel = SELECTOROF(fp);
- ofs = OFFSETOF(fp);
-
- /* special case for (large) global blocks */
- if (ofs == 0)
- {
- GlobalUnlock(sel);
- GlobalFree(sel);
- return;
- }
-
- if ((pheap = get_pheap(sel)) != NULL)
- try_free(pheap, sel, ofs);
- }
-
- size_t _fmsize(void _far *memblock)
- {
- unsigned sel = SELECTOROF(memblock);
- unsigned ofs = OFFSETOF(memblock);
- return ofs? _bmsize(sel, ofs) : GlobalSize(sel);
- }
-
- /**********************************************************************/
-
- static BOOL memheap_init(void)
- {
- HANDLE h;
-
- h = LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, MAX_SEL * sizeof(MEMHEAP));
- if (h == NULL)
- return FALSE;
- if ((memheap = (MEMHEAP _near *) LocalLock(h)) == NULL)
- return FALSE;
- if (add_heap() == NULL)
- return FALSE;
- return TRUE;
- }
-
- static MEMHEAP _near *get_pheap(unsigned sel)
- {
- static MEMHEAP _near *pheap = (MEMHEAP _near *) 0;
- int i;
- if (! pheap)
- pheap = memheap;
- if (pheap->sel == sel)
- return pheap;
- num_get_pheap_loops++;
- for (i=numheaps, pheap=memheap; i--; pheap++)
- if (pheap->sel == sel)
- return pheap;
- /* still here */
- return NULL;
- }
-
- static MEMHEAP _near *add_heap(void)
- {
- WORD sel;
- MEMHEAP _near *pheap;
- int i;
-
- if ((sel = _bheapseg(_amblksiz)) == (WORD) -1)
- return NULL;
-
- /* find first free space in memheap array */
- for (i=0, pheap=memheap; i<numheaps; i++, pheap++)
- if (pheap->sel == 0)
- break;
- if (i==numheaps)
- numheaps++;
-
- pheap->sel = sel;
- pheap->items = 0;
- pheap->capacity = 0xFF00U; /* approximate */
-
- return pheap;
- }
-
- static void _far *try_alloc(MEMHEAP _near *pheap, unsigned size)
- {
- NPSTR np;
- num_try_allocs++;
- if (pheap->sel && (pheap->capacity >= size))
- if ((np = (NPSTR) _bmalloc(pheap->sel, size)) != NULL)
- {
- pheap->items++;
- pheap->capacity -= size;
- return MAKEP(pheap->sel, np);
- }
- return NULL;
- }
-
- static BOOL try_free(MEMHEAP _near *pheap, unsigned sel, unsigned ofs)
- {
- WORD size;
-
- num_try_frees++;
-
- if (pheap->sel != sel)
- return FALSE;
-
- size = _bmsize(sel, ofs);
- _bfree(sel, (NPSTR) ofs);
- pheap->capacity += size;
- pheap->items--;
- if (pheap->items == 0) // return empties to Windows
- {
- if (_bfreeseg(pheap->sel) == 0)
- {
- pheap->sel = 0;
- return TRUE;
- }
- else
- return FALSE;
- }
- return TRUE;
- }
-
- winheap_stats()
- {
- MEMHEAP _near *pheap;
- int i;
- unsigned num_live_heaps=0;
- for (i=numheaps, pheap=memheap; i--; pheap++)
- if (pheap->sel) num_live_heaps++;
-
- printf("Calls to _fmalloc: %lu\n", num_fmalloc);
- printf("Calls to _frealloc: %lu\n", num_frealloc);
- printf("Calls to _ffree: %lu\n", num_ffree);
- printf("Heaps: %u\n", num_live_heaps);
- printf("Freed heaps: %u\n", numheaps - num_live_heaps);
- printf("Calls to try_alloc: %lu\n", num_try_allocs);
- printf("Calls to try_free: %lu\n", num_try_frees);
- printf("Get heap loops: %lu\n", num_get_pheap_loops);
- }
-
- /**********************************************************************/
-
- /* 0 as first argument to _bxxxx functions: use default data seg */
-
- typedef void _near *NPTR;
-
- NPTR _nmalloc(size_t size) { return _bmalloc(0, size); }
-
- NPTR _ncalloc(unsigned num, unsigned size) { return _bcalloc(0, num, size); }
-
- NPTR _nexpand(NPTR blk, size_t size) { return _bexpand(0, blk, size); }
-
- NPTR _nrealloc(NPTR blk, size_t size) { return _brealloc(0, blk, size); }
-
- void _nfree(NPTR memblock) { return _bfree(0, memblock); }
-
- size_t _nmsize(NPTR memblock) { return _bmsize(0, memblock); }
-
- /**********************************************************************/
-
- #if defined(M_I86SM) || defined(M_I86MM)
- /* small or medium model */
- #define _FN(x) _n ## x
- #else
- /* large or compact model */
- #define _FN(x) _f ## x
- #endif
-
- void *malloc(size_t size) { return _FN(malloc(size)); }
-
- void *calloc(size_t num, size_t size) { return _FN(calloc(num, size)); }
-
- void *realloc(void *blk, size_t size) { return _FN(realloc(blk, size)); }
-
- void *_expand(void *blk, size_t size) { return _FN(expand(blk, size)); }
-
- void free(void *blk) { return _FN(free(blk)); }
-
- size_t _msize(void *blk) { return _FN(msize(blk)); }
-
-