home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 5 / Amiga Tools 5.iso / tools / developer-tools / aros / source / exec / memory / src / freemem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-16  |  4.9 KB  |  209 lines

  1. /*
  2.     (C) 1995 AROS - The Amiga Replacement OS
  3.     $Id: freemem.c 1.1 1995/11/14 22:31:07 digulla Exp digulla $
  4.     $Log: freemem.c $
  5.  * Revision 1.1  1995/11/14  22:31:07  digulla
  6.  * Initial revision
  7.  *
  8.     Desc:
  9.     Lang: english
  10. */
  11. #include "exec_intern.h"
  12. #include "memory.h"
  13. #include <exec/alerts.h>
  14.  
  15. /*****************************************************************************
  16.  
  17.     NAME */
  18.     #include <exec/memory.h>
  19.     #include <clib/exec_protos.h>
  20.  
  21.     __AROS_LH2(void, FreeMem,
  22.  
  23. /*  SYNOPSIS */
  24.     __AROS_LA(APTR         , memoryBlock, A1),
  25.     __AROS_LA(unsigned long, byteSize, D0),
  26.  
  27. /*  LOCATION */
  28.     struct ExecBase *, SysBase, 35, Exec)
  29.  
  30. /*  FUNCTION
  31.     Give a block of memory back to the system pool.
  32.  
  33.     INPUTS
  34.     memoryBlock - Pointer to the memory to be freed
  35.     byteSize    - Size of the block
  36.  
  37.     RESULT
  38.  
  39.     NOTES
  40.  
  41.     EXAMPLE
  42.  
  43.     BUGS
  44.  
  45.     SEE ALSO
  46.     AllocMem()
  47.  
  48.     INTERNALS
  49.  
  50.     HISTORY
  51.     08-10-95    created by m. fleischer
  52.     16-10-95    increased portability
  53.     26-10-95    digulla adjusted to new calling scheme
  54.  
  55. ******************************************************************************/
  56. {
  57.     __AROS_FUNC_INIT
  58.     struct MemHeader * mh;
  59.     struct MemChunk  * p1,
  60.              * p2,
  61.              * p3;
  62.     UBYTE         * p4;
  63.  
  64.     /* If there is no memory free nothing */
  65.     if (!byteSize)
  66.     return;
  67.  
  68.     /* Align size to the requirements */
  69.     byteSize += (ULONG)memoryBlock & (MEMCHUNK_TOTAL - 1);
  70.     byteSize = (byteSize + MEMCHUNK_TOTAL - 1) & ~(MEMCHUNK_TOTAL - 1);
  71.  
  72.     /* Align the block as well */
  73.     memoryBlock = (APTR)((ULONG)memoryBlock & ~(MEMCHUNK_TOTAL - 1));
  74.  
  75.     /* Start and end(+1) of the block */
  76.     p3 = (struct MemChunk *)memoryBlock;
  77.     p4 = (UBYTE *)p3 + byteSize;
  78.  
  79.     /* Protect the memory list from access by other tasks. */
  80.     Forbid ();
  81.  
  82.     /* Loop over MemHeader structures */
  83.     mh = (struct MemHeader *)SysBase->MemList.lh_Head;
  84.     while (mh->mh_Node.ln_Succ)
  85.     {
  86.     /* Test if the memory belongs to this MemHeader. */
  87.     if (mh->mh_Lower <= memoryBlock && mh->mh_Upper > memoryBlock)
  88.     {
  89. #if !defined(NO_CONSISTENCY_CHECKS)
  90.         /* Test if it really fits into this MemHeader. */
  91.         if ((APTR)p4 > mh->mh_Upper)
  92.         /* Something is completely wrong. */
  93.         Alert (AN_MemCorrupt|AT_DeadEnd);
  94. #endif
  95.         /*
  96.         The free memory list is only single linked, i.e. to insert
  97.         elements into the list I need the node as well as it's
  98.         predessor. For the first element I can use freeList->mh_First
  99.         instead of a real predessor.
  100.         */
  101.         p1 = (struct MemChunk *)&mh->mh_First;
  102.         p2 = p1->mc_Next;
  103.  
  104.         /* No chunk in list? Just insert the current one and return. */
  105.         if (p2 == NULL)
  106.         {
  107.         p3->mc_Bytes = byteSize;
  108.         p3->mc_Next  = NULL;
  109.         p1->mc_Next  = p3;
  110.         mh->mh_Free += byteSize;
  111.  
  112.         Permit ();
  113.  
  114.         return;
  115.         }
  116.  
  117.         /* Follow the list to find a place where to insert our memory. */
  118.         do
  119.         {
  120. #if !defined(NO_CONSISTENCY_CHECKS)
  121.         /*
  122.             Do some constistency checks:
  123.             1. All MemChunks must be aligned to
  124.                MEMCHUNK_TOTAL.
  125.             2. The end (+1) of the current MemChunk
  126.                must be lower than the start of the next one.
  127.         */
  128.         if (((ULONG)p2 | p2->mc_Bytes) & (MEMCHUNK_TOTAL - 1)
  129.             || ((UBYTE *)p2 + p2->mc_Bytes >= (UBYTE *)p2->mc_Next
  130.             && p2->mc_Next != NULL
  131.             )
  132.             )
  133.             Alert (AN_MemCorrupt|AT_DeadEnd);
  134. #endif
  135.         /* Found a block with a higher address? */
  136.         if (p2 >= p3)
  137.         {
  138. #if !defined(NO_CONSISTENCY_CHECKS)
  139.             /*
  140.             If the memory to be freed overlaps with the current
  141.             block something must be wrong.
  142.             */
  143.             if (p4 > (UBYTE *)p2)
  144.             Alert (AN_FreeTwice|AT_DeadEnd);
  145. #endif
  146.             /* End the loop with p2 non-zero */
  147.             break;
  148.         }
  149.         /* goto next block */
  150.         p1 = p2;
  151.         p2 = p2->mc_Next;
  152.  
  153.         /* If the loop ends with p2 zero add it at the end. */
  154.         } while (p2 != NULL);
  155.  
  156.         /* If there was a previous block merge with it. */
  157.         if (p1 != (struct MemChunk *)&mh->mh_First)
  158.         {
  159. #if !defined(NO_CONSISTENCY_CHECKS)
  160.         /* Check if they overlap. */
  161.         if ((UBYTE *)p1 + p1->mc_Bytes > (UBYTE *)p3)
  162.             Alert (AN_FreeTwice|AT_DeadEnd);
  163. #endif
  164.         /* Merge if possible */
  165.         if ((UBYTE *)p1 + p1->mc_Bytes == (UBYTE *)p3)
  166.             p3 = p1;
  167.         else
  168.             /* Not possible to merge */
  169.             p1->mc_Next = p3;
  170.         }else
  171.         /*
  172.             There was no previous block. Just insert the memory at
  173.             the start of the list.
  174.         */
  175.         p1->mc_Next = p3;
  176.  
  177.         /* Try to merge with next block (if there is one ;-) ). */
  178.         if (p4 == (UBYTE *)p2 && p2 != NULL)
  179.         {
  180.         /*
  181.             Overlap checking already done. Doing it here after
  182.             the list potentially changed would be a bad idea.
  183.         */
  184.         p4 += p2->mc_Bytes;
  185.         p2  = p2->mc_Next;
  186.         }
  187.  
  188.         /* relink the list and return. */
  189.         p3->mc_Next  = p2;
  190.         p3->mc_Bytes = p4 - (UBYTE *)p3;
  191.         mh->mh_Free += byteSize;
  192.  
  193.         Permit ();
  194.  
  195.         return;
  196.     }
  197.  
  198.     mh = (struct MemHeader *)mh->mh_Node.ln_Succ;
  199.     }
  200. #if !defined(NO_CONSISTENCY_CHECKS)
  201.     /* Some memory that didn't fit into any MemHeader? */
  202.     Alert (AN_MemCorrupt|AT_DeadEnd);
  203. #else
  204.     Permit ();
  205. #endif
  206.     __AROS_FUNC_EXIT
  207. } /* FreeMem */
  208.  
  209.