diff --git a/src/kernel/core/vm/vm.c b/src/kernel/core/vm/vm.c index 255d124bf2..059930d829 100755 --- a/src/kernel/core/vm/vm.c +++ b/src/kernel/core/vm/vm.c @@ -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(®ion->ref_count, -1) == 1) { + if (atomic_add(®ion->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; diff --git a/src/kernel/core/vm/vm_daemons.c b/src/kernel/core/vm/vm_daemons.c index 8596f012a5..75de07443f 100755 --- a/src/kernel/core/vm/vm_daemons.c +++ b/src/kernel/core/vm/vm_daemons.c @@ -2,6 +2,7 @@ ** Copyright 2001, Travis Geiselbrecht. All rights reserved. ** Distributed under the terms of the NewOS License. */ + #include #include #include @@ -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(®ion->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(®ion->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);