diff --git a/libports/include/libc-plugin/plugin.h b/libports/include/libc-plugin/plugin.h
index 030321e537..476946a5d5 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 0b75c99814..9180976b23 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 40620bd4a5..4564b31e10 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 0000000000..f7bbe6948d
--- /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 546787ce79..0000000000
--- 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 4d473b560c..5b99fbb79e 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 *));