/* Copyright (C) Stephen Chung, 1991-1992. All rights reserved. */ #include #define MAGIC 0x42022667 typedef struct MemoryStruct { long int magic; void far *page; unsigned int size; BOOL allocated; struct MemoryStruct far *next, far *prev; } MEMHEADER; typedef struct PageHeaderStruct { long int magic; HANDLE handle; unsigned int size; unsigned int used; unsigned int overhead; MEMHEADER far *data, far *empty; struct PageHeaderStruct far *next, far *prev; } MEMPAGEHEADER; typedef struct { MEMPAGEHEADER far *pages; int nr_pages; } MAINMEMHEADER; #define PAGESIZE (4 * 1024) #define USEABLESIZE (PAGESIZE - sizeof(MEMPAGEHEADER) - sizeof(MEMHEADER)) static MAINMEMHEADER header = { NULL, 0 }; static MEMPAGEHEADER far *AddPage(unsigned int n) { void far *cp; MEMHEADER far *mp; MEMPAGEHEADER far *p; HANDLE handle = NULL; handle = GlobalAlloc(GHND, n); if (handle == NULL) { ErrorMessage("Out of memory: allocating %d bytes", n); return (NULL); } if (header.pages == NULL || header.nr_pages <= 0) { p = header.pages = (MEMPAGEHEADER far *) GlobalLock(handle); p->prev = NULL; } else { for (p = header.pages; p->next != NULL; p = p->next); p->next = (MEMPAGEHEADER far *) GlobalLock(handle); p->next->prev = p; p = p->next; } p->magic = MAGIC; p->handle = handle; p->next = NULL; p->size = n; p->used = 0; p->overhead = sizeof(MEMPAGEHEADER) + sizeof(MEMHEADER); cp = ((char far *) p) + sizeof(MEMPAGEHEADER); mp = (MEMHEADER far *) cp; p->data = p->empty = mp; mp->magic = 0L; mp->allocated = FALSE; mp->page = p; mp->size = p->size - p->overhead; mp->next = mp->prev = NULL; header.nr_pages++; return (p); } static void DeletePage (MEMPAGEHEADER far *p) { if (p->next == NULL && p->prev == NULL) { header.pages = NULL; header.nr_pages = 0; GlobalFree(GlobalUnlock(p->handle)); } else { if (p == header.pages) header.pages = p->next; header.nr_pages--; if (p->prev != NULL) p->prev->next = p->next; if (p->next != NULL) p->next->prev = p->prev; GlobalFree(GlobalUnlock(p->handle)); } } void far *SegHeapAlloc (unsigned int n) { MEMPAGEHEADER far *p; MEMHEADER far *mp; char far *cp; if (n >= 65535) { ErrorMessage("MyGlobalAlloc: size (%u) > 64K!", n); return (NULL); } /* Larger than page size? */ if (n > USEABLESIZE) { p = AddPage(n + sizeof(MEMPAGEHEADER) + sizeof(MEMHEADER)); mp = p->data; mp->magic = MAGIC; mp->allocated = TRUE; p->used = n; p->empty = NULL; cp = ((char far *) mp) + sizeof(MEMHEADER); return ((void far *) cp); } /* Search for the hole */ for (p = header.pages; p != NULL; p = p->next) { /* Scan the chains */ if (p->size - p->used - p->overhead <= 0) continue; if (p->empty == NULL) continue; for (mp = p->empty; mp != NULL; mp = mp->next) { if (!mp->allocated && mp->size >= n) break; } if (mp != NULL) break; } /* New page needed? */ if (p == NULL) { p = AddPage(PAGESIZE); mp = p->data; } /* Do we need to break it up? */ if (mp->size - n > sizeof(MEMHEADER)) { MEMHEADER far *mp2; cp = ((char far *) mp) + n + sizeof(MEMHEADER); mp2 = (MEMHEADER far *) cp; mp2->magic = 0L; mp2->allocated = FALSE; mp2->page = p; mp2->size = mp->size - n - sizeof(MEMHEADER); mp2->next = mp->next; mp2->prev = mp; if (mp->next != NULL) mp->next->prev = mp2; mp->next = mp2; p->overhead += sizeof(MEMHEADER); mp->size = n; } mp->magic = MAGIC; mp->allocated = TRUE; p->used += n; cp = ((char far *) mp) + sizeof(MEMHEADER); /* Search for the next empty hole */ for (; mp != NULL; mp = mp->next) { if (!mp->allocated && mp->size > 0) break; } p->empty = mp; return ((void far *) cp); } void SegHeapFree (void far *vp) { MEMPAGEHEADER far *p; MEMHEADER far *mp, far *mp2; char far *cp; cp = ((char far *) vp) - sizeof(MEMHEADER); mp = (MEMHEADER far *) cp; if (mp->magic != MAGIC || !mp->allocated) { ErrorMessage("Trying to deallocate invalid memory block [%Fp, %u byte%s]!\n", vp, mp->size, (mp->size > 1) ? "s" : ""); return; } p = (MEMPAGEHEADER far *) mp->page; p->used -= mp->size; mp->magic = 0L; mp->allocated = FALSE; /* Merge? */ mp2 = mp->prev; if (mp2 != NULL && !mp2->allocated) { mp2->next = mp->next; if (mp->next != NULL) mp->next->prev = mp2; mp2->size += mp->size + sizeof(MEMHEADER); p->overhead -= sizeof(MEMHEADER); mp = mp2; } mp2 = mp->next; if (mp2 != NULL && !mp2->allocated) { mp->next = mp2->next; if (mp2->next != NULL) mp2->next->prev = mp; mp->size += mp2->size + sizeof(MEMHEADER); p->overhead -= sizeof(MEMHEADER); } if (mp->prev == NULL && mp->next == NULL) { DeletePage(p); } else { if (p->empty == NULL || mp < p->empty) p->empty = mp; } } void far *SegHeapRealloc (void far *p, unsigned int n) { MEMHEADER far *mp; char far *cp; /* Block already large enough? */ cp = ((char far *) p) - sizeof(MEMHEADER); mp = (MEMHEADER far *) cp; if (mp->magic != MAGIC) { ErrorMessage("Trying to reallocate invalid memory block [%Fp, %u byte%s]!\n", p, mp->size, (mp->size > 1) ? "s" : ""); return (p); } if (mp->size >= n) return (p); /* No need to do anything */ /* Else swap to another block */ cp = SegHeapAlloc(n); _fmemcpy(cp, p, (mp->size >= n) ? n : mp->size); SegHeapFree(p); /* This is not really safe SegHeapFree(p); cp = SegHeapAlloc(n); if ((void far *) cp != p) { _fmemcpy(cp, p, (mp->size >= n) ? n : mp->size); } */ return ((void far *) cp); } unsigned int SegHeapGetSize (void far *p) { MEMHEADER far *mp; char far *cp; cp = ((char far *) p) - sizeof(MEMHEADER); mp = (MEMHEADER far *) cp; if (mp->magic != MAGIC) { ErrorMessage("Trying to get size of invalid memory block [%Fp, %u byte%s]!\n", p, mp->size, (mp->size > 1) ? "s" : ""); return (0); } return (mp->size); } void far *SegHeapDuplicate (void far *p) { unsigned int len; void far *p1; len = SegHeapGetSize(p); p1 = SegHeapAlloc(len); _fmemcpy(p1, p, len); return (p1); } void MemoryStatistics (long int *allocated, long int *used, long int *overhead) { MEMPAGEHEADER far *p; *allocated = *used = *overhead = 0L; for (p = header.pages; p != NULL; p = p->next) { *allocated += p->size; *used += p->used; *overhead += p->overhead; } } void FreeAllMemory (void) { MEMPAGEHEADER far *p, far *p1; for (p = header.pages; p != NULL; ) { p1 = p->next; GlobalFree(GlobalUnlock(p->handle)); p = p1; } header.pages = NULL; header.nr_pages = 0; } #ifdef DEBUG /* For debugging purposes... not very pretty */ void PrintMemoryChains(void) { MEMPAGEHEADER far *p; MEMHEADER far *mp; char far *cp; char buffer[100]; /* Block already large enough? */ for (p = header.pages; p != NULL; p = p->next) { for (mp = p->data; mp != NULL; mp = mp->next) { sprintf(buffer, "%Fp | %u | %s", mp, mp->size, mp->allocated ? "Alloc" : "Free"); MessageBox (NULL, buffer, "Memory Chain", MB_ICONEXCLAMATION | MB_OK); } } } #endif DEBUG