* creating (or dividing) reserved areas did not acquire a ref to an address

space - but they were released upon deletion. It's probably not really
  needed, but now all reserved areas also grab a reference to their address
  space.
* Rearranged team tear down to be a bit more sane: the I/O context is removed
  first (where semaphores/areas/ports/whatever might still be used), and the
  address space is deleted last.
* delete_area() can now remove its address space reference again (due to the
  two changes above), and therefore fixes bug #1374.
* cleaned up vm_address_space.c a bit (no functional change there, though).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22130 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-08-31 14:20:28 +00:00
parent e94ad1e24d
commit 22e95c5911
3 changed files with 41 additions and 44 deletions
+2 -2
View File
@@ -1781,11 +1781,11 @@ team_delete_team(struct team *team)
// free team resources // free team resources
vm_delete_address_space(team->address_space); vfs_free_io_context(team->io_context);
delete_owned_ports(teamID); delete_owned_ports(teamID);
sem_delete_owned_sems(teamID); sem_delete_owned_sems(teamID);
remove_images(team); remove_images(team);
vfs_free_io_context(team->io_context); vm_delete_address_space(team->address_space);
delete_team_struct(team); delete_team_struct(team);
+3 -4
View File
@@ -741,6 +741,7 @@ find_reserved_area(vm_address_space *addressSpace, addr_t start,
if (reserved == NULL) if (reserved == NULL)
return B_NO_MEMORY; return B_NO_MEMORY;
atomic_add(&addressSpace->ref_count, 1);
reserved->address_space_next = next->address_space_next; reserved->address_space_next = next->address_space_next;
area->address_space_next = reserved; area->address_space_next = reserved;
next->address_space_next = area; next->address_space_next = area;
@@ -1185,6 +1186,7 @@ vm_reserve_address_range(team_id team, void **_address, uint32 addressSpec,
area->cache_offset = area->base; area->cache_offset = area->base;
// we cache the original base address here // we cache the original base address here
atomic_add(&locker.AddressSpace()->ref_count, 1);
return B_OK; return B_OK;
} }
@@ -1872,10 +1874,7 @@ delete_area(vm_address_space *addressSpace, vm_area *area)
arch_vm_unset_memory_type(area); arch_vm_unset_memory_type(area);
remove_area_from_address_space(addressSpace, area); remove_area_from_address_space(addressSpace, area);
// TODO: the following line fixes an address space leak - however, vm_put_address_space(addressSpace);
// there seems to be something wrong with the order in which teams
// are torn down, and the first shell command hangs on a pipe then
//vm_put_address_space(addressSpace);
vm_cache_remove_area(area->cache, area); vm_cache_remove_area(area->cache, area);
vm_cache_release_ref(area->cache); vm_cache_release_ref(area->cache);
+36 -38
View File
@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved. * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* 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.
@@ -7,7 +7,6 @@
*/ */
//#include <OS.h>
#include <KernelExport.h> #include <KernelExport.h>
#include <vm.h> #include <vm.h>
@@ -132,10 +131,9 @@ aspace_hash(void *_a, const void *key, uint32 range)
} }
/** When this function is called, all references to this address space /*! When this function is called, all references to this address space
* have been released, so it's safe to remove it. have been released, so it's safe to remove it.
*/ */
static void static void
delete_address_space(vm_address_space *addressSpace) delete_address_space(vm_address_space *addressSpace)
{ {
@@ -144,14 +142,8 @@ delete_address_space(vm_address_space *addressSpace)
if (addressSpace == sKernelAddressSpace) if (addressSpace == sKernelAddressSpace)
panic("tried to delete the kernel aspace!\n"); panic("tried to delete the kernel aspace!\n");
// put this aspace in the deletion state
// this guarantees that no one else will add regions to the list
acquire_sem_etc(addressSpace->sem, WRITE_COUNT, 0, 0); acquire_sem_etc(addressSpace->sem, WRITE_COUNT, 0, 0);
addressSpace->state = VM_ASPACE_STATE_DELETION;
(*addressSpace->translation_map.ops->destroy)(&addressSpace->translation_map); (*addressSpace->translation_map.ops->destroy)(&addressSpace->translation_map);
delete_sem(addressSpace->sem); delete_sem(addressSpace->sem);
free(addressSpace); free(addressSpace);
} }
@@ -161,17 +153,17 @@ delete_address_space(vm_address_space *addressSpace)
vm_address_space * vm_address_space *
vm_get_address_space_by_id(team_id aid) vm_get_address_space_by_id(team_id id)
{ {
vm_address_space *aspace; vm_address_space *addressSpace;
acquire_sem_etc(sAddressSpaceHashSem, READ_COUNT, 0, 0); acquire_sem_etc(sAddressSpaceHashSem, READ_COUNT, 0, 0);
aspace = hash_lookup(sAddressSpaceTable, &aid); addressSpace = hash_lookup(sAddressSpaceTable, &id);
if (aspace) if (addressSpace)
atomic_add(&aspace->ref_count, 1); atomic_add(&addressSpace->ref_count, 1);
release_sem_etc(sAddressSpaceHashSem, READ_COUNT, 0); release_sem_etc(sAddressSpaceHashSem, READ_COUNT, 0);
return aspace; return addressSpace;
} }
@@ -228,30 +220,29 @@ vm_current_user_address_space_id(void)
void void
vm_put_address_space(vm_address_space *aspace) vm_put_address_space(vm_address_space *addressSpace)
{ {
bool remove = false; bool remove = false;
acquire_sem_etc(sAddressSpaceHashSem, WRITE_COUNT, 0, 0); acquire_sem_etc(sAddressSpaceHashSem, WRITE_COUNT, 0, 0);
if (atomic_add(&aspace->ref_count, -1) == 1) { if (atomic_add(&addressSpace->ref_count, -1) == 1) {
hash_remove(sAddressSpaceTable, aspace); hash_remove(sAddressSpaceTable, addressSpace);
remove = true; remove = true;
} }
release_sem_etc(sAddressSpaceHashSem, WRITE_COUNT, 0); release_sem_etc(sAddressSpaceHashSem, WRITE_COUNT, 0);
if (remove) if (remove)
delete_address_space(aspace); delete_address_space(addressSpace);
} }
/** Deletes all areas in the specified address space, and the address /*! Deletes all areas in the specified address space, and the address
* space by decreasing all reference counters. It also marks the space by decreasing all reference counters. It also marks the
* address space of being in deletion state, so that no more areas address space of being in deletion state, so that no more areas
* can be created in it. can be created in it.
* After this, the address space is not operational anymore, but might After this, the address space is not operational anymore, but might
* still be in memory until the last reference has been released. still be in memory until the last reference has been released.
*/ */
void void
vm_delete_address_space(vm_address_space *addressSpace) vm_delete_address_space(vm_address_space *addressSpace)
{ {
@@ -298,13 +289,15 @@ vm_create_address_space(team_id id, addr_t base, addr_t size,
addressSpace->state = VM_ASPACE_STATE_NORMAL; addressSpace->state = VM_ASPACE_STATE_NORMAL;
addressSpace->fault_count = 0; addressSpace->fault_count = 0;
addressSpace->scan_va = base; addressSpace->scan_va = base;
addressSpace->working_set_size = kernel ? DEFAULT_KERNEL_WORKING_SET : DEFAULT_WORKING_SET; addressSpace->working_set_size = kernel
? DEFAULT_KERNEL_WORKING_SET : DEFAULT_WORKING_SET;
addressSpace->max_working_set = DEFAULT_MAX_WORKING_SET; addressSpace->max_working_set = DEFAULT_MAX_WORKING_SET;
addressSpace->min_working_set = DEFAULT_MIN_WORKING_SET; addressSpace->min_working_set = DEFAULT_MIN_WORKING_SET;
addressSpace->last_working_set_adjust = system_time(); addressSpace->last_working_set_adjust = system_time();
// initialize the corresponding translation map // initialize the corresponding translation map
status = arch_vm_translation_map_init_map(&addressSpace->translation_map, kernel); status = arch_vm_translation_map_init_map(&addressSpace->translation_map,
kernel);
if (status < B_OK) { if (status < B_OK) {
free(addressSpace); free(addressSpace);
return status; return status;
@@ -349,8 +342,9 @@ vm_address_space_init(void)
// create the area and address space hash tables // create the area and address space hash tables
{ {
vm_address_space *aspace; vm_address_space *aspace;
sAddressSpaceTable = hash_init(ASPACE_HASH_TABLE_SIZE, (addr_t)&aspace->hash_next - (addr_t)aspace, sAddressSpaceTable = hash_init(ASPACE_HASH_TABLE_SIZE,
&aspace_compare, &aspace_hash); (addr_t)&aspace->hash_next - (addr_t)aspace, &aspace_compare,
&aspace_hash);
if (sAddressSpaceTable == NULL) if (sAddressSpaceTable == NULL)
panic("vm_init: error creating aspace hash table\n"); panic("vm_init: error creating aspace hash table\n");
} }
@@ -362,8 +356,10 @@ vm_address_space_init(void)
true, &sKernelAddressSpace) != B_OK) true, &sKernelAddressSpace) != B_OK)
panic("vm_init: error creating kernel address space!\n"); panic("vm_init: error creating kernel address space!\n");
add_debugger_command("aspaces", &dump_aspace_list, "Dump a list of all address spaces"); add_debugger_command("aspaces", &dump_aspace_list,
add_debugger_command("aspace", &dump_aspace, "Dump info about a particular address space"); "Dump a list of all address spaces");
add_debugger_command("aspace", &dump_aspace,
"Dump info about a particular address space");
return B_OK; return B_OK;
} }
@@ -372,11 +368,13 @@ vm_address_space_init(void)
status_t status_t
vm_address_space_init_post_sem(void) vm_address_space_init_post_sem(void)
{ {
status_t status = arch_vm_translation_map_init_kernel_map_post_sem(&sKernelAddressSpace->translation_map); status_t status = arch_vm_translation_map_init_kernel_map_post_sem(
&sKernelAddressSpace->translation_map);
if (status < B_OK) if (status < B_OK)
return status; return status;
status = sKernelAddressSpace->sem = create_sem(WRITE_COUNT, "kernel_aspacelock"); status = sKernelAddressSpace->sem = create_sem(WRITE_COUNT,
"kernel_aspacelock");
if (status < B_OK) if (status < B_OK)
return status; return status;