From b84688be5fa069d69df1c4bed506cf6347d5edf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 13 Jun 2005 13:03:54 +0000 Subject: [PATCH] Added a basic low memory handler service. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13090 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/vm_low_memory.h | 37 +++++++ src/system/kernel/vm/Jamfile | 1 + src/system/kernel/vm/vm.cpp | 7 +- src/system/kernel/vm/vm_low_memory.cpp | 142 +++++++++++++++++++++++++ 4 files changed, 185 insertions(+), 2 deletions(-) create mode 100644 headers/private/kernel/vm_low_memory.h create mode 100644 src/system/kernel/vm/vm_low_memory.cpp diff --git a/headers/private/kernel/vm_low_memory.h b/headers/private/kernel/vm_low_memory.h new file mode 100644 index 0000000000..fe7dfa459d --- /dev/null +++ b/headers/private/kernel/vm_low_memory.h @@ -0,0 +1,37 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _KERNEL_VM_LOW_MEMORY_H +#define _KERNEL_VM_LOW_MEMORY_H + + +#include + + +/* warning levels for low memory handlers */ +enum { + B_LOW_MEMORY_NOTE, + B_LOW_MEMORY_WARNING, + B_LOW_MEMORY_CRITICAL, +}; + +typedef void (*low_memory_func)(void *data, int32 level); + +#ifdef __cplusplus +extern "C" { +#endif + +status_t vm_low_memory_init(void); +void vm_low_memory(size_t requirements); + +// these calls might get public some day +status_t register_low_memory_handler(low_memory_func function, void *data, + int32 priority); +status_t unregister_low_memory_handler(low_memory_func function, void *data); + +#ifdef __cplusplus +} +#endif + +#endif /* _KERNEL_VM_LOW_MEMORY_H */ diff --git a/src/system/kernel/vm/Jamfile b/src/system/kernel/vm/Jamfile index 1f00a4edaa..8a7e00e4e9 100644 --- a/src/system/kernel/vm/Jamfile +++ b/src/system/kernel/vm/Jamfile @@ -5,6 +5,7 @@ KernelMergeObject kernel_vm.o : vm_address_space.c vm_cache.c vm_daemons.c + vm_low_memory.cpp vm_page.c vm_store_anonymous_noswap.c vm_store_device.c diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index 8dd4e3cd21..bba4fe4fd2 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #define ROUNDUP(a, b) (((a) + ((b)-1)) & ~((b)-1)) #define ROUNDOWN(a, b) (((a) / (b)) * (b)) + extern vm_address_space *kernel_aspace; #define REGION_HASH_TABLE_SIZE 1024 @@ -2237,6 +2239,7 @@ vm_init_post_thread(kernel_args *args) { vm_page_init_post_thread(args); vm_daemon_init(); + vm_low_memory_init(); return heap_init_post_thread(args); } @@ -2590,7 +2593,7 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) } } - err = 0; + err = B_OK; acquire_sem_etc(map->sem, READ_COUNT, 0, 0); if (change_count != map->change_count) { // something may have changed, see if the address is still valid @@ -2603,7 +2606,7 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser) } } - if (err == 0) { + if (err == 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 diff --git a/src/system/kernel/vm/vm_low_memory.cpp b/src/system/kernel/vm/vm_low_memory.cpp new file mode 100644 index 0000000000..6d653de120 --- /dev/null +++ b/src/system/kernel/vm/vm_low_memory.cpp @@ -0,0 +1,142 @@ +/* + * Copyright 2005, Axel Dörfler, axeld@pinc-software.de. + * Distributed under the terms of the MIT License. + */ + + +#include +#include + +#include +#include +#include +#include +#include + + +static const bigtime_t kLowMemoryInterval = 2000000; // 2 secs + +static const size_t kNoteLimit = 1024; +static const size_t kWarnLimit = 256; +static const size_t kCriticalLimit = 32; + + +struct low_memory_handler : public DoublyLinkedListLinkImpl { + low_memory_func function; + void *data; + int32 priority; +}; + +typedef DoublyLinkedList HandlerList; + +static mutex sLowMemoryMutex; +static sem_id sLowMemoryWaitSem; +static HandlerList sLowMemoryHandlers; + + +static void +call_handlers(int32 level) +{ + MutexLocker locker(&sLowMemoryMutex); + HandlerList::Iterator iterator = sLowMemoryHandlers.GetIterator(); + + while (iterator.HasNext()) { + low_memory_handler *handler = iterator.Next(); + + handler->function(handler->data, level); + } +} + + +static int32 +low_memory(void *) +{ + while (true) { + snooze(kLowMemoryInterval); + + uint32 freePages = vm_page_num_free_pages(); + if (freePages >= kNoteLimit) + continue; + + // specify low memory level + int32 level = B_LOW_MEMORY_NOTE; + if (freePages < kCriticalLimit) + level = B_LOW_MEMORY_CRITICAL; + else if (freePages < kWarnLimit) + level = B_LOW_MEMORY_WARNING; + + call_handlers(level); + } + return 0; +} + + +void +vm_low_memory(size_t requirements) +{ + // ToDo: compute level with requirements in mind + + call_handlers(B_LOW_MEMORY_NOTE); +} + + +status_t +vm_low_memory_init(void) +{ + thread_id thread; + + if (mutex_init(&sLowMemoryMutex, "low memory") < B_OK) + return B_ERROR; + + sLowMemoryWaitSem = create_sem(0, "low memory wait"); + if (sLowMemoryWaitSem < B_OK) + return sLowMemoryWaitSem; + + new(&sLowMemoryHandlers) HandlerList; + // static initializers do not work in the kernel, + // so we have to do it here, manually + + thread = spawn_kernel_thread(&low_memory, "low memory handler", B_LOW_PRIORITY, NULL); + send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE); + + return B_OK; +} + + +status_t +unregister_low_memory_handler(low_memory_func function, void *data) +{ + MutexLocker locker(&sLowMemoryMutex); + + HandlerList::Iterator iterator = sLowMemoryHandlers.GetIterator(); + + while (iterator.HasNext()) { + low_memory_handler *handler = iterator.Next(); + + if (handler->function == function && handler->data == data) { + sLowMemoryHandlers.Remove(handler); + free(handler); + return B_OK; + } + } + + return B_ENTRY_NOT_FOUND; +} + + +status_t +register_low_memory_handler(low_memory_func function, void *data, int32 priority) +{ + low_memory_handler *handler = (low_memory_handler *)malloc(sizeof(low_memory_handler)); + if (handler == NULL) + return B_NO_MEMORY; + + handler->function = function; + handler->data = data; + handler->priority = priority; + + MutexLocker locker(&sLowMemoryMutex); + sLowMemoryHandlers.Add(handler); + return B_OK; +} +