2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
5 Desc: Free memory allocated by AllocMem()
8 #include <exec/alerts.h>
9 #include <exec/execbase.h>
10 #include <aros/libcall.h>
11 #include <aros/config.h>
12 #include <aros/macros.h>
15 #include <exec/memory.h>
16 #include <exec/memheaderext.h>
17 #include <proto/exec.h>
19 #include "exec_debug.h"
21 # define DEBUG_FreeMem 0
29 #include <aros/debug.h>
33 /*****************************************************************************
37 AROS_LH2(void, FreeMem
,
40 AROS_LHA(APTR
, memoryBlock
, A1
),
41 AROS_LHA(ULONG
, byteSize
, D0
),
44 struct ExecBase
*, SysBase
, 35, Exec
)
47 Give a block of memory back to the system pool.
50 memoryBlock - Pointer to the memory to be freed
51 byteSize - Size of the block
66 ******************************************************************************/
71 struct MemChunk
*p1
, *p2
, *p3
;
73 #if AROS_MUNGWALL_DEBUG
74 ULONG origsize
= byteSize
;
77 D(bug("Call FreeMem (%08lx, %ld)\n", memoryBlock
, byteSize
));
79 /* If there is no memory free nothing */
80 if(!byteSize
|| !memoryBlock
)
81 ReturnVoid ("FreeMem");
83 RT_Free (RTT_MEMORY
, memoryBlock
, byteSize
);
85 /* The following two lines are necessary because of AllocAbs(),
86 were memoryBlock might not be aligned to a multiple of
89 /* Align size to the requirements (needed because of AllocAbs) */
90 byteSize
+=(IPTR
)memoryBlock
&(MEMCHUNK_TOTAL
-1);
92 /* Align the block as well (needed because of AllocAbs) */
93 memoryBlock
=(APTR
)AROS_ROUNDDOWN2((IPTR
)memoryBlock
,MEMCHUNK_TOTAL
);
95 #if AROS_MUNGWALL_DEBUG
96 /* Add the size of mung walls and mungwall header */
97 memoryBlock
-= MUNGWALL_SIZE
+ MUNGWALLHEADER_SIZE
;
98 byteSize
+= MUNGWALL_SIZE
* 2 + MUNGWALLHEADER_SIZE
;
101 byteSize
=AROS_ROUNDUP2(byteSize
,MEMCHUNK_TOTAL
);
103 #if AROS_MUNGWALL_DEBUG
105 struct MungwallHeader
*header
;
107 header
= (struct MungwallHeader
*)memoryBlock
;
109 if (header
->mwh_magicid
!= MUNGWALL_HEADER_ID
)
111 struct Task
*__t
= FindTask(NULL
); \
112 kprintf("\x07MUNGWALL_HEADER_ID mismatch (%s) mem = %x"
113 "allocsize = %d freesize = %d Task: 0x%x, Name: %s\n", \
115 memoryBlock
+ MUNGWALL_SIZE
+ MUNGWALLHEADER_SIZE
,
116 *(ULONG
*)memoryBlock
,
119 __t
->tc_Node
.ln_Name
);\
122 if (header
->mwh_allocsize
!= origsize
)
124 struct Task
*__t
= FindTask(NULL
); \
125 kprintf("\x07FreeMem size mismatches AllocMem size (%s) mem = %x"
126 "allocsize = %d freesize = %d Task: 0x%x, Name: %s\n", \
128 memoryBlock
+ MUNGWALL_SIZE
+ MUNGWALLHEADER_SIZE
,
129 *(ULONG
*)memoryBlock
,
132 __t
->tc_Node
.ln_Name
);\
135 CHECK_WALL((UBYTE
*)memoryBlock
+ MUNGWALLHEADER_SIZE
, 0xDB, MUNGWALL_SIZE
);
136 CHECK_WALL((UBYTE
*)memoryBlock
+ MUNGWALLHEADER_SIZE
+ MUNGWALL_SIZE
+ origsize
, 0xDB,
137 MUNGWALL_SIZE
+ AROS_ROUNDUP2(origsize
, MEMCHUNK_TOTAL
) - origsize
);
139 /* Remove from AROSSupportBase->AllocMemList */
141 if ((header
->mwh_node
.mln_Pred
!= (struct MinNode
*)0x44332211) ||
142 (header
->mwh_node
.mln_Succ
!= (struct MinNode
*)0xCCBBAA99))
144 /* Reason for above checks: see allocmem.c */
146 Remove((struct Node
*)&header
->mwh_node
);
150 /* Fill block with weird stuff to esploit bugs in applications
152 * DOH! There's some _BAD_ code around that assumes memory can still be
153 * accessed after freeing by just preventing task switching. In AROS,
154 * RemTask(NULL) suffers of this problem because DOS processes are
155 * created with their TCB placed in the tc_MemEntry list. The workaround
156 * is to avoid munging when FreeMem() is called with task switching disabled.
158 /* DOH! it doesn't work even this way. What's wrong???
160 * if ((SysBase->TDNestCnt < 0) && (SysBase->IDNestCnt < 0))
161 * MUNGE_BLOCK(memoryBlock, MEMFILL_FREE, byteSize);
167 /* Start and end(+1) of the block */
168 p3
=(struct MemChunk
*)memoryBlock
;
169 p4
=(UBYTE
*)p3
+byteSize
;
171 /* Protect the memory list from access by other tasks. */
174 ForeachNode(&SysBase
->MemList
, mh
)
176 /* Test if the memory belongs to this MemHeader. */
177 if (mh
->mh_Lower
> memoryBlock
|| mh
->mh_Upper
<= memoryBlock
)
180 if (mh
->mh_Attributes
& MEMF_MANAGED
)
182 struct MemHeaderExt
*mhe
= (struct MemHeaderExt
*)mh
;
185 mhe
->mhe_Free(mhe
, memoryBlock
, byteSize
);
188 ReturnVoid ("FreeMem");
192 #if !defined(NO_CONSISTENCY_CHECKS)
193 /* Test if it really fits into this MemHeader. */
194 if ((APTR
)p4
> mh
->mh_Upper
)
195 /* Something is completely wrong. */
196 Alert(AN_MemCorrupt
|AT_DeadEnd
);
199 The free memory list is only single linked, i.e. to insert
200 elements into the list I need the node as well as it's
201 predessor. For the first element I can use freeList->mh_First
202 instead of a real predessor.
204 p1
=(struct MemChunk
*)&mh
->mh_First
;
207 /* No chunk in list? Just insert the current one and return. */
210 p3
->mc_Bytes
= byteSize
;
213 mh
->mh_Free
+= byteSize
;
216 ReturnVoid ("FreeMem");
219 /* Follow the list to find a place where to insert our memory. */
222 #if !defined(NO_CONSISTENCY_CHECKS)
224 Do some constistency checks:
225 1. All MemChunks must be aligned to
227 2. The end (+1) of the current MemChunk
228 must be lower than the start of the next one.
230 if( ((IPTR
)p2
|p2
->mc_Bytes
)&(MEMCHUNK_TOTAL
-1)
231 ||( (UBYTE
*)p2
+p2
->mc_Bytes
>=(UBYTE
*)p2
->mc_Next
232 &&p2
->mc_Next
!=NULL
))
233 Alert(AN_MemCorrupt
|AT_DeadEnd
);
235 /* Found a block with a higher address? */
238 #if !defined(NO_CONSISTENCY_CHECKS)
240 If the memory to be freed overlaps with the current
241 block something must be wrong.
244 Alert(AN_FreeTwice
|AT_DeadEnd
);
246 /* End the loop with p2 non-zero */
249 /* goto next block */
253 /* If the loop ends with p2 zero add it at the end. */
254 } while (p2
!= NULL
);
256 /* If there was a previous block merge with it. */
257 if(p1
!=(struct MemChunk
*)&mh
->mh_First
)
259 #if !defined(NO_CONSISTENCY_CHECKS)
260 /* Check if they overlap. */
261 if((UBYTE
*)p1
+p1
->mc_Bytes
>(UBYTE
*)p3
)
262 Alert(AN_FreeTwice
|AT_DeadEnd
);
264 /* Merge if possible */
265 if((UBYTE
*)p1
+p1
->mc_Bytes
==(UBYTE
*)p3
)
268 /* Not possible to merge */
274 There was no previous block. Just insert the memory at
275 the start of the list.
280 /* Try to merge with next block (if there is one ;-) ). */
281 if(p4
==(UBYTE
*)p2
&&p2
!=NULL
)
284 Overlap checking already done. Doing it here after
285 the list potentially changed would be a bad idea.
291 /* relink the list and return. */
293 p3
->mc_Bytes
= p4
-(UBYTE
*)p3
;
294 mh
->mh_Free
+= byteSize
;
296 ReturnVoid ("FreeMem");
299 #if !defined(NO_CONSISTENCY_CHECKS)
300 /* Some memory that didn't fit into any MemHeader? */
301 Alert(AN_MemCorrupt
|AT_DeadEnd
);
306 ReturnVoid ("FreeMem");