* 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
|
// create an anonymous store object
|
||||||
newStore = vm_store_create_anonymous_noswap((protection & B_STACK_AREA) != 0,
|
newStore = vm_store_create_anonymous_noswap((protection & B_STACK_AREA) != 0,
|
||||||
USER_STACK_GUARD_PAGES);
|
0, USER_STACK_GUARD_PAGES);
|
||||||
if (newStore == NULL) {
|
if (newStore == NULL) {
|
||||||
status = B_NO_MEMORY;
|
status = B_NO_MEMORY;
|
||||||
goto err1;
|
goto err1;
|
||||||
@@ -784,8 +784,9 @@ vm_create_anonymous_area(team_id aid, const char *name, void **address,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create an anonymous store object
|
// create an anonymous store object
|
||||||
store = vm_store_create_anonymous_noswap(canOvercommit, isStack ?
|
// if it's a stack, make sure that two pages are available at least
|
||||||
((protection & B_USER_PROTECTION) != 0 ?
|
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);
|
USER_STACK_GUARD_PAGES : KERNEL_STACK_GUARD_PAGES) : 0);
|
||||||
if (store == NULL) {
|
if (store == NULL) {
|
||||||
status = B_NO_MEMORY;
|
status = B_NO_MEMORY;
|
||||||
@@ -1461,7 +1462,7 @@ vm_copy_on_write_area(vm_area *area)
|
|||||||
lowerCache = upperCacheRef->cache;
|
lowerCache = upperCacheRef->cache;
|
||||||
|
|
||||||
// create an anonymous store object
|
// 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)
|
if (store == NULL)
|
||||||
return B_NO_MEMORY;
|
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);
|
err = vm_soft_fault(address, is_write, is_user);
|
||||||
if (err < 0) {
|
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",
|
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",
|
||||||
err, address, fault_address, is_write, is_user, thread_get_current_thread_id());
|
strerror(err), address, fault_address, is_write, is_user, thread_get_current_thread_id());
|
||||||
if (!is_user) {
|
if (!is_user) {
|
||||||
struct thread *t = thread_get_current_thread();
|
struct thread *t = thread_get_current_thread();
|
||||||
if (t && t->fault_handler != 0) {
|
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 dummyPage;
|
||||||
vm_page *page = NULL;
|
vm_page *page = NULL;
|
||||||
addr_t address;
|
addr_t address;
|
||||||
int change_count;
|
int32 changeCount;
|
||||||
int err;
|
status_t status;
|
||||||
|
|
||||||
FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n",
|
FTRACE(("vm_soft_fault: thid 0x%lx address 0x%lx, isWrite %d, isUser %d\n",
|
||||||
thread_get_current_thread_id(), originalAddress, isWrite, isUser));
|
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;
|
topCacheRef = area->cache_ref;
|
||||||
cacheOffset = address - area->base + area->cache_offset;
|
cacheOffset = address - area->base + area->cache_offset;
|
||||||
vm_cache_acquire_ref(topCacheRef);
|
vm_cache_acquire_ref(topCacheRef);
|
||||||
change_count = addressSpace->change_count;
|
changeCount = addressSpace->change_count;
|
||||||
release_sem_etc(addressSpace->sem, READ_COUNT, 0);
|
release_sem_etc(addressSpace->sem, READ_COUNT, 0);
|
||||||
|
|
||||||
// See if this cache has a fault handler - this will do all the work for us
|
// 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);
|
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
|
// 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);
|
cacheOffset, &vec, 1, &bytesRead, false);
|
||||||
|
if (status < B_OK)
|
||||||
|
panic("hello, dudes!");
|
||||||
addressSpace->translation_map.ops->put_physical_page((addr_t)vec.iov_base);
|
addressSpace->translation_map.ops->put_physical_page((addr_t)vec.iov_base);
|
||||||
|
|
||||||
mutex_lock(&cacheRef->lock);
|
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
|
// try to get a mapping for the src and dest page so we can copy it
|
||||||
for (;;) {
|
for (;;) {
|
||||||
(*addressSpace->translation_map.ops->get_physical_page)(src_page->physical_page_number * B_PAGE_SIZE, (addr_t *)&src, PHYSICAL_PAGE_CAN_WAIT);
|
(*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);
|
status = (*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)
|
if (status == B_NO_ERROR)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// it couldn't map the second one, so sleep and retry
|
// 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);
|
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
|
// something may have changed, see if the address is still valid
|
||||||
area = vm_area_lookup(addressSpace, address);
|
area = vm_area_lookup(addressSpace, address);
|
||||||
if (area == NULL
|
if (area == NULL
|
||||||
|| area->cache_ref != topCacheRef
|
|| area->cache_ref != topCacheRef
|
||||||
|| (address - area->base + area->cache_offset) != cacheOffset) {
|
|| (address - area->base + area->cache_offset) != cacheOffset) {
|
||||||
dprintf("vm_soft_fault: address space layout changed effecting ongoing soft fault\n");
|
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
|
// 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
|
// 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_cache_release_ref(topCacheRef);
|
||||||
vm_put_address_space(addressSpace);
|
vm_put_address_space(addressSpace);
|
||||||
|
|
||||||
return err;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,8 @@
|
|||||||
typedef struct anonymous_store {
|
typedef struct anonymous_store {
|
||||||
vm_store vm;
|
vm_store vm;
|
||||||
bool can_overcommit;
|
bool can_overcommit;
|
||||||
|
bool has_precommitted;
|
||||||
|
uint8 precommitted_pages;
|
||||||
int32 guarded_size;
|
int32 guarded_size;
|
||||||
} anonymous_store;
|
} anonymous_store;
|
||||||
|
|
||||||
@@ -49,8 +51,15 @@ anonymous_commit(struct vm_store *_store, off_t size)
|
|||||||
anonymous_store *store = (anonymous_store *)_store;
|
anonymous_store *store = (anonymous_store *)_store;
|
||||||
|
|
||||||
// if we can overcommit, we don't commit here, but in anonymous_fault()
|
// if we can overcommit, we don't commit here, but in anonymous_fault()
|
||||||
if (store->can_overcommit)
|
if (store->can_overcommit) {
|
||||||
return B_OK;
|
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;
|
size -= store->vm.cache->virtual_base;
|
||||||
// anonymous stores don't need to span over their whole source
|
// 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
|
// try to commit
|
||||||
if (vm_try_reserve_memory(size - store->vm.committed_size) != B_OK)
|
if (vm_try_reserve_memory(size - store->vm.committed_size) != B_OK)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
store->vm.committed_size = size;
|
store->vm.committed_size = size;
|
||||||
} else {
|
} else {
|
||||||
// we can release some
|
// 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 (store->precommitted_pages == 0) {
|
||||||
if (vm_try_reserve_memory(B_PAGE_SIZE) != B_OK)
|
// try to commit additional memory
|
||||||
return B_NO_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;
|
store->vm.committed_size += B_PAGE_SIZE;
|
||||||
}
|
}
|
||||||
@@ -150,7 +162,7 @@ static vm_store_ops anonymous_ops = {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
vm_store *
|
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));
|
anonymous_store *store = malloc(sizeof(anonymous_store));
|
||||||
if (store == NULL)
|
if (store == NULL)
|
||||||
@@ -163,6 +175,8 @@ vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages)
|
|||||||
store->vm.cache = NULL;
|
store->vm.cache = NULL;
|
||||||
store->vm.committed_size = 0;
|
store->vm.committed_size = 0;
|
||||||
store->can_overcommit = canOvercommit;
|
store->can_overcommit = canOvercommit;
|
||||||
|
store->has_precommitted = numPrecommittedPages != 0;
|
||||||
|
store->precommitted_pages = min(numPrecommittedPages, 255);
|
||||||
store->guarded_size = numGuardPages * B_PAGE_SIZE;
|
store->guarded_size = numGuardPages * B_PAGE_SIZE;
|
||||||
|
|
||||||
return &store->vm;
|
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.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
|
||||||
@@ -13,8 +13,14 @@
|
|||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
vm_store *vm_store_create_anonymous_noswap(bool canOvercommit,
|
||||||
|
int32 numPrecommittedPages, int32 numGuardPages);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
vm_store *vm_store_create_anonymous_noswap(bool canOvercommit, int32 numGuardPages);
|
|
||||||
|
|
||||||
#endif /* _KERNEL_VM_STORE_ANONYMOUS_H */
|
#endif /* _KERNEL_VM_STORE_ANONYMOUS_H */
|
||||||
|
|||||||
Reference in New Issue
Block a user