summaryrefslogtreecommitdiff
path: root/libhurd-mm
diff options
context:
space:
mode:
authorneal <neal>2008-06-24 14:35:20 +0000
committerneal <neal>2008-06-24 14:35:20 +0000
commitb66325df3e8b995b52f9a21e6750f20fd526db0a (patch)
treecc5c173bad5e91ce082c264508a8ace46a1a3ea8 /libhurd-mm
parent7cc0d3ed39b6cb61d897d348b7f5bd88c8294282 (diff)
hurd/
2008-06-24 Neal H. Walfield <neal@gnu.org> * cap.h (RM_object_discard): New define. (object_discard): New method. viengoos/ 2008-06-24 Neal H. Walfield <neal@gnu.org> * server.c (server_loop): Implement cap_discard. * rm.h (rm_method_id_string): Handle the RM_object_discard case. libhurd-mm/ 2008-06-24 Neal H. Walfield <neal@gnu.org> * madvise.c: New file. * Makefile.am (libhurd_mm_a_SOURCES): Add madvise.c. * pager.h (pager_advice_normal, pager_advice_random, pager_advice_sequential, pager_advice_willneed, pager_advice_dontneed): Define. (pager_advise_t): New typedef. (struct pager): Add field advise. * anonymous.c (advise): New function. (anonymous_pager_alloc): Set ANON->PAGER.ADVISE to it.
Diffstat (limited to 'libhurd-mm')
-rw-r--r--libhurd-mm/ChangeLog12
-rw-r--r--libhurd-mm/Makefile.am5
-rw-r--r--libhurd-mm/anonymous.c44
-rw-r--r--libhurd-mm/madvise.c135
-rw-r--r--libhurd-mm/pager.h17
5 files changed, 211 insertions, 2 deletions
diff --git a/libhurd-mm/ChangeLog b/libhurd-mm/ChangeLog
index c120241..4b79c47 100644
--- a/libhurd-mm/ChangeLog
+++ b/libhurd-mm/ChangeLog
@@ -1,3 +1,15 @@
+2008-06-24 Neal H. Walfield <neal@gnu.org>
+
+ * madvise.c: New file.
+ * Makefile.am (libhurd_mm_a_SOURCES): Add madvise.c.
+ * pager.h (pager_advice_normal, pager_advice_random,
+ pager_advice_sequential, pager_advice_willneed,
+ pager_advice_dontneed): Define.
+ (pager_advise_t): New typedef.
+ (struct pager): Add field advise.
+ * anonymous.c (advise): New function.
+ (anonymous_pager_alloc): Set ANON->PAGER.ADVISE to it.
+
2008-06-23 Neal H. Walfield <neal@gnu.org>
* as-build.c (as_build): Use %p, not %x, for printing a pointer.
diff --git a/libhurd-mm/Makefile.am b/libhurd-mm/Makefile.am
index c45e422..e0f08b8 100644
--- a/libhurd-mm/Makefile.am
+++ b/libhurd-mm/Makefile.am
@@ -36,19 +36,20 @@ libhurd_mm_a_CCASFLAGS = $(USER_CPPFLAGS) -DASM
libhurd_mm_a_CFLAGS = $(USER_CFLAGS) -mpreferred-stack-boundary=2
libhurd_mm_a_SOURCES = mm.h \
bits.h \
- capalloc.h capalloc.c \
+ mm-init.c \
storage.h storage.c \
as.h as.c \
as-build.c as-build-custom.c \
as-lookup.c \
as-dump.c \
exceptions.c \
+ capalloc.h capalloc.c \
map.h map.c \
pager.h pager.c \
anonymous.h anonymous.c \
mmap.c sbrk.c \
mprotect.c \
- mm-init.c \
+ madvise.c \
$(ARCH_SOURCES)
libas_kernel_a_CPPFLAGS = $(KERNEL_CPPFLAGS)
diff --git a/libhurd-mm/anonymous.c b/libhurd-mm/anonymous.c
index ae6ae41..fc45a3e 100644
--- a/libhurd-mm/anonymous.c
+++ b/libhurd-mm/anonymous.c
@@ -432,6 +432,49 @@ destroy (struct pager *pager)
hurd_slab_dealloc (&anonymous_pager_slab, anon);
}
+static void
+advise (struct pager *pager,
+ uintptr_t start, uintptr_t length, uintptr_t advice)
+{
+ if (advice != pager_advice_dontneed)
+ /* This is the only advice we currently handle. */
+ return;
+
+ struct anonymous_pager *anon = (struct anonymous_pager *) pager;
+
+ uintptr_t offset[2];
+ offset[0] = start | 1;
+ offset[1] = length;
+
+ hurd_btree_storage_desc_t *storage_descs;
+ storage_descs = (hurd_btree_storage_desc_t *) &anon->storage;
+
+ struct storage_desc *next
+ = hurd_btree_storage_desc_find (storage_descs, &offset[0]);
+ if (next)
+ {
+ struct storage_desc *prev = hurd_btree_storage_desc_prev (next);
+
+ int dir;
+ struct storage_desc *storage_desc;
+ for (dir = 0; dir < 2; dir ++, next = prev)
+ while ((storage_desc = next))
+ {
+ next = (dir == 0 ? hurd_btree_storage_desc_next (storage_desc)
+ : hurd_btree_storage_desc_prev (storage_desc));
+
+ if (storage_desc->offset < start
+ || storage_desc->offset >= start + length)
+ break;
+
+ error_t err;
+ err = rm_object_discard (anon->activity, storage_desc->storage);
+ if (err)
+ panic ("err: %d", err);
+ }
+ }
+}
+
struct anonymous_pager *
anonymous_pager_alloc (addr_t activity,
void *hint, uintptr_t length, enum map_access access,
@@ -459,6 +502,7 @@ anonymous_pager_alloc (addr_t activity,
anon->pager.length = length;
anon->pager.fault = fault;
anon->pager.no_refs = destroy;
+ anon->pager.advise = advise;
anon->activity = activity;
anon->flags = flags;
diff --git a/libhurd-mm/madvise.c b/libhurd-mm/madvise.c
new file mode 100644
index 0000000..5bdb962
--- /dev/null
+++ b/libhurd-mm/madvise.c
@@ -0,0 +1,135 @@
+/* madvise.c - madvise implementation.
+ Copyright (C) 2008 Free Software Foundation, Inc.
+ Written by Neal H. Walfield <neal@gnu.org>.
+
+ This file is part of the GNU Hurd.
+
+ GNU Hurd is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation, either version 3 of the
+ License, or (at your option) any later version.
+
+ GNU Hurd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with GNU Hurd. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <hurd/stddef.h>
+#include <hurd/addr.h>
+#include <hurd/as.h>
+#include <hurd/storage.h>
+#include <hurd/anonymous.h>
+#include <hurd/map.h>
+
+#include <sys/mman.h>
+#include <stdint.h>
+
+int
+madvise (void *addr, size_t length, int advice)
+{
+ if (((uintptr_t) addr & (PAGESIZE - 1)) != 0)
+ return EINVAL;
+ if ((length & (PAGESIZE - 1)) != 0)
+ return EINVAL;
+
+ switch (advice)
+ {
+ case MADV_NORMAL:
+ advice = pager_advice_normal;
+ break;
+ case MADV_RANDOM:
+ advice = pager_advice_random;
+ break;
+ case MADV_SEQUENTIAL:
+ advice = pager_advice_sequential;
+ break;
+ case MADV_WILLNEED:
+ advice = pager_advice_willneed;
+ break;
+ case MADV_DONTNEED:
+ advice = pager_advice_dontneed;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ uintptr_t start = (uintptr_t) addr;
+ uintptr_t end = start + length - 1;
+
+ debug (0, "(%p, %x (%p), %d)", addr, length, end, advice);
+
+ struct region region = { (uintptr_t) addr, length };
+
+ maps_lock_lock ();
+
+ /* Find any pager that overlaps within the designated region. */
+ struct map *map = map_find (region);
+ if (! map)
+ /* There are none. We're done. */
+ {
+ maps_lock_unlock ();
+ return 0;
+ }
+
+ /* There may be pagers that come lexically before as well as after
+ PAGER. We start with PAGER and scan forward and then do the same
+ but scan backwards. */
+ struct map *prev = hurd_btree_map_prev (map);
+
+ int dir;
+ for (dir = 0; dir < 2; dir ++, map = prev)
+ for (;
+ map;
+ map = (dir == 0 ? hurd_btree_map_next (map)
+ : hurd_btree_map_prev (map)))
+ {
+ uintptr_t map_start = map->region.start;
+ uintptr_t map_end = map_start + map->region.length - 1;
+
+ debug (5, "(%x-%x): considering %x-%x",
+ start, end, map_start, map_end);
+
+ if (map_start > end || map_end < start)
+ break;
+
+ /*
+ map_start/map->offset map_end
+ / \ / \
+ v v v v
+ +------------------------------------+
+ | | <- pager
+ +------------------------------------+
+
+ ^ ^ ^ ^ ^ ^
+ \ | / \ | /
+ start end
+
+ */
+ uintptr_t s = map->offset;
+ uintptr_t l = map->region.length;
+ if (start > map_start)
+ {
+ s += start - map_start;
+ l -= start - map_start;
+ }
+ if (end < map_end)
+ l -= map_end - end;
+
+ if (map->pager->advise)
+ map->pager->advise (map->pager, s, l, advice);
+ }
+
+ maps_lock_unlock ();
+
+ return 0;
+}
+
+int
+posix_madvise (void *addr, size_t len, int advice)
+{
+ return madvise (addr, len, advice);
+}
diff --git a/libhurd-mm/pager.h b/libhurd-mm/pager.h
index c292f32..6d4c517 100644
--- a/libhurd-mm/pager.h
+++ b/libhurd-mm/pager.h
@@ -48,6 +48,21 @@ typedef void (*pager_reclaim_t) (struct pager *pager,
held. This function should unlock PAGER->LOCK, if required. */
typedef void (*pager_no_refs_t) (struct pager *pager);
+enum
+ {
+ pager_advice_normal,
+ pager_advice_random,
+ pager_advice_sequential,
+ pager_advice_willneed,
+ pager_advice_dontneed,
+ };
+
+/* Called to suggest some action on a range of pages. This function
+ is called with MAPS_LOCK held. It should not be released. */
+typedef void (*pager_advise_t) (struct pager *pager,
+ uintptr_t start, uintptr_t length,
+ uintptr_t advice);
+
struct pager
{
/* List of maps that reference this pager. This is protected by
@@ -62,6 +77,8 @@ struct pager
pager_fault_t fault;
pager_no_refs_t no_refs;
+
+ pager_advise_t advise;
};
/* Initialize the pager. LENGTH and FAULT must be set