• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //----------------------------------------------------------------
2 // Statically-allocated memory manager
3 //
4 // by Eli Bendersky (eliben@gmail.com)
5 //
6 // This code is in the public domain.
7 //----------------------------------------------------------------
8 #include "memmgr.h"
9 
10 typedef ulong Align;
11 
12 union mem_header_union
13 {
14     struct
15     {
16         // Pointer to the next block in the free list
17         //
18         union mem_header_union* next;
19 
20         // Size of the block (in quantas of sizeof(mem_header_t))
21         //
22         ulong size;
23     } s;
24 
25     // Used to align headers in memory to a boundary
26     //
27     Align align_dummy;
28 };
29 
30 typedef union mem_header_union mem_header_t;
31 
32 // Initial empty list
33 //
34 static mem_header_t base;
35 
36 // Start of free list
37 //
38 static mem_header_t* freep = 0;
39 
40 // Static pool for new allocations
41 //
42 static byte pool[POOL_SIZE] = {0};
43 static ulong pool_free_pos = 0;
44 
45 
memmgr_init()46 void memmgr_init()
47 {
48     base.s.next = 0;
49     base.s.size = 0;
50     freep = 0;
51     pool_free_pos = 0;
52 }
53 
54 
get_mem_from_pool(ulong nquantas)55 static mem_header_t* get_mem_from_pool(ulong nquantas)
56 {
57     ulong total_req_size;
58 
59     mem_header_t* h;
60 
61     if (nquantas < MIN_POOL_ALLOC_QUANTAS)
62         nquantas = MIN_POOL_ALLOC_QUANTAS;
63 
64     total_req_size = nquantas * sizeof(mem_header_t);
65 
66     if (pool_free_pos + total_req_size <= POOL_SIZE)
67     {
68         h = (mem_header_t*) (pool + pool_free_pos);
69         h->s.size = nquantas;
70         memmgr_free((void*) (h + 1));
71         pool_free_pos += total_req_size;
72     }
73     else
74     {
75         return 0;
76     }
77 
78     return freep;
79 }
80 
81 
82 // Allocations are done in 'quantas' of header size.
83 // The search for a free block of adequate size begins at the point 'freep'
84 // where the last block was found.
85 // If a too-big block is found, it is split and the tail is returned (this
86 // way the header of the original needs only to have its size adjusted).
87 // The pointer returned to the user points to the free space within the block,
88 // which begins one quanta after the header.
89 //
memmgr_alloc(ulong nbytes)90 void* memmgr_alloc(ulong nbytes)
91 {
92     mem_header_t* p;
93     mem_header_t* prevp;
94 
95     // Calculate how many quantas are required: we need enough to house all
96     // the requested bytes, plus the header. The -1 and +1 are there to make sure
97     // that if nbytes is a multiple of nquantas, we don't allocate too much
98     //
99     ulong nquantas = (nbytes + sizeof(mem_header_t) - 1) / sizeof(mem_header_t) + 1;
100 
101     // First alloc call, and no free list yet ? Use 'base' for an initial
102     // denegerate block of size 0, which points to itself
103     //
104     if ((prevp = freep) == 0)
105     {
106         base.s.next = freep = prevp = &base;
107         base.s.size = 0;
108     }
109 
110     for (p = prevp->s.next; ; prevp = p, p = p->s.next)
111     {
112         // big enough ?
113         if (p->s.size >= nquantas)
114         {
115             // exactly ?
116             if (p->s.size == nquantas)
117             {
118                 // just eliminate this block from the free list by pointing
119                 // its prev's next to its next
120                 //
121                 prevp->s.next = p->s.next;
122             }
123             else // too big
124             {
125                 p->s.size -= nquantas;
126                 p += p->s.size;
127                 p->s.size = nquantas;
128             }
129 
130             freep = prevp;
131             return (void*) (p + 1);
132         }
133         // Reached end of free list ?
134         // Try to allocate the block from the pool. If that succeeds,
135         // get_mem_from_pool adds the new block to the free list and
136         // it will be found in the following iterations. If the call
137         // to get_mem_from_pool doesn't succeed, we've run out of
138         // memory
139         //
140         else if (p == freep)
141         {
142             if ((p = get_mem_from_pool(nquantas)) == 0)
143             {
144                 #ifdef DEBUG_MEMMGR_FATAL
145                 printf("!! Memory allocation failed !!\n");
146                 #endif
147                 return 0;
148             }
149         }
150     }
151 }
152 
153 
154 // Scans the free list, starting at freep, looking the the place to insert the
155 // free block. This is either between two existing blocks or at the end of the
156 // list. In any case, if the block being freed is adjacent to either neighbor,
157 // the adjacent blocks are combined.
158 //
memmgr_free(void * ap)159 void memmgr_free(void* ap)
160 {
161     mem_header_t* block;
162     mem_header_t* p;
163 
164     // acquire pointer to block header
165     block = ((mem_header_t*) ap) - 1;
166 
167     // Find the correct place to place the block in (the free list is sorted by
168     // address, increasing order)
169     //
170     for (p = freep; !(block > p && block < p->s.next); p = p->s.next)
171     {
172         // Since the free list is circular, there is one link where a
173         // higher-addressed block points to a lower-addressed block.
174         // This condition checks if the block should be actually
175         // inserted between them
176         //
177         if (p >= p->s.next && (block > p || block < p->s.next))
178             break;
179     }
180 
181     // Try to combine with the higher neighbor
182     //
183     if (block + block->s.size == p->s.next)
184     {
185         block->s.size += p->s.next->s.size;
186         block->s.next = p->s.next->s.next;
187     }
188     else
189     {
190         block->s.next = p->s.next;
191     }
192 
193     // Try to combine with the lower neighbor
194     //
195     if (p + p->s.size == block)
196     {
197         p->s.size += block->s.size;
198         p->s.next = block->s.next;
199     }
200     else
201     {
202         p->s.next = block;
203     }
204 
205     freep = p;
206 }
207