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_ref(vm_region *region);
//static void vm_region_release_ref2(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; vm_region *r = _r;
const region_id *id = key; const region_id *id = key;
if(r->id == *id) if (r->id == *id)
return 0; return 0;
else
return -1; return -1;
} }
@@ -100,10 +102,10 @@ region_hash(void *_r, const void *key, uint32 range)
vm_region *r = _r; vm_region *r = _r;
const region_id *id = key; const region_id *id = key;
if(r != NULL) if (r != NULL)
return (r->id % range); return r->id % range;
else
return (*id % range); return *id % range;
} }
@@ -113,10 +115,10 @@ aspace_compare(void *_a, const void *key)
vm_address_space *aspace = _a; vm_address_space *aspace = _a;
const aspace_id *id = key; const aspace_id *id = key;
if(aspace->id == *id) if (aspace->id == *id)
return 0; 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); acquire_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0, 0);
region = aspace->virtual_map.region_list; region = aspace->virtual_map.region_list;
while(region != NULL) { for (; region != NULL; region = region->aspace_next) {
if(strcmp(region->name, name) == 0) { // ignore reserved space regions
if (region->id == RESERVED_REGION_ID)
continue;
if (strcmp(region->name, name) == 0) {
id = region->id; id = region->id;
break; break;
} }
region = region->aspace_next;
} }
release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0); 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; return NULL;
memset(reserved, 0, sizeof(vm_region)); memset(reserved, 0, sizeof(vm_region));
reserved->id = -1; reserved->id = RESERVED_REGION_ID;
// this marks it as reserved space // this marks it as reserved space
reserved->map = map; reserved->map = map;
@@ -251,7 +256,7 @@ find_reserved_region(vm_virtual_map *map, addr_t start, addr_t size, vm_region *
while (next) { while (next) {
if (next->base <= start && next->base + next->size >= start + size) { if (next->base <= start && next->base + next->size >= start + size) {
// this region covers the requested range // 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 // but it's not reserved space, it's a real region
return ERR_VM_NO_REGION_SLOT; 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; area = addressSpace->virtual_map.region_list;
while (area) { while (area) {
// the region must be completely part of the reserved range // 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) { && area->base + area->size <= (addr_t)address + size) {
// remove reserved range // remove reserved range
vm_region *reserved = area; vm_region *reserved = area;
@@ -1109,7 +1114,7 @@ vm_clone_region(aspace_id aid, char *name, void **address, int addr_type,
int err; int err;
vm_address_space *aspace = vm_get_aspace_by_id(aid); vm_address_space *aspace = vm_get_aspace_by_id(aid);
if(aspace == NULL) if (aspace == NULL)
return ERR_VM_INVALID_ASPACE; return ERR_VM_INVALID_ASPACE;
src_region = vm_get_region_by_id(source_region); 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); vm_put_aspace(aspace);
if(err < 0) if (err < 0)
return err; 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; vm_address_space *aspace;
bool removeit = false; 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); 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); hash_remove(region_table, region);
removeit = true; removeit = true;
} }
release_sem_etc(region_hash_sem, WRITE_COUNT, 0); release_sem_etc(region_hash_sem, WRITE_COUNT, 0);
if(!removeit) if (!removeit)
return; return;
aspace = region->aspace; aspace = region->aspace;
// remove the region from the aspace's virtual map // 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); acquire_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0, 0);
temp = aspace->virtual_map.region_list; temp = aspace->virtual_map.region_list;
while(temp != NULL) { while (temp != NULL) {
if(region == temp) { if (region == temp) {
if(last != NULL) { if (last != NULL) {
last->aspace_next = temp->aspace_next; last->aspace_next = temp->aspace_next;
} else { } else {
aspace->virtual_map.region_list = temp->aspace_next; aspace->virtual_map.region_list = temp->aspace_next;
@@ -1220,12 +1229,12 @@ _vm_put_region(vm_region *region, bool aspace_locked)
last = temp; last = temp;
temp = temp->aspace_next; temp = temp->aspace_next;
} }
if(region == aspace->virtual_map.region_hint) if (region == aspace->virtual_map.region_hint)
aspace->virtual_map.region_hint = NULL; aspace->virtual_map.region_hint = NULL;
if(!aspace_locked) if (!aspace_locked)
release_sem_etc(aspace->virtual_map.sem, WRITE_COUNT, 0); 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"); panic("vm_region_release_ref: region not found in aspace's region_list\n");
vm_cache_remove_region(region->cache_ref, region); 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 // now we can give up the last ref to the aspace
vm_put_aspace(aspace); vm_put_aspace(aspace);
if(region->name) free(region->name);
free(region->name);
free(region); free(region);
return; return;
@@ -1357,11 +1365,11 @@ dump_cache_ref(int argc, char **argv)
vm_region *region; vm_region *region;
vm_cache_ref *cache_ref; vm_cache_ref *cache_ref;
if(argc < 2) { if (argc < 2) {
dprintf("cache_ref: not enough arguments\n"); dprintf("cache_ref: not enough arguments\n");
return 0; 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"); dprintf("cache_ref: invalid argument, pass address\n");
return 0; return 0;
} }
@@ -1374,7 +1382,7 @@ dump_cache_ref(int argc, char **argv)
dprintf("lock.holder: %ld\n", cache_ref->lock.holder); dprintf("lock.holder: %ld\n", cache_ref->lock.holder);
dprintf("lock.sem: 0x%lx\n", cache_ref->lock.sem); dprintf("lock.sem: 0x%lx\n", cache_ref->lock.sem);
dprintf("region_list:\n"); 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(" region 0x%lx: ", region->id);
dprintf("base_addr = 0x%lx ", region->base); dprintf("base_addr = 0x%lx ", region->base);
dprintf("size = 0x%lx ", region->size); dprintf("size = 0x%lx ", region->size);
@@ -1512,18 +1520,22 @@ dump_region(int argc, char **argv)
region_id region_id
find_region_by_address(addr_t vaddress) find_region_by_address(addr_t address)
{ {
vm_address_space *aspace; vm_address_space *aspace;
vm_region *region; vm_region *region;
region_id result=B_ERROR; region_id result = B_ERROR;
aspace = vm_get_current_user_aspace(); aspace = vm_get_current_user_aspace();
for(region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) for (region = aspace->virtual_map.region_list; region != NULL; region = region->aspace_next) {
{ if (region->id == RESERVED_REGION_ID)
if ((vaddress>=region->base) && (vaddress<=(region->base+region->size))) continue;
result=region->id;
if (address >= region->base && address <= region->base + region->size) {
result = region->id;
break;
} }
}
vm_put_aspace(aspace); vm_put_aspace(aspace);
return result; return result;
} }
@@ -1802,6 +1814,13 @@ vm_delete_aspace(aspace_id aid)
region = aspace->virtual_map.region_list; region = aspace->virtual_map.region_list;
while (region) { while (region) {
next = region->aspace_next; 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 // decrement the ref on this region, may actually push the ref < 0, but that's okay
_vm_put_region(region, true); _vm_put_region(region, true);
region = next; region = next;
@@ -1889,7 +1908,7 @@ vm_thread_dump_max_commit(void *unused)
(void)(unused); (void)(unused);
for(;;) { for (;;) {
snooze(1000000); snooze(1000000);
if (oldmax != max_commit) if (oldmax != max_commit)
TRACE(("max_commit 0x%x\n", 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; int err;
@@ -2443,6 +2463,9 @@ vm_virtual_map_lookup(vm_virtual_map *map, addr_t address)
return region; return region;
for (region = map->region_list; region != NULL; region = region->aspace_next) { 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) if (region->base <= address && (region->base + region->size) > address)
break; break;
} }
@@ -2452,17 +2475,23 @@ vm_virtual_map_lookup(vm_virtual_map *map, addr_t address)
return region; 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); 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); 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; int state;
+34 -24
View File
@@ -2,6 +2,7 @@
** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Copyright 2001, Travis Geiselbrecht. All rights reserved.
** Distributed under the terms of the NewOS License. ** Distributed under the terms of the NewOS License.
*/ */
#include <kernel.h> #include <kernel.h>
#include <thread.h> #include <thread.h>
#include <debug.h> #include <debug.h>
@@ -17,7 +18,9 @@ bool trimming_cycle;
static addr free_memory_low_water; static addr free_memory_low_water;
static addr free_memory_high_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 *first_region;
vm_region *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); acquire_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0, 0);
first_region = aspace->virtual_map.region_list; 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; first_region = first_region->aspace_next;
if(!first_region) if (!first_region)
first_region = aspace->virtual_map.region_list; first_region = aspace->virtual_map.region_list;
if(!first_region) { if (!first_region) {
release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0); release_sem_etc(aspace->virtual_map.sem, READ_COUNT, 0);
return; return;
} }
region = first_region; 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 // scan the pages in this region
mutex_lock(&region->cache_ref->lock); 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) { for(va = region->base; va < (region->base + region->size); va += PAGE_SIZE) {
aspace->translation_map.ops->lock(&aspace->translation_map); aspace->translation_map.ops->lock(&aspace->translation_map);
aspace->translation_map.ops->query(&aspace->translation_map, va, &pa, &flags); 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); aspace->translation_map.ops->unlock(&aspace->translation_map);
continue; continue;
} }
page = vm_lookup_page(pa / PAGE_SIZE); page = vm_lookup_page(pa / PAGE_SIZE);
if(!page) { if (!page) {
aspace->translation_map.ops->unlock(&aspace->translation_map); aspace->translation_map.ops->unlock(&aspace->translation_map);
continue; continue;
} }
// see if this page is busy, if it is lets forget it and move on // 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); aspace->translation_map.ops->unlock(&aspace->translation_map);
continue; continue;
} }
flags2 = 0; flags2 = 0;
if(free_target > 0) { if (free_target > 0) {
// look for a page we can steal // 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 // unmap the page
aspace->translation_map.ops->unmap(&aspace->translation_map, va, va + PAGE_SIZE); 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, // decrement the ref count on the page. If we just unmapped it for the last time,
// put the page on the inactive list // 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); vm_page_set_state(page, PAGE_STATE_INACTIVE);
free_target--; 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 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)) { && (page->state == PAGE_STATE_ACTIVE || page->state == PAGE_STATE_INACTIVE)) {
vm_page_set_state(page, PAGE_STATE_MODIFIED); vm_page_set_state(page, PAGE_STATE_MODIFIED);
} }
aspace->translation_map.ops->unlock(&aspace->translation_map); aspace->translation_map.ops->unlock(&aspace->translation_map);
if(--quantum == 0) if (--quantum == 0)
break; break;
} }
} }
mutex_unlock(&region->cache_ref->lock); mutex_unlock(&region->cache_ref->lock);
// move to the next region, wrapping around and stopping if we get back to the first region // 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; region = region->aspace_next ? region->aspace_next : aspace->virtual_map.region_list;
if(region == first_region) if (region == first_region)
break; break;
if(quantum == 0) if (quantum == 0)
break; break;
} }
@@ -121,6 +130,7 @@ static void scan_pages(vm_address_space *aspace, addr free_target)
// dprintf("exiting scan_pages\n"); // dprintf("exiting scan_pages\n");
} }
static int32 static int32
page_daemon(void *unused) page_daemon(void *unused)
{ {
@@ -135,31 +145,31 @@ page_daemon(void *unused)
dprintf("page daemon starting\n"); dprintf("page daemon starting\n");
(void)unused; (void)unused;
for(;;) { for (;;) {
snooze(PAGE_DAEMON_INTERVAL); snooze(PAGE_DAEMON_INTERVAL);
// scan through all of the address spaces // scan through all of the address spaces
vm_aspace_walk_start(&i); vm_aspace_walk_start(&i);
aspace = vm_aspace_walk_next(&i); aspace = vm_aspace_walk_next(&i);
while(aspace) { while (aspace) {
mapped_size = aspace->translation_map.ops->get_mapped_size(&aspace->translation_map); 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); // dprintf("page_daemon: looking at aspace 0x%x, id 0x%x, mapped size %d\n", aspace, aspace->id, mapped_size);
now = system_time(); 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); faults_per_second = (aspace->fault_count * 1000000) / (now - aspace->last_working_set_adjust);
// dprintf(" faults_per_second = %d\n", faults_per_second); // dprintf(" faults_per_second = %d\n", faults_per_second);
aspace->last_working_set_adjust = now; aspace->last_working_set_adjust = now;
aspace->fault_count = 0; 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 && mapped_size >= aspace->working_set_size
&& aspace->working_set_size < aspace->max_working_set) { && aspace->working_set_size < aspace->max_working_set) {
aspace->working_set_size += WORKING_SET_INCREMENT; aspace->working_set_size += WORKING_SET_INCREMENT;
// dprintf(" new working set size = %d\n", aspace->working_set_size); // 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 && mapped_size <= aspace->working_set_size
&& aspace->working_set_size > aspace->min_working_set) { && 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 // 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; 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; trimming_cycle = false;
// scan some pages, trying to free some if needed // scan some pages, trying to free some if needed
free_memory_target = 0; 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; free_memory_target = mapped_size - aspace->working_set_size;
scan_pages(aspace, free_memory_target); scan_pages(aspace, free_memory_target);