summaryrefslogtreecommitdiff
path: root/libhurd-mm/madvise.c
diff options
context:
space:
mode:
Diffstat (limited to 'libhurd-mm/madvise.c')
-rw-r--r--libhurd-mm/madvise.c117
1 files changed, 63 insertions, 54 deletions
diff --git a/libhurd-mm/madvise.c b/libhurd-mm/madvise.c
index d3985c2..b9494cd 100644
--- a/libhurd-mm/madvise.c
+++ b/libhurd-mm/madvise.c
@@ -31,6 +31,8 @@
int
madvise (void *addr, size_t length, int advice)
{
+ debug (5, "(%p, %x, %d)", addr, length, advice);
+
if (((uintptr_t) addr & (PAGESIZE - 1)) != 0)
{
debug (0, "Address %x not multiple of pagesize.", addr);
@@ -68,65 +70,72 @@ madvise (void *addr, size_t length, int advice)
struct region region = { (uintptr_t) addr, length };
+ debug (5, "Region: %x-%x",
+ region.start, region.start + region.length - 1);
+
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. */
+ /* Find the first map that overlaps with the designated region. */
+ struct map *map;
+ while (region.length > 0
+ && (map = hurd_btree_map_find_first (&maps, &region)))
{
- maps_lock_unlock ();
- return 0;
+ 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);
+
+ /*
+ 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;
+
+ /* Advance region to just after MAP. */
+ if (map_end >= region.start + region.length)
+ region.length = 0;
+ else
+ {
+ region.length -= map_end - region.start + 1;
+ region.start += map_end - region.start + 1;
+ }
+
+ struct pager *pager = map->pager;
+ if (pager->advise)
+ {
+ maps_lock_unlock ();
+ pager->advise (map->pager, s, l, advice);
+
+ /* If REGION.LENGTH is zero, don't bother to retake the
+ lock: we are done. */
+ if (region.length > 0)
+ maps_lock_lock ();
+ else
+ return 0;
+ }
+
+ debug (5, "Region: %x-%x",
+ region.start, region.start + region.length - 1);
}
- /* 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;