* Moved the vm_page initialization from vm_page.cpp:vm_page_init() to the new

vm_page::Init().
* Made vm_page::wired_count private and added accessor methods.
* Added VMCache::fWiredPagesCount (the number of wired pages the cache
  contains) and accessor methods.
* Made more use of vm_page::IsMapped().
* vm_copy_on_write_area(): Added vm_page_reservation* parameter that can be
  used to request a special handling for wired pages. If given the wired pages
  are replaced by copies and the original pages are moved to the upper cache.
* vm_copy_area():
  - We don't need to do any wired ranges handling, if the source area is a
    B_SHARED_AREA, since we don't touch the area's mappings in this case.
  - We no longer wait for wired ranges of the concerned areas to disappear.
    Instead we use the new vm_copy_on_write_area() feature and just let it
    copy the wired pages. This fixes #6288, an issue introduced with the use
    of user mutexes in libroot: When executing multiple concurrent fork()s all
    but the first one would wait on the fork mutex, which (being a user mutex)
    would wire a page that the vm_copy_area() of the first fork() would wait
    for.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@37460 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2010-07-10 15:08:13 +00:00
parent 61728e1e09
commit b944766870
10 changed files with 245 additions and 78 deletions
+48
View File
@@ -101,6 +101,10 @@ public:
void MovePage(vm_page* page); void MovePage(vm_page* page);
void MoveAllPages(VMCache* fromCache); void MoveAllPages(VMCache* fromCache);
inline page_num_t WiredPagesCount() const;
inline void IncrementWiredPagesCount();
inline void DecrementWiredPagesCount();
void AddConsumer(VMCache* consumer); void AddConsumer(VMCache* consumer);
status_t InsertAreaLocked(VMArea* area); status_t InsertAreaLocked(VMArea* area);
@@ -197,6 +201,7 @@ private:
PageEventWaiter* fPageEventWaiters; PageEventWaiter* fPageEventWaiters;
void* fUserData; void* fUserData;
VMCacheRef* fCacheRef; VMCacheRef* fCacheRef;
page_num_t fWiredPagesCount;
}; };
@@ -308,6 +313,49 @@ VMCache::MarkPageUnbusy(vm_page* page)
} }
page_num_t
VMCache::WiredPagesCount() const
{
return fWiredPagesCount;
}
void
VMCache::IncrementWiredPagesCount()
{
ASSERT(fWiredPagesCount < page_count);
fWiredPagesCount++;
}
void
VMCache::DecrementWiredPagesCount()
{
ASSERT(fWiredPagesCount > 0);
fWiredPagesCount--;
}
// vm_page methods implemented here to avoid VMCache.h inclusion in vm_types.h
inline void
vm_page::IncrementWiredCount()
{
if (fWiredCount++ == 0)
cache_ref->cache->IncrementWiredPagesCount();
}
inline void
vm_page::DecrementWiredCount()
{
if (--fWiredCount == 0)
cache_ref->cache->DecrementWiredPagesCount();
}
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
+32 -2
View File
@@ -10,6 +10,8 @@
#define _KERNEL_VM_VM_TYPES_H #define _KERNEL_VM_VM_TYPES_H
#include <new>
#include <arch/vm_types.h> #include <arch/vm_types.h>
#include <condition_variable.h> #include <condition_variable.h>
#include <kernel.h> #include <kernel.h>
@@ -142,7 +144,8 @@ public:
uint8 unused : 1; uint8 unused : 1;
uint8 usage_count; uint8 usage_count;
uint16 wired_count;
inline void Init(page_num_t pageNumber);
VMCacheRef* CacheRef() const { return cache_ref; } VMCacheRef* CacheRef() const { return cache_ref; }
void SetCacheRef(VMCacheRef* cacheRef) { this->cache_ref = cacheRef; } void SetCacheRef(VMCacheRef* cacheRef) { this->cache_ref = cacheRef; }
@@ -151,11 +154,19 @@ public:
{ return cache_ref != NULL ? cache_ref->cache : NULL; } { return cache_ref != NULL ? cache_ref->cache : NULL; }
bool IsMapped() const bool IsMapped() const
{ return wired_count > 0 || !mappings.IsEmpty(); } { return fWiredCount > 0 || !mappings.IsEmpty(); }
uint8 State() const { return state; } uint8 State() const { return state; }
void InitState(uint8 newState); void InitState(uint8 newState);
void SetState(uint8 newState); void SetState(uint8 newState);
inline uint16 WiredCount() const { return fWiredCount; }
inline void IncrementWiredCount();
inline void DecrementWiredCount();
// both implemented in VMCache.h to avoid inclusion here
private:
uint16 fWiredCount;
}; };
@@ -180,6 +191,25 @@ enum {
#define VM_PAGE_ALLOC_BUSY 0x00000020 #define VM_PAGE_ALLOC_BUSY 0x00000020
inline void
vm_page::Init(page_num_t pageNumber)
{
physical_page_number = pageNumber;
InitState(PAGE_STATE_FREE);
new(&mappings) vm_page_mappings();
fWiredCount = 0;
usage_count = 0;
busy_writing = false;
SetCacheRef(NULL);
#if DEBUG_PAGE_QUEUE
queue = NULL;
#endif
#if DEBUG_PAGE_ACCESS
accessing_thread = -1;
#endif
}
#if DEBUG_PAGE_ACCESS #if DEBUG_PAGE_ACCESS
# include <thread.h> # include <thread.h>
@@ -409,9 +409,9 @@ X86VMTranslationMap32Bit::UnmapPages(VMArea* area, addr_t base, size_t size,
page->mappings.Remove(mapping); page->mappings.Remove(mapping);
queue.Add(mapping); queue.Add(mapping);
} else } else
page->wired_count--; page->DecrementWiredCount();
if (page->wired_count == 0 && page->mappings.IsEmpty()) { if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) { if (updatePageQueue) {
@@ -475,7 +475,7 @@ X86VMTranslationMap32Bit::UnmapArea(VMArea* area, bool deletingAddressSpace,
VMCache* cache = page->Cache(); VMCache* cache = page->Cache();
bool pageFullyUnmapped = false; bool pageFullyUnmapped = false;
if (page->wired_count == 0 && page->mappings.IsEmpty()) { if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
pageFullyUnmapped = true; pageFullyUnmapped = true;
} }
@@ -451,9 +451,9 @@ X86VMTranslationMapPAE::UnmapPages(VMArea* area, addr_t base, size_t size,
page->mappings.Remove(mapping); page->mappings.Remove(mapping);
queue.Add(mapping); queue.Add(mapping);
} else } else
page->wired_count--; page->DecrementWiredCount();
if (page->wired_count == 0 && page->mappings.IsEmpty()) { if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) { if (updatePageQueue) {
@@ -515,7 +515,7 @@ X86VMTranslationMapPAE::UnmapArea(VMArea* area, bool deletingAddressSpace,
VMCache* cache = page->Cache(); VMCache* cache = page->Cache();
bool pageFullyUnmapped = false; bool pageFullyUnmapped = false;
if (page->wired_count == 0 && page->mappings.IsEmpty()) { if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
pageFullyUnmapped = true; pageFullyUnmapped = true;
} }
+2 -2
View File
@@ -1382,7 +1382,7 @@ MemoryManager::_MapChunk(VMArea* vmArea, addr_t address, size_t size,
vm_page* page = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED); vm_page* page = vm_page_allocate_page(&reservation, PAGE_STATE_WIRED);
cache->InsertPage(page, offset); cache->InsertPage(page, offset);
page->wired_count++; page->IncrementWiredCount();
atomic_add(&gMappedPagesCount, 1); atomic_add(&gMappedPagesCount, 1);
DEBUG_PAGE_ACCESS_END(page); DEBUG_PAGE_ACCESS_END(page);
@@ -1435,7 +1435,7 @@ MemoryManager::_UnmapChunk(VMArea* vmArea, addr_t address, size_t size,
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
page->wired_count--; page->DecrementWiredCount();
cache->RemovePage(page); cache->RemovePage(page);
// the iterator is remove-safe // the iterator is remove-safe
+1 -1
View File
@@ -14,7 +14,7 @@ PageCacheLocker::_IgnorePage(vm_page* page)
{ {
if (page->busy || page->State() == PAGE_STATE_WIRED if (page->busy || page->State() == PAGE_STATE_WIRED
|| page->State() == PAGE_STATE_FREE || page->State() == PAGE_STATE_CLEAR || page->State() == PAGE_STATE_FREE || page->State() == PAGE_STATE_CLEAR
|| page->State() == PAGE_STATE_UNUSED || page->wired_count > 0) || page->State() == PAGE_STATE_UNUSED || page->WiredCount() > 0)
return true; return true;
return false; return false;
+19 -4
View File
@@ -594,6 +594,7 @@ VMCache::Init(uint32 cacheType, uint32 allocationFlags)
committed_size = 0; committed_size = 0;
temporary = 0; temporary = 0;
page_count = 0; page_count = 0;
fWiredPagesCount = 0;
type = cacheType; type = cacheType;
fPageEventWaiters = NULL; fPageEventWaiters = NULL;
@@ -634,7 +635,7 @@ VMCache::Delete()
// free all of the pages in the cache // free all of the pages in the cache
while (vm_page* page = pages.Root()) { while (vm_page* page = pages.Root()) {
if (!page->mappings.IsEmpty() || page->wired_count != 0) { if (!page->mappings.IsEmpty() || page->WiredCount() != 0) {
panic("remove page %p from cache %p: page still has mappings!\n", panic("remove page %p from cache %p: page still has mappings!\n",
page, this); page, this);
} }
@@ -758,6 +759,9 @@ VMCache::InsertPage(vm_page* page, off_t offset)
#endif // KDEBUG #endif // KDEBUG
pages.Insert(page); pages.Insert(page);
if (page->WiredCount() > 0)
IncrementWiredPagesCount();
} }
@@ -781,6 +785,9 @@ VMCache::RemovePage(vm_page* page)
pages.Remove(page); pages.Remove(page);
page_count--; page_count--;
page->SetCacheRef(NULL); page->SetCacheRef(NULL);
if (page->WiredCount() > 0)
DecrementWiredPagesCount();
} }
@@ -804,6 +811,12 @@ VMCache::MovePage(vm_page* page)
pages.Insert(page); pages.Insert(page);
page_count++; page_count++;
page->SetCacheRef(fCacheRef); page->SetCacheRef(fCacheRef);
if (page->WiredCount() > 0) {
IncrementWiredPagesCount();
oldCache->DecrementWiredPagesCount();
}
T2(InsertPage(this, page, page->cache_offset << PAGE_SHIFT)); T2(InsertPage(this, page, page->cache_offset << PAGE_SHIFT));
} }
@@ -821,6 +834,8 @@ VMCache::MoveAllPages(VMCache* fromCache)
std::swap(fromCache->pages, pages); std::swap(fromCache->pages, pages);
page_count = fromCache->page_count; page_count = fromCache->page_count;
fromCache->page_count = 0; fromCache->page_count = 0;
fWiredPagesCount = fromCache->fWiredPagesCount;
fromCache->fWiredPagesCount = 0;
// swap the VMCacheRefs // swap the VMCacheRefs
mutex_lock(&sCacheListLock); mutex_lock(&sCacheListLock);
@@ -1077,7 +1092,7 @@ VMCache::Resize(off_t newSize, int priority)
// remove the page and put it into the free queue // remove the page and put it into the free queue
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
vm_remove_all_page_mappings(page); vm_remove_all_page_mappings(page);
ASSERT(page->wired_count == 0); ASSERT(page->WiredCount() == 0);
// TODO: Find a real solution! If the page is wired // TODO: Find a real solution! If the page is wired
// temporarily (e.g. by lock_memory()), we actually must not // temporarily (e.g. by lock_memory()), we actually must not
// unmap it! // unmap it!
@@ -1123,7 +1138,7 @@ VMCache::FlushAndRemoveAllPages()
continue; continue;
// We can't remove mapped pages. // We can't remove mapped pages.
if (page->wired_count > 0 || !page->mappings.IsEmpty()) if (page->IsMapped())
return B_BUSY; return B_BUSY;
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
@@ -1311,7 +1326,7 @@ VMCache::Dump(bool showPages) const
" state %u (%s) wired_count %u\n", page, " state %u (%s) wired_count %u\n", page,
page->physical_page_number, page->cache_offset, page->physical_page_number, page->cache_offset,
page->State(), page_state_to_string(page->State()), page->State(), page_state_to_string(page->State()),
page->wired_count); page->WiredCount());
} else { } else {
kprintf("\t%p DUMMY PAGE state %u (%s)\n", kprintf("\t%p DUMMY PAGE state %u (%s)\n",
page, page->State(), page_state_to_string(page->State())); page, page->State(), page_state_to_string(page->State()));
+4 -4
View File
@@ -146,11 +146,11 @@ VMTranslationMap::PageUnmapped(VMArea* area, page_num_t pageNumber,
B_PRIxPHYSADDR ", accessed: %d, modified: %d", page, B_PRIxPHYSADDR ", accessed: %d, modified: %d", page,
pageNumber, accessed, modified); pageNumber, accessed, modified);
} else } else
page->wired_count--; page->DecrementWiredCount();
recursive_lock_unlock(&fLock); recursive_lock_unlock(&fLock);
if (page->wired_count == 0 && page->mappings.IsEmpty()) { if (!page->IsMapped()) {
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
if (updatePageQueue) { if (updatePageQueue) {
@@ -203,11 +203,11 @@ VMTranslationMap::UnaccessedPageUnmapped(VMArea* area, page_num_t pageNumber)
ASSERT_PRINT(mapping != NULL, "page: %p, page number: %#" ASSERT_PRINT(mapping != NULL, "page: %p, page number: %#"
B_PRIxPHYSADDR, page, pageNumber); B_PRIxPHYSADDR, page, pageNumber);
} else } else
page->wired_count--; page->DecrementWiredCount();
recursive_lock_unlock(&fLock); recursive_lock_unlock(&fLock);
if (page->wired_count == 0 && page->mappings.IsEmpty()) if (!page->IsMapped())
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
if (mapping != NULL) { if (mapping != NULL) {
+121 -36
View File
@@ -406,8 +406,9 @@ private:
static inline void static inline void
increment_page_wired_count(vm_page* page) increment_page_wired_count(vm_page* page)
{ {
if (page->wired_count++ == 0 && page->mappings.IsEmpty()) if (!page->IsMapped())
atomic_add(&gMappedPagesCount, 1); atomic_add(&gMappedPagesCount, 1);
page->IncrementWiredCount();
} }
@@ -416,7 +417,8 @@ increment_page_wired_count(vm_page* page)
static inline void static inline void
decrement_page_wired_count(vm_page* page) decrement_page_wired_count(vm_page* page)
{ {
if (--page->wired_count == 0 && page->mappings.IsEmpty()) page->DecrementWiredCount();
if (!page->IsMapped())
atomic_add(&gMappedPagesCount, -1); atomic_add(&gMappedPagesCount, -1);
} }
@@ -486,7 +488,7 @@ map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection,
{ {
VMTranslationMap* map = area->address_space->TranslationMap(); VMTranslationMap* map = area->address_space->TranslationMap();
bool wasMapped = page->wired_count > 0 || !page->mappings.IsEmpty(); bool wasMapped = page->IsMapped();
if (area->wiring == B_NO_LOCK) { if (area->wiring == B_NO_LOCK) {
DEBUG_PAGE_ACCESS_CHECK(page); DEBUG_PAGE_ACCESS_CHECK(page);
@@ -508,7 +510,7 @@ map_page(VMArea* area, vm_page* page, addr_t address, uint32 protection,
area->MemoryType(), reservation); area->MemoryType(), reservation);
// insert mapping into lists // insert mapping into lists
if (page->mappings.IsEmpty() && page->wired_count == 0) if (!page->IsMapped())
atomic_add(&gMappedPagesCount, 1); atomic_add(&gMappedPagesCount, 1);
page->mappings.Add(mapping); page->mappings.Add(mapping);
@@ -1341,8 +1343,8 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size,
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
increment_page_wired_count(page);
cache->InsertPage(page, offset); cache->InsertPage(page, offset);
increment_page_wired_count(page);
vm_page_set_state(page, PAGE_STATE_WIRED); vm_page_set_state(page, PAGE_STATE_WIRED);
page->busy = false; page->busy = false;
@@ -1377,8 +1379,8 @@ vm_create_anonymous_area(team_id team, const char *name, addr_t size,
if (status < B_OK) if (status < B_OK)
panic("couldn't map physical page in page run\n"); panic("couldn't map physical page in page run\n");
increment_page_wired_count(page);
cache->InsertPage(page, offset); cache->InsertPage(page, offset);
increment_page_wired_count(page);
DEBUG_PAGE_ACCESS_END(page); DEBUG_PAGE_ACCESS_END(page);
} }
@@ -2152,14 +2154,22 @@ vm_delete_area(team_id team, area_id id, bool kernel)
/*! Creates a new cache on top of given cache, moves all areas from /*! Creates a new cache on top of given cache, moves all areas from
the old cache to the new one, and changes the protection of all affected the old cache to the new one, and changes the protection of all affected
areas' pages to read-only. areas' pages to read-only. If requested, wired pages are moved up to the
new cache and copies are added to the old cache in their place.
Preconditions: Preconditions:
- The given cache must be locked. - The given cache must be locked.
- All of the cache's areas' address spaces must be read locked. - All of the cache's areas' address spaces must be read locked.
- None of the cache's areas must have any wired ranges. - Either the cache must not have any wired ranges or a page reservation for
all wired pages must be provided, so they can be copied.
\param lowerCache The cache on top of which a new cache shall be created.
\param wiredPagesReservation If \c NULL there must not be any wired pages
in \a lowerCache. Otherwise as many pages must be reserved as the cache
has wired page. The wired pages are copied in this case.
*/ */
static status_t static status_t
vm_copy_on_write_area(VMCache* lowerCache) vm_copy_on_write_area(VMCache* lowerCache,
vm_page_reservation* wiredPagesReservation)
{ {
VMCache* upperCache; VMCache* upperCache;
@@ -2187,20 +2197,64 @@ vm_copy_on_write_area(VMCache* lowerCache)
lowerCache->AddConsumer(upperCache); lowerCache->AddConsumer(upperCache);
// We now need to remap all pages from all of the cache's areas read-only, so // We now need to remap all pages from all of the cache's areas read-only,
// that a copy will be created on next write access // so that a copy will be created on next write access. If there are wired
// pages, we keep their protection, move them to the upper cache and create
// copies for the lower cache.
if (wiredPagesReservation != NULL) {
// We need to handle wired pages -- iterate through the cache's pages.
for (VMCachePagesTree::Iterator it = lowerCache->pages.GetIterator();
vm_page* page = it.Next();) {
if (page->WiredCount() > 0) {
// allocate a new page and copy the wired one
vm_page* copiedPage = vm_page_allocate_page(
wiredPagesReservation, PAGE_STATE_ACTIVE);
for (VMArea* tempArea = upperCache->areas; tempArea != NULL; vm_memcpy_physical_page(
tempArea = tempArea->cache_next) { copiedPage->physical_page_number * B_PAGE_SIZE,
// The area must be readable in the same way it was previously writable page->physical_page_number * B_PAGE_SIZE);
uint32 protection = B_KERNEL_READ_AREA;
if ((tempArea->protection & B_READ_AREA) != 0)
protection |= B_READ_AREA;
VMTranslationMap* map = tempArea->address_space->TranslationMap(); // move the wired page to the upper cache (note: removing is OK
map->Lock(); // with the SplayTree iterator) and insert the copy
map->ProtectArea(tempArea, protection); upperCache->MovePage(page);
map->Unlock(); lowerCache->InsertPage(copiedPage,
page->cache_offset * B_PAGE_SIZE);
DEBUG_PAGE_ACCESS_END(copiedPage);
} else {
// Change the protection of this page in all areas.
for (VMArea* tempArea = upperCache->areas; tempArea != NULL;
tempArea = tempArea->cache_next) {
// The area must be readable in the same way it was
// previously writable.
uint32 protection = B_KERNEL_READ_AREA;
if ((tempArea->protection & B_READ_AREA) != 0)
protection |= B_READ_AREA;
VMTranslationMap* map
= tempArea->address_space->TranslationMap();
map->Lock();
map->ProtectPage(tempArea,
virtual_page_address(tempArea, page), protection);
map->Unlock();
}
}
}
} else {
// just change the protection of all areas
for (VMArea* tempArea = upperCache->areas; tempArea != NULL;
tempArea = tempArea->cache_next) {
// The area must be readable in the same way it was previously
// writable.
uint32 protection = B_KERNEL_READ_AREA;
if ((tempArea->protection & B_READ_AREA) != 0)
protection |= B_READ_AREA;
VMTranslationMap* map = tempArea->address_space->TranslationMap();
map->Lock();
map->ProtectArea(tempArea, protection);
map->Unlock();
}
} }
vm_area_put_locked_cache(upperCache); vm_area_put_locked_cache(upperCache);
@@ -2232,6 +2286,9 @@ vm_copy_area(team_id team, const char* name, void** _address,
status_t status; status_t status;
bool sharedArea; bool sharedArea;
page_num_t wiredPages = 0;
vm_page_reservation wiredPagesReservation;
bool restart; bool restart;
do { do {
restart = false; restart = false;
@@ -2249,22 +2306,48 @@ vm_copy_area(team_id team, const char* name, void** _address,
sharedArea = (source->protection & B_SHARED_AREA) != 0; sharedArea = (source->protection & B_SHARED_AREA) != 0;
// Make sure the source area (respectively, if not shared, all areas of page_num_t oldWiredPages = wiredPages;
// the cache) doesn't have any wired ranges. wiredPages = 0;
if (sharedArea) {
if (wait_if_area_is_wired(source, &locker, &cacheLocker)) // If the source area isn't shared, count the number of wired pages in
// the cache and reserve as many pages.
if (!sharedArea) {
wiredPages = cache->WiredPagesCount();
if (wiredPages > oldWiredPages) {
cacheLocker.Unlock();
locker.Unlock();
if (oldWiredPages > 0)
vm_page_unreserve_pages(&wiredPagesReservation);
vm_page_reserve_pages(&wiredPagesReservation, wiredPages,
VM_PRIORITY_USER);
restart = true; restart = true;
} else {
for (VMArea* area = cache->areas; area != NULL;
area = area->cache_next) {
if (wait_if_area_is_wired(area, &locker, &cacheLocker)) {
restart = true;
break;
}
} }
} } else if (oldWiredPages > 0)
vm_page_unreserve_pages(&wiredPagesReservation);
} while (restart); } while (restart);
// unreserve pages later
struct PagesUnreserver {
PagesUnreserver(vm_page_reservation* reservation)
:
fReservation(reservation)
{
}
~PagesUnreserver()
{
if (fReservation != NULL)
vm_page_unreserve_pages(fReservation);
}
private:
vm_page_reservation* fReservation;
} pagesUnreserver(wiredPages > 0 ? &wiredPagesReservation : NULL);
if (addressSpec == B_CLONE_ADDRESS) { if (addressSpec == B_CLONE_ADDRESS) {
addressSpec = B_EXACT_ADDRESS; addressSpec = B_EXACT_ADDRESS;
*_address = (void*)source->Base(); *_address = (void*)source->Base();
@@ -2296,8 +2379,10 @@ vm_copy_area(team_id team, const char* name, void** _address,
if (!sharedArea) { if (!sharedArea) {
if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) { if ((source->protection & (B_KERNEL_WRITE_AREA | B_WRITE_AREA)) != 0) {
// TODO: do something more useful if this fails! // TODO: do something more useful if this fails!
if (vm_copy_on_write_area(cache) < B_OK) if (vm_copy_on_write_area(cache,
wiredPages > 0 ? &wiredPagesReservation : NULL) < B_OK) {
panic("vm_copy_on_write_area() failed!\n"); panic("vm_copy_on_write_area() failed!\n");
}
} }
} }
@@ -2409,7 +2494,7 @@ vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
// There are consumers -- we have to insert a new cache. Fortunately // There are consumers -- we have to insert a new cache. Fortunately
// vm_copy_on_write_area() does everything that's needed. // vm_copy_on_write_area() does everything that's needed.
changePageProtection = false; changePageProtection = false;
status = vm_copy_on_write_area(cache); status = vm_copy_on_write_area(cache, NULL);
} else { } else {
// No consumers, so we don't need to insert a new one. // No consumers, so we don't need to insert a new one.
if (cache->source != NULL && cache->temporary) { if (cache->source != NULL && cache->temporary) {
@@ -2593,7 +2678,7 @@ vm_clear_page_mapping_accessed_flags(struct vm_page *page)
int32 int32
vm_remove_all_page_mappings_if_unaccessed(struct vm_page *page) vm_remove_all_page_mappings_if_unaccessed(struct vm_page *page)
{ {
ASSERT(page->wired_count == 0); ASSERT(page->WiredCount() == 0);
if (page->accessed) if (page->accessed)
return vm_clear_page_mapping_accessed_flags(page); return vm_clear_page_mapping_accessed_flags(page);
+12 -23
View File
@@ -495,7 +495,7 @@ class SetPageState : public AbstractTraceEntry {
fOldState(page->State()), fOldState(page->State()),
fNewState(newState), fNewState(newState),
fBusy(page->busy), fBusy(page->busy),
fWired(page->wired_count > 0), fWired(page->WiredCount() > 0),
fMapped(!page->mappings.IsEmpty()), fMapped(!page->mappings.IsEmpty()),
fAccessed(page->accessed), fAccessed(page->accessed),
fModified(page->modified) fModified(page->modified)
@@ -698,7 +698,7 @@ dump_page(int argc, char **argv)
kprintf("cache_offset: %" B_PRIuPHYSADDR "\n", page->cache_offset); kprintf("cache_offset: %" B_PRIuPHYSADDR "\n", page->cache_offset);
kprintf("cache_next: %p\n", page->cache_next); kprintf("cache_next: %p\n", page->cache_next);
kprintf("state: %s\n", page_state_to_string(page->State())); kprintf("state: %s\n", page_state_to_string(page->State()));
kprintf("wired_count: %d\n", page->wired_count); kprintf("wired_count: %d\n", page->WiredCount());
kprintf("usage_count: %d\n", page->usage_count); kprintf("usage_count: %d\n", page->usage_count);
kprintf("busy: %d\n", page->busy); kprintf("busy: %d\n", page->busy);
kprintf("busy_writing: %d\n", page->busy_writing); kprintf("busy_writing: %d\n", page->busy_writing);
@@ -818,7 +818,7 @@ dump_page_queue(int argc, char **argv)
for (i = 0; page; i++, page = queue->Next(page)) { for (i = 0; page; i++, page = queue->Next(page)) {
kprintf("%p %p %-7s %8s %5d %5d\n", page, page->Cache(), kprintf("%p %p %-7s %8s %5d %5d\n", page, page->Cache(),
type, page_state_to_string(page->State()), type, page_state_to_string(page->State()),
page->wired_count, page->usage_count); page->WiredCount(), page->usage_count);
} }
} }
return 0; return 0;
@@ -862,7 +862,7 @@ dump_page_stats(int argc, char **argv)
if (pageState == PAGE_STATE_MODIFIED if (pageState == PAGE_STATE_MODIFIED
&& sPages[i].Cache() != NULL && sPages[i].Cache() != NULL
&& sPages[i].Cache()->temporary && sPages[i].wired_count == 0) { && sPages[i].Cache()->temporary && sPages[i].WiredCount() == 0) {
swappableModified++; swappableModified++;
if (sPages[i].usage_count == 0) if (sPages[i].usage_count == 0)
swappableModifiedInactive++; swappableModifiedInactive++;
@@ -948,7 +948,7 @@ dump_page_stats(int argc, char **argv)
static void static void
track_page_usage(vm_page* page) track_page_usage(vm_page* page)
{ {
if (page->wired_count == 0) { if (page->WiredCount() == 0) {
sNextPageUsage[(int32)page->usage_count + 128]++; sNextPageUsage[(int32)page->usage_count + 128]++;
sNextPageUsagePageCount++; sNextPageUsagePageCount++;
} }
@@ -1981,7 +1981,7 @@ page_writer(void* /*unused*/)
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
// Don't write back wired (locked) pages. // Don't write back wired (locked) pages.
if (page->wired_count > 0) { if (page->WiredCount() > 0) {
set_page_state(page, PAGE_STATE_ACTIVE); set_page_state(page, PAGE_STATE_ACTIVE);
DEBUG_PAGE_ACCESS_END(page); DEBUG_PAGE_ACCESS_END(page);
continue; continue;
@@ -2073,7 +2073,7 @@ free_page_swap_space(int32 index)
DEBUG_PAGE_ACCESS_START(page); DEBUG_PAGE_ACCESS_START(page);
VMCache* cache = page->Cache(); VMCache* cache = page->Cache();
if (cache->temporary && page->wired_count == 0 if (cache->temporary && page->WiredCount() == 0
&& cache->HasPage(page->cache_offset << PAGE_SHIFT) && cache->HasPage(page->cache_offset << PAGE_SHIFT)
&& page->usage_count > 0) { && page->usage_count > 0) {
// TODO: how to judge a page is highly active? // TODO: how to judge a page is highly active?
@@ -2242,9 +2242,10 @@ idle_scan_active_pages(page_stats& pageStats)
// wouldn't notice when those would become unused and could thus be // wouldn't notice when those would become unused and could thus be
// moved to the cached list. // moved to the cached list.
int32 usageCount; int32 usageCount;
if (page->wired_count > 0 || page->usage_count > 0 || !cache->temporary) if (page->WiredCount() > 0 || page->usage_count > 0
|| !cache->temporary) {
usageCount = vm_clear_page_mapping_accessed_flags(page); usageCount = vm_clear_page_mapping_accessed_flags(page);
else } else
usageCount = vm_remove_all_page_mappings_if_unaccessed(page); usageCount = vm_remove_all_page_mappings_if_unaccessed(page);
if (usageCount > 0) { if (usageCount > 0) {
@@ -2333,7 +2334,7 @@ full_scan_inactive_pages(page_stats& pageStats, int32 despairLevel)
// Get the accessed count, clear the accessed/modified flags and // Get the accessed count, clear the accessed/modified flags and
// unmap the page, if it hasn't been accessed. // unmap the page, if it hasn't been accessed.
int32 usageCount; int32 usageCount;
if (page->wired_count > 0) if (page->WiredCount() > 0)
usageCount = vm_clear_page_mapping_accessed_flags(page); usageCount = vm_clear_page_mapping_accessed_flags(page);
else else
usageCount = vm_remove_all_page_mappings_if_unaccessed(page); usageCount = vm_remove_all_page_mappings_if_unaccessed(page);
@@ -2869,19 +2870,7 @@ vm_page_init(kernel_args *args)
// initialize the free page table // initialize the free page table
for (uint32 i = 0; i < sNumPages; i++) { for (uint32 i = 0; i < sNumPages; i++) {
sPages[i].physical_page_number = sPhysicalPageOffset + i; sPages[i].Init(sPhysicalPageOffset + i);
sPages[i].InitState(PAGE_STATE_FREE);
new(&sPages[i].mappings) vm_page_mappings();
sPages[i].wired_count = 0;
sPages[i].usage_count = 0;
sPages[i].busy_writing = false;
sPages[i].SetCacheRef(NULL);
#if DEBUG_PAGE_QUEUE
sPages[i].queue = NULL;
#endif
#if DEBUG_PAGE_ACCESS
sPages[i].accessing_thread = -1;
#endif
sFreePageQueue.Append(&sPages[i]); sFreePageQueue.Append(&sPages[i]);
} }