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

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