2012-05-18 17:04:52 +02:00
|
|
|
/*
|
|
|
|
* \brief Allocator for anonymous memory used by libc
|
|
|
|
* \author Norman Feske
|
|
|
|
* \date 2012-05-18
|
|
|
|
*
|
|
|
|
* The libc uses a dedicated allocator instead of 'env()->heap()' because the
|
|
|
|
* 'Allocator' interface of 'env()->heap()' does not allow for aligned
|
|
|
|
* allocations. Some libc functions, however, rely on aligned memory. For
|
|
|
|
* example the blocks returned by mmap for allocating anonymous memory are
|
|
|
|
* assumed to be page-aligned.
|
|
|
|
*
|
|
|
|
* The code is largely based on 'base/include/base/heap.h' and
|
2016-04-29 13:23:19 +02:00
|
|
|
* 'base/src/lib/base/heap.cc'.
|
2012-05-18 17:04:52 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
#include <base/env.h>
|
|
|
|
#include <base/allocator_avl.h>
|
|
|
|
|
libc: split task.cc into multiple files
This patch is the first step of re-organizing the internal structure of
the libc. The original version involved many direct calls of global
functions (often with side effects) across compilation units, which
made the control flow (e.g., the initialization sequence) hard to
follow.
The new version replaces those ad-hoc interactions with dedicated
interfaces (like suspend.h, resume.h, select.h, current_time.h). The
underlying facilities are provided by the central Libc::Kernel and
selectively propagated to the various compilation units. The latter is
done by a sequence of 'init_*' calls, which eventually will be replaced
by constructor calls.
The addition of new headers increases the chance for name clashes with
existing (public) headers. To disambiguate libc-internal header files
from public headers, this patch moves the former into a new 'internal/'
subdirectory. This makes the include directives easier to follow and the
libc's source-tree structure more tidy.
There are still a few legacies left, which cannot easily be removed
right now (e.g., because noux relies on them). However, the patch moves
those bad apples to legacy.h and legacy.cc, which highlights the
deprecation of those functions.
Issue #3497
2019-09-18 20:19:10 +02:00
|
|
|
/* libc-internal includes */
|
|
|
|
#include <internal/mem_alloc.h>
|
|
|
|
#include <internal/init.h>
|
2012-05-18 17:04:52 +02:00
|
|
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
|
|
|
|
|
|
|
Libc::Mem_alloc_impl::Dataspace_pool::~Dataspace_pool()
|
|
|
|
{
|
|
|
|
/* free all ram_dataspaces */
|
|
|
|
for (Dataspace *ds; (ds = first()); ) {
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read dataspace capability and modify _ds_list before detaching
|
|
|
|
* possible backing store for Dataspace - we rely on LIFO list
|
|
|
|
* manipulation here!
|
|
|
|
*/
|
|
|
|
|
|
|
|
Ram_dataspace_capability ds_cap = ds->cap;
|
2017-10-18 14:14:07 +02:00
|
|
|
void const * const local_addr = ds->local_addr;
|
2012-05-18 17:04:52 +02:00
|
|
|
|
|
|
|
remove(ds);
|
|
|
|
delete ds;
|
2017-10-18 14:14:07 +02:00
|
|
|
|
|
|
|
_region_map->detach(local_addr);
|
2019-01-21 15:59:00 +01:00
|
|
|
_ram->free(ds_cap);
|
2012-05-18 17:04:52 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Libc::Mem_alloc_impl::Dataspace_pool::expand(size_t size, Range_allocator *alloc)
|
|
|
|
{
|
|
|
|
Ram_dataspace_capability new_ds_cap;
|
|
|
|
void *local_addr, *ds_addr = 0;
|
|
|
|
|
|
|
|
/* make new ram dataspace available at our local address space */
|
|
|
|
try {
|
2019-01-21 15:59:00 +01:00
|
|
|
new_ds_cap = _ram->alloc(size);
|
2017-10-18 14:14:07 +02:00
|
|
|
|
|
|
|
enum { MAX_SIZE = 0, NO_OFFSET = 0, ANY_LOCAL_ADDR = false };
|
|
|
|
local_addr = _region_map->attach(new_ds_cap, MAX_SIZE, NO_OFFSET,
|
|
|
|
ANY_LOCAL_ADDR, nullptr, _executable);
|
2017-05-08 19:55:54 +02:00
|
|
|
}
|
|
|
|
catch (Out_of_ram) { return -2; }
|
|
|
|
catch (Out_of_caps) { return -4; }
|
Streamline exception types
This patch reduces the number of exception types by facilitating
globally defined exceptions for common usage patterns shared by most
services. In particular, RPC functions that demand a session-resource
upgrade not longer reflect this condition via a session-specific
exception but via the 'Out_of_ram' or 'Out_of_caps' types.
Furthermore, the 'Parent::Service_denied', 'Parent::Unavailable',
'Root::Invalid_args', 'Root::Unavailable', 'Service::Invalid_args',
'Service::Unavailable', and 'Local_service::Factory::Denied' types have
been replaced by the single 'Service_denied' exception type defined in
'session/session.h'.
This consolidation eases the error handling (there are fewer exceptions
to handle), alleviates the need to convert exceptions along the
session-creation call chain, and avoids possible aliasing problems
(catching the wrong type with the same name but living in a different
scope).
2017-05-07 22:03:22 +02:00
|
|
|
catch (Region_map::Region_conflict) {
|
2019-01-21 15:59:00 +01:00
|
|
|
_ram->free(new_ds_cap);
|
2012-05-18 17:04:52 +02:00
|
|
|
return -3;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add new local address range to our local allocator */
|
|
|
|
alloc->add_range((addr_t)local_addr, size);
|
|
|
|
|
|
|
|
/* now that we have new backing store, allocate Dataspace structure */
|
2016-05-11 18:21:47 +02:00
|
|
|
if (alloc->alloc_aligned(sizeof(Dataspace), &ds_addr, 2).error()) {
|
2017-01-31 16:01:07 +01:00
|
|
|
Genode::warning("libc: could not allocate meta data - this should never happen");
|
2012-05-18 17:04:52 +02:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add dataspace information to list of dataspaces */
|
|
|
|
Dataspace *ds = new (ds_addr) Dataspace(new_ds_cap, local_addr);
|
|
|
|
insert(ds);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void *Libc::Mem_alloc_impl::alloc(size_t size, size_t align_log2)
|
|
|
|
{
|
|
|
|
/* serialize access of heap functions */
|
|
|
|
Lock::Guard lock_guard(_lock);
|
|
|
|
|
|
|
|
/* try allocation at our local allocator */
|
|
|
|
void *out_addr = 0;
|
2016-05-11 18:21:47 +02:00
|
|
|
if (_alloc.alloc_aligned(size, &out_addr, align_log2).ok())
|
2012-05-18 17:04:52 +02:00
|
|
|
return out_addr;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate block size of needed backing store. The block must hold the
|
2018-07-26 14:50:12 +02:00
|
|
|
* requested 'size' with the requested alignment, a new Dataspace structure
|
|
|
|
* and space for AVL-node slab blocks if the allocation above failed.
|
2013-11-15 22:40:46 +01:00
|
|
|
* Finally, we align the size to a 4K page.
|
2012-05-18 17:04:52 +02:00
|
|
|
*/
|
2018-07-26 14:50:12 +02:00
|
|
|
size_t request_size = size + max((1 << align_log2), 1024) +
|
|
|
|
Allocator_avl::slab_block_size() + sizeof(Dataspace);
|
2012-05-18 17:04:52 +02:00
|
|
|
|
|
|
|
if (request_size < _chunk_size*sizeof(umword_t)) {
|
|
|
|
request_size = _chunk_size*sizeof(umword_t);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Exponentially increase chunk size with each allocated chunk until
|
|
|
|
* we hit 'MAX_CHUNK_SIZE'.
|
|
|
|
*/
|
|
|
|
_chunk_size = min(2*_chunk_size, (size_t)MAX_CHUNK_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_ds_pool.expand(align_addr(request_size, 12), &_alloc) < 0) {
|
2017-01-31 16:01:07 +01:00
|
|
|
Genode::warning("libc: could not expand dataspace pool");
|
2012-05-18 17:04:52 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate originally requested block */
|
2016-05-11 18:21:47 +02:00
|
|
|
return _alloc.alloc_aligned(size, &out_addr, align_log2).ok() ? out_addr : 0;
|
2012-05-18 17:04:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Libc::Mem_alloc_impl::free(void *addr)
|
|
|
|
{
|
|
|
|
/* serialize access of heap functions */
|
|
|
|
Lock::Guard lock_guard(_lock);
|
|
|
|
|
|
|
|
/* forward request to our local allocator */
|
|
|
|
_alloc.free(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-08-26 17:26:13 +02:00
|
|
|
Genode::size_t Libc::Mem_alloc_impl::size_at(void const *addr) const
|
|
|
|
{
|
|
|
|
/* serialize access of heap functions */
|
|
|
|
Lock::Guard lock_guard(_lock);
|
|
|
|
|
|
|
|
/* forward request to our local allocator */
|
|
|
|
return _alloc.size_at(addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-18 14:20:49 +02:00
|
|
|
static Libc::Mem_alloc *_libc_mem_alloc_rw = nullptr;
|
|
|
|
static Libc::Mem_alloc *_libc_mem_alloc_rwx = nullptr;
|
2017-01-31 16:01:07 +01:00
|
|
|
|
|
|
|
|
2019-01-21 15:59:00 +01:00
|
|
|
static void _init_mem_alloc(Genode::Region_map &rm, Genode::Ram_allocator &ram)
|
2017-02-07 15:10:24 +01:00
|
|
|
{
|
2017-10-18 14:20:49 +02:00
|
|
|
enum { MEMORY_EXECUTABLE = true };
|
|
|
|
|
|
|
|
static Libc::Mem_alloc_impl inst_rw(rm, ram, !MEMORY_EXECUTABLE);
|
|
|
|
static Libc::Mem_alloc_impl inst_rwx(rm, ram, MEMORY_EXECUTABLE);
|
|
|
|
|
|
|
|
_libc_mem_alloc_rw = &inst_rw;
|
|
|
|
_libc_mem_alloc_rwx = &inst_rwx;
|
2017-02-07 15:10:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-01-31 16:01:07 +01:00
|
|
|
namespace Libc {
|
|
|
|
|
|
|
|
void init_mem_alloc(Genode::Env &env)
|
|
|
|
{
|
2017-02-07 15:10:24 +01:00
|
|
|
_init_mem_alloc(env.rm(), env.ram());
|
2017-01-31 16:01:07 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-10-18 14:20:49 +02:00
|
|
|
Libc::Mem_alloc *Libc::mem_alloc(bool executable)
|
2012-05-18 17:04:52 +02:00
|
|
|
{
|
2017-10-18 14:20:49 +02:00
|
|
|
if (!_libc_mem_alloc_rw || !_libc_mem_alloc_rwx)
|
2017-01-31 16:01:07 +01:00
|
|
|
error("attempt to use 'Libc::mem_alloc' before call of 'init_mem_alloc'");
|
2012-05-18 17:04:52 +02:00
|
|
|
|
2017-10-18 14:20:49 +02:00
|
|
|
return executable ? _libc_mem_alloc_rwx : _libc_mem_alloc_rw;
|
|
|
|
}
|