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

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