diff --git a/headers/private/kernel/low_resource_manager.h b/headers/private/kernel/low_resource_manager.h index de60d48df4..de3037eb21 100644 --- a/headers/private/kernel/low_resource_manager.h +++ b/headers/private/kernel/low_resource_manager.h @@ -1,6 +1,6 @@ /* * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ #ifndef _KERNEL_LOW_RESOURCE_MANAGER_H @@ -22,10 +22,12 @@ enum { B_KERNEL_RESOURCE_PAGES = 0x01, /* physical pages */ B_KERNEL_RESOURCE_MEMORY = 0x02, /* reservable memory */ B_KERNEL_RESOURCE_SEMAPHORES = 0x04, /* semaphores */ + B_KERNEL_RESOURCE_ADDRESS_SPACE = 0x08, /* address space */ B_ALL_KERNEL_RESOURCES = B_KERNEL_RESOURCE_PAGES | B_KERNEL_RESOURCE_MEMORY | B_KERNEL_RESOURCE_SEMAPHORES + | B_KERNEL_RESOURCE_ADDRESS_SPACE }; typedef void (*low_resource_func)(void *data, uint32 resources, int32 level); diff --git a/headers/private/kernel/vm.h b/headers/private/kernel/vm.h index b3cfa4a134..ef81a7d108 100644 --- a/headers/private/kernel/vm.h +++ b/headers/private/kernel/vm.h @@ -115,6 +115,7 @@ void vm_get_info(struct system_memory_info *info); uint32 vm_num_page_faults(void); off_t vm_available_memory(void); off_t vm_available_not_needed_memory(void); +size_t vm_kernel_address_space_left(void); status_t vm_memset_physical(addr_t address, int value, size_t length); status_t vm_memcpy_from_physical(void* to, addr_t from, size_t length, diff --git a/src/system/kernel/low_resource_manager.cpp b/src/system/kernel/low_resource_manager.cpp index feb137916a..8d09c3eb04 100644 --- a/src/system/kernel/low_resource_manager.cpp +++ b/src/system/kernel/low_resource_manager.cpp @@ -1,6 +1,6 @@ /* * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. - * Copyright 2005-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2005-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. */ @@ -35,7 +35,7 @@ struct low_resource_handler : public DoublyLinkedListLinkImpl { low_resource_func function; - void *data; + void* data; uint32 resources; int32 priority; }; @@ -63,6 +63,7 @@ static off_t sCriticalMemoryLimit; static int32 sLowPagesState = B_NO_LOW_RESOURCE; static int32 sLowMemoryState = B_NO_LOW_RESOURCE; static int32 sLowSemaphoresState = B_NO_LOW_RESOURCE; +static int32 sLowSpaceState = B_NO_LOW_RESOURCE; static uint32 sLowResources = 0; // resources that are not B_NO_LOW_RESOURCE static bigtime_t sLastMeasurement; @@ -85,6 +86,8 @@ low_resource_state_no_update(uint32 resources) state = max_c(state, sLowMemoryState); if ((resources & B_KERNEL_RESOURCE_SEMAPHORES) != 0) state = max_c(state, sLowSemaphoresState); + if ((resources & B_KERNEL_RESOURCE_ADDRESS_SPACE) != 0) + state = max_c(state, sLowSpaceState); return state; } @@ -104,7 +107,7 @@ call_handlers(uint32 lowResources) low_resource_handler marker; sLowResourceHandlers.Insert(&marker, false); - while (low_resource_handler *handler + while (low_resource_handler* handler = sLowResourceHandlers.GetNext(&marker)) { // swap with handler sLowResourceHandlers.Swap(&marker, handler); @@ -173,11 +176,27 @@ compute_state(void) sLowSemaphoresState = B_NO_LOW_RESOURCE; sLowResources &= ~B_KERNEL_RESOURCE_SEMAPHORES; } + + // free kernel address space state + // TODO: this should take fragmentation into account + size_t maxSpace = KERNEL_SIZE; + size_t freeSpace = vm_kernel_address_space_left(); + + if (freeSpace < maxSpace >> 16) + sLowSpaceState = B_LOW_RESOURCE_CRITICAL; + if (freeSpace < maxSpace >> 8) + sLowSpaceState = B_LOW_RESOURCE_WARNING; + if (freeSpace < maxSpace >> 4) + sLowSpaceState = B_LOW_RESOURCE_NOTE; + else { + sLowSpaceState = B_NO_LOW_RESOURCE; + sLowResources &= ~B_KERNEL_RESOURCE_ADDRESS_SPACE; + } } -static int32 -low_resource_manager(void *) +static status_t +low_resource_manager(void*) { bigtime_t timeout = kLowResourceInterval; while (true) { @@ -231,15 +250,17 @@ state_to_string(uint32 state) static int -dump_handlers(int argc, char **argv) +dump_handlers(int argc, char** argv) { - kprintf("current state: %c%c%c\n", + kprintf("current state: %c%c%c%c\n", (sLowResources & B_KERNEL_RESOURCE_PAGES) != 0 ? 'p' : '-', (sLowResources & B_KERNEL_RESOURCE_MEMORY) != 0 ? 'm' : '-', - (sLowResources & B_KERNEL_RESOURCE_SEMAPHORES) != 0 ? 's' : '-'); + (sLowResources & B_KERNEL_RESOURCE_SEMAPHORES) != 0 ? 's' : '-', + (sLowResources & B_KERNEL_RESOURCE_ADDRESS_SPACE) != 0 ? 'a' : '-'); kprintf(" pages: %s\n", state_to_string(sLowPagesState)); kprintf(" memory: %s\n", state_to_string(sLowMemoryState)); - kprintf(" sems: %s\n\n", state_to_string(sLowSemaphoresState)); + kprintf(" sems: %s\n", state_to_string(sLowSemaphoresState)); + kprintf(" aspace: %s\n\n", state_to_string(sLowSpaceState)); HandlerList::Iterator iterator = sLowResourceHandlers.GetIterator(); kprintf("function data resources prio function-name\n"); @@ -282,9 +303,10 @@ low_resource(uint32 resource, uint64 requirements, uint32 flags, uint32 timeout) case B_KERNEL_RESOURCE_PAGES: vm_schedule_page_scanner(requirements); break; + case B_KERNEL_RESOURCE_MEMORY: - break; case B_KERNEL_RESOURCE_SEMAPHORES: + case B_KERNEL_RESOURCE_ADDRESS_SPACE: break; } @@ -354,7 +376,7 @@ low_resource_manager_init_post_thread(void) status_t -unregister_low_resource_handler(low_resource_func function, void *data) +unregister_low_resource_handler(low_resource_func function, void* data) { TRACE(("unregister_low_resource_handler(function = %p, data = %p)\n", function, data)); @@ -363,7 +385,7 @@ unregister_low_resource_handler(low_resource_func function, void *data) HandlerList::Iterator iterator = sLowResourceHandlers.GetIterator(); while (iterator.HasNext()) { - low_resource_handler *handler = iterator.Next(); + low_resource_handler* handler = iterator.Next(); if (handler->function == function && handler->data == data) { sLowResourceHandlers.Remove(handler); @@ -380,13 +402,13 @@ unregister_low_resource_handler(low_resource_func function, void *data) the handler will be called in low resource situations. */ status_t -register_low_resource_handler(low_resource_func function, void *data, +register_low_resource_handler(low_resource_func function, void* data, uint32 resources, int32 priority) { TRACE(("register_low_resource_handler(function = %p, data = %p)\n", function, data)); - low_resource_handler *newHandler = (low_resource_handler *)malloc( + low_resource_handler *newHandler = (low_resource_handler*)malloc( sizeof(low_resource_handler)); if (newHandler == NULL) return B_NO_MEMORY; @@ -402,7 +424,7 @@ register_low_resource_handler(low_resource_func function, void *data, HandlerList::ReverseIterator iterator = sLowResourceHandlers.GetReverseIterator(); - low_resource_handler *last = NULL; + low_resource_handler* last = NULL; while (iterator.HasNext()) { low_resource_handler *handler = iterator.Next(); diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index b232c4eeaf..5181c8434d 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -227,6 +227,9 @@ static status_t map_backing_store(vm_address_space* addressSpace, vm_area** _area, const char* areaName, bool unmapAddressRange, bool kernel); +static size_t sKernelAddressSpaceLeft = KERNEL_SIZE; + + // #pragma mark - @@ -1383,8 +1386,12 @@ insert_area(vm_address_space* addressSpace, void** _address, status = find_and_insert_area_slot(addressSpace, searchBase, size, searchEnd, addressSpec, area); - if (status == B_OK) + if (status == B_OK) { *_address = (void*)area->base; + + if (addressSpace == vm_kernel_address_space()) + sKernelAddressSpaceLeft -= area->size; + } return status; } @@ -1668,8 +1675,16 @@ map_backing_store(vm_address_space* addressSpace, vm_cache* cache, } status = insert_area(addressSpace, _virtualAddress, addressSpec, size, area); - if (status != B_OK) + if (status != B_OK) { + // TODO: wait and try again once this is working in the backend +#if 0 + if (status == B_NO_MEMORY && addressSpec == B_ANY_KERNEL_ADDRESS) { + low_resource(B_KERNEL_RESOURCE_ADDRESS_SPACE, size, + 0, 0); + } +#endif goto err2; + } // attach the cache to the area area->cache = cache; @@ -2006,7 +2021,7 @@ vm_create_anonymous_area(team_id team, const char* name, void** address, addressSpec, wiring, protection, REGION_NO_PRIVATE_MAP, &area, name, (flags & CREATE_AREA_UNMAP_ADDRESS_RANGE) != 0, kernel); - if (status < B_OK) { + if (status != B_OK) { cache->ReleaseRefAndUnlock(); goto err1; } @@ -2751,6 +2766,9 @@ remove_area_from_address_space(vm_address_space* addressSpace, vm_area* area) if (area == addressSpace->area_hint) addressSpace->area_hint = NULL; + if (addressSpace == vm_kernel_address_space()) + sKernelAddressSpaceLeft -= area->size; + if (temp == NULL) panic("vm_area_release_ref: area not found in aspace's area list\n"); } @@ -5264,6 +5282,13 @@ vm_available_not_needed_memory(void) } +size_t +vm_kernel_address_space_left(void) +{ + return sKernelAddressSpaceLeft; +} + + void vm_unreserve_memory(size_t amount) {