axeld + bonefish:

* More conditional debug code (wrt page transitions between caches).
* Replaced debugger command cache_chain by a nicer cache_tree.
* While handling a soft fault: When we temporarily unlock a cache, it
  can theoretically become busy. One such occurrence is now handled
  properly, two more panic() ATM, though should be fixed.
* When merging caches, we do now always replace a dummy page in the
  upper cache, not only when the concurrent page fault is a read fault.
  This prevents a page from the lower (to be discarded) cache from still
  remaining mapped (causing a panic).
* When merging caches and replacing a dummy page, we were trying to
  remove the dummy page from the wrong cache (causing a panic).

The Haiku kernel seems now to run shockingly stable. ATM, we have more
than two hours uptime of a system booted and running over network. We
didn't manage to get it down by fully building Pe, downloading, unzipping,
and playing with various stuff. Someone should finally fix all those app
server drawing bugs, though (hint, hint! ;-)).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21672 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2007-07-19 22:52:23 +00:00
parent fd0831b98d
commit 6d1c68155a
4 changed files with 110 additions and 14 deletions
+8
View File
@@ -21,6 +21,9 @@
// be in.
//#define DEBUG_PAGE_QUEUE 1
// Enables extra debug fields in the vm_page used to track page transitions
// between caches.
//#define DEBUG_PAGE_CACHE_TRANSITIONS 1
#ifdef __cplusplus
struct vm_page_mapping;
@@ -92,6 +95,11 @@ typedef struct vm_page {
void* queue;
#endif
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
uint32 debug_flags;
struct vm_page *collided_page;
#endif
uint8 type : 2;
uint8 state : 3;
uint8 busy_reading : 1;
+73 -8
View File
@@ -2195,8 +2195,29 @@ page_state_to_string(int state)
}
static void
dump_cache_tree_recursively(vm_cache* cache, int level,
vm_cache* highlightCache)
{
// print this cache
for (int i = 0; i < level; i++)
kprintf(" ");
if (cache == highlightCache)
kprintf("%p <--\n", cache);
else
kprintf("%p\n", cache);
// recursively print its consumers
vm_cache* consumer = NULL;
while ((consumer = (vm_cache *)list_get_next_item(&cache->consumers,
consumer)) != NULL) {
dump_cache_tree_recursively(consumer, level + 1, highlightCache);
}
}
static int
dump_cache_chain(int argc, char **argv)
dump_cache_tree(int argc, char **argv)
{
if (argc < 2 || strlen(argv[1]) < 2
|| argv[1][0] != '0'
@@ -2210,10 +2231,13 @@ dump_cache_chain(int argc, char **argv)
return 0;
vm_cache *cache = (vm_cache *)address;
while (cache != NULL) {
dprintf("%p\n", cache);
cache = cache->source;
}
vm_cache *root = cache;
// find the root cache (the transitive source)
while (root->source != NULL)
root = root->source;
dump_cache_tree_recursively(root, 0, cache);
return 0;
}
@@ -2914,7 +2938,7 @@ vm_init(kernel_args *args)
add_debugger_command("areas", &dump_area_list, "Dump a list of all areas");
add_debugger_command("area", &dump_area, "Dump info about a particular area");
add_debugger_command("cache", &dump_cache, "Dump vm_cache");
add_debugger_command("cache_chain", &dump_cache_chain, "Dump vm_cache chain");
add_debugger_command("cache_tree", &dump_cache_tree, "Dump vm_cache tree");
add_debugger_command("avail", &dump_available_memory, "Dump available memory");
add_debugger_command("dl", &display_mem, "dump memory long words (64-bit)");
add_debugger_command("dw", &display_mem, "dump memory words (32-bit)");
@@ -3197,8 +3221,22 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
// page must be busy
// ToDo: don't wait forever!
mutex_unlock(&cache->lock);
snooze(20000);
thread_yield();
mutex_lock(&cache->lock);
if (cache->busy) {
// The cache became busy, which means, it is about to be
// removed by vm_cache_remove_consumer(). We start again with
// the top cache.
mutex_unlock(&cache->lock);
vm_cache_release_ref(cache);
cache = topCache;
lastCache = cache;
vm_cache_acquire_ref(cache);
mutex_lock(&cache->lock);
}
}
if (page != NULL && page != &dummyPage)
@@ -3267,6 +3305,9 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
// upwards, too, we try this cache again
mutex_unlock(&cache->lock);
mutex_lock(&cache->lock);
if (cache->busy)
panic("fault_find_page(): cache became busy: %p\n", cache);
// TODO: Don't panic()!
lastCache = NULL;
continue;
} else if (status < B_OK)
@@ -3288,6 +3329,9 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
// top most cache may have direct write access.
vm_cache_acquire_ref(cache);
mutex_lock(&cache->lock);
if (cache->busy)
panic("fault_find_page(): 2. cache became busy: %p\n", cache);
// TOOD: Don't panic()!
}
// release the reference of the last vm_cache we still have from the loop above
@@ -3324,12 +3368,29 @@ fault_get_page(vm_translation_map *map, vm_cache *topCache,
// Insert the new page into our cache, and replace it with the dummy page if necessary
// if we inserted a dummy page into this cache, we have to remove it now
if (dummyPage.state == PAGE_STATE_BUSY && dummyPage.cache == cache)
if (dummyPage.state == PAGE_STATE_BUSY && dummyPage.cache == cache) {
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
page->debug_flags = dummyPage.debug_flags | 0x8;
if (dummyPage.collided_page != NULL) {
dummyPage.collided_page->collided_page = page;
page->collided_page = dummyPage.collided_page;
}
#endif // DEBUG_PAGE_CACHE_TRANSITIONS
fault_remove_dummy_page(dummyPage, true);
}
vm_cache_insert_page(cache, page, cacheOffset);
if (dummyPage.state == PAGE_STATE_BUSY) {
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
page->debug_flags = dummyPage.debug_flags | 0x10;
if (dummyPage.collided_page != NULL) {
dummyPage.collided_page->collided_page = page;
page->collided_page = dummyPage.collided_page;
}
#endif // DEBUG_PAGE_CACHE_TRANSITIONS
// we had inserted the dummy cache in another cache, so let's remove it from there
fault_remove_dummy_page(dummyPage, false);
}
@@ -3502,6 +3563,10 @@ vm_soft_fault(addr_t originalAddress, bool isWrite, bool isUser)
dummyPage.type = PAGE_TYPE_DUMMY;
dummyPage.busy_writing = isWrite;
dummyPage.wired_count = 0;
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
dummyPage.debug_flags = 0;
dummyPage.collided_page = NULL;
#endif // DEBUG_PAGE_CACHE_TRANSITIONS
vm_cache *copiedPageSource = NULL;
vm_cache *pageSource;
+20 -5
View File
@@ -314,8 +314,10 @@ vm_cache_remove_page(vm_cache *cache, vm_page *page)
TRACE(("vm_cache_remove_page: cache %p, page %p\n", cache, page));
ASSERT_LOCKED_MUTEX(&cache->lock);
if (page->cache != cache)
panic("remove page from %p: page cache is set to %p\n", cache, page->cache);
if (page->cache != cache) {
panic("remove page %p from cache %p: page cache is set to %p\n", page,
cache, page->cache);
}
state = disable_interrupts();
acquire_spinlock(&sPageCacheTableLock);
@@ -478,6 +480,8 @@ vm_cache_remove_consumer(vm_cache *cache, vm_cache *consumer)
|| list_is_empty(&cache->consumers)
|| cache->consumers.link.next != cache->consumers.link.prev
|| consumer != list_get_first_item(&cache->consumers)) {
dprintf("vm_cache_remove_consumer(): cache %p was modified; "
"not merging it\n");
merge = false;
cache->busy = false;
mutex_unlock(&consumer->lock);
@@ -512,18 +516,29 @@ if (consumer->virtual_base == 0x11000)
vm_cache_insert_page(consumer, page,
(off_t)page->cache_offset << PAGE_SHIFT);
} else if (consumerPage->state == PAGE_STATE_BUSY
&& consumerPage->type == PAGE_TYPE_DUMMY
&& !consumerPage->busy_writing) {
&& consumerPage->type == PAGE_TYPE_DUMMY) {
// the page is currently busy taking a read fault - IOW,
// vm_soft_fault() has mapped our page so we can just
// move it up
//dprintf("%ld: merged busy page %p, cache %p, offset %ld\n", find_thread(NULL), page, cacheRef->cache, page->cache_offset);
vm_cache_remove_page(cache, consumerPage);
vm_cache_remove_page(consumer, consumerPage);
consumerPage->state = PAGE_STATE_INACTIVE;
vm_cache_remove_page(cache, page);
vm_cache_insert_page(consumer, page,
(off_t)page->cache_offset << PAGE_SHIFT);
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
} else {
page->debug_flags = 0;
if (consumerPage->state == PAGE_STATE_BUSY)
page->debug_flags |= 0x1;
if (consumerPage->type == PAGE_TYPE_DUMMY)
page->debug_flags |= 0x2;
if (!consumerPage->busy_writing)
page->debug_flags |= 0x4;
page->collided_page = consumerPage;
consumerPage->collided_page = page;
#endif // DEBUG_PAGE_CACHE_TRANSITIONS
}
#if 0
else if (consumer->virtual_base == 0x11000)
+9 -1
View File
@@ -269,8 +269,12 @@ dump_page(int argc, char **argv)
kprintf("wired_count: %u\n", page->wired_count);
kprintf("usage_count: %u\n", page->usage_count);
#ifdef DEBUG_PAGE_QUEUE
kprintf("queue: %p\n", page->queue);
kprintf("queue: %p\n", page->queue);
#endif
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
kprintf("debug_flags: 0x%lx\n", page->debug_flags);
kprintf("collided page: %p\n", page->collided_page);
#endif // DEBUG_PAGE_CACHE_TRANSITIONS
kprintf("area mappings:\n");
mapping = page->mappings;
@@ -831,6 +835,10 @@ vm_page_init(kernel_args *args)
#ifdef DEBUG_PAGE_QUEUE
sPages[i].queue = NULL;
#endif
#ifdef DEBUG_PAGE_CACHE_TRANSITIONS
sPages[i].debug_flags = 0;
sPages[i].collided_page = NULL;
#endif // DEBUG_PAGE_CACHE_TRANSITIONS
enqueue_page(&page_free_queue, &sPages[i]);
}