From 6591010f66a05538ddc29b3404d64a27dfc29b3f Mon Sep 17 00:00:00 2001 From: Max Horn Date: Mon, 26 Oct 2009 16:01:34 +0000 Subject: TINSEL: Further untangle memory managment. * Add new function MemoryNoAlloc * Make MemoryAlloc private * Get rid of params to various memory related functions svn-id: r45409 --- engines/tinsel/handle.cpp | 35 +++++++----------- engines/tinsel/heapmem.cpp | 92 ++++++++++++++++++++++++---------------------- engines/tinsel/heapmem.h | 16 ++------ 3 files changed, 65 insertions(+), 78 deletions(-) (limited to 'engines') diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp index 5ea273379c..cbfd782942 100644 --- a/engines/tinsel/handle.cpp +++ b/engines/tinsel/handle.cpp @@ -170,7 +170,7 @@ void SetupHandleTable(void) { #endif else { // allocate a discarded memory node for other files - pH->_node = MemoryAlloc(DWM_DISCARDABLE | DWM_NOALLOC, pH->filesize & FSIZE_MASK); + pH->_node = MemoryNoAlloc(); pH->_ptr = NULL; // make sure memory allocated @@ -306,17 +306,6 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) { // discardable - lock the memory addr = (uint8 *)MemoryLock(pH->_node); } -#ifdef DEBUG - if (addr == NULL) { - if (pH->filesize & fPreload) - // preload - no need to lock the memory - addr = pH->_ptr; - else { - // discardable - lock the memory - addr = (uint8 *)MemoryLock(pH->_node); - } - } -#endif // make sure address is valid assert(addr); @@ -381,7 +370,7 @@ byte *LockMem(SCNHANDLE offset) { if (pH->_node->pBaseAddr == NULL) // must have been discarded - reallocate the memory - MemoryReAlloc(pH->_node, cdTopHandle - cdBaseHandle, DWM_DISCARDABLE); + MemoryReAlloc(pH->_node, cdTopHandle - cdBaseHandle); if (pH->_node->pBaseAddr == NULL) error("Out of memory"); @@ -403,7 +392,7 @@ byte *LockMem(SCNHANDLE offset) { if (pH->_node->pBaseAddr == NULL) // must have been discarded - reallocate the memory - MemoryReAlloc(pH->_node, pH->filesize & FSIZE_MASK, DWM_DISCARDABLE); + MemoryReAlloc(pH->_node, pH->filesize & FSIZE_MASK); if (pH->_node->pBaseAddr == NULL) error("Out of memory"); @@ -422,7 +411,7 @@ byte *LockMem(SCNHANDLE offset) { } /** - * Called to make the current scene non-discardable. + * Called to lock the current scene and make it non-discardable. * @param offset Handle and offset to data */ void LockScene(SCNHANDLE offset) { @@ -443,11 +432,12 @@ void LockScene(SCNHANDLE offset) { HeapCompact(MAX_INT, false); if ((pH->filesize & fPreload) == 0) { - // change the flags for the node - // WORKAROUND: The original didn't include the DWM_LOCKED flag. It's being - // included because the method is 'LockScene' so it's presumed that the - // point of this was that the scene's memory block be locked - MemoryReAlloc(pH->_node, pH->filesize & FSIZE_MASK, DWM_LOCKED); + // Ensure the scene handle is allocated. + MemoryReAlloc(pH->_node, pH->filesize & FSIZE_MASK); + + // Now lock it to make sure it stays allocated and in a fixed position. + MemoryLock(pH->_node); + #ifdef DEBUG bLockedScene = true; #endif @@ -469,8 +459,9 @@ void UnlockScene(SCNHANDLE offset) { pH = handleTable + handle; if ((pH->filesize & fPreload) == 0) { - // change the flags for the node - MemoryReAlloc(pH->_node, pH->filesize & FSIZE_MASK, DWM_DISCARDABLE); + // unlock the scene data + MemoryUnlock(pH->_node); + #ifdef DEBUG bLockedScene = false; #endif diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp index bc4183ce35..7a0766098b 100644 --- a/engines/tinsel/heapmem.cpp +++ b/engines/tinsel/heapmem.cpp @@ -30,6 +30,14 @@ namespace Tinsel { + +// internal allocation flags +#define DWM_DISCARDED 0x0100 ///< the objects memory block has been discarded +#define DWM_LOCKED 0x0200 ///< the objects memory block is locked +#define DWM_SENTINEL 0x0400 ///< the objects memory block is a sentinel + + + // Specifies the total amount of memory required for DW1 demo, DW1, or DW2 respectively. // Currently this is set at 5MB for the DW1 demo and DW1 and 10MB for DW2 // This could probably be reduced somewhat @@ -161,6 +169,7 @@ void FreeMemNode(MEM_NODE *pMemNode) { * Tries to make space for the specified number of bytes on the specified heap. * @param size Number of bytes to free up * @param bDiscard When set - will discard blocks to fullfill the request + * @return true if any blocks were discarded, false otherwise */ bool HeapCompact(long size, bool bDiscard) { MEM_NODE *pHeap = &heapSentinel; @@ -239,8 +248,7 @@ bool HeapCompact(long size, bool bDiscard) { oldest = DwGetCurrentTime(); pOldest = NULL; for (pCur = pHeap->pNext; pCur != pHeap; pCur = pCur->pNext) { - if ((pCur->flags & (DWM_DISCARDABLE | DWM_DISCARDED | DWM_LOCKED)) - == DWM_DISCARDABLE) { + if ((pCur->flags & (DWM_DISCARDED | DWM_LOCKED)) == 0) { // found a non-discarded discardable block if (pCur->lruTime < oldest) { oldest = pCur->lruTime; @@ -263,17 +271,16 @@ bool HeapCompact(long size, bool bDiscard) { * @param flags Allocation attributes * @param size Number of bytes to allocate */ -MEM_NODE *MemoryAlloc(int flags, long size) { - MEM_NODE *pHeap = &heapSentinel; +static MEM_NODE *MemoryAlloc(int flags, long size) { + const MEM_NODE *pHeap = &heapSentinel; MEM_NODE *pNode; - bool bCompacted = true; // set when heap has been compacted #ifdef SCUMM_NEED_ALIGNMENT const int alignPadding = sizeof(void*) - 1; size = (size + alignPadding) & ~alignPadding; //round up to nearest multiple of sizeof(void*), this ensures the addresses that are returned are alignment-safe. #endif - while ((flags & DWM_NOALLOC) == 0 && bCompacted) { + do { // search the heap for a free block for (pNode = pHeap->pNext; pNode != pHeap; pNode = pNode->pNext) { @@ -313,36 +320,42 @@ MEM_NODE *MemoryAlloc(int flags, long size) { } } // compact the heap if we get to here - bCompacted = HeapCompact(size, true); - } + } while (HeapCompact(size, true)); - // not allocated a block if we get to here - if (flags & DWM_DISCARDABLE) { - // chain a discarded node onto the end of the heap - pNode = AllocMemNode(); - pNode->flags = flags | DWM_DISCARDED; + // could not allocate a block + return 0; +} - // set mnode at the end of the list - pNode->pPrev = pHeap->pPrev; - pNode->pNext = pHeap; +/** + * Allocate a discarded MEM_NODE. Actual memory can be assigned to it + * by using MemoryReAlloc(). + */ +MEM_NODE *MemoryNoAlloc() { + MEM_NODE *pHeap = &heapSentinel; - // fix links to this mnode - pHeap->pPrev->pNext = pNode; - pHeap->pPrev = pNode; + // chain a discarded node onto the end of the heap + MEM_NODE *pNode = AllocMemNode(); + pNode->flags = DWM_DISCARDED; - // return the discarded node - return pNode; - } + // set mnode at the end of the list + pNode->pPrev = pHeap->pPrev; + pNode->pNext = pHeap; - // could not allocate a block - return NULL; -} + // fix links to this mnode + pHeap->pPrev->pNext = pNode; + pHeap->pPrev = pNode; + // return the discarded node + return pNode; +} +/** + * Allocate a fixed block of data. + * @note For now, we simply malloc it! + * @todo We really should keep a list of the allocated pointers, + * so that we can discard them later on, when the engine quits. + */ void *MemoryAllocFixed(long size) { - // Allocate a fixed block of data. For now, we simply malloc it! - // TODO: We really should keep a list of the allocated pointers, - // so that we can discard them later on, when the engine quits. #ifdef SCUMM_NEED_ALIGNMENT const int alignPadding = sizeof(void*) - 1; @@ -361,9 +374,6 @@ void MemoryDiscard(MEM_NODE *pMemNode) { // validate mnode pointer assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1); - // object must be discardable - assert(pMemNode->flags & DWM_DISCARDABLE); - // object cannot be locked assert((pMemNode->flags & DWM_LOCKED) == 0); @@ -425,12 +435,11 @@ void *MemoryLock(MEM_NODE *pMemNode) { } /** - * Changes the size or attributes of a specified memory object. + * Changes the size of a specified memory object and re-allocate it if necessary. * @param pMemNode Node of the memory object * @param size New size of block - * @param flags How to reallocate the object */ -void MemoryReAlloc(MEM_NODE *pMemNode, long size, int flags) { +void MemoryReAlloc(MEM_NODE *pMemNode, long size) { MEM_NODE *pNew; // validate mnode pointer @@ -442,25 +451,22 @@ void MemoryReAlloc(MEM_NODE *pMemNode, long size, int flags) { // validate the size assert(size); - if (size == pMemNode->size) { - // must be just a change in flags + if (size != pMemNode->size) { + + // make sure memory object is not locked and discarded + assert(pMemNode->flags == DWM_LOCKED | DWM_DISCARDED); + assert(pMemNode->size == 0); - // update the nodes flags - pMemNode->flags = flags; - } else { // unlink the mnode from the current heap pMemNode->pNext->pPrev = pMemNode->pPrev; pMemNode->pPrev->pNext = pMemNode->pNext; // allocate a new node - pNew = MemoryAlloc(flags, size); + pNew = MemoryAlloc(pMemNode->flags & ~DWM_DISCARDED, size); // make sure memory allocated assert(pNew != NULL); - // update the nodes flags - pNew->flags = flags; - // copy the node to the current node memcpy(pMemNode, pNew, sizeof(MEM_NODE)); diff --git a/engines/tinsel/heapmem.h b/engines/tinsel/heapmem.h index c7631da8ce..5ebf2e7062 100644 --- a/engines/tinsel/heapmem.h +++ b/engines/tinsel/heapmem.h @@ -43,13 +43,6 @@ struct MEM_NODE { }; // allocation flags for the MemoryAlloc function -#define DWM_DISCARDABLE 0x0004 ///< allocates discardable memory -#define DWM_NOALLOC 0x0008 ///< when used with discardable memory - allocates a discarded block - -// internal allocation flags -#define DWM_DISCARDED 0x0100 ///< the objects memory block has been discarded -#define DWM_LOCKED 0x0200 ///< the objects memory block is locked -#define DWM_SENTINEL 0x0400 ///< the objects memory block is a sentinel /*----------------------------------------------------------------------*\ @@ -58,10 +51,8 @@ struct MEM_NODE { void MemoryInit(void); // initialises the memory manager -// allocates a movable block with the specified number of bytes from the heap -MEM_NODE *MemoryAlloc( - int flags, // allocation attributes - long size); // number of bytes to allocate +// reserves a memory node for a movable & discardable block +MEM_NODE *MemoryNoAlloc(); // allocates a fixed block with the specified number of bytes void *MemoryAllocFixed(long size); @@ -74,8 +65,7 @@ void *MemoryLock( // locks a memory object and returns a pointer to the first b void MemoryReAlloc( // changes the size or attributes of a specified memory object MEM_NODE *pMemNode, // node of the memory object - long size, // new size of block - int flags); // how to reallocate the object + long size); // new size of block void MemoryUnlock( // unlocks a memory object MEM_NODE *pMemNode); // node of the memory object -- cgit v1.2.3