From 491403280090eed2eadf71229806b90bc0559152 Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Fri, 17 Aug 2012 08:27:15 +0200 Subject: [PATCH] libc: Add munmap support to plugin interface With this patch, libc plugins become able to handle munmap for regions attached by the plugin. --- libports/include/libc-plugin/plugin.h | 2 + libports/lib/mk/libc.mk | 2 +- libports/src/lib/libc/file_operations.cc | 47 ++++++++- libports/src/lib/libc/libc_mmap_registry.h | 108 +++++++++++++++++++++ libports/src/lib/libc/munmap.cc | 22 ----- libports/src/lib/libc/plugin.cc | 8 ++ 6 files changed, 162 insertions(+), 27 deletions(-) create mode 100644 libports/src/lib/libc/libc_mmap_registry.h delete mode 100644 libports/src/lib/libc/munmap.cc diff --git a/libports/include/libc-plugin/plugin.h b/libports/include/libc-plugin/plugin.h index 030321e53..476946a5d 100644 --- a/libports/include/libc-plugin/plugin.h +++ b/libports/include/libc-plugin/plugin.h @@ -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); diff --git a/libports/lib/mk/libc.mk b/libports/lib/mk/libc.mk index 0b75c9981..9180976b2 100644 --- a/libports/lib/mk/libc.mk +++ b/libports/lib/mk/libc.mk @@ -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 \ diff --git a/libports/src/lib/libc/file_operations.cc b/libports/src/lib/libc/file_operations.cc index 40620bd4a..4564b31e1 100644 --- a/libports/src/lib/libc/file_operations.cc +++ b/libports/src/lib/libc/file_operations.cc @@ -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 ®istry; +} + + /*************** ** 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); } diff --git a/libports/src/lib/libc/libc_mmap_registry.h b/libports/src/lib/libc/libc_mmap_registry.h new file mode 100644 index 000000000..f7bbe6948 --- /dev/null +++ b/libports/src/lib/libc/libc_mmap_registry.h @@ -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 +#include +#include + +/* libc-internal includes */ +#include + +/* libc includes */ +#include + +namespace Libc { + + class Mmap_registry; + + /** + * Return singleton instance of mmap registry + */ + Mmap_registry *mmap_registry(); +} + + +class Libc::Mmap_registry +{ + public: + + struct Entry : Genode::List::Element + { + void * const start; + Plugin * const plugin; + + Entry(void *start, Plugin *plugin) + : start(start), plugin(plugin) { } + }; + + private: + + Genode::List _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_ */ diff --git a/libports/src/lib/libc/munmap.cc b/libports/src/lib/libc/munmap.cc deleted file mode 100644 index 546787ce7..000000000 --- a/libports/src/lib/libc/munmap.cc +++ /dev/null @@ -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 - -#include "libc_debug.h" - -extern "C" int munmap(void *start, size_t length) -{ - raw_write_str("munmap called, not yet implemented!\n"); - return 0; -} diff --git a/libports/src/lib/libc/plugin.cc b/libports/src/lib/libc/plugin.cc index 4d473b560..5b99fbb79 100644 --- a/libports/src/lib/libc/plugin.cc +++ b/libports/src/lib/libc/plugin.cc @@ -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 *));