12#include <l4/cxx/arith>
13#include <l4/cxx/minmax>
14#include <l4/cxx/type_traits>
17#ifdef CXX_LIST_ALLOC_SANITY
29 friend class List_alloc_sanity_guard;
39 inline void check_overlap(
void *,
unsigned long)
const;
40 inline void sanity_check_list(
char const *,
char const *,
42 inline void merge(Mem_block *, Mem_block *);
66 inline void free(
void *block,
unsigned long size,
bool initial_free =
false);
82 inline void *
alloc(
unsigned long size,
unsigned long align,
83 unsigned long lower = 0,
unsigned long upper = ~0UL);
105 inline void *
alloc_max(
unsigned long min,
unsigned long *max,
106 unsigned long align,
unsigned granularity,
107 unsigned long lower = 0,
unsigned long upper = ~0UL);
114 inline unsigned long avail()
const;
116 template <
typename DBG>
117 void dump_free_list(DBG &out)
const;
120#if !defined (CXX_LIST_ALLOC_SANITY)
121class List_alloc_sanity_guard
124 List_alloc_sanity_guard(List_alloc
const *,
char const *,
bool)
131List_alloc::check_overlap(
void *,
unsigned long)
const
135List_alloc::sanity_check_list(
char const *,
char const *,
bool)
const
140class List_alloc_sanity_guard
147 List_alloc_sanity_guard(List_alloc
const *a,
char const *func,
bool unmerged)
149 { a->sanity_check_list(func,
"entry", unmerged); }
151 ~List_alloc_sanity_guard()
152 { a->sanity_check_list(func,
"exit",
false); }
156List_alloc::check_overlap(
void *b,
unsigned long s)
const
158 unsigned long const mb_align = (1UL << arith::Ld<
sizeof(Mem_block)>::value) - 1;
159 if ((
unsigned long)b & mb_align)
161 L4::cerr <<
"List_alloc(FATAL): trying to free unaligned memory: "
162 << b <<
" align=" << arith::Ld<
sizeof(Mem_block)>::value <<
"\n";
165 Mem_block
const *c = _first;
166 for (;c ; c = c->next)
168 unsigned long x_s = (
unsigned long)b;
169 unsigned long x_e = x_s + s;
170 unsigned long b_s = (
unsigned long)c;
171 unsigned long b_e = b_s + c->size;
173 if ((x_s >= b_s && x_s < b_e)
174 || (x_e > b_s && x_e <= b_e)
175 || (b_s >= x_s && b_s < x_e)
176 || (b_e > x_s && b_e <= x_e))
178 L4::cerr <<
"List_alloc(FATAL): trying to free memory that "
179 "is already free: \n ["
180 << (
void*)x_s <<
'-' << (
void*)x_e <<
") overlaps ["
181 << (
void*)b_s <<
'-' << (
void*)b_e <<
")\n";
187List_alloc::sanity_check_list(
char const *func,
char const *info,
190 Mem_block
const *c = _first;
191 for (;c ; c = c->next)
197 L4::cerr <<
"List_alloc(FATAL): " << func <<
'(' << info
198 <<
"): list order violation\n";
201 unsigned long c_end =
reinterpret_cast<unsigned long>(c) + c->size;
202 unsigned long n_start =
reinterpret_cast<unsigned long>(c->next);
203 if (c_end > n_start || (c_end == n_start && !unmerged))
205 L4::cerr <<
"List_alloc(FATAL): " << func <<
'(' << info
206 <<
"): list order violation\n";
218List_alloc::merge(Mem_block *prev, Mem_block *c)
221 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__,
true);
230 while (c && c->next && iters--)
232 unsigned long f_start =
reinterpret_cast<unsigned long>(c);
233 unsigned long f_end = f_start + c->size;
234 unsigned long n_start =
reinterpret_cast<unsigned long>(c->next);
236 if (f_end == n_start)
238 c->size += c->next->size;
239 c->next = c->next->next;
250 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__,
false);
252 unsigned long const mb_align = (1UL <<
arith::Ld<
sizeof(Mem_block)>::value) - 1;
257 unsigned long nblock = (
reinterpret_cast<unsigned long>(block) + mb_align)
259 size = (size - (nblock -
reinterpret_cast<unsigned long>(block)))
261 block =
reinterpret_cast<void*
>(nblock);
265 size = (size + mb_align) & ~mb_align;
267 check_overlap(block, size);
270 Mem_block **c = &_first;
275 while (*c && *c < block)
284 *c =
reinterpret_cast<Mem_block*
>(block);
294 unsigned granularity,
unsigned long lower,
297 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__,
false);
299 unsigned char const mb_bits =
arith::Ld<
sizeof(Mem_block)>::value;
300 unsigned long const mb_align = (1UL << mb_bits) - 1;
307 *max = *max & ~(granularity - 1UL);
312 unsigned long almask = align ? (align - 1UL) : 0;
315 if (almask < mb_align)
318 Mem_block **c = &_first;
320 unsigned long max_fit = 0;
321 unsigned long a_lower = (lower + almask) & ~almask;
323 for (; *c; c = &(*c)->next)
326 unsigned long n_start =
reinterpret_cast<unsigned long>(*c);
330 if ((*c)->size < min)
334 if (upper < n_start || a_lower > n_start + (*c)->size)
338 unsigned long a_start = (n_start + almask) & ~almask;
341 if (a_start - n_start >= (*c)->size)
344 a_start = a_start < a_lower ? a_lower : a_start;
347 if (min > ~0UL - a_start)
351 if (a_start + min - 1UL > upper)
355 unsigned long r_size = (*c)->size - a_start + n_start;
358 if (a_start + r_size - 1UL > upper)
359 r_size = upper - a_start + 1UL;
362 r_size &= ~(granularity - 1UL);
375 if (r_size > max_fit)
384 unsigned long n_start =
reinterpret_cast<unsigned long>(*fit);
385 unsigned long a_lower = (lower + almask) & ~almask;
386 unsigned long a_start = (n_start + almask) & ~almask;
387 a_start = a_start < a_lower ? a_lower : a_start;
388 unsigned long r_size = (*fit)->size - a_start + n_start;
390 if (a_start > n_start)
392 (*fit)->size -= r_size;
399 if (r_size == max_fit)
400 return reinterpret_cast<void *
>(a_start);
402 Mem_block *m =
reinterpret_cast<Mem_block*
>(a_start + max_fit);
404 m->size = r_size - max_fit;
406 return reinterpret_cast<void *
>(a_start);
416 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__,
false);
418 unsigned long const mb_align
419 = (1UL <<
arith::Ld<
sizeof(Mem_block)>::value) - 1;
422 size = (size + mb_align) & ~mb_align;
424 unsigned long almask = align ? (align - 1UL) : 0;
427 if (almask < mb_align)
430 Mem_block **c = &_first;
431 unsigned long a_lower = (lower + almask) & ~almask;
433 for (; *c; c=&(*c)->next)
436 unsigned long n_start =
reinterpret_cast<unsigned long>(*c);
440 if ((*c)->size < size)
444 if (upper < n_start || a_lower > n_start + (*c)->size)
448 unsigned long a_start = (n_start + almask) & ~almask;
451 if (a_start - n_start >= (*c)->size)
454 a_start = a_start < a_lower ? a_lower : a_start;
457 if (size > ~0UL - a_start)
461 if (a_start + size - 1UL > upper)
466 unsigned long r_size = (*c)->size - a_start + n_start;
472 if (a_start > n_start)
477 (*c)->size -= r_size;
487 return reinterpret_cast<void*
>(a_start);
490 Mem_block *m =
reinterpret_cast<Mem_block*
>(a_start + size);
492 m->size = r_size - size;
494 return reinterpret_cast<void *
>(a_start);
503 List_alloc_sanity_guard
504 __attribute__((unused)) guard(
this, __FUNCTION__,
false);
505 Mem_block
const *c = _first;
516template <
typename DBG>
518List_alloc::dump_free_list(DBG &out)
const
520 Mem_block
const *c = _first;
523 static constexpr char const *
const unitstr[4] =
524 {
"Byte",
"KiB",
"MiB",
"GiB" };
526 unsigned sz = c->size;
528 for (i = 0; i < cxx::array_size(unitstr) && sz > 8 << 10; ++i)
531 out.printf(
"%12p - %12p (%u %s)\n",
532 c,
reinterpret_cast<char const *
>(c) + c->size - 1, sz, unitstr[i]);
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.
unsigned long avail() const
Get the amount of available memory.
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.