diff options
author | neal <neal> | 2008-06-24 14:35:20 +0000 |
---|---|---|
committer | neal <neal> | 2008-06-24 14:35:20 +0000 |
commit | b66325df3e8b995b52f9a21e6750f20fd526db0a (patch) | |
tree | cc5c173bad5e91ce082c264508a8ace46a1a3ea8 /libhurd-mm | |
parent | 7cc0d3ed39b6cb61d897d348b7f5bd88c8294282 (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/ChangeLog | 12 | ||||
-rw-r--r-- | libhurd-mm/Makefile.am | 5 | ||||
-rw-r--r-- | libhurd-mm/anonymous.c | 44 | ||||
-rw-r--r-- | libhurd-mm/madvise.c | 135 | ||||
-rw-r--r-- | libhurd-mm/pager.h | 17 |
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 |