added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / rom / exec / allocmem.c
blob204215e134ee5b469707eb34896b10cfd5140c21
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(if (SysBase->DebugAROSBase))
95 D(bug("Call AllocMem (%d, %08x)\n", byteSize, requirements));
97 /* Zero bytes requested? May return everything ;-). */
98 if(!byteSize)
99 return NULL;
101 #if AROS_MUNGWALL_DEBUG
102 /* Make room for safety walls around allocated block and an some more extra space
103 for other interesting things, actually --> the size.
105 This all will look like this:
107 [MEMCHUNK_FOR_EXTRA_STUFF][BEFORE-MUNGWALL][<alloced-memory-for-user>][AFTER_MUNGWALL]
109 The first ULONG in MEMCHUNK_FOR_EXTRA_STUFF is used to save the original alloc
110 size (byteSize) param. So it is possible in FreeMem to check, if freemem size
111 matches allocmem size or not.
114 byteSize += MUNGWALL_SIZE * 2 + MUNGWALLHEADER_SIZE;
115 #endif /* AROS_MUNGWALL_DEBUG */
117 /* First round byteSize to a multiple of MEMCHUNK_TOTAL */
118 byteSize = AROS_ROUNDUP2(byteSize, MEMCHUNK_TOTAL);
120 cmhs.cmhs_CurNode = (struct Node *)SysBase->ex_MemHandlers.mlh_Head;
121 cmhs.cmhs_Data.memh_RequestSize = byteSize;
122 cmhs.cmhs_Data.memh_RequestFlags = requirements;
123 cmhs.cmhs_Data.memh_Flags = 0;
125 /* Protect memory list against other tasks */
126 Forbid();
130 struct MemHeader *mh;
132 /* Loop over MemHeader structures */
133 ForeachNode(&SysBase->MemList, mh)
136 Check for the right requirements and enough free memory.
137 The requirements are OK if there's no bit in the
138 'attributes' that isn't set in the 'mh->mh_Attributes'.
139 MEMF_CLEAR, MEMF_REVERSE and MEMF_NO_EXPUNGE are treated
140 as if they were always set in the memheader.
142 if((requirements & ~(MEMF_CLEAR|MEMF_REVERSE|
143 MEMF_NO_EXPUNGE|mh->mh_Attributes))
144 || mh->mh_Free < byteSize)
145 continue;
147 if (mh->mh_Attributes & MEMF_MANAGED)
149 struct MemHeaderExt *mhe = (struct MemHeaderExt *)mh;
150 if (mhe->mhe_Alloc)
151 res = mhe->mhe_Alloc(mhe, byteSize, &requirements);
153 else
155 res = stdAlloc(mh, byteSize, requirements);
157 if (res)
158 break;
160 } while (res == NULL && checkMemHandlers(&cmhs) == MEM_TRY_AGAIN);
162 Permit();
165 if(res && (requirements & MEMF_CLEAR))
166 memset(res, 0, byteSize);
168 #if ENABLE_RT
169 RT_Add (RTT_MEMORY, res, origSize);
170 #endif
172 #if AROS_MUNGWALL_DEBUG
173 requirements = origRequirements;
175 if (res)
177 struct MungwallHeader *header;
178 struct List *allocmemlist;
180 /* Save orig byteSize before wall (there is one room of MUNGWALLHEADER_SIZE
181 bytes before wall for such stuff (see above).
184 header = (struct MungwallHeader *)res;
186 header->mwh_magicid = MUNGWALL_HEADER_ID;
187 header->mwh_allocsize = origSize;
189 /* Check whether list does exist. AllocMem() might have been
190 called before PrepareAROSSupportBase() which is responsible for
191 initialization of AllocMemList */
193 if (SysBase->DebugAROSBase)
195 allocmemlist = (struct List *)&((struct AROSSupportBase *)SysBase->DebugAROSBase)->AllocMemList;
196 Forbid();
197 AddHead(allocmemlist, (struct Node *)&header->mwh_node);
198 Permit();
200 else
202 header->mwh_node.mln_Pred = (struct MinNode *)0x44332211;
203 header->mwh_node.mln_Succ = (struct MinNode *)0xCCBBAA99;
206 /* Skip to the start of the pre-wall */
207 res += MUNGWALLHEADER_SIZE;
209 /* Initialize pre-wall */
210 BUILD_WALL(res, 0xDB, MUNGWALL_SIZE);
212 /* move over the block between the walls */
213 res += MUNGWALL_SIZE;
215 /* Fill the block with weird stuff to exploit bugs in applications */
216 if (!(requirements & MEMF_CLEAR))
217 MUNGE_BLOCK(res, MEMFILL_ALLOC, byteSize - MUNGWALL_SIZE * 2 - MEMCHUNK_TOTAL);
219 /* Initialize post-wall */
220 BUILD_WALL(res + origSize, 0xDB, MUNGWALL_SIZE + AROS_ROUNDUP2(origSize, MEMCHUNK_TOTAL) - origSize);
222 #endif /* AROS_MUNGWALL_DEBUG */
224 #if DEBUG
225 if (SysBase->DebugAROSBase)
226 ReturnPtr ("AllocMem", APTR, res)
227 else
228 return res;
229 #else
230 ReturnPtr ("AllocMem", APTR, res);
231 #endif
233 AROS_LIBFUNC_EXIT
235 } /* AllocMem */
238 static APTR stdAlloc(struct MemHeader *mh, ULONG byteSize, ULONG requirements)
240 struct MemChunk *mc=NULL, *p1, *p2;
243 The free memory list is only single linked, i.e. to remove
244 elements from the list I need node's predessor. For the
245 first element I can use mh->mh_First instead of a real predessor.
247 p1 = (struct MemChunk *)&mh->mh_First;
248 p2 = p1->mc_Next;
250 /* Is there anything in the list? */
251 if (p2 != NULL)
253 /* Then follow it */
254 for (;;)
256 #if !defined(NO_CONSISTENCY_CHECKS)
257 /* Consistency check: Check alignment restrictions */
258 if( ((IPTR)p2|(ULONG)p2->mc_Bytes)
259 & (MEMCHUNK_TOTAL-1) )
260 Alert(AN_MemCorrupt|AT_DeadEnd);
261 #endif
263 /* Check if the current block is large enough */
264 if(p2->mc_Bytes>=byteSize)
266 /* It is. */
267 mc=p1;
268 /* Use this one if MEMF_REVERSE is not set.*/
269 if(!(requirements&MEMF_REVERSE))
270 break;
271 /* Else continue - there may be more to come. */
274 /* Go to next block */
275 p1=p2;
276 p2=p1->mc_Next;
278 /* Check if this was the end */
279 if(p2==NULL)
280 break;
281 #if !defined(NO_CONSISTENCY_CHECKS)
283 Consistency check:
284 If the end of the last block+1 is bigger or equal to
285 the start of the current block something must be wrong.
287 if((UBYTE *)p2<=(UBYTE *)p1+p1->mc_Bytes)
288 Alert(AN_MemCorrupt|AT_DeadEnd);
289 #endif
292 /* Something found? */
293 if (mc != NULL)
296 Remember: if MEMF_REVERSE is set
297 p1 and p2 are now invalid.
299 p1=mc;
300 p2=p1->mc_Next;
302 /* Remove the block from the list and return it. */
303 if(p2->mc_Bytes == byteSize)
305 /* Fits exactly. Just relink the list. */
306 p1->mc_Next = p2->mc_Next;
307 mc = p2;
309 else
311 if(requirements & MEMF_REVERSE)
313 /* Return the last bytes. */
314 p1->mc_Next=p2;
315 mc=(struct MemChunk *)((UBYTE *)p2+p2->mc_Bytes-byteSize);
317 else
319 /* Return the first bytes. */
320 p1->mc_Next=(struct MemChunk *)((UBYTE *)p2+byteSize);
321 mc=p2;
324 p1 = p1->mc_Next;
325 p1->mc_Next = p2->mc_Next;
326 p1->mc_Bytes = p2->mc_Bytes-byteSize;
329 mh->mh_Free -= byteSize;
333 return mc;
336 ULONG checkMemHandlers(struct checkMemHandlersState *cmhs)
338 struct Node *tmp;
339 struct Interrupt *lmh;
341 if (cmhs->cmhs_Data.memh_RequestFlags & MEMF_NO_EXPUNGE)
342 return MEM_DID_NOTHING;
344 /* Loop over low memory handlers. Handlers can remove
345 themselves from the list while being invoked, thus
346 we need to be careful! */
349 lmh = (struct Interrupt *)cmhs->cmhs_CurNode;
350 (tmp = lmh->is_Node.ln_Succ);
351 lmh = (struct Interrupt *)(cmhs->cmhs_CurNode = tmp)
354 ULONG ret;
356 ret = AROS_UFC3 (LONG, lmh->is_Code,
357 AROS_UFCA(struct MemHandlerData *, &cmhs->cmhs_Data, A0),
358 AROS_UFCA(APTR, lmh->is_Data, A1),
359 AROS_UFCA(struct ExecBase *, SysBase, A6)
362 if (ret == MEM_TRY_AGAIN)
364 /* MemHandler said he did something. Try again. */
365 /* Is there any program that depends on this flag??? */
366 cmhs->cmhs_Data.memh_Flags |= MEMHF_RECYCLE;
367 return MEM_TRY_AGAIN;
369 else
371 /* Nothing more to expect from this handler. */
372 cmhs->cmhs_Data.memh_Flags &= ~MEMHF_RECYCLE;
376 return MEM_DID_NOTHING;