Support rastport clipping rectangle for layerless rastports
[tangerine.git] / rom / exec / allocmem.c
blob5cc92415d60e77e473b7a6d2d5ebc1054a661061
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Allocate some memory
6 Lang: english
7 */
8 #include <exec/alerts.h>
9 #include <exec/execbase.h>
10 #include <aros/libcall.h>
11 #include <aros/asmcall.h>
12 #include <aros/rt.h>
13 #include <aros/macros.h>
14 #include <aros/config.h>
15 #include <aros/arossupportbase.h>
16 #include "memory.h"
17 #include <exec/memory.h>
18 #include <exec/memheaderext.h>
19 #include <proto/exec.h>
21 #include <string.h>
23 #include "exec_debug.h"
24 #ifndef DEBUG_AllocMem
25 # define DEBUG_AllocMem 0
26 #endif
27 #undef DEBUG
28 #if DEBUG_AllocMem
29 # define DEBUG 1
30 #endif
31 #define MDEBUG 1
32 # include <aros/debug.h>
34 struct checkMemHandlersState
36 struct Node *cmhs_CurNode;
37 struct MemHandlerData cmhs_Data;
40 static APTR stdAlloc(struct MemHeader *mh, ULONG byteSize, ULONG requiements);
41 static ULONG checkMemHandlers(struct checkMemHandlersState *cmhs);
43 /*****************************************************************************
45 NAME */
47 AROS_LH2(APTR, AllocMem,
49 /* SYNOPSIS */
50 AROS_LHA(ULONG, byteSize, D0),
51 AROS_LHA(ULONG, requirements, D1),
53 /* LOCATION */
54 struct ExecBase *, SysBase, 33, Exec)
56 /* FUNCTION
57 Allocate some memory from the sytem memory pool with the given
58 requirements.
60 INPUTS
61 byteSize - Number of bytes you want to get
62 requirements - Type of memory
64 RESULT
65 A pointer to the number of bytes you wanted or NULL if the memory
66 couldn't be allocated
68 NOTES
69 The memory is aligned to sizeof(struct MemChunk). All requests
70 are rounded up to a multiple of that size.
72 EXAMPLE
73 mytask=(struct Task *)AllocMem(sizeof(struct Task),MEMF_PUBLIC|MEMF_CLEAR);
75 BUGS
77 SEE ALSO
78 FreeMem()
80 INTERNALS
82 ******************************************************************************/
84 AROS_LIBFUNC_INIT
86 APTR res = NULL;
87 struct checkMemHandlersState cmhs;
89 #if ENABLE_RT || AROS_MUNGWALL_DEBUG
90 ULONG origSize = byteSize;
91 ULONG origRequirements = requirements;
92 #endif
94 D(bug("Call AllocMem (%d, %08lx)\n", byteSize, requirements));
96 /* Zero bytes requested? May return everything ;-). */
97 if(!byteSize)
98 return NULL;
100 #if AROS_MUNGWALL_DEBUG
101 /* Make room for safety walls around allocated block and an some more extra space
102 for other interesting things, actually --> the size.
104 This all will look like this:
106 [MEMCHUNK_FOR_EXTRA_STUFF][BEFORE-MUNGWALL][<alloced-memory-for-user>][AFTER_MUNGWALL]
108 The first ULONG in MEMCHUNK_FOR_EXTRA_STUFF is used to save the original alloc
109 size (byteSize) param. So it is possible in FreeMem to check, if freemem size
110 matches allocmem size or not.
113 byteSize += MUNGWALL_SIZE * 2 + MUNGWALLHEADER_SIZE;
114 #endif /* AROS_MUNGWALL_DEBUG */
116 /* First round byteSize to a multiple of MEMCHUNK_TOTAL */
117 byteSize = AROS_ROUNDUP2(byteSize, MEMCHUNK_TOTAL);
119 cmhs.cmhs_CurNode = (struct Node *)SysBase->ex_MemHandlers.mlh_Head;
120 cmhs.cmhs_Data.memh_RequestSize = byteSize;
121 cmhs.cmhs_Data.memh_RequestFlags = requirements;
122 cmhs.cmhs_Data.memh_Flags = 0;
124 /* Protect memory list against other tasks */
125 Forbid();
129 struct MemHeader *mh;
131 /* Loop over MemHeader structures */
132 ForeachNode(&SysBase->MemList, mh)
135 Check for the right requirements and enough free memory.
136 The requirements are OK if there's no bit in the
137 'attributes' that isn't set in the 'mh->mh_Attributes'.
138 MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
139 as if they were always set in the memheader.
141 if((requirements & ~(MEMF_CLEAR|MEMF_REVERSE|
142 MEMF_NO_EXPUNGE|mh->mh_Attributes))
143 || mh->mh_Free < byteSize)
144 continue;
146 if (mh->mh_Attributes & MEMF_MANAGED)
148 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
149 if (mhe->mhe_Alloc)
150 res = mhe->mhe_Alloc(mhe, byteSize, &requirements);
152 else
154 res = stdAlloc(mh, byteSize, requirements);
156 if (res)
157 break;
159 } while (res == NULL && checkMemHandlers(&cmhs) == MEM_TRY_AGAIN);
161 Permit();
164 if(res && (requirements & MEMF_CLEAR))
165 memset(res, 0, byteSize);
167 #if ENABLE_RT
168 RT_Add (RTT_MEMORY, res, origSize);
169 #endif
171 #if AROS_MUNGWALL_DEBUG
172 requirements = origRequirements;
174 if (res)
176 struct MungwallHeader *header;
177 struct List *allocmemlist;
179 /* Save orig byteSize before wall (there is one room of MUNGWALLHEADER_SIZE
180 bytes before wall for such stuff (see above).
183 header = (struct MungwallHeader *)res;
185 header->mwh_magicid = MUNGWALL_HEADER_ID;
186 header->mwh_allocsize = origSize;
188 /* Check whether list does exist. AllocMem() might have been
189 called before PrepareAROSSupportBase() which is responsible for
190 initialization of AllocMemList */
192 if (SysBase->DebugAROSBase)
194 allocmemlist = (struct List *)&((struct AROSSupportBase *)SysBase->DebugAROSBase)->AllocMemList;
195 Forbid();
196 AddHead(allocmemlist, (struct Node *)&header->mwh_node);
197 Permit();
199 else
201 header->mwh_node.mln_Pred = (struct MinNode *)0x44332211;
202 header->mwh_node.mln_Succ = (struct MinNode *)0xCCBBAA99;
205 /* Skip to the start of the pre-wall */
206 res += MUNGWALLHEADER_SIZE;
208 /* Initialize pre-wall */
209 BUILD_WALL(res, 0xDB, MUNGWALL_SIZE);
211 /* move over the block between the walls */
212 res += MUNGWALL_SIZE;
214 /* Fill the block with weird stuff to exploit bugs in applications */
215 if (!(requirements & MEMF_CLEAR))
216 MUNGE_BLOCK(res, MEMFILL_ALLOC, byteSize - MUNGWALL_SIZE * 2 - MEMCHUNK_TOTAL);
218 /* Initialize post-wall */
219 BUILD_WALL(res + origSize, 0xDB, MUNGWALL_SIZE + AROS_ROUNDUP2(origSize, MEMCHUNK_TOTAL) - origSize);
221 #endif /* AROS_MUNGWALL_DEBUG */
223 ReturnPtr ("AllocMem", APTR, res);
225 AROS_LIBFUNC_EXIT
227 } /* AllocMem */
230 static APTR stdAlloc(struct MemHeader *mh, ULONG byteSize, ULONG requirements)
232 struct MemChunk *mc=NULL, *p1, *p2;
235 The free memory list is only single linked, i.e. to remove
236 elements from the list I need node's predessor. For the
237 first element I can use mh->mh_First instead of a real predessor.
239 p1 = (struct MemChunk *)&mh->mh_First;
240 p2 = p1->mc_Next;
242 /* Is there anything in the list? */
243 if (p2 != NULL)
245 /* Then follow it */
246 for (;;)
248 #if !defined(NO_CONSISTENCY_CHECKS)
249 /* Consistency check: Check alignment restrictions */
250 if( ((IPTR)p2|(ULONG)p2->mc_Bytes)
251 & (MEMCHUNK_TOTAL-1) )
252 Alert(AN_MemCorrupt|AT_DeadEnd);
253 #endif
255 /* Check if the current block is large enough */
256 if(p2->mc_Bytes>=byteSize)
258 /* It is. */
259 mc=p1;
260 /* Use this one if MEMF_REVERSE is not set.*/
261 if(!(requirements&MEMF_REVERSE))
262 break;
263 /* Else continue - there may be more to come. */
266 /* Go to next block */
267 p1=p2;
268 p2=p1->mc_Next;
270 /* Check if this was the end */
271 if(p2==NULL)
272 break;
273 #if !defined(NO_CONSISTENCY_CHECKS)
275 Consistency check:
276 If the end of the last block+1 is bigger or equal to
277 the start of the current block something must be wrong.
279 if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
280 Alert(AN_MemCorrupt|AT_DeadEnd);
281 #endif
284 /* Something found? */
285 if (mc != NULL)
288 Remember: if MEMF_REVERSE is set
289 p1 and p2 are now invalid.
291 p1=mc;
292 p2=p1->mc_Next;
294 /* Remove the block from the list and return it. */
295 if(p2->mc_Bytes == byteSize)
297 /* Fits exactly. Just relink the list. */
298 p1->mc_Next = p2->mc_Next;
299 mc = p2;
301 else
303 if(requirements & MEMF_REVERSE)
305 /* Return the last bytes. */
306 p1->mc_Next=p2;
307 mc=(struct MemChunk *)((UBYTE *)p2+p2->mc_Bytes-byteSize);
309 else
311 /* Return the first bytes. */
312 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
313 mc=p2;
316 p1 = p1->mc_Next;
317 p1->mc_Next = p2->mc_Next;
318 p1->mc_Bytes = p2->mc_Bytes-byteSize;
321 mh->mh_Free -= byteSize;
325 return mc;
328 ULONG checkMemHandlers(struct checkMemHandlersState *cmhs)
330 struct Node *tmp;
331 struct Interrupt *lmh;
333 if (cmhs->cmhs_Data.memh_RequestFlags & MEMF_NO_EXPUNGE)
334 return MEM_DID_NOTHING;
336 /* Loop over low memory handlers. Handlers can remove
337 themselves from the list while being invoked, thus
338 we need to be careful! */
341 lmh = (struct Interrupt *)cmhs->cmhs_CurNode;
342 (tmp = lmh->is_Node.ln_Succ);
343 lmh = (struct Interrupt *)(cmhs->cmhs_CurNode = tmp)
346 ULONG ret;
348 ret = AROS_UFC3 (LONG, lmh->is_Code,
349 AROS_UFCA(struct MemHandlerData *, &cmhs->cmhs_Data, A0),
350 AROS_UFCA(APTR, lmh->is_Data, A1),
351 AROS_UFCA(struct ExecBase *, SysBase, A6)
354 if (ret == MEM_TRY_AGAIN)
356 /* MemHandler said he did something. Try again. */
357 /* Is there any program that depends on this flag??? */
358 cmhs->cmhs_Data.memh_Flags |= MEMHF_RECYCLE;
359 return MEM_TRY_AGAIN;
361 else
363 /* Nothing more to expect from this handler. */
364 cmhs->cmhs_Data.memh_Flags &= ~MEMHF_RECYCLE;
368 return MEM_DID_NOTHING;