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
This commit is contained in:
Alexander Boettcher 2012-07-16 10:01:56 +02:00 committed by Norman Feske
parent 67fdc1b44b
commit 44ef8912d6
4 changed files with 211 additions and 17 deletions

View File

@ -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 <base/bit_array.h>
namespace Genode {
template<addr_t WORDS>
class Bit_allocator
{
protected:
Bit_array<WORDS> _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_ */

View File

@ -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 <base/stdint.h>
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 <addr_t WORDS>
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_ */

View File

@ -19,17 +19,19 @@
#define _INCLUDE__BASE__CAP_SEL_ALLOC_H_
#include <base/stdint.h>
#include <base/printf.h>
#include <base/bit_allocator.h>
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();
};
/**

View File

@ -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);
}