Now other code accounts for reserved regions in the standard region_list as well.

Introduced RESERVED_REGION_ID definition.
Some minor cleanups.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7886 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-06-10 02:03:55 +00:00
parent c9df0d11c8
commit fab1cad1b8
2 changed files with 109 additions and 70 deletions
+75 -46
View File
@@ -82,15 +82,17 @@ static vm_region *vm_virtual_map_lookup(vm_virtual_map *map, addr_t address);
//static void vm_region_release_ref(vm_region *region);
//static void vm_region_release_ref2(vm_region *region);
static int region_compare(void *_r, const void *key)
static int
region_compare(void *_r, const void *key)
{
vm_region *r = _r;
const region_id *id = key;
if(r->id == *id)
if (r->id == *id)
return 0;
else
return -1;
return -1;
}
@@ -100,10 +102,10 @@ region_hash(void *_r, const void *key, uint32 range)
vm_region *r = _r;
const region_id *id = key;
if(r != NULL)
return (r->id % range);
else
return (*id % range);
if (r != NULL)
return r->id % range;
return *id % range;
}
@@ -113,10 +115,10 @@ aspace_compare(void *_a, const void *key)
vm_address_space *aspace = _a;
const aspace_id *id = key;
if(aspace->id == *id)
if (aspace->id == *id)
return 0;
else
return -1;
return -1;
}
@@ -171,12 +173,15 @@ region_id vm_find_region_by_name(aspace_id aid, const char *name)
acquire_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0, 0);
region = aspace->virtual_map.region_list;
while(region != NULL) {
if(strcmp(region->name, name) == 0) {
for (; region != NULL; region = region->aspace_next) {
// ignore reserved space regions
if (region->id == RESERVED_REGION_ID)
continue;
if (strcmp(region->name, name) == 0) {
id = region->id;
break;
}
region = region->aspace_next;
}
release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0);
@@ -193,7 +198,7 @@ _vm_create_reserved_region_struct(vm_virtual_map *map)
return NULL;
memset(reserved, 0, sizeof(vm_region));
reserved->id = -1;
reserved->id = RESERVED_REGION_ID;
// this marks it as reserved space
reserved->map = map;
@@ -251,7 +256,7 @@ find_reserved_region(vm_virtual_map *map, addr_t start, addr_t size, vm_region *
while (next) {
if (next->base <= start && next->base + next->size >= start + size) {
// this region covers the requested range
if (next->id != -1) {
if (next->id != RESERVED_REGION_ID) {
// but it's not reserved space, it's a real region
return ERR_VM_NO_REGION_SLOT;
}
@@ -648,7 +653,7 @@ vm_unreserve_address_range(aspace_id aid, void *address, addr_t size)
area = addressSpace->virtual_map.region_list;
while (area) {
// the region must be completely part of the reserved range
if (area->id == -1 && area->base >= (addr_t)address
if (area->id == RESERVED_REGION_ID && area->base >= (addr_t)address
&& area->base + area->size <= (addr_t)address + size) {
// remove reserved range
vm_region *reserved = area;
@@ -1109,7 +1114,7 @@ vm_clone_region(aspace_id aid, char *name, void **address, int addr_type,
int err;
vm_address_space *aspace = vm_get_aspace_by_id(aid);
if(aspace == NULL)
if (aspace == NULL)
return ERR_VM_INVALID_ASPACE;
src_region = vm_get_region_by_id(source_region);
@@ -1128,10 +1133,10 @@ vm_clone_region(aspace_id aid, char *name, void **address, int addr_type,
vm_put_aspace(aspace);
if(err < 0)
if (err < 0)
return err;
else
return new_region->id;
return new_region->id;
}
@@ -1191,25 +1196,29 @@ _vm_put_region(vm_region *region, bool aspace_locked)
vm_address_space *aspace;
bool removeit = false;
// we should never get here, but if we do, we can handle it
if (region->id == RESERVED_REGION_ID)
return;
acquire_sem_etc(region_hash_sem, WRITE_COUNT, 0, 0);
if(atomic_add(&region->ref_count, -1) == 1) {
if (atomic_add(&region->ref_count, -1) == 1) {
hash_remove(region_table, region);
removeit = true;
}
release_sem_etc(region_hash_sem, WRITE_COUNT, 0);
if(!removeit)
if (!removeit)
return;
aspace = region->aspace;
// remove the region from the aspace's virtual map
if(!aspace_locked)
if (!aspace_locked)
acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0);
temp = aspace->virtual_map.region_list;
while(temp != NULL) {
if(region == temp) {
if(last != NULL) {
while (temp != NULL) {
if (region == temp) {
if (last != NULL) {
last->aspace_next = temp->aspace_next;
} else {
aspace->virtual_map.region_list = temp->aspace_next;
@@ -1220,12 +1229,12 @@ _vm_put_region(vm_region *region, bool aspace_locked)
last = temp;
temp = temp->aspace_next;
}
if(region == aspace->virtual_map.region_hint)
if (region == aspace->virtual_map.region_hint)
aspace->virtual_map.region_hint = NULL;
if(!aspace_locked)
if (!aspace_locked)
release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0);
if(temp == NULL)
if (temp == NULL)
panic("vm_region_release_ref: region not found in aspace's region_list\n");
vm_cache_remove_region(region->cache_ref, region);
@@ -1239,8 +1248,7 @@ _vm_put_region(vm_region *region, bool aspace_locked)
// now we can give up the last ref to the aspace
vm_put_aspace(aspace);
if(region->name)
free(region->name);
free(region->name);
free(region);
return;
@@ -1357,11 +1365,11 @@ dump_cache_ref(int argc, char **argv)
vm_region *region;
vm_cache_ref *cache_ref;
if(argc < 2) {
if (argc < 2) {
dprintf("cache_ref: not enough arguments\n");
return 0;
}
if(strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') {
if (strlen(argv[1]) < 2 || argv[1][0] != '0' || argv[1][1] != 'x') {
dprintf("cache_ref: invalid argument, pass address\n");
return 0;
}
@@ -1374,7 +1382,7 @@ dump_cache_ref(int argc, char **argv)
dprintf("lock.holder: %ld\n", cache_ref->lock.holder);
dprintf("lock.sem: 0x%lx\n", cache_ref->lock.sem);
dprintf("region_list:\n");
for(region = cache_ref->region_list; region != NULL; region = region->cache_next) {
for (region = cache_ref->region_list; region != NULL; region = region->cache_next) {
dprintf(" region 0x%lx: ", region->id);
dprintf("base_addr = 0x%lx ", region->base);
dprintf("size = 0x%lx ", region->size);
@@ -1512,18 +1520,22 @@ dump_region(int argc, char **argv)
region_id
find_region_by_address(addr_t vaddress)
find_region_by_address(addr_t address)
{
vm_address_space *aspace;
vm_region *region;
region_id result=B_ERROR;
region_id result = B_ERROR;
aspace = vm_get_current_user_aspace();
for(region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next)
{
if ((vaddress>=region->base) && (vaddress<=(region->base+region->size)))
result=region->id;
for (region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) {
if (region->id == RESERVED_REGION_ID)
continue;
if (address >= region->base && address <= region->base + region->size) {
result = region->id;
break;
}
}
vm_put_aspace(aspace);
return result;
}
@@ -1802,6 +1814,13 @@ vm_delete_aspace(aspace_id aid)
region = aspace->virtual_map.region_list;
while (region) {
next = region->aspace_next;
if (region->id == RESERVED_REGION_ID) {
// just remove it
free(region);
region = next;
continue;
}
// decrement the ref on this region, may actually push the ref < 0, but that's okay
_vm_put_region(region, true);
region = next;
@@ -1889,7 +1908,7 @@ vm_thread_dump_max_commit(void *unused)
(void)(unused);
for(;;) {
for (;;) {
snooze(1000000);
if (oldmax != max_commit)
TRACE(("max_commit 0x%x\n", max_commit));
@@ -2103,7 +2122,8 @@ forbid_page_faults(void)
}
int vm_page_fault(addr_t address, addr_t fault_address, bool is_write, bool is_user, addr_t *newip)
int
vm_page_fault(addr_t address, addr_t fault_address, bool is_write, bool is_user, addr_t *newip)
{
int err;
@@ -2443,6 +2463,9 @@ vm_virtual_map_lookup(vm_virtual_map *map, addr_t address)
return region;
for (region = map->region_list; region != NULL; region = region->aspace_next) {
if (region->id == RESERVED_REGION_ID)
continue;
if (region->base <= address && (region->base + region->size) > address)
break;
}
@@ -2452,17 +2475,23 @@ vm_virtual_map_lookup(vm_virtual_map *map, addr_t address)
return region;
}
int vm_get_physical_page(addr_t paddr, addr_t *vaddr, int flags)
int
vm_get_physical_page(addr_t paddr, addr_t *vaddr, int flags)
{
return (*kernel_aspace->translation_map.ops->get_physical_page)(paddr, vaddr, flags);
}
int vm_put_physical_page(addr_t vaddr)
int
vm_put_physical_page(addr_t vaddr)
{
return (*kernel_aspace->translation_map.ops->put_physical_page)(vaddr);
}
void vm_increase_max_commit(addr_t delta)
void
vm_increase_max_commit(addr_t delta)
{
int state;
+34 -24
View File
@@ -2,6 +2,7 @@
** Copyright 2001, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#include <kernel.h>
#include <thread.h>
#include <debug.h>
@@ -17,7 +18,9 @@ bool trimming_cycle;
static addr free_memory_low_water;
static addr free_memory_high_water;
static void scan_pages(vm_address_space *aspace, addr free_target)
static void
scan_pages(vm_address_space *aspace, addr free_target)
{
vm_region *first_region;
vm_region *region;
@@ -33,46 +36,52 @@ static void scan_pages(vm_address_space *aspace, addr free_target)
acquire_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0, 0);
first_region = aspace->virtual_map.region_list;
while(first_region && (first_region->base + (first_region->size - 1)) < aspace->scan_va)
while (first_region && (first_region->base + (first_region->size - 1)) < aspace->scan_va)
first_region = first_region->aspace_next;
if(!first_region)
if (!first_region)
first_region = aspace->virtual_map.region_list;
if(!first_region) {
if (!first_region) {
release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0);
return;
}
region = first_region;
for(;;) {
for (;;) {
// ignore reserved ranges
while (region != NULL && region->id == RESERVED_REGION_ID)
region = region->aspace_next;
if (region == NULL)
break;
// scan the pages in this region
mutex_lock(&region->cache_ref->lock);
if(!region->cache_ref->cache->scan_skip) {
if (!region->cache_ref->cache->scan_skip) {
for(va = region->base; va < (region->base + region->size); va += PAGE_SIZE) {
aspace->translation_map.ops->lock(&aspace->translation_map);
aspace->translation_map.ops->query(&aspace->translation_map, va, &pa, &flags);
if((flags & PAGE_PRESENT) == 0) {
if ((flags & PAGE_PRESENT) == 0) {
aspace->translation_map.ops->unlock(&aspace->translation_map);
continue;
}
page = vm_lookup_page(pa / PAGE_SIZE);
if(!page) {
if (!page) {
aspace->translation_map.ops->unlock(&aspace->translation_map);
continue;
}
// see if this page is busy, if it is lets forget it and move on
if(page->state == PAGE_STATE_BUSY || page->state == PAGE_STATE_WIRED) {
if (page->state == PAGE_STATE_BUSY || page->state == PAGE_STATE_WIRED) {
aspace->translation_map.ops->unlock(&aspace->translation_map);
continue;
}
flags2 = 0;
if(free_target > 0) {
if (free_target > 0) {
// look for a page we can steal
if(!(flags & PAGE_ACCESSED) && page->state == PAGE_STATE_ACTIVE) {
if (!(flags & PAGE_ACCESSED) && page->state == PAGE_STATE_ACTIVE) {
// unmap the page
aspace->translation_map.ops->unmap(&aspace->translation_map, va, va + PAGE_SIZE);
@@ -87,7 +96,7 @@ static void scan_pages(vm_address_space *aspace, addr free_target)
// decrement the ref count on the page. If we just unmapped it for the last time,
// put the page on the inactive list
if(atomic_add(&page->ref_count, -1) == 1) {
if (atomic_add(&page->ref_count, -1) == 1) {
vm_page_set_state(page, PAGE_STATE_INACTIVE);
free_target--;
}
@@ -95,23 +104,23 @@ static void scan_pages(vm_address_space *aspace, addr free_target)
}
// if the page is modified, but the state is active or inactive, put it on the modified list
if(((flags & PAGE_MODIFIED) || (flags2 & PAGE_MODIFIED))
if (((flags & PAGE_MODIFIED) || (flags2 & PAGE_MODIFIED))
&& (page->state == PAGE_STATE_ACTIVE || page->state == PAGE_STATE_INACTIVE)) {
vm_page_set_state(page, PAGE_STATE_MODIFIED);
}
aspace->translation_map.ops->unlock(&aspace->translation_map);
if(--quantum == 0)
if (--quantum == 0)
break;
}
}
mutex_unlock(&region->cache_ref->lock);
// move to the next region, wrapping around and stopping if we get back to the first region
region = region->aspace_next ? region->aspace_next : aspace->virtual_map.region_list;
if(region == first_region)
if (region == first_region)
break;
if(quantum == 0)
if (quantum == 0)
break;
}
@@ -121,6 +130,7 @@ static void scan_pages(vm_address_space *aspace, addr free_target)
// dprintf("exiting scan_pages\n");
}
static int32
page_daemon(void *unused)
{
@@ -135,31 +145,31 @@ page_daemon(void *unused)
dprintf("page daemon starting\n");
(void)unused;
for(;;) {
for (;;) {
snooze(PAGE_DAEMON_INTERVAL);
// scan through all of the address spaces
vm_aspace_walk_start(&i);
aspace = vm_aspace_walk_next(&i);
while(aspace) {
while (aspace) {
mapped_size = aspace->translation_map.ops->get_mapped_size(&aspace->translation_map);
// dprintf("page_daemon: looking at aspace 0x%x, id 0x%x, mapped size %d\n", aspace, aspace->id, mapped_size);
now = system_time();
if(now - aspace->last_working_set_adjust > WORKING_SET_ADJUST_INTERVAL) {
if (now - aspace->last_working_set_adjust > WORKING_SET_ADJUST_INTERVAL) {
faults_per_second = (aspace->fault_count * 1000000) / (now - aspace->last_working_set_adjust);
// dprintf(" faults_per_second = %d\n", faults_per_second);
aspace->last_working_set_adjust = now;
aspace->fault_count = 0;
if(faults_per_second > MAX_FAULTS_PER_SECOND
if (faults_per_second > MAX_FAULTS_PER_SECOND
&& mapped_size >= aspace->working_set_size
&& aspace->working_set_size < aspace->max_working_set) {
aspace->working_set_size += WORKING_SET_INCREMENT;
// dprintf(" new working set size = %d\n", aspace->working_set_size);
} else if(faults_per_second < MIN_FAULTS_PER_SECOND
} else if (faults_per_second < MIN_FAULTS_PER_SECOND
&& mapped_size <= aspace->working_set_size
&& aspace->working_set_size > aspace->min_working_set) {
@@ -169,14 +179,14 @@ page_daemon(void *unused)
}
// decide if we need to enter or leave the trimming cycle
if(!trimming_cycle && vm_page_num_free_pages() < free_memory_low_water)
if (!trimming_cycle && vm_page_num_free_pages() < free_memory_low_water)
trimming_cycle = true;
else if(trimming_cycle && vm_page_num_free_pages() > free_memory_high_water)
else if (trimming_cycle && vm_page_num_free_pages() > free_memory_high_water)
trimming_cycle = false;
// scan some pages, trying to free some if needed
free_memory_target = 0;
if(trimming_cycle && mapped_size > aspace->working_set_size)
if (trimming_cycle && mapped_size > aspace->working_set_size)
free_memory_target = mapped_size - aspace->working_set_size;
scan_pages(aspace, free_memory_target);