libc: Add munmap support to plugin interface

With this patch, libc plugins become able to handle munmap for regions
attached by the plugin.
This commit is contained in:
Norman Feske 2012-08-17 08:27:15 +02:00
parent 3546b17827
commit 4914032800
6 changed files with 162 additions and 27 deletions

View File

@ -58,6 +58,7 @@ namespace Libc {
virtual bool supports_socket(int domain, int type, int protocol);
virtual bool supports_stat(const char *path);
virtual bool supports_unlink(const char *path);
virtual bool supports_mmap();
virtual File_descriptor *accept(File_descriptor *,
struct ::sockaddr *addr,
@ -98,6 +99,7 @@ namespace Libc {
virtual int mkdir(const char *pathname, mode_t mode);
virtual void *mmap(void *addr, ::size_t length, int prot, int flags,
File_descriptor *, ::off_t offset);
virtual int munmap(void *addr, ::size_t length);
virtual File_descriptor *open(const char *pathname, int flags);
virtual int pipe(File_descriptor *pipefd[2]);
virtual ssize_t read(File_descriptor *, void *buf, ::size_t count);

View File

@ -10,7 +10,7 @@ LIBS += timed_semaphore cxx
#
# Back end
#
SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.cc munmap.cc \
SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc readlink.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 \

View File

@ -30,6 +30,7 @@
/* libc-internal includes */
#include "libc_mem_alloc.h"
#include "libc_mmap_registry.h"
using namespace Libc;
@ -43,6 +44,13 @@ using namespace Libc;
enum { INVALID_FD = -1 };
Libc::Mmap_registry *Libc::mmap_registry()
{
static Libc::Mmap_registry registry;
return &registry;
}
/***************
** Utilities **
***************/
@ -295,17 +303,48 @@ 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 Libc::mem_alloc()->alloc(length, PAGE_SHIFT);
if (!addr && libc_fd == -1) {
PDBG("call Libc::mem_alloc()->alloc(%zd)", length);
void *start = Libc::mem_alloc()->alloc(length, PAGE_SHIFT);
mmap_registry()->insert(start, length, 0);
PDBG("return addr %p", start);
return start;
}
/* lookup plugin responsible for file descriptor */
File_descriptor *fd = libc_fd_to_fd(libc_fd, "mmap");
if (!fd || !fd->plugin) {
if (!fd || !fd->plugin || !fd->plugin->supports_mmap()) {
PWRN("mmap not supported for file descriptor %d", libc_fd);
return (void *)INVALID_FD;
}
return fd->plugin->mmap(addr, length, prot, flags, fd, offset);
void *start = fd->plugin->mmap(addr, length, prot, flags, fd, offset);
mmap_registry()->insert(start, length, fd->plugin);
return start;
}
extern "C" int munmap(void *start, size_t length)
{
if (!mmap_registry()->is_registered(start)) {
PWRN("munmap: could not lookup plugin for address %p", start);
errno = EINVAL;
return -1;
}
/*
* Lookup plugin that was used for mmap
*
* If the pointer is NULL, 'start' refers to an anonymous mmap.
*/
Plugin *plugin = mmap_registry()->lookup_plugin_by_addr(start);
if (!plugin) {
Libc::mem_alloc()->free(start);
return 0;
}
return plugin->munmap(start, length);
}

View File

@ -0,0 +1,108 @@
/*
* \brief Registry for keeping track of mmapped regions
* \author Norman Feske
* \date 2012-08-16
*/
#ifndef _LIBC_MMAP_REGISTRY_H_
#define _LIBC_MMAP_REGISTRY_H_
/* Genode includes */
#include <base/lock.h>
#include <base/env.h>
#include <base/printf.h>
/* libc-internal includes */
#include <libc-plugin/plugin.h>
/* libc includes */
#include <errno.h>
namespace Libc {
class Mmap_registry;
/**
* Return singleton instance of mmap registry
*/
Mmap_registry *mmap_registry();
}
class Libc::Mmap_registry
{
public:
struct Entry : Genode::List<Entry>::Element
{
void * const start;
Plugin * const plugin;
Entry(void *start, Plugin *plugin)
: start(start), plugin(plugin) { }
};
private:
Genode::List<Mmap_registry::Entry> _list;
Genode::Lock mutable _lock;
Entry *_lookup_by_addr_unsynchronized(void * const start) const
{
Entry *curr = _list.first();
for (; curr; curr = curr->next())
if (curr->start == start)
return curr;
return 0;
}
public:
void insert(void *start, Genode::size_t len, Plugin *plugin)
{
Genode::Lock::Guard guard(_lock);
if (_lookup_by_addr_unsynchronized(start)) {
PINF("mmap region at %p is already registered", start);
return;
}
_list.insert(new (Genode::env()->heap()) Entry(start, plugin));
}
Plugin *lookup_plugin_by_addr(void *start) const
{
Genode::Lock::Guard guard(_lock);
Entry * const e = _lookup_by_addr_unsynchronized(start);
return e ? e->plugin : 0;
}
bool is_registered(void *start) const
{
Genode::Lock::Guard guard(_lock);
return _lookup_by_addr_unsynchronized(start) != 0;
}
void remove(void *start)
{
Genode::Lock::Guard guard(_lock);
Entry *e = _lookup_by_addr_unsynchronized(start);
if (!e) {
PWRN("lookup for address %p in in mmap registry failed", start);
return;
}
_list.remove(e);
destroy(Genode::env()->heap(), e);
}
};
#endif /* _LIBC_MMAP_REGISTRY_H_ */

View File

@ -1,22 +0,0 @@
/*
* \brief C-library back end
* \author Norman Feske
* \date 2008-11-11
*/
/*
* Copyright (C) 2008-2012 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 <sys/mman.h>
#include "libc_debug.h"
extern "C" int munmap(void *start, size_t length)
{
raw_write_str("munmap called, not yet implemented!\n");
return 0;
}

View File

@ -110,6 +110,13 @@ bool Plugin::supports_unlink(const char*)
return false;
}
bool Plugin::supports_mmap()
{
return false;
}
/**
* Default implementations
*/
@ -181,6 +188,7 @@ DUMMY(int, -1, getaddrinfo, (const char *, const char *, const struct ::addrinf
DUMMY(int, -1, mkdir, (const char*, mode_t));
DUMMY(void *, (void *)(-1), mmap, (void *addr, ::size_t length, int prot, int flags,
File_descriptor *, ::off_t offset));
DUMMY(int, -1, munmap, (void *, ::size_t));
DUMMY(int, -1, pipe, (File_descriptor*[2]));
DUMMY(int, -1, rename, (const char *, const char *));
DUMMY(int, -1, select, (int, fd_set *, fd_set *, fd_set *, struct timeval *));