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

  1. /*
  2.     (C) 1995 AROS - The Amiga Replacement OS
  3.     $Id: allocmem.c 1.1 1995/11/14 22:31:07 digulla Exp digulla $
  4.     $Log: allocmem.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 <aros/abscall.h>
  14. #include <exec/alerts.h>
  15.  
  16. typedef LONG (*LowMemHandlerPtr)(struct MemHandlerData *mhd,APTR data);
  17.  
  18. /*****************************************************************************
  19.  
  20.     NAME */
  21.     #include <exec/memory.h>
  22.     #include <clib/exec_protos.h>
  23.  
  24.     __AROS_LH2(APTR, AllocMem,
  25.  
  26. /*  SYNOPSIS */
  27.     __AROS_LA(unsigned long, byteSize, D0),
  28.     __AROS_LA(unsigned long, requirements, D1),
  29.  
  30. /*  LOCATION */
  31.     struct ExecBase *, SysBase, 33, Exec)
  32.  
  33. /*  FUNCTION
  34.     Allocate some memory from the sytem memory pool with the given
  35.     requirements.
  36.  
  37.     INPUTS
  38.     byteSize     - Number of bytes you want to get
  39.     requirements - Type of memory
  40.  
  41.     RESULT
  42.     A pointer to the number of bytes you wanted or NULL if the memory
  43.     couldn't be allocated
  44.  
  45.     NOTES
  46.     The memory is aligned to sizeof(struct MemChunk). All requests
  47.     are rounded up to a multiple of that size.
  48.  
  49.     EXAMPLE
  50.     mytask=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
  51.  
  52.     BUGS
  53.  
  54.     SEE ALSO
  55.     FreeMem()
  56.  
  57.     INTERNALS
  58.  
  59.     HISTORY
  60.     08-10-95    created by m. fleischer
  61.     16-10-95    increased portability
  62.     20-10-95    digulla lmhd has been auto-initialized with non-constant
  63.             values -> initialized by hand.
  64.     26-10-95    digulla adjusted to new calling scheme
  65.  
  66. ******************************************************************************/
  67. {
  68.     __AROS_FUNC_INIT
  69.     struct Interrupt *lmh;
  70.     struct MemHandlerData lmhd;
  71.  
  72.     /* Zero bytes requested? May return everything ;-). */
  73.     if(!byteSize)
  74.     return NULL;
  75.  
  76.     /* Initialize lmhd */
  77.     lmhd.memh_RequestSize  = byteSize;
  78.     lmhd.memh_RequestFlags = requirements;
  79.     lmhd.memh_Flags       = 0;
  80.  
  81.     /* First round byteSize to a multiple of MEMCHUNK_TOTAL. */
  82.     byteSize=(byteSize+MEMCHUNK_TOTAL-1)&~(MEMCHUNK_TOTAL-1);
  83.  
  84.     /* Protect memory list against other tasks */
  85.     Forbid();
  86.  
  87.     /* Loop over low memory handlers */
  88.     lmh=(struct Interrupt *)SysBase->ex_MemHandlers.mlh_Head;
  89.     for(;;)
  90.     {
  91.     struct MemHeader *mh;
  92.     ULONG lmhr;
  93.  
  94.     /* Loop over MemHeader structures */
  95.     mh=(struct MemHeader *)SysBase->MemList.lh_Head;
  96.     while(mh->mh_Node.ln_Succ!=NULL)
  97.     {
  98.         struct MemChunk *p1,*p2;
  99.  
  100.         /*
  101.         Check for the right requirements and enough free memory.
  102.         The requirements are OK if there's no bit in the
  103.         'attributes' that isn't set in the 'mh->mh_Attributes'.
  104.         MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
  105.         as if they were always set in the memheader.
  106.         */
  107.         if(!(requirements&~(MEMF_CLEAR|MEMF_REVERSE|
  108.                 MEMF_NO_EXPUNGE|mh->mh_Attributes))
  109.            &&mh->mh_Free>=byteSize)
  110.         {
  111.         struct MemChunk *mc=NULL;
  112.  
  113.         /*
  114.             The free memory list is only single linked, i.e. to remove
  115.             elements from the list I need node's predessor. For the
  116.             first element I can use mh->mh_First instead of a real predessor.
  117.         */
  118.         p1=(struct MemChunk *)&mh->mh_First;
  119.         p2=p1->mc_Next;
  120.  
  121.         /* Is there anything in the list? */
  122.         if(p2!=NULL)
  123.         {
  124.             /* Then follow it */
  125.             for(;;)
  126.             {
  127. #if !defined(NO_CONSISTENCY_CHECKS)
  128.             /* Consistency check: Check alignment restrictions */
  129.             if( ((ULONG)p2|(ULONG)p2->mc_Bytes)
  130.                & (MEMCHUNK_TOTAL-1) )
  131.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  132. #endif
  133.             /* Check if the current block is large enough */
  134.             if(p2->mc_Bytes>=byteSize)
  135.             {
  136.                 /* It is. */
  137.                 mc=p1;
  138.                 /* Use this one if MEMF_REVERSE is not set.*/
  139.                 if(!(requirements&MEMF_REVERSE))
  140.                 break;
  141.                 /* Else continue - there may be more to come. */
  142.             }
  143.  
  144.             /* Go to next block */
  145.             p1=p2;
  146.             p2=p1->mc_Next;
  147.  
  148.             /* Check if this was the end */
  149.             if(p2==NULL)
  150.                 break;
  151. #if !defined(NO_CONSISTENCY_CHECKS)
  152.             /*
  153.                 Consistency check:
  154.                 If the end of the last block+1 is bigger or equal to
  155.                 the start of the current block something must be wrong.
  156.             */
  157.             if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
  158.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  159. #endif
  160.             }
  161.             /* Something found? */
  162.             if(mc!=NULL)
  163.             {
  164.             /*
  165.                 Remember: if MEMF_REVERSE is set
  166.                 p1 and p2 are now invalid.
  167.             */
  168.             p1=mc;
  169.             p2=p1->mc_Next;
  170.  
  171.             /* Remove the block from the list and return it. */
  172.             if(p2->mc_Bytes==byteSize)
  173.             {
  174.                 /* Fits exactly. Just relink the list. */
  175.                 p1->mc_Next=p2->mc_Next;
  176.                 mc=p2;
  177.             }else
  178.             {
  179.                 if(requirements&MEMF_REVERSE)
  180.                 {
  181.                 /* Return the last bytes. */
  182.                 p1->mc_Next=p2;
  183.                 mc=(struct MemChunk *)((UBYTE *)p2+byteSize);
  184.                 }else
  185.                 {
  186.                 /* Return the first bytes. */
  187.                 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
  188.                 mc=p2;
  189.                 }
  190.                 p1=p1->mc_Next;
  191.                 p1->mc_Next=p2->mc_Next;
  192.                 p1->mc_Bytes=p2->mc_Bytes-byteSize;
  193.             }
  194.             mh->mh_Free-=byteSize;
  195.  
  196.             /* No need to forbid dispatching any longer. */
  197.             Permit();
  198.             if(requirements&MEMF_CLEAR)
  199.             {
  200.                 /* Clear memory. */
  201.                 ULONG cnt,*p;
  202.  
  203.                 p=(ULONG *)mc;
  204.                 cnt=byteSize/sizeof(ULONG);
  205.  
  206.                 while(cnt--)
  207.                 *p++=0;
  208.             }
  209.             return mc;
  210.             }
  211.         }
  212.         }
  213.         /* Go to next memory header */
  214.         mh=(struct MemHeader *)mh->mh_Node.ln_Succ;
  215.     }
  216.  
  217.     /* Is it forbidden to call low-memory handlers? */
  218.     if(requirements&MEMF_NO_EXPUNGE)
  219.     {
  220.         Permit();
  221.         return NULL;
  222.     }
  223.  
  224.     /* All memory headers done. Check low memory handlers. */
  225.     do
  226.     {
  227.         /* Is there another one? */
  228.         if(lmh->is_Node.ln_Succ==NULL)
  229.         {
  230.         /* No. return 'Not enough memory'. */
  231.         Permit();
  232.         return NULL;
  233.         }
  234.         /* Yes. Execute it. */
  235.         lmhr=__AROS_AC3(LONG,lmh->is_Code,
  236.         __AROS_ACA(struct MemHandlerData *, &lmhd,        A0),
  237.         __AROS_ACA(APTR,                    lmh->is_Data, A1),
  238.         __AROS_ACA(struct ExecBase *,       SysBase,      A6));
  239.  
  240.         /* Check returncode. */
  241.         if(lmhr==MEM_TRY_AGAIN)
  242.         {
  243.         /* MemHandler said he did something. Try again. */
  244.         /* Is there any program that depends on this flag??? */
  245.         lmhd.memh_Flags|=MEMHF_RECYCLE;
  246.         break;
  247.         }
  248.         /* Nothing more to expect from this handler. */
  249.         lmh=(struct Interrupt *)lmh->is_Node.ln_Succ;
  250.         lmhd.memh_Flags&=~MEMHF_RECYCLE;
  251.  
  252.     /*
  253.         If this handler did nothing at all there's no need
  254.         to try the allocation. Try the next handler immediately.
  255.     */
  256.     }while(lmhr==MEM_DID_NOTHING);
  257.     }
  258.     __AROS_FUNC_EXIT
  259. } /* AllocMem */
  260.  
  261.