home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware 1 2 the Maxx
/
sw_1.zip
/
sw_1
/
WINDOWS
/
UTILS
/
MEWIN10S.ZIP
/
MSWMEM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-02-22
|
11KB
|
387 lines
/* The routines in this file provide memory allocation under the
Microsoft Windows environment on an IBM-PC or compatible computer.
Must be compiled with Borland C++ 2.0 or later version.
It should not be compiled if the WINDOW_MSWIN symbol is not set */
/* this module allocates memory by performing subsegment allocation from
a list of global segments. This technique is inspired by an article
by Paul Yao in Microsoft Systems Journal (January 1991) */
#pragma inline /* there is some assembler code in here... */
#include "estruct.h"
#include <stdio.h>
#include "eproto.h"
#include "edef.h"
#include "elang.h"
#include "mswin.h"
#if SUBALLOC
#ifdef malloc
#undef malloc
#endif
#ifdef free
#undef free
#endif
#ifdef realloc
#undef realloc
#endif
#define SEGHEADOFFSET 16 /* offset of the segment header (the first
16 bytes of a heap segment are reserved
for windows) */
#define HEAPOFFSET (SEGHEADOFFSET + sizeof(SEGHEADER))
#define HEAPOVH 0x400 /* estimated heap overhead */
#define MINSEGSIZE 0x1000L /* minimum segment allocation: 4K */
/* Data segment switching macroes. The wS argument MUST be a stack
variable */
#define SWITCH_DS(wS) asm {push ds; mov ax,wS; mov ds,ax;}
#define RESTORE_DS asm {pop ds;}
typedef struct SegHeader { /* segment header */
struct SegHeader *next; /* link to next segment header */
int alloc_count; /* number of allocated blocks */
} SEGHEADER;
static SEGHEADER SegList = {NULL, -1};/* list of segments (dummy header) */
static SEGHEADER *OptimumSeg = NULL;
static BOOL FarStorage = FALSE; /* validates the use of suballocation */
#if MEMTRACE
static unsigned char mtrx = 0;
static struct mtr_tag {
WORD m_func; /* ASCII signature of function */
union {
WORD m_wseg; /* segment selector */
void *m_block; /* block address */
SEGHEADER *m_segh; /* segment header */
} m_ptr;
WORD m_cnt; /* alloc count */
DWORD m_size; /* size of segment or block */
SEGHEADER *m_optimseg; /* value of OptimumSeg */
} mtr [256];
/* m_func values ... */
#define MTR_SUBALLOC 'SU'
#define MTR_MALLOC 'MA'
#define MTR_MALLOCSEG 'MS'
#define MTR_FREE 'FR'
#define MTR_FREESEG 'FS'
#define MTR_REALLOC 'RA'
#endif
/* SubAlloc: performs suballocation from a global segment */
/* ======== */
void * near SubAlloc (WORD wSeg, unsigned size)
/* wSeg is the global segment's selector */
{
HANDLE hBlock; /* better be a stack variable */
void *Block; /* better be a stack variable */
#if MEMTRACE
WORD RealSize = 0;/* better be a stack variable */
#endif
SWITCH_DS(wSeg)
hBlock = LocalAlloc (LMEM_FIXED | LMEM_NOCOMPACT, size);
/* no point attempting compaction: everything is FIXED
in this heap! */
if (hBlock) {
Block = (void*)(LPSTR)LocalLock (hBlock);
#if MEMTRACE
RealSize = LocalSize (hBlock);
#endif
}
RESTORE_DS
#if MEMTRACE
mtr[mtrx].m_func = MTR_SUBALLOC;
mtr[mtrx].m_ptr.m_block = hBlock ? Block : NULL;
mtr[mtrx].m_size = RealSize;
mtr[mtrx++].m_optimseg = OptimumSeg;
#endif
if (hBlock) return Block; /* success ! */
else return NULL; /* failure!! */
} /* SubAlloc */
/* malloc: allocates a chunk of memory */
/* ====== */
char * malloc (int size)
{
SEGHEADER *Seg; /* segment header pointer */
WORD wSeg; /* segment's selector, must be a stack variable */
BOOL NewSeg = FALSE; /* TRUE: a new segment has been allocated */
void *Block; /* obtained block's address */
#if MEMTRACE
mtr[mtrx].m_func = MTR_MALLOC;
mtr[mtrx].m_ptr.m_block = NULL;
mtr[mtrx].m_size = size;
mtr[mtrx++].m_optimseg = OptimumSeg;
#endif
if (size == 0) return NULL;
if (FarStorage == FALSE) { /* use the local heap */
HANDLE hMem;
if ((hMem = LocalAlloc (LMEM_FIXED, size)) != NULL) {
return (LPSTR)LocalLock (hMem);
}
else return NULL;
}
/*-Attempt to suballocate from last used segment */
if (OptimumSeg) {
wSeg = HIWORD(OptimumSeg);
#if MEMTRACE
mtr[mtrx].m_cnt = OptimumSeg->alloc_count;
#endif
Block = SubAlloc (wSeg, size);
if (Block != NULL) {
++(OptimumSeg->alloc_count);
return (char*)Block; /* quick success ! */
}
}
/*-Scan segment list, attempting to find one where suballocation is
possible */
Seg = &SegList;
for (;;) {
if (Seg->next == NULL) {
/*-initialize a new Segment and chain it on tail */
HANDLE hSeg;
DWORD SegSize;
SegSize = max (MINSEGSIZE, HEAPOVH + SEGHEADOFFSET +
sizeof(SEGHEADER) + (DWORD)size);
hSeg = GlobalAlloc (GMEM_MOVEABLE, SegSize);
if (hSeg == NULL) return (char*)NULL; /* segment allocation
failure */
SegSize = GlobalSize (hSeg);
wSeg = HIWORD(GlobalLock (hSeg));
LocalInit (wSeg, 0, SegSize - HEAPOFFSET);
GlobalUnlock (hSeg);
/* the segment remains locked once, due to LocalInit */
SWITCH_DS(wSeg)
LockData (0); /* this ensures the segment's selector will
never change */
/* note that allocating a GMEM_FIXED segment would have been
cleaner but, in Windows 3.0, such segments also end up
being page-locked */
RESTORE_DS
Seg->next = (SEGHEADER*)MAKELONG(SEGHEADOFFSET,wSeg);
Seg = Seg->next;
Seg->next = NULL;
Seg->alloc_count = 0;
NewSeg = TRUE;
#if MEMTRACE
mtr[mtrx].m_func = MTR_MALLOCSEG;
mtr[mtrx].m_ptr.m_segh = Seg;
mtr[mtrx].m_cnt = Seg->alloc_count;
mtr[mtrx].m_size = SegSize;
mtr[mtrx++].m_optimseg = OptimumSeg;
#endif
}
else {
Seg = Seg->next;
wSeg = HIWORD(Seg);
}
if (Seg == OptimumSeg) continue; /* skip this already tried
one */
/*-try to allocate space in that segment */
#if MEMTRACE
mtr[mtrx].m_cnt = Seg->alloc_count;
#endif
Block = SubAlloc (wSeg, size);
if (Block != NULL) ++(Seg->alloc_count);
if ((Block != NULL) || NewSeg) {
OptimumSeg = Seg; /* next malloc will try this segment
first */
return (char*)Block;
}
}
} /* malloc */
/* free: frees an allocated block */
/* ===== */
void free (char *block)
{
HANDLE hSeg;
WORD wSeg;
SEGHEADER *Seg;
HANDLE hBlock;
#if MEMTRACE
WORD RealSize = 0;
#endif
if (FarStorage == FALSE) { /* use the local heap */
HANDLE hMem;
hMem = LocalHandle (LOWORD(block));
LocalUnlock (hMem);
LocalFree (hMem);
return;
}
wSeg = HIWORD((DWORD)block);
hSeg = LOWORD(GlobalHandle (wSeg));
SWITCH_DS(wSeg)
LocalUnlock (hBlock = LocalHandle (LOWORD(block)));
#if MEMTRACE
RealSize = LocalSize (hBlock);
#endif
LocalFree (hBlock);
RESTORE_DS
Seg = (SEGHEADER *)(MAKELONG(SEGHEADOFFSET,HIWORD(block)));
#if MEMTRACE
mtr[mtrx].m_func = MTR_FREE;
mtr[mtrx].m_ptr.m_block = block;
mtr[mtrx].m_cnt = Seg->alloc_count;
mtr[mtrx].m_size = RealSize;
mtr[mtrx++].m_optimseg = OptimumSeg;
#endif
if (--(Seg->alloc_count) == 0) { /* this segment is no longer used!
Let's get rid of it */
SEGHEADER *sp;
if (Seg == OptimumSeg) OptimumSeg = NULL;
sp = &SegList;
while (sp->next != Seg) {
sp = sp->next;
if (sp == NULL) { /* this segment is not in the list!!! */
/* this should not happen, but you never know... */
static BOOL WarningDisplayed = FALSE;
if (!WarningDisplayed) {
MessageBox (hFrameWnd,
"Please shutdown EMACS as soon as possible",
"Corrupted memory",
MB_OK | MB_ICONSTOP);
}
WarningDisplayed = TRUE;
return;
}
}
sp->next = Seg->next; /* unlink the segment */
#if MEMTRACE
mtr[mtrx].m_func = MTR_FREESEG;
mtr[mtrx].m_ptr.m_segh = Seg;
mtr[mtrx].m_cnt = Seg->alloc_count;
mtr[mtrx].m_size = GlobalSize (hSeg);
mtr[mtrx++].m_optimseg = OptimumSeg;
#endif
SWITCH_DS(wSeg)
UnlockData (0);
RESTORE_DS
GlobalUnlock (hSeg);
GlobalFree (hSeg); /* and release it */
}
else { /* segment still in use */
OptimumSeg = Seg; /* next malloc will try this segment
first */
}
} /* free */
/* realloc: reallocates a chunk of memory (shrink or expand) */
/* ======== */
char * realloc (char *oldblock, int size)
{
HANDLE hBlock, hOldBlock;
char *Block;
WORD wSeg;
int OldSize;
#if MEMTRACE
WORD RealSize = 0;
#endif
if (oldblock == NULL) return malloc (size);
if (FarStorage == FALSE) { /* use the local heap */
HANDLE hMem;
hMem = LocalHandle (LOWORD(oldblock));
LocalUnlock (hMem);
if ((hMem = LocalReAlloc (hMem, LMEM_MOVEABLE, size)) != NULL) {
return (LPSTR)LocalLock (hMem);
}
else return NULL;
}
wSeg = HIWORD(oldblock);
SWITCH_DS(wSeg)
LocalUnlock (hOldBlock = LocalHandle (LOWORD(oldblock)));
OldSize = LocalSize (hOldBlock);
hBlock = LocalReAlloc (hOldBlock, size, LMEM_MOVEABLE | LMEM_NOCOMPACT);
if (hBlock) {
Block = (LPSTR)LocalLock (hBlock);
#if MEMTRACE
RealSize = LocalSize (hBlock);
#endif
}
else oldblock = LocalLock (hOldBlock);
RESTORE_DS
#if MEMTRACE
mtr[mtrx].m_func = MTR_REALLOC;
mtr[mtrx].m_ptr.m_block = hBlock ? Block : NULL;
mtr[mtrx].m_cnt = ((SEGHEADER *)(MAKELONG(SEGHEADOFFSET,wSeg)))->alloc_count;
mtr[mtrx].m_size = RealSize;
mtr[mtrx++].m_optimseg = OptimumSeg;
#endif
if (hBlock) return Block;
else { /* we have to malloc, possibly into another segment, and
copy the data over */
if ((Block = malloc (size)) != NULL) {
_fmemcpy (Block, oldblock, min(size, OldSize));
free (oldblock);
}
return Block;
}
} /* realloc */
#endif /* SUBALLOC */
/* InitializeFarStorage: start the suballocation mechanism */
/* ==================== */
void far pascal InitializeFarStorage (void)
{
#if SUBALLOC
FarStorage = TRUE;
#endif
} /* InitializeFarStorage */
/* JettisonFarStorage: Release all the global segments (quitting time) */
/* ================== */
void far pascal JettisonFarStorage (void)
{
#if SUBALLOC
SEGHEADER *sp;
HANDLE hSeg;
sp = SegList.next;
while (sp != NULL) {
hSeg = LOWORD(GlobalHandle (HIWORD((DWORD)sp)));
sp = sp->next;
GlobalUnlock (hSeg);
GlobalFree (hSeg);
}
FarStorage = FALSE;
#endif
} /* JettisonFarStorage */