genode/repos/base/include/base/heap.h
Norman Feske 511acad507 Consolidate RM service into PD session
This patch integrates three region maps into each PD session to
reduce the session overhead and to simplify the PD creation procedure.
Please refer to the issue cited below for an elaborative discussion.

Note the API change:

With this patch, the semantics of core's RM service have changed. Now,
the service is merely a tool for creating and destroying managed
dataspaces, which are rarely needed. Regular components no longer need a
RM session. For this reason, the corresponding argument for the
'Process' and 'Child' constructors has been removed.

The former interface of the 'Rm_session' is not named 'Region_map'. As a
minor refinement, the 'Fault_type' enum values are now part of the
'Region_map::State' struct.

Issue #1938
2016-05-09 13:10:51 +02:00

210 lines
5.5 KiB
C++

/*
* \brief Heap partition
* \author Norman Feske
* \date 2006-05-15
*/
/*
* Copyright (C) 2006-2013 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__HEAP_H_
#define _INCLUDE__BASE__HEAP_H_
#include <util/list.h>
#include <util/volatile_object.h>
#include <ram_session/ram_session.h>
#include <region_map/region_map.h>
#include <base/allocator_avl.h>
#include <base/lock.h>
namespace Genode {
class Heap;
class Sliced_heap;
}
/**
* Heap that uses dataspaces as backing store
*
* The heap class provides an allocator that uses a list of dataspaces of a RAM
* session as backing store. One dataspace may be used for holding multiple blocks.
*/
class Genode::Heap : public Allocator
{
private:
enum {
MIN_CHUNK_SIZE = 4*1024, /* in machine words */
MAX_CHUNK_SIZE = 256*1024,
/*
* Meta data includes the Dataspace structure and meta data of
* the AVL allocator.
*/
META_DATA_SIZE = 1024, /* in bytes */
/*
* Allocation sizes >= this value are considered as big
* allocations, which get their own dataspace. In contrast
* to smaller allocations, this memory is released to
* the RAM session when 'free()' is called.
*/
BIG_ALLOCATION_THRESHOLD = 64*1024 /* in bytes */
};
class Dataspace : public List<Dataspace>::Element
{
public:
Ram_dataspace_capability cap;
void *local_addr;
size_t size;
Dataspace(Ram_dataspace_capability c, void *local_addr, size_t size)
: cap(c), local_addr(local_addr), size(size) { }
};
/*
* This structure exists only to make sure that the dataspaces are
* destroyed after the AVL allocator.
*/
struct Dataspace_pool : public List<Dataspace>
{
Ram_session *ram_session; /* RAM session for backing store */
Region_map *region_map;
Dataspace_pool(Ram_session *ram, Region_map *rm)
: ram_session(ram), region_map(rm) { }
~Dataspace_pool();
void reassign_resources(Ram_session *ram, Region_map *rm) {
ram_session = ram, region_map = rm; }
};
Lock _lock;
Volatile_object<Allocator_avl> _alloc; /* local allocator */
Dataspace_pool _ds_pool; /* list of dataspaces */
size_t _quota_limit;
size_t _quota_used;
size_t _chunk_size;
/**
* Allocate a new dataspace of the specified size
*
* \param size number of bytes to allocate
* \param enforce_separate_metadata if true, the new dataspace
* will not contain any meta data
* \throw Region_map::Invalid_dataspace,
* Region_map::Region_conflict
* \return 0 on success or negative error code
*/
Heap::Dataspace *_allocate_dataspace(size_t size, bool enforce_separate_metadata);
/**
* Try to allocate block at our local allocator
*
* \return true on success
*
* This method is a utility used by '_unsynchronized_alloc' to
* avoid code duplication.
*/
bool _try_local_alloc(size_t size, void **out_addr);
/**
* Unsynchronized implementation of 'alloc'
*/
bool _unsynchronized_alloc(size_t size, void **out_addr);
public:
enum { UNLIMITED = ~0 };
Heap(Ram_session *ram_session,
Region_map *region_map,
size_t quota_limit = UNLIMITED,
void *static_addr = 0,
size_t static_size = 0)
:
_alloc(nullptr),
_ds_pool(ram_session, region_map),
_quota_limit(quota_limit), _quota_used(0),
_chunk_size(MIN_CHUNK_SIZE)
{
if (static_addr)
_alloc->add_range((addr_t)static_addr, static_size);
}
~Heap();
/**
* Reconfigure quota limit
*
* \return negative error code if new quota limit is higher than
* currently used quota.
*/
int quota_limit(size_t new_quota_limit);
/**
* Re-assign RAM and RM sessions
*/
void reassign_resources(Ram_session *ram, Region_map *rm) {
_ds_pool.reassign_resources(ram, rm); }
/*************************
** Allocator interface **
*************************/
bool alloc(size_t, void **) override;
void free(void *, size_t) override;
size_t consumed() const override { return _quota_used; }
size_t overhead(size_t size) const override { return _alloc->overhead(size); }
bool need_size_for_free() const override { return false; }
};
/**
* Heap that allocates each block at a separate dataspace
*/
class Genode::Sliced_heap : public Allocator
{
private:
class Block;
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 */
Lock _lock; /* serialize allocations */
public:
/**
* Constructor
*/
Sliced_heap(Ram_session *ram_session, Region_map *region_map);
/**
* Destructor
*/
~Sliced_heap();
/*************************
** Allocator interface **
*************************/
bool alloc(size_t, void **);
void free(void *, size_t);
size_t consumed() const { return _consumed; }
size_t overhead(size_t size) const;
bool need_size_for_free() const override { return false; }
};
#endif /* _INCLUDE__BASE__HEAP_H_ */