mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-18 18:56:29 +00:00
Let mmap return aligned anonymous memory
This commit is contained in:
parent
66290ea46d
commit
95766bd4a1
@ -12,7 +12,8 @@ LIBS += timed_semaphore cxx
|
||||
SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.cc munmap.cc \
|
||||
issetugid.cc errno.cc gai_strerror.cc clock_gettime.cc \
|
||||
gettimeofday.cc malloc.cc progname.cc fd_alloc.cc file_operations.cc \
|
||||
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc
|
||||
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
|
||||
libc_mem_alloc.cc
|
||||
|
||||
#
|
||||
# Files from string library that are not included in libc-raw_string because
|
||||
|
@ -31,6 +31,9 @@ extern "C" {
|
||||
|
||||
void exit(int status)
|
||||
{
|
||||
if (status == 4) {
|
||||
PDBG("PT: %p %p %p", __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
|
||||
}
|
||||
if (__cleanup)
|
||||
(*__cleanup)();
|
||||
|
||||
|
@ -12,19 +12,25 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/env.h>
|
||||
|
||||
/* Genode-specific libc interfaces */
|
||||
#include <libc-plugin/fd_alloc.h>
|
||||
#include <libc-plugin/plugin_registry.h>
|
||||
#include <libc-plugin/plugin.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* libc-internal includes */
|
||||
#include "libc_mem_alloc.h"
|
||||
|
||||
using namespace Libc;
|
||||
|
||||
|
||||
@ -258,9 +264,8 @@ extern "C" void *mmap(void *addr, ::size_t length, int prot, int flags,
|
||||
int libc_fd, ::off_t offset)
|
||||
{
|
||||
/* handle requests for anonymous memory */
|
||||
if (!addr && libc_fd == -1) {
|
||||
return malloc(length);
|
||||
}
|
||||
if (!addr && libc_fd == -1)
|
||||
return Libc::mem_alloc()->alloc(length, PAGE_SHIFT);
|
||||
|
||||
/* lookup plugin responsible for file descriptor */
|
||||
File_descriptor *fd = libc_fd_to_fd(libc_fd, "mmap");
|
||||
|
231
libports/src/lib/libc/libc_mem_alloc.cc
Normal file
231
libports/src/lib/libc/libc_mem_alloc.cc
Normal file
@ -0,0 +1,231 @@
|
||||
/*
|
||||
* \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
|
||||
* 'base/src/base/heap/heap.cc'.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/env.h>
|
||||
#include <base/allocator_avl.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* local includes */
|
||||
#include "libc_mem_alloc.h"
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
namespace Libc {
|
||||
|
||||
class Mem_alloc_impl : public Mem_alloc
|
||||
{
|
||||
private:
|
||||
|
||||
enum {
|
||||
MIN_CHUNK_SIZE = 4*1024, /* in machine words */
|
||||
MAX_CHUNK_SIZE = 1024*1024
|
||||
};
|
||||
|
||||
class Dataspace : public List<Dataspace>::Element
|
||||
{
|
||||
public:
|
||||
|
||||
Ram_dataspace_capability cap;
|
||||
void *local_addr;
|
||||
|
||||
Dataspace(Ram_dataspace_capability c, void *a)
|
||||
: cap(c), local_addr(a) {}
|
||||
|
||||
inline void * operator new(Genode::size_t, void* addr) {
|
||||
return addr; }
|
||||
|
||||
inline void operator delete(void*) { }
|
||||
};
|
||||
|
||||
class Dataspace_pool : public List<Dataspace>
|
||||
{
|
||||
private:
|
||||
|
||||
Ram_session *_ram_session; /* ram session for backing store */
|
||||
Rm_session *_rm_session; /* region manager */
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Dataspace_pool(Ram_session *ram_session, Rm_session *rm_session):
|
||||
_ram_session(ram_session), _rm_session(rm_session) { }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Dataspace_pool();
|
||||
|
||||
/**
|
||||
* Expand dataspace by specified size
|
||||
*
|
||||
* \param size number of bytes to add to the dataspace pool
|
||||
* \param md_alloc allocator to expand. This allocator is also
|
||||
* used for meta data allocation (only after
|
||||
* being successfully expanded).
|
||||
* \throw Rm_session::Invalid_dataspace,
|
||||
* Rm_session::Region_conflict
|
||||
* \return 0 on success or negative error code
|
||||
*/
|
||||
int expand(size_t size, Range_allocator *alloc);
|
||||
|
||||
void reassign_resources(Ram_session *ram, Rm_session *rm) {
|
||||
_ram_session = ram, _rm_session = rm; }
|
||||
};
|
||||
|
||||
Lock _lock;
|
||||
Dataspace_pool _ds_pool; /* list of dataspaces */
|
||||
Allocator_avl _alloc; /* local allocator */
|
||||
size_t _chunk_size;
|
||||
|
||||
/**
|
||||
* Try to allocate block at our local allocator
|
||||
*
|
||||
* \return true on success
|
||||
*
|
||||
* This function is a utility used by 'alloc' to avoid
|
||||
* code duplication.
|
||||
*/
|
||||
bool _try_local_alloc(size_t size, void **out_addr);
|
||||
|
||||
public:
|
||||
|
||||
Mem_alloc_impl()
|
||||
:
|
||||
_ds_pool(env()->ram_session(), env()->rm_session()),
|
||||
_alloc(0),
|
||||
_chunk_size(MIN_CHUNK_SIZE)
|
||||
{ }
|
||||
|
||||
void *alloc(Genode::size_t size, Genode::size_t align_log2);
|
||||
void free(void *ptr);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
|
||||
remove(ds);
|
||||
delete ds;
|
||||
_rm_session->detach(ds->local_addr);
|
||||
_ram_session->free(ds_cap);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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 {
|
||||
new_ds_cap = _ram_session->alloc(size);
|
||||
local_addr = _rm_session->attach(new_ds_cap);
|
||||
} catch (Ram_session::Alloc_failed) {
|
||||
return -2;
|
||||
} catch (Rm_session::Attach_failed) {
|
||||
_ram_session->free(new_ds_cap);
|
||||
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 */
|
||||
if (!alloc->alloc_aligned(sizeof(Dataspace), &ds_addr, 2)) {
|
||||
PWRN("could not allocate meta data - this should never happen");
|
||||
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;
|
||||
if (_alloc.alloc_aligned(size, &out_addr, align_log2))
|
||||
return out_addr;
|
||||
|
||||
/*
|
||||
* Calculate block size of needed backing store. The block must hold the
|
||||
* requested 'size' and a new Dataspace structure if the allocation above
|
||||
* failed. Finally, we align the size to a 4K page.
|
||||
*/
|
||||
size_t request_size = size + 1024;
|
||||
|
||||
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) {
|
||||
PWRN("could not expand dataspace pool");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate originally requested block */
|
||||
return _alloc.alloc_aligned(size, &out_addr, align_log2) ? out_addr : 0;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
Libc::Mem_alloc *Libc::mem_alloc()
|
||||
{
|
||||
static Libc::Mem_alloc_impl inst;
|
||||
return &inst;
|
||||
}
|
||||
|
||||
|
27
libports/src/lib/libc/libc_mem_alloc.h
Normal file
27
libports/src/lib/libc/libc_mem_alloc.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* \brief Allocator for anonymous memory used by libc
|
||||
* \author Norman Feske
|
||||
* \date 2012-05-18
|
||||
*/
|
||||
|
||||
#ifndef _LIBC_MEM_ALLOC_H_
|
||||
#define _LIBC_MEM_ALLOC_H_
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/allocator.h>
|
||||
|
||||
namespace Libc {
|
||||
|
||||
struct Mem_alloc
|
||||
{
|
||||
virtual void *alloc(Genode::size_t size, Genode::size_t align_log2) = 0;
|
||||
virtual void free(void *ptr) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return singleton instance of the memory allocator
|
||||
*/
|
||||
Mem_alloc *mem_alloc();
|
||||
}
|
||||
|
||||
#endif /* _LIBC_MEM_ALLOC_H_ */
|
Loading…
Reference in New Issue
Block a user