home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / misc / emu / AROSdev.lha / AROS / rom / exec / allocmem.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-10  |  7.3 KB  |  310 lines

  1. /*
  2.     (C) 1995-96 AROS - The Amiga Replacement OS
  3.     $Id: allocmem.c,v 1.12 1997/01/10 04:06:49 ldp Exp $
  4.     $Log: allocmem.c,v $
  5.     Revision 1.12  1997/01/10 04:06:49  ldp
  6.     Added <aros/libcall.h>
  7.  
  8.     Revision 1.11  1997/01/01 03:46:05  ldp
  9.     Committed Amiga native (support) code
  10.  
  11.     Changed clib to proto
  12.  
  13.     Revision 1.10  1996/12/10 13:51:37  aros
  14.     Moved all #include's in the first column so makedepend can see it.
  15.  
  16.     Revision 1.9  1996/10/24 15:50:44  aros
  17.     Use the official AROS macros over the __AROS versions.
  18.  
  19.     Revision 1.8  1996/10/19 17:07:24  aros
  20.     Include <aros/machine.h> instead of machine.h
  21.  
  22.     Revision 1.7  1996/09/13 17:51:22  digulla
  23.     Use IPTR
  24.  
  25.     Revision 1.6  1996/08/23 17:06:56  digulla
  26.     Began work on ressource tracking
  27.  
  28.     Revision 1.5  1996/08/16 14:05:12  digulla
  29.     Added debug output
  30.  
  31.     Revision 1.4  1996/08/13 13:55:57  digulla
  32.     Replaced AROS_LA by AROS_LHA
  33.     Replaced some AROS_LH*I by AROS_LH*
  34.     Sorted and added includes
  35.  
  36.     Revision 1.3  1996/08/01 17:41:04  digulla
  37.     Added standard header for all files
  38.  
  39.     Desc:
  40.     Lang:
  41. */
  42. #include <exec/alerts.h>
  43. #include <exec/execbase.h>
  44. #include <aros/libcall.h>
  45. #include <aros/asmcall.h>
  46. #include <aros/rt.h>
  47. #include <aros/machine.h>
  48. #include "memory.h"
  49. #include <exec/memory.h>
  50. #include <proto/exec.h>
  51.  
  52. #include "exec_debug.h"
  53. #ifndef DEBUG_AllocMem
  54. #   define DEBUG_AllocMem 0
  55. #endif
  56. #if DEBUG_AllocMem
  57. #   undef DEBUG
  58. #   define DEBUG 1
  59. #endif
  60. #include <aros/debug.h>
  61.  
  62. /*****************************************************************************
  63.  
  64.     NAME */
  65.  
  66.     AROS_LH2(APTR, AllocMem,
  67.  
  68. /*  SYNOPSIS */
  69.     AROS_LHA(ULONG, byteSize,     D0),
  70.     AROS_LHA(ULONG, requirements, D1),
  71.  
  72. /* LOCATION */
  73.     struct ExecBase *, SysBase, 33, Exec)
  74.  
  75. /*  FUNCTION
  76.     Allocate some memory from the sytem memory pool with the given
  77.     requirements.
  78.  
  79.     INPUTS
  80.     byteSize     - Number of bytes you want to get
  81.     requirements - Type of memory
  82.  
  83.     RESULT
  84.     A pointer to the number of bytes you wanted or NULL if the memory
  85.     couldn't be allocated
  86.  
  87.     NOTES
  88.     The memory is aligned to sizeof(struct MemChunk). All requests
  89.     are rounded up to a multiple of that size.
  90.  
  91.     EXAMPLE
  92.     mytask=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
  93.  
  94.     BUGS
  95.  
  96.     SEE ALSO
  97.     FreeMem()
  98.  
  99.     INTERNALS
  100.  
  101.     HISTORY
  102.     8-10-95    created by m. fleischer
  103.        16-10-95    increased portability
  104.  
  105. ******************************************************************************/
  106. {
  107.     AROS_LIBFUNC_INIT
  108.     struct Interrupt *lmh;
  109.     struct MemHandlerData lmhd={ byteSize,requirements,0 };
  110.     APTR res = NULL;
  111. #if ENABLE_RT
  112.     ULONG origSize = byteSize;
  113. #endif
  114.  
  115.     D(bug("Call AllocMem (%d, %08lx)\n", byteSize, requirements));
  116.  
  117.     /* Zero bytes requested? May return everything ;-). */
  118.     if(!byteSize)
  119.     goto end;
  120.  
  121.     /* First round byteSize to a multiple of MEMCHUNK_TOTAL. */
  122.     byteSize=(byteSize+MEMCHUNK_TOTAL-1)&~(MEMCHUNK_TOTAL-1);
  123.  
  124.     /* Protect memory list against other tasks */
  125.     Forbid();
  126.  
  127.     /* Loop over low memory handlers */
  128.     lmh=(struct Interrupt *)SysBase->ex_MemHandlers.mlh_Head;
  129.     for(;;)
  130.     {
  131.     struct MemHeader *mh;
  132.     ULONG lmhr;
  133.  
  134.     /* Loop over MemHeader structures */
  135.     mh=(struct MemHeader *)SysBase->MemList.lh_Head;
  136.     while(mh->mh_Node.ln_Succ!=NULL)
  137.     {
  138.         struct MemChunk *p1,*p2;
  139.  
  140.         /*
  141.         Check for the right requirements and enough free memory.
  142.         The requirements are OK if there's no bit in the
  143.         'attributes' that isn't set in the 'mh->mh_Attributes'.
  144.         MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
  145.         as if they were always set in the memheader.
  146.         */
  147.         if(!(requirements&~(MEMF_CLEAR|MEMF_REVERSE|
  148.                 MEMF_NO_EXPUNGE|mh->mh_Attributes))
  149.            &&mh->mh_Free>=byteSize)
  150.         {
  151.         struct MemChunk *mc=NULL;
  152.  
  153.         /*
  154.             The free memory list is only single linked, i.e. to remove
  155.             elements from the list I need node's predessor. For the
  156.             first element I can use mh->mh_First instead of a real predessor.
  157.         */
  158.         p1=(struct MemChunk *)&mh->mh_First;
  159.         p2=p1->mc_Next;
  160.  
  161.         /* Is there anything in the list? */
  162.         if(p2!=NULL)
  163.         {
  164.             /* Then follow it */
  165.             for(;;)
  166.             {
  167. #if !defined(NO_CONSISTENCY_CHECKS)
  168.             /* Consistency check: Check alignment restrictions */
  169.             if( ((IPTR)p2|(ULONG)p2->mc_Bytes)
  170.                & (MEMCHUNK_TOTAL-1) )
  171.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  172. #endif
  173.             /* Check if the current block is large enough */
  174.             if(p2->mc_Bytes>=byteSize)
  175.             {
  176.                 /* It is. */
  177.                 mc=p1;
  178.                 /* Use this one if MEMF_REVERSE is not set.*/
  179.                 if(!(requirements&MEMF_REVERSE))
  180.                 break;
  181.                 /* Else continue - there may be more to come. */
  182.             }
  183.  
  184.             /* Go to next block */
  185.             p1=p2;
  186.             p2=p1->mc_Next;
  187.  
  188.             /* Check if this was the end */
  189.             if(p2==NULL)
  190.                 break;
  191. #if !defined(NO_CONSISTENCY_CHECKS)
  192.             /*
  193.                 Consistency check:
  194.                 If the end of the last block+1 is bigger or equal to
  195.                 the start of the current block something must be wrong.
  196.             */
  197.             if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
  198.                 Alert(AN_MemCorrupt|AT_DeadEnd);
  199. #endif
  200.             }
  201.             /* Something found? */
  202.             if(mc!=NULL)
  203.             {
  204.             /*
  205.                 Remember: if MEMF_REVERSE is set
  206.                 p1 and p2 are now invalid.
  207.             */
  208.             p1=mc;
  209.             p2=p1->mc_Next;
  210.  
  211.             /* Remove the block from the list and return it. */
  212.             if(p2->mc_Bytes==byteSize)
  213.             {
  214.                 /* Fits exactly. Just relink the list. */
  215.                 p1->mc_Next=p2->mc_Next;
  216.                 mc=p2;
  217.             }else
  218.             {
  219.                 if(requirements&MEMF_REVERSE)
  220.                 {
  221.                 /* Return the last bytes. */
  222.                 p1->mc_Next=p2;
  223.                 mc=(struct MemChunk *)((UBYTE *)p2+byteSize);
  224.                 }else
  225.                 {
  226.                 /* Return the first bytes. */
  227.                 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
  228.                 mc=p2;
  229.                 }
  230.                 p1=p1->mc_Next;
  231.                 p1->mc_Next=p2->mc_Next;
  232.                 p1->mc_Bytes=p2->mc_Bytes-byteSize;
  233.             }
  234.             mh->mh_Free-=byteSize;
  235.  
  236.             /* No need to forbid dispatching any longer. */
  237.             Permit();
  238.             if(requirements&MEMF_CLEAR)
  239.             {
  240.                 /* Clear memory. */
  241.                 ULONG cnt,*p;
  242.  
  243.                 p=(ULONG *)mc;
  244.                 cnt=byteSize/sizeof(ULONG);
  245.  
  246.                 while(cnt--)
  247.                 *p++=0;
  248.             }
  249.             res=mc;
  250.             goto end;
  251.             }
  252.         }
  253.         }
  254.         /* Go to next memory header */
  255.         mh=(struct MemHeader *)mh->mh_Node.ln_Succ;
  256.     }
  257.  
  258.     /* Is it forbidden to call low-memory handlers? */
  259.     if(requirements&MEMF_NO_EXPUNGE)
  260.     {
  261.         Permit();
  262.         goto end;
  263.     }
  264.  
  265.     /* All memory headers done. Check low memory handlers. */
  266.     do
  267.     {
  268.         /* Is there another one? */
  269.         if(lmh->is_Node.ln_Succ==NULL)
  270.         {
  271.         /* No. return 'Not enough memory'. */
  272.         Permit();
  273.         goto end;
  274.         }
  275.         /* Yes. Execute it. */
  276.         lmhr = AROS_UFC3 (LONG, lmh->is_Code,
  277.         AROS_UFCA(struct MemHandlerData *,&lmhd,A0),
  278.         AROS_UFCA(APTR,lmh->is_Data,A1),
  279.         AROS_UFCA(struct ExecBase *,SysBase,A6)
  280.         );
  281.  
  282.         /* Check returncode. */
  283.         if(lmhr==MEM_TRY_AGAIN)
  284.         {
  285.         /* MemHandler said he did something. Try again. */
  286.         /* Is there any program that depends on this flag??? */
  287.         lmhd.memh_Flags|=MEMHF_RECYCLE;
  288.         break;
  289.         }
  290.         /* Nothing more to expect from this handler. */
  291.         lmh=(struct Interrupt *)lmh->is_Node.ln_Succ;
  292.         lmhd.memh_Flags&=~MEMHF_RECYCLE;
  293.  
  294.     /*
  295.         If this handler did nothing at all there's no need
  296.         to try the allocation. Try the next handler immediately.
  297.     */
  298.     }while(lmhr==MEM_DID_NOTHING);
  299.     }
  300.  
  301. end:
  302. #if ENABLE_RT
  303.     RT_Add (RTT_MEMORY, res, origSize);
  304. #endif
  305.  
  306.     ReturnPtr ("AllocMem", APTR, res);
  307.     AROS_LIBFUNC_EXIT
  308. } /* AllocMem */
  309.  
  310.