* 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:
+20
-17
@@ -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,9 +51,16 @@ 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)
|
||||
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
|
||||
|
||||
@@ -121,9 +130,12 @@ anonymous_fault(struct vm_store *_store, struct vm_address_space *aspace, off_t
|
||||
}
|
||||
}
|
||||
|
||||
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, axeld@pinc-software.de.
|
||||
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||
* 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 */
|
||||
|
||||
Reference in New Issue
Block a user