Cleanup and doc

This commit is contained in:
Baptiste Wicht 2016-09-27 15:13:57 +02:00
parent 7343b48e8d
commit 0d567e5332
No known key found for this signature in database
GPG Key ID: C5566B6C7F884532
2 changed files with 96 additions and 24 deletions

View File

@ -1,6 +1,5 @@
//======================================================================= //=======================================================================
// Copyright Baptiste Wicht 2013-2016. // Copyright Baptiste Wicht 2013-2016. // Distributed under the terms of the MIT License.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at // (See accompanying file LICENSE or copy at
// http://www.opensource.org/licenses/MIT) // http://www.opensource.org/licenses/MIT)
//======================================================================= //=======================================================================
@ -10,13 +9,15 @@
#include "assert.hpp" #include "assert.hpp"
/*!
* \brief A static bitmap.
*
* This bitmap cannot be extended. The data must be provided via one of its init functions.
*/
struct static_bitmap { struct static_bitmap {
typedef uint64_t data_type; using data_type = uint64_t; ///< The word type
static constexpr const size_t bits_per_word = sizeof(data_type) * 8; static constexpr const size_t bits_per_word = sizeof(data_type) * 8; ///< The number of bits stored in each word
size_t words;
data_type* data;
template<typename Array> template<typename Array>
void init(Array& array){ void init(Array& array){
@ -29,33 +30,51 @@ struct static_bitmap {
data = d; data = d;
} }
/*!
* \brief Returns the word in which the bit is
*/
static constexpr size_t word_offset(size_t bit){ static constexpr size_t word_offset(size_t bit){
return bit / bits_per_word; return bit / bits_per_word;
} }
/*!
* \brief Returns the offset of the bit inside its word
*/
static constexpr size_t bit_offset(size_t bit){ static constexpr size_t bit_offset(size_t bit){
return bit % bits_per_word; return bit % bits_per_word;
} }
/*
* \brief Constructs a bit mask for the given bit
*/
static constexpr data_type bit_mask(size_t bit){ static constexpr data_type bit_mask(size_t bit){
return static_cast<data_type>(1) << bit_offset(bit); return static_cast<data_type>(1) << bit_offset(bit);
} }
/*!
* \brief Clear the complete bit map (set everything to zero)
*/
void clear_all(){ void clear_all(){
for(size_t i = 0; i < words; ++i){ for(size_t i = 0; i < words; ++i){
data[i] = 0; data[i] = 0;
} }
} }
/*!
* \brief Set the complete bit map (set everything to one)
*/
void set_all(){ void set_all(){
for(size_t i = 0; i < words; ++i){ for(size_t i = 0; i < words; ++i){
data[i] = ~static_cast<data_type>(0); data[i] = ~static_cast<data_type>(0);
} }
} }
size_t free_bit() const { /*!
* \brief Returns the first set bit in the bit map
*/
size_t set_bit() const {
for(size_t w = 0; w < words; ++w){ for(size_t w = 0; w < words; ++w){
if(data[w] > 0){ if(data[w]){
for(size_t b = 0; b < bits_per_word; ++b){ for(size_t b = 0; b < bits_per_word; ++b){
if(data[w] & bit_mask(b)){ if(data[w] & bit_mask(b)){
return w * bits_per_word + b; return w * bits_per_word + b;
@ -67,7 +86,10 @@ struct static_bitmap {
thor_unreachable("static_bitmap has no free bit"); thor_unreachable("static_bitmap has no free bit");
} }
size_t free_word() const { /*!
* \brief Returns the first set word in the bit map
*/
size_t set_word() const {
for(size_t w = 0; w < words; ++w){ for(size_t w = 0; w < words; ++w){
if(data[w] == ~static_cast<data_type>(0)){ if(data[w] == ~static_cast<data_type>(0)){
return w * bits_per_word; return w * bits_per_word;
@ -77,17 +99,30 @@ struct static_bitmap {
thor_unreachable("static_bitmap has no free word"); thor_unreachable("static_bitmap has no free word");
} }
/*!
* \brief Indicates if the given bit is set
*/
bool is_set(size_t bit) const { bool is_set(size_t bit) const {
return data[word_offset(bit)] & bit_mask(bit); return data[word_offset(bit)] & bit_mask(bit);
} }
/*!
* \brief Sets the given bit to 1
*/
void set(size_t bit){ void set(size_t bit){
data[word_offset(bit)] |= bit_mask(bit); data[word_offset(bit)] |= bit_mask(bit);
} }
/*!
* \brief clear the given bit to 1
*/
void unset(size_t bit){ void unset(size_t bit){
data[word_offset(bit)] &= ~bit_mask(bit); data[word_offset(bit)] &= ~bit_mask(bit);
} }
private:
size_t words; ///< Number of words used in the bitmap
data_type* data; ///< The data storage
}; };
#endif #endif

View File

@ -13,32 +13,51 @@
#include "bitmap.hpp" #include "bitmap.hpp"
#include "logging.hpp" #include "logging.hpp"
/*!
* \brief Returns the nth power of x
*/
template <class T> template <class T>
inline constexpr T pow(T const& x, size_t n){ inline constexpr T pow(T const& x, size_t n){
return n > 0 ? x * pow(x, n - 1) : 1; return n > 0 ? x * pow(x, n - 1) : 1;
} }
/*!
* \brief Buddy allocator system.
*
* This is used to allocate physical and virtual memory
*/
template<size_t Levels, size_t Unit> template<size_t Levels, size_t Unit>
struct buddy_allocator { struct buddy_allocator {
static constexpr const size_t levels = Levels; static constexpr const size_t levels = Levels; ///< The number of levels in the allocator
static constexpr const size_t max_block = pow(2, levels - 1); static constexpr const size_t max_block = pow(2, levels - 1); ///< The size of the maximum block
std::array<static_bitmap, levels> bitmaps; std::array<static_bitmap, levels> bitmaps; ///< The bit maps for each level
size_t first_address; size_t first_address; ///< The first managed address
size_t last_address; size_t last_address; ///< The last managed address
public: public:
/*!
* \brief Sets the memory range of the allocator
*/
void set_memory_range(size_t first, size_t last){ void set_memory_range(size_t first, size_t last){
first_address = first; first_address = first;
last_address = last; last_address = last;
} }
/*!
* \brief Initialize the layer I
* \param words The number of words
* \param data The memory to use
*/
template<size_t I> template<size_t I>
void init(size_t words, uint64_t* data){ void init(size_t words, uint64_t* data){
bitmaps[I].init(words, data); bitmaps[I].init(words, data);
} }
/*!
* \brief Initialize the allocator
*/
void init(){ void init(){
//By default all blocks are free //By default all blocks are free
for(auto& bitmap : bitmaps){ for(auto& bitmap : bitmaps){
@ -46,6 +65,9 @@ public:
} }
} }
/*!
* \brief Allocate memory for the given amount of pages
*/
size_t allocate(size_t pages){ size_t allocate(size_t pages){
if(pages > max_block){ if(pages > max_block){
if(pages > max_block * static_bitmap::bits_per_word){ if(pages > max_block * static_bitmap::bits_per_word){
@ -55,7 +77,7 @@ public:
} else { } else {
// Select a level for which a whole word can hold the necessary pages // Select a level for which a whole word can hold the necessary pages
auto l = word_level(pages); auto l = word_level(pages);
auto index = bitmaps[l].free_word(); auto index = bitmaps[l].set_word();
auto address = block_start(l, index); auto address = block_start(l, index);
if(address + level_size(l) >= last_address){ if(address + level_size(l) >= last_address){
@ -72,7 +94,7 @@ public:
} }
} else { } else {
auto l = level(pages); auto l = level(pages);
auto index = bitmaps[l].free_bit(); auto index = bitmaps[l].set_bit();
auto address = block_start(l, index); auto address = block_start(l, index);
if(address + level_size(l) >= last_address){ if(address + level_size(l) >= last_address){
@ -86,6 +108,11 @@ public:
} }
} }
/*!
* \brief Free allocated memory pages
* \param address The allocated memory
* \param pages The number of pages to free
*/
void free(size_t address, size_t pages){ void free(size_t address, size_t pages){
if(pages > max_block){ if(pages > max_block){
if(pages > max_block * static_bitmap::bits_per_word){ if(pages > max_block * static_bitmap::bits_per_word){
@ -108,17 +135,17 @@ public:
} }
} }
/*!
* \brief The size of the given level
*/
static size_t level_size(size_t level){ static size_t level_size(size_t level){
size_t size = 1; return pow(2, level);
for(size_t i = 0; i < level; ++i){
size *= 2;
}
return size;
} }
private: private:
/*!
* \brief Returns the level to use for the given amount of pages
*/
static size_t level(size_t pages){ static size_t level(size_t pages){
if(pages > 64){ if(pages > 64){
return 7; return 7;
@ -153,6 +180,11 @@ private:
return levels; return levels;
} }
/*!
* \brief Mark the given buddy as used
* \param l The used level
* \param index The used index
*/
void mark_used(size_t l, size_t index){ void mark_used(size_t l, size_t index){
//Mark all sub blocks as taken //Mark all sub blocks as taken
taken_down(l, index); taken_down(l, index);
@ -164,6 +196,11 @@ private:
taken_up(l, index); taken_up(l, index);
} }
/*!
* \brief Mark the given buddy as free
* \param l The freed level
* \param index The freeed index
*/
void mark_free(size_t l, size_t index){ void mark_free(size_t l, size_t index){
//Free all sub blocks //Free all sub blocks
free_down(l, index); free_down(l, index);