Files
haiku-beta6/src/system/kernel/vm/vm_low_memory.cpp
T
Axel Dörfler c918a987a0 * Removed my old doubly linked list implementation, and stay with Ingo's.
* Adapt other sources where needed (the boot loader's RootFileSystem still
  used the old implementation).
* Implemented RootFileSystem::Rewind().


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16889 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-03-27 10:27:05 +00:00

184 lines
3.7 KiB
C++

/*
* Copyright 2005-2006, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*/
#include <KernelExport.h>
#include <vm_low_memory.h>
#include <vm_page.h>
#include <lock.h>
#include <util/DoublyLinkedList.h>
#include <util/AutoLock.h>
#include <new>
#include <signal.h>
#include <stdlib.h>
//#define TRACE_LOW_MEMORY
#ifdef TRACE_LOW_MEMORY
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
// TODO: the priority is currently ignored, and probably can be removed
static const bigtime_t kLowMemoryInterval = 3000000; // 3 secs
// page limits
static const size_t kNoteLimit = 1024;
static const size_t kWarnLimit = 256;
static const size_t kCriticalLimit = 32;
static int32 sLowMemoryState = B_NO_LOW_MEMORY;
struct low_memory_handler : public DoublyLinkedListLinkImpl<low_memory_handler> {
low_memory_func function;
void *data;
int32 priority;
};
typedef DoublyLinkedList<low_memory_handler> 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
compute_state(void)
{
uint32 freePages = vm_page_num_free_pages();
if (freePages >= kNoteLimit)
return B_NO_LOW_MEMORY;
// specify low memory level
if (freePages < kCriticalLimit)
return B_LOW_MEMORY_CRITICAL;
else if (freePages < kWarnLimit)
return B_LOW_MEMORY_WARNING;
return B_LOW_MEMORY_NOTE;
}
static int32
low_memory(void *)
{
while (true) {
snooze(kLowMemoryInterval);
sLowMemoryState = compute_state();
TRACE(("vm_low_memory: state = %ld, %ld free pages\n",
sLowMemoryState, vm_page_num_free_pages()));
if (sLowMemoryState < B_LOW_MEMORY_NOTE)
continue;
call_handlers(sLowMemoryState);
}
return 0;
}
void
vm_low_memory(size_t requirements)
{
// ToDo: compute level with requirements in mind
call_handlers(B_LOW_MEMORY_NOTE);
}
int32
vm_low_memory_state(void)
{
return sLowMemoryState;
}
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)
{
TRACE(("unregister_low_memory_handler(function = %p, data = %p)\n",
function, 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)
{
TRACE(("register_low_memory_handler(function = %p, data = %p)\n",
function, data));
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;
}