📄 memmgr.c
字号:
/*
========================================================================
DEVise Data Visualization Software
(c) Copyright 1992-1996
By the DEVise Development Group
Madison, Wisconsin
All Rights Reserved.
========================================================================
Under no circumstances is this software to be copied, distributed,
or altered in any way without prior permission from the DEVise
Development Group.
*/
/*
$Id: MemMgr.C,v 1.3 1996/12/13 22:59:39 jussi Exp $
$Log: MemMgr.C,v $
Revision 1.3 1996/12/13 22:59:39 jussi
Added missing return statement.
Revision 1.2 1996/12/13 21:34:38 jussi
Added checking of available semaphores and shared memory.
Revision 1.1 1996/12/03 20:28:48 jussi
Initial revision.
*/
#include <memory.h>
#include "MemMgr.h"
#include "Exit.h"
#define DEBUGLVL 0
MemMgr *MemMgr::_instance = 0;
MemMgr::MemMgr(int numPages, int pageSize, int &status) :
_numPages(numPages), _tableSize(numPages), _pageSize(pageSize)
{
_instance = this;
status = SetupSharedMemory();
if (status < 0)
status = SetupLocalMemory();
if (status >= 0)
status = Initialize();
}
int MemMgr::SetupSharedMemory()
{
if (SemaphoreV::numAvailable() < 2) {
fprintf(stderr,
"Unable to use shared memory. Using local memory instead.\n");
return -1;
}
// We need space for page and also address in _freePage
int size = _numPages * _pageSize
+ _tableSize * (sizeof(char *) + sizeof(int))
+ sizeof(CountStruct);
key_t _shmKey = SharedMemory::newKey();
int created = 0;
_shm = new SharedMemory(_shmKey, size, _buf, created);
if (!_shm || !_buf) {
fprintf(stderr, "Cannot create shared memory\n");
return -1;
}
if (!created)
printf("Warning: pre-existing shared memory initialized\n");
#if DEBUGLVL >= 1
printf("Created a %d-byte shared memory segment at 0x%p\n", size, _buf);
#endif
int status;
_sem = new SemaphoreV(Semaphore::newKey(), status, 1);
if (!_sem || status < 0) {
fprintf(stderr, "Cannot create semaphore\n");
delete _shm;
return -1;
}
_sem->setValue(1);
_free = new SemaphoreV(Semaphore::newKey(), status, 1);
if (!_free || status < 0) {
fprintf(stderr, "Cannot create semaphore\n");
delete _shm;
_sem->destroy();
delete _sem;
return -1;
}
_free->setValue(0);
return 0;
}
int MemMgr::SetupLocalMemory()
{
// Make sure we don't reference (deleted) shared memory structures
_shm = 0;
_sem = 0;
_free = 0;
// We need space for page and also address in _freePage
int size = _numPages * _pageSize
+ _tableSize * (sizeof(char *) + sizeof(int))
+ sizeof(CountStruct);
_buf = new char [size];
if (!_buf) {
fprintf(stderr, "Cannot allocate local memory\n");
return -1;
}
#if DEBUGLVL >= 1
printf("Created a %d-byte local memory buffer at 0x%p\n", size, _buf);
#endif
return 0;
}
int MemMgr::Initialize()
{
#if DEBUGLVL >= 1
printf("Initializing memory manager\n");
#endif
memset(_buf, 0, _numPages * _pageSize);
#if DEBUGLVL >= 1
printf("Creating free, cache, and buffer lists\n");
#endif
_freePage = (char **)(_buf + _numPages * _pageSize);
_freePageCount = (int *)(_freePage + _tableSize);
_count = (CountStruct *)(_freePageCount + _tableSize);
// Initially, there is one contiguous free memory area
_freePage[0] = _buf;
_freePageCount[0] = _numPages;
for(int i = 1; i < _tableSize; i++) {
_freePage[i] = 0;
_freePageCount[i] = 0;
}
_count->entries = 1;
_count->free = _numPages;
_count->cache = 0;
_count->buffer = 0;
_count->maxCache = _numPages;
_count->maxBuffer = _numPages;
return 0;
}
MemMgr::~MemMgr()
{
delete _shm;
if (_sem)
_sem->destroy();
delete _sem;
if (_free)
_free->destroy();
delete _free;
}
int MemMgr::SetMaxUsage(PageType type, int pages)
{
AcquireMutex();
if (type == Cache)
_count->maxCache = pages;
else
_count->maxBuffer = pages;
ReleaseMutex();
return 0;
}
int MemMgr::Allocate(PageType type, char *&buf, int &pages, Boolean block)
{
// Return immediately if no pages requested
if (pages <= 0)
return -1;
AcquireMutex();
// Return immediately if no free pages available in non-blocking mode,
// or if no pages of given type are available.
if (!block) {
if (!_count->free
|| (type == Cache && _count->cache >= _count->maxCache)
|| (type == Buffer && _count->buffer >= _count->maxBuffer)) {
ReleaseMutex();
return -1;
}
}
while (!_count->free) {
#if DEBUGLVL >= 5
printf("Out of free pages: %d cache, %d buffer\n",
_count->cache, _count->buffer);
#endif
ReleaseMutex();
AcquireFree();
AcquireMutex();
#if DEBUGLVL >= 5
printf("Woke up from sleep, %d free pages, %d cache, %d buffer\n",
_count->free, _count->cache, _count->buffer);
#endif
}
// Find first contiguous area that is at least the size requested.
// Make note of largest contiguous area smaller than requested size.
int pick = -1;
int i = 0;
for(; i < _count->entries; i++) {
if (_freePageCount[i] >= pages) {
#if DEBUGLVL >= 3
printf("Found %d-page contiguous block at index %d\n",
_freePageCount[i], i);
#endif
pick = i;
break;
}
if (pick < 0 || _freePageCount[i] > _freePageCount[pick])
pick = i;
}
DOASSERT(pick >= 0 && pick < _count->entries, "Invalid index");
if (_freePageCount[pick] < pages) {
#if DEBUGLVL >= 3
printf("Reducing %d-page request to largest available %d\n",
pages, _freePageCount[pick]);
#endif
pages = _freePageCount[pick];
DOASSERT(pages > 0, "Invalid page count");
}
DOASSERT(_count->free >= pages, "Invalid free count");
_count->free -= pages;
buf = _freePage[pick];
DOASSERT(buf, "Invalid page");
_freePageCount[pick] -= pages;
// If nothing left of memory chunk, move another chunk into this
// table position. Otherwise, adjust memory chunk location.
if (!_freePageCount[pick]) {
_count->entries--;
if (pick < _count->entries) {
_freePage[pick] = _freePage[_count->entries];
_freePageCount[pick] = _freePageCount[_count->entries];
_freePage[_count->entries] = 0;
_freePageCount[_count->entries] = 0;
} else {
_freePage[pick] = 0;
}
} else {
_freePage[i] = buf + pages * _pageSize;
}
if (type == Buffer)
_count->buffer += pages;
else
_count->cache += pages;
#if DEBUGLVL >= 3
printf("Allocated %d %s page(s) at 0x%p\n",
pages, (type == Cache ? "cache" : "buffer"), buf);
#endif
#if DEBUGLVL >= 5
printf("Memory allocation table now:\n");
Dump();
#endif
ReleaseMutex();
return 0;
}
int MemMgr::Deallocate(PageType type, char *buf, int pages)
{
AcquireMutex();
DOASSERT(buf, "Invalid page");
DOASSERT(_count->free + pages <= _numPages, "Invalid page");
// Find free page area that merges perfectly with deallocated range.
char *endBuf = buf + pages * _pageSize;
int mergeLeft = -1;
int mergeRight = -1;
for(int i = 0; i < _count->entries; i++) {
DOASSERT(_freePageCount[i] > 0, "Invalid free page count");
DOASSERT(_freePage[i], "Invalid free memory area");
char *endFreeBuf = _freePage[i] + _freePageCount[i] * _pageSize;
if (_freePage[i] == endBuf)
mergeLeft = i;
if (buf == endFreeBuf)
mergeRight = i;
}
if (mergeLeft >= 0 && mergeRight >= 0) {
// Freed area sits perfectly between two previously freed areas
DOASSERT(mergeLeft != mergeRight, "Impossible merge");
_freePageCount[mergeRight] += pages + _freePageCount[mergeLeft];
_count->entries--;
if (mergeLeft < _count->entries) {
_freePage[mergeLeft] = _freePage[_count->entries];
_freePageCount[mergeLeft] = _freePageCount[_count->entries];
_freePage[_count->entries] = 0;
_freePageCount[_count->entries] = 0;
} else {
_freePageCount[mergeLeft] = 0;
_freePage[mergeLeft] = 0;
}
} else if (mergeLeft >= 0) {
// Freed area is just to the left of a previously freed area
_freePage[mergeLeft] -= pages * _pageSize;
_freePageCount[mergeLeft] += pages;
} else if (mergeRight >= 0) {
// Freed area is just to the right of a previously freed area
_freePageCount[mergeRight] += pages;
} else {
// Freed area is not adjacent to any previously freed area
int freeEntry = _count->entries;
DOASSERT(freeEntry <= _tableSize, "Inconsistent state");
DOASSERT(!_freePage[freeEntry] && !_freePageCount[freeEntry],
"Entry not free");
_freePage[freeEntry] = buf;
_freePageCount[freeEntry] = pages;
_count->entries++;
}
_count->free += pages;
#if DEBUGLVL >= 3
printf("Deallocated %d %s page(s) at 0x%p\n",
pages, (type == Cache ? "cache" : "buffer"), buf);
#endif
if (type == Buffer) {
_count->buffer -= pages;
#if DEBUGLVL >= 3
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -