diff --git a/servers/vm/exec.c b/servers/vm/exec.c index 3cc58e23a..049280e76 100644 --- a/servers/vm/exec.c +++ b/servers/vm/exec.c @@ -187,6 +187,7 @@ SANITYCHECK(SCL_DETAIL); #endif region_init(&rmp->vm_regions_avl); /* exec()ing process regions thrown out. */ + rmp->vm_region_top = 0; SANITYCHECK(SCL_DETAIL); /* Build new process in current slot, without freeing old diff --git a/servers/vm/exit.c b/servers/vm/exit.c index 84f0ac1e9..1c876ed9c 100644 --- a/servers/vm/exit.c +++ b/servers/vm/exit.c @@ -32,6 +32,7 @@ PUBLIC void free_proc(struct vmproc *vmp) pt_free(&vmp->vm_pt); } region_init(&vmp->vm_regions_avl); + vmp->vm_region_top = 0; #if VMSTATS vmp->vm_bytecopies = 0; #endif @@ -40,6 +41,7 @@ PUBLIC void free_proc(struct vmproc *vmp) PUBLIC void clear_proc(struct vmproc *vmp) { region_init(&vmp->vm_regions_avl); + vmp->vm_region_top = 0; vmp->vm_callback = NULL; /* No pending vfs callback. */ vmp->vm_flags = 0; /* Clear INUSE, so slot is free. */ vmp->vm_heap = NULL; diff --git a/servers/vm/region.c b/servers/vm/region.c index b764e51c9..51054c282 100644 --- a/servers/vm/region.c +++ b/servers/vm/region.c @@ -365,19 +365,18 @@ PRIVATE int map_ph_writept(struct vmproc *vmp, struct vir_region *vr, return OK; } +#define SLOT_FAIL ((vir_bytes) -1) + /*===========================================================================* - * region_find_slot * + * region_find_slot_range * *===========================================================================*/ -PRIVATE vir_bytes region_find_slot(struct vmproc *vmp, - vir_bytes minv, vir_bytes maxv, vir_bytes length, - struct vir_region **prev) +PRIVATE vir_bytes region_find_slot_range(struct vmproc *vmp, + vir_bytes minv, vir_bytes maxv, vir_bytes length) { - struct vir_region *firstregion, *prevregion = NULL; + struct vir_region *firstregion; vir_bytes startv; int foundflag = 0; - - /* XXX start search closer to minv to optimise. */ - firstregion = region_search_least(&vmp->vm_regions_avl); + region_iter iter; SANITYCHECK(SCL_FUNCTIONS); @@ -395,7 +394,7 @@ PRIVATE vir_bytes region_find_slot(struct vmproc *vmp, printf("region_find_slot: minv 0x%lx and bytes 0x%lx\n", minv, length); map_printmap(vmp); - return (vir_bytes) -1; + return SLOT_FAIL; } } @@ -408,30 +407,37 @@ PRIVATE vir_bytes region_find_slot(struct vmproc *vmp, assert(minv < maxv); assert(minv + length <= maxv); -#define FREEVRANGE(rangestart, rangeend, foundcode) { \ +#define FREEVRANGE(rangestart, rangeend) { \ vir_bytes frstart = (rangestart), frend = (rangeend); \ frstart = MAX(frstart, minv); \ frend = MIN(frend, maxv); \ if(frend > frstart && (frend - frstart) >= length) { \ startv = frstart; \ foundflag = 1; \ - foundcode; \ } } - /* This is the free virtual address space before the first region. */ - FREEVRANGE(0, firstregion ? firstregion->vaddr : VM_DATATOP, ;); + /* find region before minv. */ + region_start_iter(&vmp->vm_regions_avl, &iter, minv, AVL_LESS_EQUAL); + firstregion = region_get_iter(&iter); + + if(!firstregion) { + /* This is the free virtual address space before the first region. */ + region_start_iter(&vmp->vm_regions_avl, &iter, minv, AVL_GREATER_EQUAL); + firstregion = region_get_iter(&iter); + FREEVRANGE(0, firstregion ? firstregion->vaddr : VM_DATATOP); + } if(!foundflag) { struct vir_region *vr; - region_iter iter; - region_start_iter_least(&vmp->vm_regions_avl, &iter); while((vr = region_get_iter(&iter)) && !foundflag) { struct vir_region *nextvr; region_incr_iter(&iter); nextvr = region_get_iter(&iter); FREEVRANGE(vr->vaddr + vr->length, - nextvr ? nextvr->vaddr : VM_DATATOP, - prevregion = vr;); + nextvr ? nextvr->vaddr : VM_DATATOP); + if(!foundflag) { + printf("incr from 0x%lx to 0x%lx; v range 0x%lx-0x%lx\n", vr->vaddr, nextvr->vaddr); + } } } @@ -439,23 +445,42 @@ PRIVATE vir_bytes region_find_slot(struct vmproc *vmp, printf("VM: region_find_slot: no 0x%lx bytes found for %d between 0x%lx and 0x%lx\n", length, vmp->vm_endpoint, minv, maxv); map_printmap(vmp); - return (vir_bytes) -1; + return SLOT_FAIL; } -#if SANITYCHECKS - if(prevregion) assert(prevregion->vaddr < startv); -#endif - /* However we got it, startv must be in the requested range. */ assert(startv >= minv); assert(startv < maxv); assert(startv + length <= maxv); - if (prev) - *prev = prevregion; + /* remember this position as a hint for next time. */ + vmp->vm_region_top = startv + length; + return startv; } +/*===========================================================================* + * region_find_slot * + *===========================================================================*/ +PRIVATE vir_bytes region_find_slot(struct vmproc *vmp, + vir_bytes minv, vir_bytes maxv, vir_bytes length) +{ + vir_bytes v, hint = vmp->vm_region_top; + + /* use the top of the last inserted region as a minv hint if + * possible. remember that a zero maxv is a special case. + */ + + if(maxv && hint < maxv) { + v = region_find_slot_range(vmp, hint, maxv, length); + + if(v != SLOT_FAIL) + return v; + } + + return region_find_slot_range(vmp, minv, maxv, length); +} + /*===========================================================================* * map_page_region * *===========================================================================*/ @@ -469,7 +494,7 @@ vir_bytes what; u32_t flags; int mapflags; { - struct vir_region *prevregion = NULL, *newregion; + struct vir_region *newregion; vir_bytes startv; struct phys_region *ph; physr_avl *phavl; @@ -478,8 +503,8 @@ int mapflags; SANITYCHECK(SCL_FUNCTIONS); - startv = region_find_slot(vmp, minv, maxv, length, &prevregion); - if (startv == (vir_bytes) -1) + startv = region_find_slot(vmp, minv, maxv, length); + if (startv == SLOT_FAIL) return NULL; /* Now we want a new region. */ @@ -1305,7 +1330,7 @@ int write; } #if SANITYCHECKS -static int countregions(struct vir_region *vr) +static int count_phys_regions(struct vir_region *vr) { int n = 0; struct phys_region *ph; @@ -1338,7 +1363,7 @@ PRIVATE struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region physr_avl *phavl; #if SANITYCHECKS int cr; - cr = countregions(vr); + cr = count_phys_regions(vr); #endif if(!SLABALLOC(newvr)) @@ -1372,13 +1397,13 @@ PRIVATE struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region #endif physr_insert(newvr->phys, newph); #if SANITYCHECKS - assert(countregions(vr) == cr); + assert(count_phys_regions(vr) == cr); #endif physr_incr_iter(&iter); } #if SANITYCHECKS - assert(countregions(vr) == countregions(newvr)); + assert(count_phys_regions(vr) == count_phys_regions(newvr)); #endif return newvr; @@ -1738,7 +1763,7 @@ PUBLIC int map_unmap_region(struct vmproc *vmp, struct vir_region *r, PUBLIC int map_remap(struct vmproc *dvmp, vir_bytes da, size_t size, struct vir_region *region, vir_bytes *r) { - struct vir_region *vr, *prev; + struct vir_region *vr; struct phys_region *ph; vir_bytes startv, dst_addr; physr_iter iter; @@ -1754,11 +1779,10 @@ PUBLIC int map_remap(struct vmproc *dvmp, vir_bytes da, size_t size, dst_addr = da; dst_addr = arch_vir2map(dvmp, dst_addr); - prev = NULL; /* round up to page size */ assert(!(size % VM_PAGE_SIZE)); - startv = region_find_slot(dvmp, dst_addr, VM_DATATOP, size, &prev); - if (startv == (vir_bytes) -1) { + startv = region_find_slot(dvmp, dst_addr, VM_DATATOP, size); + if (startv == SLOT_FAIL) { printf("map_remap: search 0x%lx...\n", dst_addr); map_printmap(dvmp); return ENOMEM; diff --git a/servers/vm/vmproc.h b/servers/vm/vmproc.h index bd5d2dede..2f67db371 100644 --- a/servers/vm/vmproc.h +++ b/servers/vm/vmproc.h @@ -31,6 +31,7 @@ struct vmproc { /* Regions in virtual address space. */ region_avl vm_regions_avl; + vir_bytes vm_region_top; /* highest vaddr last inserted */ yielded_avl vm_yielded_blocks; /* avl of yielded physblocks */ /* Heap for brk() to extend. */