home *** CD-ROM | disk | FTP | other *** search
- /*
- (C) 1995 AROS - The Amiga Replacement OS
- $Id: freemem.c 1.1 1995/11/14 22:31:07 digulla Exp digulla $
- $Log: freemem.c $
- * Revision 1.1 1995/11/14 22:31:07 digulla
- * Initial revision
- *
- Desc:
- Lang: english
- */
- #include "exec_intern.h"
- #include "memory.h"
- #include <exec/alerts.h>
-
- /*****************************************************************************
-
- NAME */
- #include <exec/memory.h>
- #include <clib/exec_protos.h>
-
- __AROS_LH2(void, FreeMem,
-
- /* SYNOPSIS */
- __AROS_LA(APTR , memoryBlock, A1),
- __AROS_LA(unsigned long, byteSize, D0),
-
- /* LOCATION */
- struct ExecBase *, SysBase, 35, Exec)
-
- /* FUNCTION
- Give a block of memory back to the system pool.
-
- INPUTS
- memoryBlock - Pointer to the memory to be freed
- byteSize - Size of the block
-
- RESULT
-
- NOTES
-
- EXAMPLE
-
- BUGS
-
- SEE ALSO
- AllocMem()
-
- INTERNALS
-
- HISTORY
- 08-10-95 created by m. fleischer
- 16-10-95 increased portability
- 26-10-95 digulla adjusted to new calling scheme
-
- ******************************************************************************/
- {
- __AROS_FUNC_INIT
- struct MemHeader * mh;
- struct MemChunk * p1,
- * p2,
- * p3;
- UBYTE * p4;
-
- /* If there is no memory free nothing */
- if (!byteSize)
- return;
-
- /* Align size to the requirements */
- byteSize += (ULONG)memoryBlock & (MEMCHUNK_TOTAL - 1);
- byteSize = (byteSize + MEMCHUNK_TOTAL - 1) & ~(MEMCHUNK_TOTAL - 1);
-
- /* Align the block as well */
- memoryBlock = (APTR)((ULONG)memoryBlock & ~(MEMCHUNK_TOTAL - 1));
-
- /* Start and end(+1) of the block */
- p3 = (struct MemChunk *)memoryBlock;
- p4 = (UBYTE *)p3 + byteSize;
-
- /* Protect the memory list from access by other tasks. */
- Forbid ();
-
- /* Loop over MemHeader structures */
- mh = (struct MemHeader *)SysBase->MemList.lh_Head;
- while (mh->mh_Node.ln_Succ)
- {
- /* Test if the memory belongs to this MemHeader. */
- if (mh->mh_Lower <= memoryBlock && mh->mh_Upper > memoryBlock)
- {
- #if !defined(NO_CONSISTENCY_CHECKS)
- /* Test if it really fits into this MemHeader. */
- if ((APTR)p4 > mh->mh_Upper)
- /* Something is completely wrong. */
- Alert (AN_MemCorrupt|AT_DeadEnd);
- #endif
- /*
- The free memory list is only single linked, i.e. to insert
- elements into the list I need the node as well as it's
- predessor. For the first element I can use freeList->mh_First
- instead of a real predessor.
- */
- p1 = (struct MemChunk *)&mh->mh_First;
- p2 = p1->mc_Next;
-
- /* No chunk in list? Just insert the current one and return. */
- if (p2 == NULL)
- {
- p3->mc_Bytes = byteSize;
- p3->mc_Next = NULL;
- p1->mc_Next = p3;
- mh->mh_Free += byteSize;
-
- Permit ();
-
- return;
- }
-
- /* Follow the list to find a place where to insert our memory. */
- do
- {
- #if !defined(NO_CONSISTENCY_CHECKS)
- /*
- Do some constistency checks:
- 1. All MemChunks must be aligned to
- MEMCHUNK_TOTAL.
- 2. The end (+1) of the current MemChunk
- must be lower than the start of the next one.
- */
- if (((ULONG)p2 | p2->mc_Bytes) & (MEMCHUNK_TOTAL - 1)
- || ((UBYTE *)p2 + p2->mc_Bytes >= (UBYTE *)p2->mc_Next
- && p2->mc_Next != NULL
- )
- )
- Alert (AN_MemCorrupt|AT_DeadEnd);
- #endif
- /* Found a block with a higher address? */
- if (p2 >= p3)
- {
- #if !defined(NO_CONSISTENCY_CHECKS)
- /*
- If the memory to be freed overlaps with the current
- block something must be wrong.
- */
- if (p4 > (UBYTE *)p2)
- Alert (AN_FreeTwice|AT_DeadEnd);
- #endif
- /* End the loop with p2 non-zero */
- break;
- }
- /* goto next block */
- p1 = p2;
- p2 = p2->mc_Next;
-
- /* If the loop ends with p2 zero add it at the end. */
- } while (p2 != NULL);
-
- /* If there was a previous block merge with it. */
- if (p1 != (struct MemChunk *)&mh->mh_First)
- {
- #if !defined(NO_CONSISTENCY_CHECKS)
- /* Check if they overlap. */
- if ((UBYTE *)p1 + p1->mc_Bytes > (UBYTE *)p3)
- Alert (AN_FreeTwice|AT_DeadEnd);
- #endif
- /* Merge if possible */
- if ((UBYTE *)p1 + p1->mc_Bytes == (UBYTE *)p3)
- p3 = p1;
- else
- /* Not possible to merge */
- p1->mc_Next = p3;
- }else
- /*
- There was no previous block. Just insert the memory at
- the start of the list.
- */
- p1->mc_Next = p3;
-
- /* Try to merge with next block (if there is one ;-) ). */
- if (p4 == (UBYTE *)p2 && p2 != NULL)
- {
- /*
- Overlap checking already done. Doing it here after
- the list potentially changed would be a bad idea.
- */
- p4 += p2->mc_Bytes;
- p2 = p2->mc_Next;
- }
-
- /* relink the list and return. */
- p3->mc_Next = p2;
- p3->mc_Bytes = p4 - (UBYTE *)p3;
- mh->mh_Free += byteSize;
-
- Permit ();
-
- return;
- }
-
- mh = (struct MemHeader *)mh->mh_Node.ln_Succ;
- }
- #if !defined(NO_CONSISTENCY_CHECKS)
- /* Some memory that didn't fit into any MemHeader? */
- Alert (AN_MemCorrupt|AT_DeadEnd);
- #else
- Permit ();
- #endif
- __AROS_FUNC_EXIT
- } /* FreeMem */
-
-