* steal_page() called remove_page_from_queue() without holding the sPageLock.

This fixes bug #1900 for real.
* Rearranged find_page_candidate() a bit, removed duplicate code, added a panic
  in case the marker state is invalid.
* Some cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25255 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-04-29 19:45:13 +00:00
parent d96c90096f
commit c16d05cff9
+39 -34
View File
@@ -792,8 +792,7 @@ page_scrubber(void *unused)
// get some pages from the free queue // get some pages from the free queue
state = disable_interrupts(); InterruptsSpinLocker locker(sPageLock);
acquire_spinlock(&sPageLock);
// Since we temporarily remove pages from the free pages reserve, // Since we temporarily remove pages from the free pages reserve,
// we must make sure we don't cause a violation of the page // we must make sure we don't cause a violation of the page
@@ -820,8 +819,7 @@ page_scrubber(void *unused)
T(ScrubbingPages(scrubCount)); T(ScrubbingPages(scrubCount));
} }
release_spinlock(&sPageLock); locker.Unlock();
restore_interrupts(state);
// clear them // clear them
@@ -829,8 +827,7 @@ page_scrubber(void *unused)
clear_page(page[i]); clear_page(page[i]);
} }
state = disable_interrupts(); locker.Lock();
acquire_spinlock(&sPageLock);
// and put them into the clear queue // and put them into the clear queue
@@ -842,9 +839,6 @@ page_scrubber(void *unused)
if (scrubCount > 0) { if (scrubCount > 0) {
T(ScrubbedPages(scrubCount)); T(ScrubbedPages(scrubCount));
} }
release_spinlock(&sPageLock);
restore_interrupts(state);
} }
} }
@@ -885,15 +879,20 @@ write_page(vm_page *page, bool fsReenter)
} }
static inline bool
is_marker_page(struct vm_page *page)
{
return page->type == PAGE_TYPE_DUMMY;
}
static void static void
remove_page_marker(struct vm_page &marker) remove_page_marker(struct vm_page &marker)
{ {
if (marker.state == PAGE_STATE_UNUSED) if (marker.state == PAGE_STATE_UNUSED)
return; return;
InterruptsSpinLocker locker(sPageLock);
page_queue *queue; page_queue *queue;
vm_page *page;
switch (marker.state) { switch (marker.state) {
case PAGE_STATE_ACTIVE: case PAGE_STATE_ACTIVE:
@@ -910,7 +909,9 @@ remove_page_marker(struct vm_page &marker)
return; return;
} }
InterruptsSpinLocker locker(sPageLock);
remove_page_from_queue(queue, &marker); remove_page_from_queue(queue, &marker);
marker.state = PAGE_STATE_UNUSED; marker.state = PAGE_STATE_UNUSED;
} }
@@ -929,7 +930,7 @@ next_modified_page(struct vm_page &marker)
page = sModifiedPageQueue.head; page = sModifiedPageQueue.head;
for (; page != NULL; page = page->queue_next) { for (; page != NULL; page = page->queue_next) {
if (page->type != PAGE_TYPE_DUMMY && page->state != PAGE_STATE_BUSY) { if (!is_marker_page(page) && page->state != PAGE_STATE_BUSY) {
// insert marker // insert marker
marker.state = PAGE_STATE_MODIFIED; marker.state = PAGE_STATE_MODIFIED;
insert_page_after(&sModifiedPageQueue, page, &marker); insert_page_after(&sModifiedPageQueue, page, &marker);
@@ -1094,36 +1095,38 @@ find_page_candidate(struct vm_page &marker, bool stealActive)
page_queue *queue; page_queue *queue;
vm_page *page; vm_page *page;
switch (marker.state) { if (marker.state == PAGE_STATE_UNUSED) {
case PAGE_STATE_ACTIVE: // Get the first free pages of the (in)active queue
queue = &sInactivePageQueue;
page = sInactivePageQueue.head;
if (page == NULL && stealActive) {
queue = &sActivePageQueue; queue = &sActivePageQueue;
page = marker.queue_next; page = sActivePageQueue.head;
remove_page_from_queue(queue, &marker); }
marker.state = PAGE_STATE_UNUSED; } else {
break; // Get the next page of the current queue
case PAGE_STATE_INACTIVE: if (marker.state == PAGE_STATE_INACTIVE)
queue = &sInactivePageQueue; queue = &sInactivePageQueue;
page = marker.queue_next; else if (marker.state == PAGE_STATE_ACTIVE)
remove_page_from_queue(queue, &marker); queue = &sActivePageQueue;
marker.state = PAGE_STATE_UNUSED; else {
break; panic("invalid marker %p state", &marker);
default: queue = NULL;
queue = &sInactivePageQueue; }
page = sInactivePageQueue.head;
if (page == NULL && stealActive) { page = marker.queue_next;
queue = &sActivePageQueue; remove_page_from_queue(queue, &marker);
page = sActivePageQueue.head; marker.state = PAGE_STATE_UNUSED;
}
break;
} }
while (page != NULL) { while (page != NULL) {
if (page->type != PAGE_TYPE_DUMMY if (!is_marker_page(page)
&& (page->state == PAGE_STATE_INACTIVE && (page->state == PAGE_STATE_INACTIVE
|| (stealActive && page->state == PAGE_STATE_ACTIVE || (stealActive && page->state == PAGE_STATE_ACTIVE
&& page->wired_count == 0))) { && page->wired_count == 0))) {
// insert marker // we found a candidate, insert marker
marker.state = queue == &sActivePageQueue ? PAGE_STATE_ACTIVE : PAGE_STATE_INACTIVE; marker.state = queue == &sActivePageQueue
? PAGE_STATE_ACTIVE : PAGE_STATE_INACTIVE;
insert_page_after(queue, page, &marker); insert_page_after(queue, page, &marker);
return page; return page;
} }
@@ -1209,6 +1212,8 @@ steal_page(vm_page *page, bool stealActive)
// page->state == PAGE_STATE_INACTIVE ? "" : " (ACTIVE)"); // page->state == PAGE_STATE_INACTIVE ? "" : " (ACTIVE)");
vm_cache_remove_page(page->cache, page); vm_cache_remove_page(page->cache, page);
InterruptsSpinLocker _(sPageLock);
remove_page_from_queue(page->state == PAGE_STATE_ACTIVE remove_page_from_queue(page->state == PAGE_STATE_ACTIVE
? &sActivePageQueue : &sInactivePageQueue, page); ? &sActivePageQueue : &sInactivePageQueue, page);
return true; return true;