Updated PCI IDs to latest snapshot.
[tangerine.git] / rom / exec / allocate.c
blobac68b68efeefd7d6e32d68dd1e3640c6b3060e34
1 /*
2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
3 $Id$
5 Allocate memory from a specific MemHeader.
6 */
8 #include "exec_intern.h"
9 #include "memory.h"
10 #include <exec/alerts.h>
11 #include <aros/libcall.h>
12 #include <aros/macros.h>
13 #include <exec/memory.h>
14 #include <proto/exec.h>
16 /*****************************************************************************
18 NAME */
20 AROS_LH2(APTR, Allocate,
22 /* SYNOPSIS */
23 AROS_LHA(struct MemHeader *, freeList, A0),
24 AROS_LHA(ULONG, byteSize, D0),
26 /* LOCATION */
27 struct ExecBase *, SysBase, 31, Exec)
29 /* FUNCTION
30 Allocate memory out of a private region handled by the MemHeader
31 structure.
33 INPUTS
34 freeList - Pointer to the MemHeader structure which holds the memory
35 byteSize - Number of bytes you want to get
37 RESULT
38 A pointer to the number of bytes you wanted or NULL if the memory
39 couldn't be allocated
41 NOTES
42 The memory is aligned to sizeof(struct MemChunk). All requests
43 are rounded up to a multiple of that size.
45 EXAMPLE
46 #define POOLSIZE 4096
47 \* Get a MemHeader structure and some private memory *\
48 mh=(struct MemHeader *)
49 AllocMem(sizeof(struct MemHeader)+POOLSIZE,MEMF_ANY);
50 if(mh!=NULL)
52 \* Build a private pool *\
53 mh->mh_First=(struct MemChunk *)(mh+1);
54 mh->mh_First->mc_Next=NULL;
55 mh->mh_First->mc_Bytes=POOLSIZE;
56 mh->mh_Free=POOLSIZE;
58 \* Use the pool *\
59 UBYTE *mem1,*mem2;
60 mem1=Allocate(mh,1000);
61 mem2=Allocate(mh,2000);
62 \* Do something with memory... *\
64 \* Free everything at once *\
65 FreeMem(mh,sizeof(struct MemHeader)+POOLSIZE);
68 BUGS
70 SEE ALSO
71 Deallocate()
73 INTERNALS
75 ******************************************************************************/
77 AROS_LIBFUNC_INIT
79 struct MemChunk *p1, *p2;
81 ASSERT_VALID_PTR(freeList);
84 /* Zero bytes requested? May return everything ;-). */
85 if(!byteSize)
86 return NULL;
88 /* First round byteSize to a multiple of MEMCHUNK_TOTAL. */
89 byteSize=AROS_ROUNDUP2(byteSize,MEMCHUNK_TOTAL);
91 /* Is there enough free memory in the list? */
92 if(freeList->mh_Free<byteSize)
93 return NULL;
96 The free memory list is only single linked, i.e. to remove
97 elements from 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 predecessor.
101 p1=(struct MemChunk *)&freeList->mh_First;
102 p2=p1->mc_Next;
104 /* Is the list enpty? */
105 if(p2==NULL)
106 return NULL;
108 /* Follow the list */
109 for(;;)
111 #if !defined(NO_CONSISTENCY_CHECKS)
112 /* Consistency check: Check alignment restrictions */
113 if( ((IPTR)p2|(ULONG)p2->mc_Bytes) & (MEMCHUNK_TOTAL-1) )
115 if (SysBase != NULL) Alert(AN_MemCorrupt);
116 return NULL;
118 #endif
119 /* Check if current block is large enough */
120 if(p2->mc_Bytes>=byteSize)
122 /* It is. Remove it from the list and return it. */
123 if(p2->mc_Bytes==byteSize)
124 /* Fits exactly. Just relink the list. */
125 p1->mc_Next=p2->mc_Next;
126 else
128 /* Split the current chunk and return the first bytes. */
129 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
130 p1=p1->mc_Next;
131 p1->mc_Next=p2->mc_Next;
132 p1->mc_Bytes=p2->mc_Bytes-byteSize;
134 /* Adjust free memory count and return */
135 freeList->mh_Free-=byteSize;
137 /* Fill the block with weird stuff to exploit bugs in applications */
138 MUNGE_BLOCK(p2,MEMFILL_ALLOC,byteSize);
140 /* Return allocated block to caller */
141 return p2;
144 /* Go to next block */
145 p1=p2;
146 p2=p1->mc_Next;
148 /* Check if this was the end */
149 if(p2==NULL)
150 return NULL;
151 #if !defined(NO_CONSISTENCY_CHECKS)
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.
157 if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
159 if (SysBase != NULL) Alert(AN_MemCorrupt);
160 return NULL;
162 #endif
164 AROS_LIBFUNC_EXIT
165 } /* Allocate() */