📄 memalloc.c
字号:
MemoryData(theEnv)->TopMemoryBlock->nextFree->lastFree = NULL;
MemoryData(theEnv)->TopMemoryBlock->nextFree->prevChunk = NULL;
MemoryData(theEnv)->TopMemoryBlock->nextFree->size = (long) usableBlockSize;
MemoryData(theEnv)->BlockMemoryInitialized = TRUE;
return(1);
}
/***************************************************************************/
/* AllocateBlock: Adds a new block of memory to the list of memory blocks. */
/***************************************************************************/
static int AllocateBlock(
void *theEnv,
struct blockInfo *blockPtr,
unsigned int requestSize)
{
unsigned int blockSize, usableBlockSize;
struct blockInfo *newBlock;
struct chunkInfo *newTopChunk;
/*============================================================*/
/* Determine the size of the block that needs to be allocated */
/* to satisfy the request. Normally, a default block size is */
/* used, but if the requested size is larger than the default */
/* size, then the requested size is used for the block size. */
/*============================================================*/
blockSize = (BLOCKSIZE > requestSize ? BLOCKSIZE : requestSize);
blockSize += MemoryData(theEnv)->BlockInfoSize + MemoryData(theEnv)->ChunkInfoSize * 2;
blockSize = (((blockSize - 1) / STRICT_ALIGN_SIZE) + 1) * STRICT_ALIGN_SIZE;
usableBlockSize = blockSize - MemoryData(theEnv)->BlockInfoSize - (2 * MemoryData(theEnv)->ChunkInfoSize);
/*=========================*/
/* Allocate the new block. */
/*=========================*/
newBlock = (struct blockInfo *) malloc((STD_SIZE) blockSize);
if (newBlock == NULL) return(0);
/*======================================*/
/* Initialize the block data structure. */
/*======================================*/
newBlock->nextBlock = NULL;
newBlock->prevBlock = blockPtr;
newBlock->nextFree = (struct chunkInfo *) (((char *) newBlock) + MemoryData(theEnv)->BlockInfoSize);
newBlock->size = (long) usableBlockSize;
blockPtr->nextBlock = newBlock;
newTopChunk = (struct chunkInfo *) (((char *) newBlock) + MemoryData(theEnv)->BlockInfoSize + MemoryData(theEnv)->ChunkInfoSize + usableBlockSize);
newTopChunk->nextFree = NULL;
newTopChunk->lastFree = NULL;
newTopChunk->size = 0;
newTopChunk->prevChunk = newBlock->nextFree;
newBlock->nextFree->nextFree = NULL;
newBlock->nextFree->lastFree = NULL;
newBlock->nextFree->prevChunk = NULL;
newBlock->nextFree->size = (long) usableBlockSize;
return(1);
}
/*******************************************************/
/* RequestChunk: Allocates memory by returning a chunk */
/* of memory from a larger block of memory. */
/*******************************************************/
globle void *RequestChunk(
void *theEnv,
unsigned int requestSize)
{
struct chunkInfo *chunkPtr;
struct blockInfo *blockPtr;
/*==================================================*/
/* Allocate initial memory pool block if it has not */
/* already been allocated. */
/*==================================================*/
if (MemoryData(theEnv)->BlockMemoryInitialized == FALSE)
{
if (InitializeBlockMemory(theEnv,requestSize) == 0) return(NULL);
}
/*====================================================*/
/* Make sure that the amount of memory requested will */
/* fall on a boundary of strictest alignment */
/*====================================================*/
requestSize = (((requestSize - 1) / STRICT_ALIGN_SIZE) + 1) * STRICT_ALIGN_SIZE;
/*=====================================================*/
/* Search through the list of free memory for a block */
/* of the appropriate size. If a block is found, then */
/* allocate and return a pointer to it. */
/*=====================================================*/
blockPtr = MemoryData(theEnv)->TopMemoryBlock;
while (blockPtr != NULL)
{
chunkPtr = blockPtr->nextFree;
while (chunkPtr != NULL)
{
if ((chunkPtr->size == requestSize) ||
(chunkPtr->size > (requestSize + MemoryData(theEnv)->ChunkInfoSize)))
{
AllocateChunk(theEnv,blockPtr,chunkPtr,requestSize);
return((void *) (((char *) chunkPtr) + MemoryData(theEnv)->ChunkInfoSize));
}
chunkPtr = chunkPtr->nextFree;
}
if (blockPtr->nextBlock == NULL)
{
if (AllocateBlock(theEnv,blockPtr,requestSize) == 0) /* get another block */
{ return(NULL); }
}
blockPtr = blockPtr->nextBlock;
}
SystemError(theEnv,"MEMORY",2);
EnvExitRouter(theEnv,EXIT_FAILURE);
return(NULL); /* Unreachable, but prevents warning. */
}
/********************************************/
/* AllocateChunk: Allocates a chunk from an */
/* existing chunk in a block of memory. */
/********************************************/
static void AllocateChunk(
void *theEnv,
struct blockInfo *parentBlock,
struct chunkInfo *chunkPtr,
unsigned int requestSize)
{
struct chunkInfo *splitChunk, *nextChunk;
/*=============================================================*/
/* If the size of the memory chunk is an exact match for the */
/* requested amount of memory, then the chunk can be allocated */
/* without splitting it. */
/*=============================================================*/
if (requestSize == chunkPtr->size)
{
chunkPtr->size = - (long int) requestSize;
if (chunkPtr->lastFree == NULL)
{
if (chunkPtr->nextFree != NULL)
{ parentBlock->nextFree = chunkPtr->nextFree; }
else
{ parentBlock->nextFree = NULL; }
}
else
{ chunkPtr->lastFree->nextFree = chunkPtr->nextFree; }
if (chunkPtr->nextFree != NULL)
{ chunkPtr->nextFree->lastFree = chunkPtr->lastFree; }
chunkPtr->lastFree = NULL;
chunkPtr->nextFree = NULL;
return;
}
/*===========================================================*/
/* If the size of the memory chunk is larger than the memory */
/* request, then split the chunk into two pieces. */
/*===========================================================*/
nextChunk = (struct chunkInfo *)
(((char *) chunkPtr) + MemoryData(theEnv)->ChunkInfoSize + chunkPtr->size);
splitChunk = (struct chunkInfo *)
(((char *) chunkPtr) + (MemoryData(theEnv)->ChunkInfoSize + requestSize));
splitChunk->size = (long) (chunkPtr->size - (requestSize + MemoryData(theEnv)->ChunkInfoSize));
splitChunk->prevChunk = chunkPtr;
splitChunk->nextFree = chunkPtr->nextFree;
splitChunk->lastFree = chunkPtr->lastFree;
nextChunk->prevChunk = splitChunk;
if (splitChunk->lastFree == NULL)
{ parentBlock->nextFree = splitChunk; }
else
{ splitChunk->lastFree->nextFree = splitChunk; }
if (splitChunk->nextFree != NULL)
{ splitChunk->nextFree->lastFree = splitChunk; }
chunkPtr->size = - (long int) requestSize;
chunkPtr->lastFree = NULL;
chunkPtr->nextFree = NULL;
return;
}
/***********************************************************/
/* ReturnChunk: Frees memory allocated using RequestChunk. */
/***********************************************************/
globle int ReturnChunk(
void *theEnv,
void *memPtr,
unsigned int size)
{
struct chunkInfo *chunkPtr, *lastChunk, *nextChunk, *topChunk;
struct blockInfo *blockPtr;
/*=====================================================*/
/* Determine if the expected size of the chunk matches */
/* the size stored in the chunk's information record. */
/*=====================================================*/
size = (((size - 1) / STRICT_ALIGN_SIZE) + 1) * STRICT_ALIGN_SIZE;
chunkPtr = (struct chunkInfo *) (((char *) memPtr) - MemoryData(theEnv)->ChunkInfoSize);
if (chunkPtr == NULL)
{ return(FALSE); }
if (chunkPtr->size >= 0)
{ return(FALSE); }
if (chunkPtr->size != - (long int) size)
{ return(FALSE); }
chunkPtr->size = - chunkPtr->size;
/*=============================================*/
/* Determine in which block the chunk resides. */
/*=============================================*/
topChunk = chunkPtr;
while (topChunk->prevChunk != NULL)
{ topChunk = topChunk->prevChunk; }
blockPtr = (struct blockInfo *) (((char *) topChunk) - MemoryData(theEnv)->BlockInfoSize);
/*===========================================*/
/* Determine the chunks physically preceding */
/* and following the returned chunk. */
/*===========================================*/
lastChunk = chunkPtr->prevChunk;
nextChunk = (struct chunkInfo *) (((char *) memPtr) + size);
/*=========================================================*/
/* Add the chunk to the list of free chunks for the block. */
/*=========================================================*/
if (blockPtr->nextFree != NULL)
{ blockPtr->nextFree->lastFree = chunkPtr; }
chunkPtr->nextFree = blockPtr->nextFree;
chunkPtr->lastFree = NULL;
blockPtr->nextFree = chunkPtr;
/*=====================================================*/
/* Combine this chunk with previous chunk if possible. */
/*=====================================================*/
if (lastChunk != NULL)
{
if (lastChunk->size > 0)
{
lastChunk->size += (MemoryData(theEnv)->ChunkInfoSize + chunkPtr->size);
if (nextChunk != NULL)
{ nextChunk->prevChunk = lastChunk; }
else
{ return(FALSE); }
if (lastChunk->lastFree != NULL)
{ lastChunk->lastFree->nextFree = lastChunk->nextFree; }
if (lastChunk->nextFree != NULL)
{ lastChunk->nextFree->lastFree = lastChunk->lastFree; }
lastChunk->nextFree = chunkPtr->nextFree;
if (chunkPtr->nextFree != NULL)
{ chunkPtr->nextFree->lastFree = lastChunk; }
lastChunk->lastFree = NULL;
blockPtr->nextFree = lastChunk;
chunkPtr->lastFree = NULL;
chunkPtr->nextFree = NULL;
chunkPtr = lastChunk;
}
}
/*=====================================================*/
/* Combine this chunk with the next chunk if possible. */
/*=====================================================*/
if (nextChunk == NULL) return(FALSE);
if (chunkPtr == NULL) return(FALSE);
if (nextChunk->size > 0)
{
chunkPtr->size += (MemoryData(theEnv)->ChunkInfoSize + nextChunk->size);
topChunk = (struct chunkInfo *) (((char *) nextChunk) + nextChunk->size + MemoryData(theEnv)->ChunkInfoSize);
if (topChunk != NULL)
{ topChunk->prevChunk = chunkPtr; }
else
{ return(FALSE); }
if (nextChunk->lastFree != NULL)
{ nextChunk->lastFree->nextFree = nextChunk->nextFree; }
if (nextChunk->nextFree != NULL)
{ nextChunk->nextFree->lastFree = nextChunk->lastFree; }
}
/*===========================================*/
/* Free the buffer if we can, but don't free */
/* the first buffer if it's the only one. */
/*===========================================*/
if ((chunkPtr->prevChunk == NULL) &&
(chunkPtr->size == blockPtr->size))
{
if (blockPtr->prevBlock != NULL)
{
blockPtr->prevBlock->nextBlock = blockPtr->nextBlock;
if (blockPtr->nextBlock != NULL)
{ blockPtr->nextBlock->prevBlock = blockPtr->prevBlock; }
free((char *) blockPtr);
}
else
{
if (blockPtr->nextBlock != NULL)
{
blockPtr->nextBlock->prevBlock = NULL;
MemoryData(theEnv)->TopMemoryBlock = blockPtr->nextBlock;
free((char *) blockPtr);
}
}
}
return(TRUE);
}
/***********************************************/
/* ReturnAllBlocks: Frees all allocated blocks */
/* back to the operating system. */
/***********************************************/
globle void ReturnAllBlocks(
void *theEnv)
{
struct blockInfo *theBlock, *nextBlock;
struct longMemoryPtr *theLongMemory, *nextLongMemory;
/*======================================*/
/* Free up int based memory allocation. */
/*======================================*/
theBlock = MemoryData(theEnv)->TopMemoryBlock;
while (theBlock != NULL)
{
nextBlock = theBlock->nextBlock;
free((char *) theBlock);
theBlock = nextBlock;
}
MemoryData(theEnv)->TopMemoryBlock = NULL;
/*=======================================*/
/* Free up long based memory allocation. */
/*=======================================*/
theLongMemory = MemoryData(theEnv)->TopLongMemoryPtr;
while (theLongMemory != NULL)
{
nextLongMemory = theLongMemory->next;
genlongfree(theEnv,theLongMemory,(unsigned long) theLongMemory->size);
theLongMemory = nextLongMemory;
}
MemoryData(theEnv)->TopLongMemoryPtr = NULL;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -