12#include <l4/cxx/arith>
13#include <l4/cxx/minmax>
14#include <l4/cxx/type_traits>
25 friend class List_alloc_sanity_guard;
35 inline void check_overlap(
void *,
unsigned long );
36 inline void sanity_check_list(
char const *,
char const *);
61 inline void free(
void *block,
unsigned long size,
bool initial_free =
false);
77 inline void *
alloc(
unsigned long size,
unsigned long align,
78 unsigned long lower = 0,
unsigned long upper = ~0UL);
100 inline void *
alloc_max(
unsigned long min,
unsigned long *max,
101 unsigned long align,
unsigned granularity,
102 unsigned long lower = 0,
unsigned long upper = ~0UL);
109 inline unsigned long avail();
111 template <
typename DBG>
112 void dump_free_list(DBG &out);
115#if !defined (CXX_LIST_ALLOC_SANITY)
116class List_alloc_sanity_guard
119 List_alloc_sanity_guard(List_alloc *,
char const *)
126List_alloc::check_overlap(
void *,
unsigned long )
130List_alloc::sanity_check_list(
char const *,
char const *)
135class List_alloc_sanity_guard
142 List_alloc_sanity_guard(List_alloc *a,
char const *func)
144 { a->sanity_check_list(func,
"entry"); }
146 ~List_alloc_sanity_guard()
147 { a->sanity_check_list(func,
"exit"); }
151List_alloc::check_overlap(
void *b,
unsigned long s)
153 unsigned long const mb_align = (1UL << arith::Ld<
sizeof(Mem_block)>::value) - 1;
154 if ((
unsigned long)b & mb_align)
156 L4::cerr <<
"List_alloc(FATAL): trying to free unaligned memory: "
157 << b <<
" align=" << arith::Ld<
sizeof(Mem_block)>::value <<
"\n";
160 Mem_block *c = _first;
161 for (;c ; c = c->next)
163 unsigned long x_s = (
unsigned long)b;
164 unsigned long x_e = x_s + s;
165 unsigned long b_s = (
unsigned long)c;
166 unsigned long b_e = b_s + c->size;
168 if ((x_s >= b_s && x_s < b_e)
169 || (x_e > b_s && x_e <= b_e)
170 || (b_s >= x_s && b_s < x_e)
171 || (b_e > x_s && b_e <= x_e))
173 L4::cerr <<
"List_alloc(FATAL): trying to free memory that "
174 "is already free: \n ["
175 << (
void*)x_s <<
'-' << (
void*)x_e <<
") overlaps ["
176 << (
void*)b_s <<
'-' << (
void*)b_e <<
")\n";
182List_alloc::sanity_check_list(
char const *func,
char const *info)
184 Mem_block *c = _first;
185 for (;c ; c = c->next)
191 L4::cerr <<
"List_alloc(FATAL): " << func <<
'(' << info
192 <<
"): list order violation\n";
195 if (((
unsigned long)c) + c->size > (
unsigned long)c->next)
197 L4::cerr <<
"List_alloc(FATAL): " << func <<
'(' << info
198 <<
"): list order violation\n";
209 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
210 Mem_block *c = _first;
213 unsigned long f_start =
reinterpret_cast<unsigned long>(c);
214 unsigned long f_end = f_start + c->size;
215 unsigned long n_start =
reinterpret_cast<unsigned long>(c->next);
217 if (f_end == n_start)
219 c->size += c->next->size;
220 c->next = c->next->next;
231 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
233 unsigned long const mb_align = (1UL <<
arith::Ld<
sizeof(Mem_block)>::value) - 1;
238 unsigned long nblock = (
reinterpret_cast<unsigned long>(block) + mb_align)
240 size = (size - (nblock -
reinterpret_cast<unsigned long>(block)))
242 block =
reinterpret_cast<void*
>(nblock);
246 size = (size + mb_align) & ~mb_align;
248 check_overlap(block, size);
250 Mem_block **c = &_first;
255 while (*c && *c < block)
261 *c =
reinterpret_cast<Mem_block*
>(block);
271 unsigned granularity,
unsigned long lower,
274 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
276 unsigned char const mb_bits =
arith::Ld<
sizeof(Mem_block)>::value;
277 unsigned long const mb_align = (1UL << mb_bits) - 1;
284 *max = *max & ~(granularity - 1UL);
289 unsigned long almask = align ? (align - 1UL) : 0;
292 if (almask < mb_align)
295 Mem_block **c = &_first;
297 unsigned long max_fit = 0;
298 unsigned long a_lower = (lower + almask) & ~almask;
300 for (; *c; c = &(*c)->next)
303 unsigned long n_start =
reinterpret_cast<unsigned long>(*c);
307 if ((*c)->size < min)
311 if (upper < n_start || a_lower > n_start + (*c)->size)
315 unsigned long a_start = (n_start + almask) & ~almask;
318 if (a_start - n_start >= (*c)->size)
321 a_start = a_start < a_lower ? a_lower : a_start;
324 if (min > ~0UL - a_start)
328 if (a_start + min - 1UL > upper)
332 unsigned long r_size = (*c)->size - a_start + n_start;
335 if (a_start + r_size - 1UL > upper)
336 r_size = upper - a_start + 1UL;
339 r_size &= ~(granularity - 1UL);
352 if (r_size > max_fit)
361 unsigned long n_start =
reinterpret_cast<unsigned long>(*fit);
362 unsigned long a_lower = (lower + almask) & ~almask;
363 unsigned long a_start = (n_start + almask) & ~almask;
364 a_start = a_start < a_lower ? a_lower : a_start;
365 unsigned long r_size = (*fit)->size - a_start + n_start;
367 if (a_start > n_start)
369 (*fit)->size -= r_size;
376 if (r_size == max_fit)
377 return reinterpret_cast<void *
>(a_start);
379 Mem_block *m =
reinterpret_cast<Mem_block*
>(a_start + max_fit);
381 m->size = r_size - max_fit;
383 return reinterpret_cast<void *
>(a_start);
393 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
395 unsigned long const mb_align
396 = (1UL <<
arith::Ld<
sizeof(Mem_block)>::value) - 1;
399 size = (size + mb_align) & ~mb_align;
401 unsigned long almask = align ? (align - 1UL) : 0;
404 if (almask < mb_align)
407 Mem_block **c = &_first;
408 unsigned long a_lower = (lower + almask) & ~almask;
410 for (; *c; c=&(*c)->next)
413 unsigned long n_start =
reinterpret_cast<unsigned long>(*c);
417 if ((*c)->size < size)
421 if (upper < n_start || a_lower > n_start + (*c)->size)
425 unsigned long a_start = (n_start + almask) & ~almask;
428 if (a_start - n_start >= (*c)->size)
431 a_start = a_start < a_lower ? a_lower : a_start;
434 if (size > ~0UL - a_start)
438 if (a_start + size - 1UL > upper)
443 unsigned long r_size = (*c)->size - a_start + n_start;
449 if (a_start > n_start)
454 (*c)->size -= r_size;
464 return reinterpret_cast<void*
>(a_start);
467 Mem_block *m =
reinterpret_cast<Mem_block*
>(a_start + size);
469 m->size = r_size - size;
471 return reinterpret_cast<void *
>(a_start);
480 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __FUNCTION__);
481 Mem_block *c = _first;
492template <
typename DBG>
494List_alloc::dump_free_list(DBG &out)
496 Mem_block *c = _first;
499 static constexpr char const *
const unitstr[4] =
500 {
"Byte",
"KiB",
"MiB",
"GiB" };
502 unsigned sz = c->size;
504 for (i = 0; i < cxx::array_size(unitstr) && sz > 8 << 10; ++i)
507 out.printf(
"%12p - %12p (%u %s)\n",
508 c,
reinterpret_cast<char *
>(c) + c->size - 1, sz, unitstr[i]);
unsigned long avail()
Get the amount of available memory.
void * alloc_max(unsigned long min, unsigned long *max, unsigned long align, unsigned granularity, unsigned long lower=0, unsigned long upper=~0UL)
Allocate a memory block of min <= size <= max.
List_alloc()
Initializes an empty list allocator.
void * alloc(unsigned long size, unsigned long align, unsigned long lower=0, unsigned long upper=~0UL)
Allocate a memory block.
void free(void *block, unsigned long size, bool initial_free=false)
Return a free memory block to the allocator.
l4_addr_t l4_trunc_size(l4_addr_t address, unsigned char bits) L4_NOTHROW
Round an address down to the next lower flexpage with size bits.
l4_addr_t l4_round_size(l4_addr_t value, unsigned char bits) L4_NOTHROW
Round value up to the next alignment with bits size.
BasicOStream cerr
Standard error stream.
Computes the binary logarithm of the given number at compile time.