Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Easy and fast memory allocator from
  3.  * https://wiki.osdev.org/Memory_Allocation
  4.  * Coded by Siemargl, 2018
  5.  *
  6.  * No Garbage Collector
  7.  */
  8.  
  9. #include <stddef.h>
  10. #include <stdint.h>
  11. #include <string.h>
  12. #include <assert.h>
  13. #include <stdlib.h>
  14.  
  15. #define UINT_MAX  (4294967295U)
  16.  
  17. #ifndef NDEBUG
  18. #include <stdio.h>
  19. #       define TRACE1(s, a) printf(s, a)
  20. #       define TRACE2(s, a, b) printf(s, a, b)
  21. #else
  22. #       define TRACE1(s, a) (void)0
  23. #       define TRACE2(s, a, b) (void)0
  24. #endif
  25.  
  26. // get address, fromwhere function was called
  27. #define CALLEDFROM(param1) (*(int*)((char*)&param1-4)-5)
  28.    
  29. const uint32_t c_used = 0x44455355; //'USED'
  30. const uint32_t c_free = 0x45455246; //'FREE'
  31.  
  32. struct hdrfree {
  33.         uint32_t        mark; // 'FREE'
  34.         size_t          size; // including header
  35.         struct hdrfree  *prev;
  36.         struct hdrfree  *next;
  37. };
  38.  
  39. struct hdrused {
  40.         uint32_t        mark; // 'USED'
  41.         size_t          size;
  42. };
  43.  
  44.  
  45. static char *__freebase = NULL;         // begin of free area
  46. static char *__freetop = NULL;          // after last byte of free area
  47. static struct hdrfree *__firstfree = NULL;      // ptr to first node in dual-link list
  48. static unsigned __crtfreeblocks = 0; // number of free blocks, checking corruptions
  49.  
  50.  
  51. void *wtmalloc(size_t sz)
  52. {
  53.         struct hdrfree *fndnode, *newnode;
  54.         sz = (sizeof(struct hdrused) + sz + 15) & ~15; // align 16bytes
  55. //TRACE1("_call alloc(%d)\n", sz);
  56.        
  57.         // try to find free block enough size
  58.         fndnode = __firstfree;
  59.         while(fndnode)
  60.         {
  61. #ifndef NDEBUG
  62.                 if (fndnode->mark != c_free)
  63.                 {
  64.                         TRACE2("heap free block list corrupt %x  EIP@%x\n", fndnode, CALLEDFROM(sz));
  65.                         assert(0);
  66.                 }
  67. #endif
  68.                 if (fndnode->size >= sz) break;
  69.                 fndnode = fndnode->next;
  70.         }
  71.        
  72.         if (fndnode) // found free block
  73.         {
  74.                 if (fndnode->size - sz > 15) // split smaller size, move free node
  75.                 {
  76. //TRACE2("alloc(%d) split (%x)\n", sz, fndnode);
  77.                         newnode = (struct hdrfree*)((char*)fndnode + sz);
  78.                         newnode->mark = c_free;
  79.                         newnode->size = fndnode->size - sz;
  80.                         newnode->next = fndnode->next;
  81.                         newnode->prev = fndnode->prev;
  82.                        
  83.                         if (fndnode->next)
  84.                                 fndnode->next->prev = newnode;
  85.                        
  86.                         //перед может быть не нода, а 1й указатель
  87.                         if (!fndnode->prev)
  88.                                 __firstfree = newnode;
  89.                         else
  90.                                 newnode->prev->next = newnode;
  91.                 } else // nothing to split, just exclude
  92.                 {
  93. //TRACE1("alloc(%d) remove freenode\n", sz);
  94.  
  95.                         __crtfreeblocks--;
  96.                         if (fndnode->next)
  97.                                 fndnode->next->prev = fndnode->prev;
  98.                         //перед может быть не нода, а 1й указатель
  99.                         if (!fndnode->prev)
  100.                                 __firstfree = fndnode->next;
  101.                         else
  102.                                 fndnode->prev->next = fndnode->next;
  103.                 }
  104.                
  105.                 fndnode->mark = c_used;
  106.                 fndnode->size = sz;
  107.                 return (char*)fndnode + sizeof(struct hdrused);
  108.         }
  109.        
  110.         char *ptr;
  111.         // free block not found, try to add @end
  112.         if (__freetop - __freebase < sz)  // not enough memory - call system
  113.         {
  114.                 if (sz > UINT_MAX - 16) return NULL;  // check 32-bit heap overflow
  115.                 size_t new_heap_size = (__freetop - __freebase + sz + 4095) & ~4095;  
  116.                
  117.                 //хвост сунуть в свободные, а фритоп и базу перености на новый кусок
  118.                 ptr = sysmalloc(new_heap_size);   // rounded 4k
  119. //TRACE2("call systemalloc(%d) returned %x\n", new_heap_size, ptr);
  120.                 if (!ptr)
  121.                 {
  122.                         TRACE2("sysmalloc failed trying to allocate %u bytes EIP@%x\n", sz, CALLEDFROM(sz));
  123.                         return NULL;
  124.                 }
  125.                 // add new free block in front of list
  126.                 if (__freetop - __freebase > 15)
  127.                 {
  128.                         newnode = (struct hdrfree*)__freebase;
  129.                         newnode->mark = c_free;
  130.                         newnode->size = __freetop - __freebase;
  131.                         newnode->next = __firstfree;
  132.                         newnode->prev = NULL;
  133.                         if (__firstfree)
  134.                                 __firstfree->prev = newnode;
  135.                         __firstfree = newnode;
  136.                         __crtfreeblocks++;
  137. //TRACE2("alloc(%d) add tail %d to freenode", sz, newnode->size);
  138. //TRACE1(".tail [%x]\n", newnode);
  139.                 }
  140.                 // we don't save allocated block from system, so cant free them ltr
  141.                
  142.                 __freebase = ptr;
  143.                 __freetop = __freebase + new_heap_size;
  144.         }
  145.        
  146.         ptr = __freebase + sizeof(struct hdrused);
  147.         ((struct hdrused*)__freebase)->mark = c_used;
  148.         ((struct hdrused*)__freebase)->size = sz;
  149.         __freebase += sz;
  150. //TRACE1("__freebase [%x]\n", __freebase);
  151.        
  152.         return ptr;
  153. }
  154.  
  155. void wtfree(void *ptr)
  156. {
  157.         if (!ptr) return;
  158.  
  159. #ifndef NDEBUG
  160.         if (((struct hdrused*)((char*)ptr - 8))->mark != c_used)
  161.         {
  162.                 TRACE2("try free unallocated block ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr));
  163.                 assert(0);
  164.         }
  165. #endif
  166.         struct hdrfree *newnode = (struct hdrfree*)((char*)ptr - 8);
  167.         newnode->mark = c_free;
  168.         //size stays
  169.         newnode->next = __firstfree;
  170.         newnode->prev = NULL;
  171.         if (__firstfree)
  172.                 __firstfree->prev = newnode;
  173.         __firstfree = newnode;
  174.         __crtfreeblocks++;
  175. //TRACE1("free to freenode\n", 0);
  176. }      
  177.  
  178.  
  179. void *wtrealloc(void *ptr, size_t sz)
  180. {
  181.         if (!ptr) return wtmalloc(sz);
  182.        
  183.         struct hdrused* oldptr = (struct hdrused*)((char*)ptr - 8);
  184.  
  185. #ifndef NDEBUG
  186.         if (oldptr->mark != c_used)
  187.         {
  188.                 TRACE2("try realloc unallocated block ptr = %x  EIP@%x\n", ptr, CALLEDFROM(ptr));
  189.                 assert(0);
  190.         }
  191. #endif
  192.  
  193.         if (oldptr->size - 8 >= sz) return ptr; // enough room in this block, ex from freelist
  194.        
  195.         void *newptr = wtmalloc(sz);
  196.         if (newptr)
  197.         {
  198.                 memcpy(newptr, (char*)oldptr +8, oldptr->size -8); // why -8 dont fail test?!?
  199.                 wtfree((char*)oldptr +8);
  200.                 return newptr;
  201.         }
  202.        
  203.         return NULL;
  204. }      
  205.  
  206. void* wtcalloc( size_t num, size_t size )
  207. {
  208.         void *newptr = wtmalloc(num * size);
  209.         if (newptr)
  210.                 memset(newptr, 0, num * size);
  211.         return newptr;
  212. }
  213.  
  214.  
  215.  
  216.  
  217. int wtmalloc_freelist_check()
  218. //контроль целостности списка фри OK == 1
  219. {
  220.         int cnt = 0;
  221.         struct hdrfree *ptr = __firstfree;
  222.        
  223.         if(ptr && ptr->prev)
  224.         {
  225.                 TRACE1("allocated memory freelist 1st block fail, ptr = %x\n", ptr);
  226.                 return 0;
  227.         }
  228.        
  229.         for(;ptr; ptr = ptr->next)
  230.         {
  231. //TRACE1("(%x)", ptr);
  232.  
  233.                 cnt++;
  234.                 if (ptr->mark != c_free)
  235.                 {
  236.                         TRACE1("allocated memory freelist check fail, ptr = %x\n", ptr);
  237.                         return 0;
  238.                 }
  239.         }
  240.         if (cnt != __crtfreeblocks)
  241.         {
  242.                 TRACE1("allocated memory freelist check fail, length must be = %u\n", __crtfreeblocks);
  243.                 return 0;
  244.         }
  245.         return 1;      
  246. }
  247.  
  248. int wtmalloc_poiner_check(void *ptr)
  249. //контроль указателя - mark  OK == 1
  250. {
  251.         if (((struct hdrused*)((char*)ptr - 8))->mark != c_used)
  252.         {
  253.                 TRACE2("pointer watermark check fail ptr = %x bytes EIP@%x\n", ptr, CALLEDFROM(ptr));
  254.                 return 0;
  255.         }
  256.         return 1;
  257. }
  258.