12#include <l4/cxx/arith>
13#include <l4/cxx/minmax>
14#include <l4/sys/consts.h>
24 friend class List_alloc_sanity_guard;
34 inline void check_overlap(
void *,
unsigned long );
35 inline void sanity_check_list(
char const *,
char const *);
60 inline void free(
void *block,
unsigned long size,
bool initial_free =
false);
76 inline void *
alloc(
unsigned long size,
unsigned long align,
77 unsigned long lower = 0,
unsigned long upper = ~0UL);
99 inline void *
alloc_max(
unsigned long min,
unsigned long *max,
100 unsigned long align,
unsigned granularity,
101 unsigned long lower = 0,
unsigned long upper = ~0UL);
108 inline unsigned long avail();
110 template <
typename DBG>
111 void dump_free_list(DBG &out);
114#if !defined (CXX_LIST_ALLOC_SANITY)
115class List_alloc_sanity_guard
118 List_alloc_sanity_guard(List_alloc *,
char const *)
125List_alloc::check_overlap(
void *,
unsigned long )
129List_alloc::sanity_check_list(
char const *,
char const *)
134class List_alloc_sanity_guard
141 List_alloc_sanity_guard(List_alloc *a,
char const *func)
143 { a->sanity_check_list(func,
"entry"); }
145 ~List_alloc_sanity_guard()
146 { a->sanity_check_list(func,
"exit"); }
150List_alloc::check_overlap(
void *b,
unsigned long s)
152 unsigned long const mb_align = (1UL << arith::Ld<
sizeof(Mem_block)>::value) - 1;
153 if ((
unsigned long)b & mb_align)
155 L4::cerr <<
"List_alloc(FATAL): trying to free unaligned memory: "
156 << b <<
" align=" << arith::Ld<
sizeof(Mem_block)>::value <<
"\n";
159 Mem_block *c = _first;
160 for (;c ; c = c->next)
162 unsigned long x_s = (
unsigned long)b;
163 unsigned long x_e = x_s + s;
164 unsigned long b_s = (
unsigned long)c;
165 unsigned long b_e = b_s + c->size;
167 if ((x_s >= b_s && x_s < b_e)
168 || (x_e > b_s && x_e <= b_e)
169 || (b_s >= x_s && b_s < x_e)
170 || (b_e > x_s && b_e <= x_e))
172 L4::cerr <<
"List_alloc(FATAL): trying to free memory that "
173 "is already free: \n ["
174 << (
void*)x_s <<
'-' << (
void*)x_e <<
") overlaps ["
175 << (
void*)b_s <<
'-' << (
void*)b_e <<
")\n";
181List_alloc::sanity_check_list(
char const *func,
char const *info)
183 Mem_block *c = _first;
184 for (;c ; c = c->next)
190 L4::cerr <<
"List_alloc(FATAL): " << func <<
'(' << info
191 <<
"): list order violation\n";
194 if (((
unsigned long)c) + c->size > (
unsigned long)c->next)
196 L4::cerr <<
"List_alloc(FATAL): " << func <<
'(' << info
197 <<
"): list order violation\n";
208 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
209 Mem_block *c = _first;
212 unsigned long f_start =
reinterpret_cast<unsigned long>(c);
213 unsigned long f_end = f_start + c->size;
214 unsigned long n_start =
reinterpret_cast<unsigned long>(c->next);
216 if (f_end == n_start)
218 c->size += c->next->size;
219 c->next = c->next->next;
230 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
232 unsigned long const mb_align = (1UL << arith::Ld<
sizeof(Mem_block)>::value) - 1;
237 unsigned long nblock = (
reinterpret_cast<unsigned long>(block) + mb_align)
239 size = (size - (nblock -
reinterpret_cast<unsigned long>(block)))
241 block =
reinterpret_cast<void*
>(nblock);
245 size = (size + mb_align) & ~mb_align;
247 check_overlap(block, size);
249 Mem_block **c = &_first;
254 while (*c && *c < block)
260 *c =
reinterpret_cast<Mem_block*
>(block);
270 unsigned granularity,
unsigned long lower,
273 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
275 unsigned char const mb_bits = arith::Ld<
sizeof(Mem_block)>::value;
276 unsigned long const mb_align = (1UL << mb_bits) - 1;
283 *max = *max & ~(granularity - 1UL);
288 unsigned long almask = align ? (align - 1UL) : 0;
291 if (almask < mb_align)
294 Mem_block **c = &_first;
296 unsigned long max_fit = 0;
297 unsigned long a_lower = (lower + almask) & ~almask;
299 for (; *c; c = &(*c)->next)
302 unsigned long n_start =
reinterpret_cast<unsigned long>(*c);
306 if ((*c)->size < min)
310 if (upper < n_start || a_lower > n_start + (*c)->size)
314 unsigned long a_start = (n_start + almask) & ~almask;
317 if (a_start - n_start >= (*c)->size)
320 a_start = a_start < a_lower ? a_lower : a_start;
323 if (min > ~0UL - a_start)
327 if (a_start + min - 1UL > upper)
331 unsigned long r_size = (*c)->size - a_start + n_start;
334 if (a_start + r_size - 1UL > upper)
335 r_size = upper - a_start + 1UL;
338 r_size &= ~(granularity - 1UL);
351 if (r_size > max_fit)
360 unsigned long n_start =
reinterpret_cast<unsigned long>(*fit);
361 unsigned long a_lower = (lower + almask) & ~almask;
362 unsigned long a_start = (n_start + almask) & ~almask;
363 a_start = a_start < a_lower ? a_lower : a_start;
364 unsigned long r_size = (*fit)->size - a_start + n_start;
366 if (a_start > n_start)
368 (*fit)->size -= r_size;
375 if (r_size == max_fit)
376 return reinterpret_cast<void *
>(a_start);
378 Mem_block *m =
reinterpret_cast<Mem_block*
>(a_start + max_fit);
380 m->size = r_size - max_fit;
382 return reinterpret_cast<void *
>(a_start);
392 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __func__);
394 unsigned long const mb_align
395 = (1UL << arith::Ld<
sizeof(Mem_block)>::value) - 1;
398 size = (size + mb_align) & ~mb_align;
400 unsigned long almask = align ? (align - 1UL) : 0;
403 if (almask < mb_align)
406 Mem_block **c = &_first;
407 unsigned long a_lower = (lower + almask) & ~almask;
409 for (; *c; c=&(*c)->next)
412 unsigned long n_start =
reinterpret_cast<unsigned long>(*c);
416 if ((*c)->size < size)
420 if (upper < n_start || a_lower > n_start + (*c)->size)
424 unsigned long a_start = (n_start + almask) & ~almask;
427 if (a_start - n_start >= (*c)->size)
430 a_start = a_start < a_lower ? a_lower : a_start;
433 if (size > ~0UL - a_start)
437 if (a_start + size - 1UL > upper)
442 unsigned long r_size = (*c)->size - a_start + n_start;
448 if (a_start > n_start)
453 (*c)->size -= r_size;
463 return reinterpret_cast<void*
>(a_start);
466 Mem_block *m =
reinterpret_cast<Mem_block*
>(a_start + size);
468 m->size = r_size - size;
470 return reinterpret_cast<void *
>(a_start);
479 List_alloc_sanity_guard __attribute__((unused)) guard(
this, __FUNCTION__);
480 Mem_block *c = _first;
491template <
typename DBG>
493List_alloc::dump_free_list(DBG &out)
495 Mem_block *c = _first;
506 else if (c->size < 1 << 20)
517 out.printf(
"%12p - %12p (%u %s)\n", c,
518 reinterpret_cast<char *
>(c) + c->size - 1, sz, unit);
Standard list-based allocator.
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.