diff --git a/repos/base/include/base/heap.h b/repos/base/include/base/heap.h index 4b92131b22..ec97d00315 100644 --- a/repos/base/include/base/heap.h +++ b/repos/base/include/base/heap.h @@ -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::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_list; /* list of allocated blocks */ + List _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 ®ion_map); /** * Destructor diff --git a/repos/base/src/base/heap/sliced_heap.cc b/repos/base/src/base/heap/sliced_heap.cc index 7d7f88a5c8..9ad5b3f8fe 100644 --- a/repos/base/src/base/heap/sliced_heap.cc +++ b/repos/base/src/base/heap/sliced_heap.cc @@ -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 #include #include -namespace Genode { - - class Sliced_heap::Block : public List::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 ®ion_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, 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(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); }