* Added the possibility to pre-commit pages for areas that can overcommit.

* This is now used for userland stack - they now always pre-commit two pages, enough
  to initialize TLS and copy the user-thread-exit stub to that area.
* Minor cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-01-12 18:51:01 +00:00
parent 8fc075ac5c
commit dc688434ed
3 changed files with 50 additions and 27 deletions
+20 -17
View File
@@ -529,7 +529,7 @@ map_backing_store(vm_address_space *addressSpace, vm_store *store, void **_virtu
// create an anonymous store object
newStore = vm_store_create_anonymous_noswap((protection & B_STACK_AREA) != 0,
USER_STACK_GUARD_PAGES);
0, USER_STACK_GUARD_PAGES);
if (newStore == NULL) {
status = B_NO_MEMORY;
goto err1;
@@ -784,8 +784,9 @@ vm_create_anonymous_area(team_id aid, const char *name, void **address,
}
// create an anonymous store object
store = vm_store_create_anonymous_noswap(canOvercommit, isStack ?
((protection & B_USER_PROTECTION) != 0 ?
// if it's a stack, make sure that two pages are available at least
store = vm_store_create_anonymous_noswap(canOvercommit, isStack ? 2 : 0,
isStack ? ((protection & B_USER_PROTECTION) != 0 ?
USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0);
if (store == NULL) {
status = B_NO_MEMORY;
@@ -1461,7 +1462,7 @@ vm_copy_on_write_area(vm_area *area)
lowerCache = upperCacheRef->cache;
// create an anonymous store object
store = vm_store_create_anonymous_noswap(false, 0);
store = vm_store_create_anonymous_noswap(false, 0, 0);
if (store == NULL)
return B_NO_MEMORY;
@@ -2456,8 +2457,8 @@ vm_page_fault(addr_t address, addr_t fault_address, bool is_write, bool is_user,
err = vm_soft_fault(address, is_write, is_user);
if (err < 0) {
dprintf("vm_page_fault: vm_soft_fault returned error %d on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n",
err, address, fault_address, is_write, is_user, thread_get_current_thread_id());
dprintf("vm_page_fault: vm_soft_fault returned error '%s' on fault at 0x%lx, ip 0x%lx, write %d, user %d, thread 0x%lx\n",
strerror(err), address, fault_address, is_write, is_user, thread_get_current_thread_id());
if (!is_user) {
struct thread *t = thread_get_current_thread();
if (t && t->fault_handler != 0) {
@@ -2542,8 +2543,8 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
vm_page dummyPage;
vm_page *page = NULL;
addr_t address;
int change_count;
int err;
int32 changeCount;
status_t status;
FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n",
thread_get_current_thread_id(), originalAddress, isWrite, isUser));
@@ -2604,7 +2605,7 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
topCacheRef = area->cache_ref;
cacheOffset = address - area->base + area->cache_offset;
vm_cache_acquire_ref(topCacheRef);
change_count = addressSpace->change_count;
changeCount = addressSpace->change_count;
release_sem_etc(addressSpace->sem, READ_COUNT, 0);
// See if this cache has a fault handler - this will do all the work for us
@@ -2687,8 +2688,10 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
addressSpace->translation_map.ops->get_physical_page(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&vec.iov_base, PHYSICAL_PAGE_CAN_WAIT);
// ToDo: handle errors here
err = cacheRef->cache->store->ops->read(cacheRef->cache->store,
status = cacheRef->cache->store->ops->read(cacheRef->cache->store,
cacheOffset, &vec, 1, &bytesRead, false);
if (status < B_OK)
panic("hello, dudes!");
addressSpace->translation_map.ops->put_physical_page((addr_t)vec.iov_base);
mutex_lock(&cacheRef->lock);
@@ -2783,8 +2786,8 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
// try to get a mapping for the src and dest page so we can copy it
for (;;) {
(*addressSpace->translation_map.ops->get_physical_page)(src_page->physical_page_number * B_PAGE_SIZE, (addr_t *)&src, PHYSICAL_PAGE_CAN_WAIT);
err = (*addressSpace->translation_map.ops->get_physical_page)(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&dest, PHYSICAL_PAGE_NO_WAIT);
if (err == B_NO_ERROR)
status = (*addressSpace->translation_map.ops->get_physical_page)(page->physical_page_number * B_PAGE_SIZE, (addr_t *)&dest, PHYSICAL_PAGE_NO_WAIT);
if (status == B_NO_ERROR)
break;
// it couldn't map the second one, so sleep and retry
@@ -2822,20 +2825,20 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
}
}
err = B_OK;
status = B_OK;
acquire_sem_etc(addressSpace->sem, READ_COUNT, 0, 0);
if (change_count != addressSpace->change_count) {
if (changeCount != addressSpace->change_count) {
// something may have changed, see if the address is still valid
area = vm_area_lookup(addressSpace, address);
if (area == NULL
|| area->cache_ref != topCacheRef
|| (address - area->base + area->cache_offset) != cacheOffset) {
dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n");
err = B_BAD_ADDRESS;
status = B_BAD_ADDRESS;
}
}
if (err == B_OK) {
if (status == B_OK) {
// All went fine, all there is left to do is to map the page into the address space
// If the page doesn't reside in the area's cache, we need to make sure it's
@@ -2868,7 +2871,7 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
vm_cache_release_ref(topCacheRef);
vm_put_address_space(addressSpace);
return err;
return status;
}
@@ -31,6 +31,8 @@
typedef struct anonymous_store {
vm_store vm;
bool can_overcommit;
bool has_precommitted;
uint8 precommitted_pages;
int32 guarded_size;
} anonymous_store;
@@ -49,8 +51,15 @@ anonymous_commit(struct vm_store *_store, off_t size)
anonymous_store *store = (anonymous_store *)_store;
// if we can overcommit, we don't commit here, but in anonymous_fault()
if (store->can_overcommit)
return B_OK;
if (store->can_overcommit) {
if (store->has_precommitted)
return B_OK;
// pre-commit some pages to make a later failure less probable
store->has_precommitted = true;
if (size > store->vm.cache->virtual_base + store->precommitted_pages)
size = store->vm.cache->virtual_base + store->precommitted_pages;
}
size -= store->vm.cache->virtual_base;
// anonymous stores don't need to span over their whole source
@@ -61,7 +70,7 @@ anonymous_commit(struct vm_store *_store, off_t size)
// try to commit
if (vm_try_reserve_memory(size - store->vm.committed_size) != B_OK)
return B_NO_MEMORY;
store->vm.committed_size = size;
} else {
// we can release some
@@ -121,9 +130,12 @@ anonymous_fault(struct vm_store *_store, struct vm_address_space *aspace, off_t
}
}
// try to commit additional memory
if (vm_try_reserve_memory(B_PAGE_SIZE) != B_OK)
return B_NO_MEMORY;
if (store->precommitted_pages == 0) {
// try to commit additional memory
if (vm_try_reserve_memory(B_PAGE_SIZE) != B_OK)
return B_NO_MEMORY;
} else
store->precommitted_pages--;
store->vm.committed_size += B_PAGE_SIZE;
}
@@ -150,7 +162,7 @@ static vm_store_ops anonymous_ops = {
*/
vm_store *
vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages)
vm_store_create_anonymous_noswap(bool canOvercommit, int32 numPrecommittedPages, int32 numGuardPages)
{
anonymous_store *store = malloc(sizeof(anonymous_store));
if (store == NULL)
@@ -163,6 +175,8 @@ vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages)
store->vm.cache = NULL;
store->vm.committed_size = 0;
store->can_overcommit = canOvercommit;
store->has_precommitted = numPrecommittedPages != 0;
store->precommitted_pages = min(numPrecommittedPages, 255);
store->guarded_size = numGuardPages * B_PAGE_SIZE;
return &store->vm;
@@ -1,5 +1,5 @@
/*
* Copyright 2004-2005, Axel Dörfler, [email protected].
* Copyright 2004-2007, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@@ -13,8 +13,14 @@
#ifdef __cplusplus
extern "C"
extern "C" {
#endif
vm_store *vm_store_create_anonymous_noswap(bool canOvercommit,
int32 numPrecommittedPages, int32 numGuardPages);
#ifdef __cplusplus
}
#endif
vm_store *vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages);
#endif /* _KERNEL_VM_STORE_ANONYMOUS_H */