From 44ef8912d6581499f5156fb45690236b4f763cad Mon Sep 17 00:00:00 2001 From: Alexander Boettcher Date: Mon, 16 Jul 2012 10:01:56 +0200 Subject: [PATCH] Add a bit array and bit allocator, issue #247 Add a allocator using bit maps to maintain used/unused caps. It supports the allocation of 2^n aligned caps solely and freeing of caps. Fixes #247 --- base-nova/include/base/bit_allocator.h | 67 ++++++++++++ base-nova/include/base/bit_array.h | 131 ++++++++++++++++++++++++ base-nova/include/base/cap_sel_alloc.h | 7 +- base-nova/src/base/env/cap_sel_alloc.cc | 23 ++--- 4 files changed, 211 insertions(+), 17 deletions(-) create mode 100644 base-nova/include/base/bit_allocator.h create mode 100644 base-nova/include/base/bit_array.h diff --git a/base-nova/include/base/bit_allocator.h b/base-nova/include/base/bit_allocator.h new file mode 100644 index 000000000..4cc966b3a --- /dev/null +++ b/base-nova/include/base/bit_allocator.h @@ -0,0 +1,67 @@ +/* + * \brief Allocator using bitmaps to maintain cap space + * \author Alexander Boettcher + * \date 2012-06-14 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__BASE__BIT_ALLOCATOR_H_ +#define _INCLUDE__BASE__BIT_ALLOCATOR_H_ + +#include + +namespace Genode { + + template + class Bit_allocator + { + protected: + Bit_array _array; + + void _reserve(addr_t bit_start, size_t const num_cap) + { + if (!num_cap) return; + + _array.set(bit_start, num_cap); + } + + public: + + addr_t alloc(size_t const num_log2) + { + addr_t const step = 1UL << num_log2; + addr_t i = 0; + + try { + /* + * Throws exception if array is + * accessed outside bounds + */ + while (true) { + if (_array.get(i, step)) { + i += step; + continue; + } + _array.set(i, step); + return i; + } + } catch (Bit_array_invalid_index_access) {} + + throw Bit_array_out_of_indexes(); + } + + void free(addr_t const bit_start, + size_t const num_log2) + { + _array.clear(bit_start, 1UL << num_log2); + } + + }; +} +#endif /* _INCLUDE__BASE__BIT_ALLOCATOR_H_ */ diff --git a/base-nova/include/base/bit_array.h b/base-nova/include/base/bit_array.h new file mode 100644 index 000000000..165195c6b --- /dev/null +++ b/base-nova/include/base/bit_array.h @@ -0,0 +1,131 @@ +/* + * \brief Allocator using bitmaps to maintain cap space + * \author Alexander Boettcher + * \date 2012-06-14 + */ + +/* + * Copyright (C) 2012 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU General Public License version 2. + */ + +#ifndef _INCLUDE__BASE__BIT_ARRAY_H_ +#define _INCLUDE__BASE__BIT_ARRAY_H_ + +#include + +namespace Genode { + + class Bit_array_invalid_index_access{}; + class Bit_array_invalid_clear{}; + class Bit_array_invalid_set{}; + class Bit_array_out_of_indexes{}; + + template + class Bit_array + { + private: + + enum { + _BITS_PER_BYTE = 8UL, + _BITS_PER_WORD = sizeof(addr_t) * _BITS_PER_BYTE, + }; + + addr_t _words[WORDS]; + + addr_t _word(addr_t index) const + { + return index / _BITS_PER_WORD; + } + + void _check_range(addr_t const index, + addr_t const width) const + { + if ((index >= WORDS * _BITS_PER_WORD) || + width > WORDS * _BITS_PER_WORD || + WORDS * _BITS_PER_WORD - width < index) + throw Bit_array_invalid_index_access(); + } + + addr_t _mask(addr_t const index, addr_t const width, + addr_t &rest) const + { + addr_t const shift = index - _word(index) * _BITS_PER_WORD; + + rest = width + shift > _BITS_PER_WORD ? + width + shift - _BITS_PER_WORD : 0; + + if (width >= _BITS_PER_WORD) + return ~0UL << shift; + else + return ((1UL << width) - 1) << shift; + + } + + void _set(addr_t index, addr_t width, bool free) + { + _check_range(index, width); + + addr_t rest, word, mask; + do { + word = _word(index); + mask = _mask(index, width, rest); + + if (free) { + if ((_words[word] & mask) != mask) + throw Bit_array_invalid_clear(); + _words[word] &= ~mask; + } else { + if (_words[word] & mask) + throw Bit_array_invalid_set(); + _words[word] |= mask; + } + + index = (_word(index) + 1) * _BITS_PER_WORD; + width = rest; + + } while (rest); + } + + public: + + Bit_array() + { + for (addr_t i = 0; i < WORDS; i++) _words[i] = 0UL; + } + + /** + * Return true if at least one bit is set between + * index until index + width - 1 + */ + bool get(addr_t index, addr_t width) const + { + _check_range(index, width); + + bool used = false; + addr_t rest, mask; + do { + mask = _mask(index, width, rest); + used = _words[_word(index)] & mask; + index = (_word(index) + 1) * _BITS_PER_WORD; + width = rest; + } while (!used && rest); + + return used; + } + + void set(addr_t const index, addr_t const width) + { + _set(index, width, false); + } + + void clear(addr_t const index, addr_t const width) + { + _set(index, width, true); + } + }; + +} +#endif /* _INCLUDE__BASE__BIT_ARRAY_H_ */ diff --git a/base-nova/include/base/cap_sel_alloc.h b/base-nova/include/base/cap_sel_alloc.h index 6ec0671af..b7b4a4e9c 100644 --- a/base-nova/include/base/cap_sel_alloc.h +++ b/base-nova/include/base/cap_sel_alloc.h @@ -19,17 +19,19 @@ #define _INCLUDE__BASE__CAP_SEL_ALLOC_H_ #include +#include +#include namespace Genode { - class Cap_selector_allocator + class Cap_selector_allocator : public Bit_allocator<4096> { public: /** * Constructor */ - Cap_selector_allocator(); + Cap_selector_allocator(); /** * Allocate range of capability selectors @@ -60,6 +62,7 @@ namespace Genode { * \return PD selector */ static unsigned pd_sel(); + }; /** diff --git a/base-nova/src/base/env/cap_sel_alloc.cc b/base-nova/src/base/env/cap_sel_alloc.cc index 1c21d6068..614cd4a68 100644 --- a/base-nova/src/base/env/cap_sel_alloc.cc +++ b/base-nova/src/base/env/cap_sel_alloc.cc @@ -4,7 +4,7 @@ * \author Sebastian Sumpf * \date 2010-01-19 * - * This is a NOVA-specific addition to the process enviroment. + * This is a NOVA-specific addition to the process environment. */ /* @@ -71,39 +71,32 @@ static Alloc_lock *alloc_lock() } -static int _cap_free; - - addr_t Cap_selector_allocator::alloc(size_t num_caps_log2) { alloc_lock()->lock(); - int num_caps = 1 << num_caps_log2; - int ret_base = (_cap_free + num_caps - 1) & ~(num_caps - 1); - _cap_free = ret_base + num_caps; + addr_t ret_base = Bit_allocator::alloc(num_caps_log2); alloc_lock()->unlock(); return ret_base; } - void Cap_selector_allocator::free(addr_t cap, size_t num_caps_log2) { - /* - * We don't free capability selectors because revoke is not supported - * on NOVA yet, anyway. - */ + alloc_lock()->lock(); + Bit_allocator::free(cap, num_caps_log2); + alloc_lock()->unlock(); + } unsigned Cap_selector_allocator::pd_sel() { return __local_pd_sel; } - -Cap_selector_allocator::Cap_selector_allocator() +Cap_selector_allocator::Cap_selector_allocator() : Bit_allocator<4096>() { /* initialize lock */ alloc_lock(); /* the first free selector is used for the lock */ - _cap_free = __first_free_cap_selector + 1; + Bit_allocator::_reserve(0, __first_free_cap_selector + 1); }