Cleanup and Bugfixes
[tpg/acess2.git] / Usermode / Libraries / libc.so_src / heap.c
1 /*\r
2 AcessOS Basic LibC\r
3 heap.c - Heap Manager\r
4 */\r
5 #include <acess/sys.h>\r
6 #include <stdlib.h>\r
7 #include "lib.h"\r
8 \r
9 // === Constants ===\r
10 #define MAGIC   0xACE55051      //AcessOS1\r
11 #define MAGIC_FREE      (~MAGIC)\r
12 #define BLOCK_SIZE      16      //Minimum\r
13 #define HEAP_INIT_SIZE  0x10000\r
14 \r
15 typedef unsigned int Uint;\r
16 \r
17 //Typedefs\r
18 typedef struct {\r
19         Uint    magic;\r
20         Uint    size;\r
21 }       heap_head;\r
22 typedef struct {\r
23         heap_head       *header;\r
24         Uint    magic;\r
25 }       heap_foot;\r
26 \r
27 //Globals\r
28 void    *_heap_start = NULL;\r
29 void    *_heap_end = NULL;\r
30 \r
31 //Prototypes\r
32 EXPORT void     *malloc(Uint bytes);\r
33 EXPORT void     free(void *mem);\r
34 EXPORT void     *realloc(void *mem, Uint bytes);\r
35 EXPORT void     *sbrk(int increment);\r
36 LOCAL void      *extendHeap(int bytes);\r
37 LOCAL uint      brk(Uint newpos);\r
38 \r
39 //Code\r
40 \r
41 /**\r
42  \fn EXPORT void *malloc(size_t bytes)\r
43  \brief Allocates memory from the heap space\r
44  \param bytes   Integer - Size of buffer to return\r
45  \return Pointer to buffer\r
46 */\r
47 EXPORT void *malloc(size_t bytes)\r
48 {\r
49         Uint    bestSize;\r
50         Uint    closestMatch = 0;\r
51         Uint    bestMatchAddr = 0;\r
52         heap_head       *curBlock;\r
53         \r
54         // Initialise Heap\r
55         if(_heap_start == NULL)\r
56         {\r
57                 _heap_start = sbrk(0);\r
58                 _heap_end = _heap_start;\r
59                 extendHeap(HEAP_INIT_SIZE);\r
60         }\r
61         \r
62         curBlock = _heap_start;\r
63         \r
64         bestSize = bytes + sizeof(heap_head) + sizeof(heap_foot) + BLOCK_SIZE - 1;\r
65         bestSize = (bestSize/BLOCK_SIZE)*BLOCK_SIZE;    //Round up to block size\r
66         \r
67         while((Uint)curBlock < (Uint)_heap_end)\r
68         {\r
69                 //SysDebug(" malloc: curBlock = 0x%x, curBlock->magic = 0x%x\n", curBlock, curBlock->magic);\r
70                 if(curBlock->magic == MAGIC_FREE)\r
71                 {\r
72                         if(curBlock->size == bestSize)\r
73                                 break;\r
74                         if(bestSize < curBlock->size && (curBlock->size < closestMatch || closestMatch == 0)) {\r
75                                 closestMatch = curBlock->size;\r
76                                 bestMatchAddr = (Uint)curBlock;\r
77                         }\r
78                 }\r
79                 else if(curBlock->magic != MAGIC)\r
80                 {\r
81                         //Corrupt Heap\r
82                         //SysDebug("malloc: Corrupt Heap\n");\r
83                         return NULL;\r
84                 }\r
85                 curBlock = (heap_head*)((Uint)curBlock + curBlock->size);\r
86         }\r
87         \r
88         if((Uint)curBlock < (Uint)_heap_start) {\r
89                 //SysDebug("malloc: Heap underrun for some reason\n");\r
90                 return NULL;\r
91         }\r
92         \r
93         //Found a perfect match\r
94         if((Uint)curBlock < (Uint)_heap_end) {\r
95                 curBlock->magic = MAGIC;\r
96                 return (void*)((Uint)curBlock + sizeof(heap_head));\r
97         }\r
98         \r
99         //Out of Heap Space\r
100         if(!closestMatch) {\r
101                 curBlock = extendHeap(bestSize);        //Allocate more\r
102                 if(curBlock == NULL) {\r
103                         //SysDebug("malloc: Out of Heap Space\n");\r
104                         return NULL;\r
105                 }\r
106                 curBlock->magic = MAGIC;\r
107                 return (void*)((Uint)curBlock + sizeof(heap_head));\r
108         }\r
109         \r
110         //Split Block?\r
111         if(closestMatch - bestSize > BLOCK_SIZE) {\r
112                 heap_foot       *foot;\r
113                 curBlock = (heap_head*)bestMatchAddr;\r
114                 curBlock->magic = MAGIC;\r
115                 curBlock->size = bestSize;\r
116                 foot = (heap_foot*)(bestMatchAddr + bestSize - sizeof(heap_foot));\r
117                 foot->header = curBlock;\r
118                 foot->magic = MAGIC;\r
119 \r
120                 curBlock = (heap_head*)(bestMatchAddr + bestSize);\r
121                 curBlock->magic = MAGIC_FREE;\r
122                 curBlock->size = closestMatch - bestSize;\r
123                 \r
124                 foot = (heap_foot*)(bestMatchAddr + closestMatch - sizeof(heap_foot));\r
125                 foot->header = curBlock;\r
126                 \r
127                 ((heap_head*)bestMatchAddr)->magic = MAGIC;     //mark as used\r
128                 return (void*)(bestMatchAddr + sizeof(heap_head));\r
129         }\r
130         \r
131         //Don't Split the block\r
132         ((heap_head*)bestMatchAddr)->magic = MAGIC;\r
133         return (void*)(bestMatchAddr+sizeof(heap_head));\r
134 }\r
135 \r
136 /**\r
137  \fn EXPORT void free(void *mem)\r
138  \brief Free previously allocated memory\r
139  \param mem     Pointer - Memory to free\r
140 */\r
141 EXPORT void free(void *mem)\r
142 {\r
143         heap_head       *head = (void*)((intptr_t)mem-sizeof(heap_head));\r
144         \r
145         // Sanity please!\r
146         if(!mem)        return;\r
147         \r
148         if(head->magic != MAGIC)        //Valid Heap Address\r
149                 return;\r
150         \r
151         head->magic = MAGIC_FREE;\r
152         \r
153         //Unify Right\r
154         if((intptr_t)head + head->size < (intptr_t)_heap_end)\r
155         {\r
156                 heap_head       *nextHead = (heap_head*)((intptr_t)head + head->size);\r
157                 if(nextHead->magic == MAGIC_FREE) {     //Is the next block free\r
158                         head->size += nextHead->size;   //Amalgamate\r
159                         nextHead->magic = 0;    //For Security\r
160                 }\r
161         }\r
162         //Unify Left\r
163         if((intptr_t)head - sizeof(heap_foot) > (intptr_t)_heap_start)\r
164         {\r
165                 heap_head       *prevHead;\r
166                 heap_foot       *prevFoot = (heap_foot *)((intptr_t)head - sizeof(heap_foot));\r
167                 if(prevFoot->magic == MAGIC) {\r
168                         prevHead = prevFoot->header;\r
169                         if(prevHead->magic == MAGIC_FREE) {\r
170                                 prevHead->size += head->size;   //Amalgamate\r
171                                 head->magic = 0;        //For Security\r
172                         }\r
173                 }\r
174         }\r
175 }\r
176 \r
177 /**\r
178  \fn EXPORT void *realloc(void *oldPos, size_t bytes)\r
179  \brief Reallocate a block of memory\r
180  \param bytes   Integer - Size of new buffer\r
181  \param oldPos  Pointer - Old Buffer\r
182  \return Pointer to new buffer\r
183 */\r
184 EXPORT void *realloc(void *oldPos, size_t bytes)\r
185 {\r
186         void *ret;\r
187         heap_head       *head;\r
188         \r
189         if(oldPos == NULL) {\r
190                 return malloc(bytes);\r
191         }\r
192         \r
193         //Check for free space after block\r
194         head = (heap_head*)((Uint)oldPos-sizeof(heap_head));\r
195         \r
196         //Hack to used free's amagamating algorithym and malloc's splitting\r
197         free(oldPos);\r
198         \r
199         //Allocate new memory\r
200         ret = malloc(bytes);\r
201         if(ret == NULL)\r
202                 return NULL;\r
203         \r
204         //Copy Old Data\r
205         if((Uint)ret != (Uint)oldPos) {\r
206                 memcpy(ret, oldPos, head->size-sizeof(heap_head)-sizeof(heap_foot));\r
207         }\r
208         \r
209         //Return\r
210         return ret;\r
211 }\r
212 \r
213 /**\r
214  * \fn LOCAL void *extendHeap(int bytes)\r
215  * \brief Create a new block at the end of the heap area\r
216  * \param bytes Integer - Size reqired\r
217  * \return Pointer to last free block\r
218  */\r
219 \r
220 LOCAL void *extendHeap(int bytes)\r
221 {\r
222         heap_head       *head = _heap_end;\r
223         heap_foot       *foot;\r
224         \r
225         //Expand Memory Space  (Use foot as a temp pointer)\r
226         foot = sbrk(bytes);\r
227         if(foot == (void*)-1)\r
228                 return NULL;\r
229         \r
230         \r
231         //Create New Block\r
232         // Header\r
233         head->magic = MAGIC_FREE;       //Unallocated\r
234         head->size = bytes;\r
235         // Footer\r
236         foot = _heap_end + bytes - sizeof(heap_foot);\r
237         foot->header = head;\r
238         foot->magic = MAGIC;\r
239         \r
240         //Combine with previous block if nessasary\r
241         if(_heap_end != _heap_start && ((heap_foot*)((Uint)_heap_end-sizeof(heap_foot)))->magic == MAGIC) {\r
242                 heap_head       *tmpHead = ((heap_foot*)((Uint)_heap_end-sizeof(heap_foot)))->header;\r
243                 if(tmpHead->magic == MAGIC_FREE) {\r
244                         tmpHead->size += bytes;\r
245                         foot->header = tmpHead;\r
246                         head = tmpHead;\r
247                 }\r
248         }\r
249         \r
250         _heap_end = (void*) ((Uint)foot+sizeof(heap_foot));\r
251         return head;\r
252 }\r
253 \r
254 /**\r
255  \fn EXPORT void *sbrk(int increment)\r
256  \brief Increases the program's memory space\r
257  \param count   Integer - Size of heap increase\r
258  \return Pointer to start of new region\r
259 */\r
260 EXPORT void *sbrk(int increment)\r
261 {\r
262         size_t newEnd;\r
263         static size_t oldEnd = 0;\r
264         static size_t curEnd = 0;\r
265 \r
266         //_SysDebug("sbrk: (increment=%i)\n", increment);\r
267 \r
268         if (oldEnd == 0)        curEnd = oldEnd = brk(0);\r
269 \r
270         //SysDebug(" sbrk: oldEnd = 0x%x\n", oldEnd);\r
271         if (increment == 0)     return (void *) curEnd;\r
272 \r
273         newEnd = curEnd + increment;\r
274 \r
275         if (brk(newEnd) == curEnd)      return (void *) -1;\r
276         oldEnd = curEnd;\r
277         curEnd = newEnd;\r
278         //SysDebug(" sbrk: newEnd = 0x%x\n", newEnd);\r
279 \r
280         return (void *) oldEnd;\r
281 }\r
282 \r
283 /**\r
284  * \fn EXPORT int IsHeap(void *ptr)\r
285  */\r
286 EXPORT int IsHeap(void *ptr)\r
287 {\r
288         #if 0\r
289         heap_head       *head;\r
290         heap_foot       *foot;\r
291         #endif\r
292         if( (Uint)ptr < (Uint)_heap_start )     return 0;\r
293         if( (Uint)ptr > (Uint)_heap_end )       return 0;\r
294         \r
295         #if 0\r
296         head = (void*)((Uint)ptr - 4);\r
297         if( head->magic != MAGIC )      return 0;\r
298         foot = (void*)( (Uint)ptr + head->size - sizeof(heap_foot) );\r
299         if( foot->magic != MAGIC )      return 0;\r
300         #endif\r
301         return 1;\r
302 }\r
303 \r
304 // === STATIC FUNCTIONS ===\r
305 /**\r
306  * Does the job of brk(0)\r
307  */\r
308 static void *FindHeapBase()\r
309 {\r
310         #if 0\r
311         #define MAX             0xC0000000      // Address\r
312         #define THRESHOLD       512     // Pages\r
313         uint    addr;\r
314         uint    stretch = 0;\r
315         uint64_t        tmp;\r
316         \r
317         // Scan address space\r
318         for(addr = 0;\r
319                 addr < MAX;\r
320                 addr += 0x1000\r
321                 )\r
322         {\r
323                 tmp = _SysGetPhys(addr);\r
324                 if( tmp != 0 ) {\r
325                         stretch = 0;\r
326                 } else {\r
327                         stretch ++;\r
328                         if(stretch > THRESHOLD)\r
329                         {\r
330                                 return (void*)( addr - stretch*0x1000 );\r
331                         }\r
332                 }\r
333                 //__asm__ __volatile__ (\r
334                 //      "push %%ebx;mov %%edx,%%ebx;int $0xAC;pop %%ebx"\r
335                 //      ::"a"(256),"d"("%x"),"c"(addr));\r
336         }\r
337         \r
338         return NULL;\r
339         #else\r
340         return (void*)0x00900000;\r
341         #endif\r
342 }\r
343 \r
344 LOCAL uint brk(Uint newpos)\r
345 {\r
346         static uint     curpos;\r
347         uint    pages;\r
348         uint    ret = curpos;\r
349          int    delta;\r
350         \r
351         //_SysDebug("brk: (newpos=0x%x)", newpos);\r
352         \r
353         // Find initial position\r
354         if(curpos == 0) curpos = (uint)FindHeapBase();\r
355         \r
356         // Get Current Position\r
357         if(newpos == 0) return curpos;\r
358         \r
359         if(newpos < curpos)     return newpos;\r
360         \r
361         delta = newpos - curpos;\r
362         //_SysDebug(" brk: delta = 0x%x", delta);\r
363         \r
364         // Do we need to add pages\r
365         if(curpos & 0xFFF && (curpos & 0xFFF) + delta < 0x1000)\r
366                 return curpos += delta;\r
367         \r
368         // Page align current position\r
369         if(curpos & 0xFFF)      delta -= 0x1000 - (curpos & 0xFFF);\r
370         curpos = (curpos + 0xFFF) & ~0xFFF;\r
371         \r
372         // Allocate Pages\r
373         pages = (delta + 0xFFF) >> 12;\r
374         while(pages--)\r
375         {\r
376                 _SysAllocate(curpos);\r
377                 curpos += 0x1000;\r
378                 delta -= 0x1000;\r
379         }\r
380         \r
381         // Bring the current position to exactly what we want\r
382         curpos -= ((delta + 0xFFF) & ~0xFFF) - delta;\r
383         \r
384         return ret;     // Return old curpos\r
385 }\r

UCC git Repository :: git.ucc.asn.au