/* Copyright (C) 1994-2003 Revolution Software Ltd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * $Header$ */ //memory manager - "remember, it's not good to leave memory locked for a moment longer than necessary" Tony // "actually, in a sequential system theoretically you never need to lock any memory!" Chris ;) // // This is a very simple implementation but I see little advantage to being any cleverer // with the coding - i could have put the mem blocks before the defined blocks instead // of in an array and then used pointers to child/parent blocks. But why bother? I've Kept it simple. // When it needs updating or customising it will be accessable to anyone who looks at it. // *doesn't have a purgeable/age consituant yet - if anyone wants this then I'll add it in. // MemMan v1.1 #include #include #include #include "stdafx.h" #include "driver/driver96.h" #include "console.h" #include "debug.h" #include "memory.h" #include "resman.h" uint32 total_blocks; uint32 base_mem_block; uint32 total_free_memory; uint8 *free_memman; //address of init malloc to be freed later //#define MEMDEBUG 1 mem mem_list[MAX_mem_blocks]; //list of defined memory handles - each representing a block of memory. int32 VirtualDefrag( uint32 size ); // Used to determine if the required size can be obtained if the defragger is allowed to run. int32 suggestedStart = 0; // Start position of the Defragger as indicated by its sister VirtualDefrag. //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ void Close_memory_manager(void) //Tony2Oct96 { free(free_memman); } //------------------------------------------------------------------------------------ void Init_memory_manager(void) //Tony9April96 { uint32 j; uint8 *memory_base; total_free_memory=12000*1024; //12MB //malloc memory and adjust for long boundaries memory_base = (uint8 *) malloc(total_free_memory); if (!memory_base) //could not grab the memory { Zdebug("couldn't malloc %d in Init_memory_manager", total_free_memory); ExitWithReport("Init_memory_manager() couldn't malloc %d bytes [line=%d file=%s]",total_free_memory,__LINE__,__FILE__); } free_memman = memory_base; //the original malloc address //force to long word boundary memory_base+=3; memory_base = (uint8 *)((uint32)memory_base & 0xfffffffc); // ** was (int)memory_base // total_free_memory-=3; //play safe //set all but first handle to unused for (j=1;jstate=MEM_free; block->uid=UID_memman; //belongs to the memory manager again #ifdef MEMDEBUG Mem_debug(); #endif //MEMDEBUG } //------------------------------------------------------------------------------------ void Float_mem(mem *block) //Tony10Apr96 { //set a block to float //wont be trashed but will move around in memory block->state=MEM_float; #ifdef MEMDEBUG Mem_debug(); #endif //MEMDEBUG } //------------------------------------------------------------------------------------ void Lock_mem(mem *block) //Tony11Apr96 { //set a block to lock //wont be moved - don't lock memory for any longer than necessary unless you know the locked memory is at the bottom of the heap block->state=MEM_locked; //can't move now - this block is now crying out to be floated or free'd again #ifdef MEMDEBUG Mem_debug(); #endif //MEMDEBUG } //------------------------------------------------------------------------------------ int32 Defrag_mem(uint32 req_size) //Tony10Apr96 { //moves floating blocks down and/or merges free blocks until a large enough space is found //or there is nothing left to do and a big enough block cannot be found //we stop when we find/create a large enough block - this is enough defragging. int32 cur_block; //block 0 remains the parent block int32 original_parent,child, end_child; uint32 j; uint32 *a; uint32 *b; // cur_block=base_mem_block; //the mother of all parents cur_block = suggestedStart; do { if (mem_list[cur_block].state==MEM_free) //is current block a free block? { if (mem_list[cur_block].size>=req_size) { return(cur_block); //this block is big enough - return its id } if (mem_list[cur_block].child==-1) //the child is the end block - stop if the next block along is the end block return(-1); //no luck, couldn't find a big enough block // current free block is too small, but if its child is *also* free then merge the two together if (mem_list[mem_list[cur_block].child].state==MEM_free) { // ok, we nuke the child and inherit its child child=mem_list[cur_block].child; mem_list[cur_block].size+= mem_list[child].size; //our size grows by the size of our child mem_list[cur_block].child = mem_list[child].child; //our new child is our old childs, child if (mem_list[child].child!=-1) //not if the chld we're nuking is the end child (it has no child) mem_list[mem_list[child].child].parent=cur_block; //the (nuked) old childs childs parent is now us mem_list[child].state=MEM_null; //clean up the nuked child, so it can be used again total_blocks--; } // current free block is too small, but if its child is a float then we move the floating memory block down and the free up // but, parent/child relationships must be such that the memory is all continuous between blocks. ie. a childs memory always // begins 1 byte after its parent finishes. However, the positions in the memory list may become truly random, but, any particular // block of locked or floating memory must retain its position within the mem_list - the float stays a float because the handle/pointer has been passed back // what this means is that when the physical memory of the foat moves down (and the free up) the child becomes the parent and the parent the child // but, remember, the parent had a parent and the child another child - these swap over too as the parent/child swap takes place - phew. else if (mem_list[mem_list[cur_block].child].state==MEM_float) { child=mem_list[cur_block].child; //our child is currently floating // memcpy(mem_list[cur_block].ad, mem_list[child].ad, mem_list[child].size); //move the higher float down over the free block a=(uint32*) mem_list[cur_block].ad; b=(uint32*) mem_list[child].ad; for (j=0;j MAX_WASTAGE) currentBubbleSize += mem_list[cur_block].size; if (currentBubbleSize >= size) return 0; } else if (mem_list[cur_block].state == MEM_locked) { currentBubbleSize = 0; suggestedStart = mem_list[cur_block].child; // Any free block of the correct size will be above this locked block. } cur_block = mem_list[cur_block].child; } while(cur_block != -1); return(1); } //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------