Clean up 'Sliced_heap'

This patch cleans up the implementation of the sliced heap, adds a
constructor that takes references instead of pointers, and adds the
function 'meta_data_size' to determine the meta-data overhead per block.
The latter can be used to dimension slab allocators such that slab
blocks use whole pages.
This commit is contained in:
Norman Feske 2016-04-28 16:39:45 +02:00 committed by Christian Helmuth
parent 4f69772ecc
commit ba0545de07
2 changed files with 76 additions and 67 deletions

View File

@ -174,20 +174,44 @@ class Genode::Sliced_heap : public Allocator
{
private:
class Block;
/**
* Meta-data header placed in front of each allocated block
*/
struct Block : List<Block>::Element
{
Ram_dataspace_capability const ds;
size_t const size;
Ram_session *_ram_session; /* RAM session for backing store */
Region_map *_region_map; /* region map of the address space */
Block(Ram_dataspace_capability ds, size_t size) : ds(ds), size(size)
{ }
};
Ram_session &_ram_session; /* RAM session for backing store */
Region_map &_region_map; /* region map of the address space */
size_t _consumed; /* number of allocated bytes */
List<Block> _block_list; /* list of allocated blocks */
List<Block> _blocks; /* list of allocated blocks */
Lock _lock; /* serialize allocations */
public:
/**
* Return size of header prepended to each allocated block in bytes
*/
static constexpr size_t meta_data_size() { return sizeof(Block); }
/**
* Constructor
*
* \deprecated Use the other constructor that takes reference
* arguments
*/
Sliced_heap(Ram_session *ram_session, Region_map *region_map)
: Sliced_heap(*ram_session, *region_map) { }
/**
* Constructor
*/
Sliced_heap(Ram_session *ram_session, Region_map *region_map);
Sliced_heap(Ram_session &ram_session, Region_map &region_map);
/**
* Destructor

View File

@ -5,67 +5,37 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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.
*/
#include <util/construct_at.h>
#include <base/heap.h>
#include <base/printf.h>
namespace Genode {
class Sliced_heap::Block : public List<Sliced_heap::Block>::Element
{
private:
Ram_dataspace_capability _ds_cap;
size_t _size;
char _data[];
public:
inline void *operator new(size_t size, void *at_addr) {
return at_addr; }
inline void operator delete (void*) { }
/**
* Constructor
*/
Block(Ram_dataspace_capability ds_cap, size_t size):
_ds_cap(ds_cap), _size(size) { }
/**
* Accessors
*/
Ram_dataspace_capability ds_cap() { return _ds_cap; }
size_t size() { return _size; }
void *data_start() { return &_data[0]; }
/**
* Lookup Slab_entry by given address
*
* The specified address is supposed to point to data[0].
*/
static Block *block(void *addr) {
return (Block *)((addr_t)addr - sizeof(Block)); }
};
}
using namespace Genode;
Sliced_heap::Sliced_heap(Ram_session *ram_session, Region_map *region_map):
_ram_session(ram_session), _region_map(region_map),
_consumed(0) { }
Sliced_heap::Sliced_heap(Ram_session &ram_session, Region_map &region_map)
:
_ram_session(ram_session), _region_map(region_map), _consumed(0)
{ }
Sliced_heap::~Sliced_heap()
{
for (Block *b; (b = _block_list.first()); )
free(b->data_start(), b->size()); }
for (Block *b; (b = _blocks.first()); ) {
/*
* Compute pointer to payload, which follows the meta-data header.
* Note the pointer arithmetics. By adding 1 to 'b', we end up with
* 'payload' pointing to the data portion of the block.
*/
void * const payload = b + 1;
free(payload, b->size);
}
}
bool Sliced_heap::alloc(size_t size, void **out_addr)
@ -74,14 +44,14 @@ bool Sliced_heap::alloc(size_t size, void **out_addr)
size = align_addr(size + sizeof(Block), 12);
Ram_dataspace_capability ds_cap;
void *local_addr;
Block *block = nullptr;
try {
ds_cap = _ram_session->alloc(size);
local_addr = _region_map->attach(ds_cap);
ds_cap = _ram_session.alloc(size);
block = _region_map.attach(ds_cap);
} catch (Region_map::Attach_failed) {
PERR("Could not attach dataspace to local address space");
_ram_session->free(ds_cap);
_ram_session.free(ds_cap);
return false;
} catch (Ram_session::Alloc_failed) {
PERR("Could not allocate dataspace with size %zu", size);
@ -91,10 +61,14 @@ bool Sliced_heap::alloc(size_t size, void **out_addr)
/* serialize access to block list */
Lock::Guard lock_guard(_lock);
Block *b = new(local_addr) Block(ds_cap, size);
construct_at<Block>(block, ds_cap, size);
_consumed += size;
_block_list.insert(b);
*out_addr = b->data_start();
_blocks.insert(block);
/* skip meta data prepended to the payload portion of the block */
*out_addr = block + 1;
return true;
}
@ -102,21 +76,32 @@ bool Sliced_heap::alloc(size_t size, void **out_addr)
void Sliced_heap::free(void *addr, size_t size)
{
Ram_dataspace_capability ds_cap;
void * local_addr;
void *local_addr = nullptr;
{
/* serialize access to block list */
Lock::Guard lock_guard(_lock);
Block *b = Block::block(addr);
_block_list.remove(b);
_consumed -= b->size();
ds_cap = b->ds_cap();
local_addr = b;
delete b;
/*
* The 'addr' argument points to the payload. We use pointer
* arithmetics to determine the pointer to the block's meta data that
* is prepended to the payload.
*/
Block * const block = reinterpret_cast<Block *>(addr) - 1;
_blocks.remove(block);
_consumed -= block->size;
ds_cap = block->ds;
local_addr = block;
/*
* Call destructor to properly destruct the dataspace capability
* member of the 'Block'.
*/
block->~Block();
}
_region_map->detach(local_addr);
_ram_session->free(ds_cap);
_region_map.detach(local_addr);
_ram_session.free(ds_cap);
}