mmlr (distracted) + bonefish:
* Turn VMCache::consumers C list into a DoublyLinkedList. * Use object caches for the different VMCache types and the VMCacheRefs. The purpose is to reduce slab area fragmentation. * Requires the introduction of a pure virtual VMCache::DeleteObject() method, implemented in the derived classes. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@43133 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <util/list.h>
|
#include <util/DoublyLinkedList.h>
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <vm/vm_types.h>
|
#include <vm/vm_types.h>
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
|
|
||||||
struct kernel_args;
|
struct kernel_args;
|
||||||
|
class ObjectCache;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -34,6 +35,14 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern ObjectCache* gCacheRefObjectCache;
|
||||||
|
extern ObjectCache* gAnonymousCacheObjectCache;
|
||||||
|
extern ObjectCache* gAnonymousNoSwapCacheObjectCache;
|
||||||
|
extern ObjectCache* gVnodeCacheObjectCache;
|
||||||
|
extern ObjectCache* gDeviceCacheObjectCache;
|
||||||
|
extern ObjectCache* gNullCacheObjectCache;
|
||||||
|
|
||||||
|
|
||||||
struct VMCachePagesTreeDefinition {
|
struct VMCachePagesTreeDefinition {
|
||||||
typedef page_num_t KeyType;
|
typedef page_num_t KeyType;
|
||||||
typedef vm_page NodeType;
|
typedef vm_page NodeType;
|
||||||
@@ -63,7 +72,10 @@ struct VMCachePagesTreeDefinition {
|
|||||||
typedef IteratableSplayTree<VMCachePagesTreeDefinition> VMCachePagesTree;
|
typedef IteratableSplayTree<VMCachePagesTreeDefinition> VMCachePagesTree;
|
||||||
|
|
||||||
|
|
||||||
struct VMCache {
|
struct VMCache : public DoublyLinkedListLinkImpl<VMCache> {
|
||||||
|
public:
|
||||||
|
typedef DoublyLinkedList<VMCache> ConsumerList;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VMCache();
|
VMCache();
|
||||||
virtual ~VMCache();
|
virtual ~VMCache();
|
||||||
@@ -163,10 +175,12 @@ public:
|
|||||||
|
|
||||||
virtual void Dump(bool showPages) const;
|
virtual void Dump(bool showPages) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DeleteObject() = 0;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VMArea* areas;
|
VMArea* areas;
|
||||||
list_link consumer_link;
|
ConsumerList consumers;
|
||||||
list consumers;
|
|
||||||
// list of caches that use this cache as a source
|
// list of caches that use this cache as a source
|
||||||
VMCachePagesTree pages;
|
VMCachePagesTree pages;
|
||||||
VMCache* source;
|
VMCache* source;
|
||||||
|
|||||||
+1
-1
@@ -290,7 +290,7 @@ reserve_pages(file_cache_ref* ref, vm_page_reservation* reservation,
|
|||||||
VMCache* cache = ref->cache;
|
VMCache* cache = ref->cache;
|
||||||
cache->Lock();
|
cache->Lock();
|
||||||
|
|
||||||
if (list_is_empty(&cache->consumers) && cache->areas == NULL
|
if (cache->consumers.IsEmpty() && cache->areas == NULL
|
||||||
&& access_is_sequential(ref)) {
|
&& access_is_sequential(ref)) {
|
||||||
// we are not mapped, and we're accessed sequentially
|
// we are not mapped, and we're accessed sequentially
|
||||||
|
|
||||||
|
|||||||
+9
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <file_cache.h>
|
#include <file_cache.h>
|
||||||
|
#include <slab/Slab.h>
|
||||||
#include <vfs.h>
|
#include <vfs.h>
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
|
|
||||||
@@ -164,3 +165,10 @@ VMVnodeCache::Dump(bool showPages) const
|
|||||||
kprintf(" vnode: %p <%" B_PRIdDEV ", %" B_PRIdINO ">\n", fVnode,
|
kprintf(" vnode: %p <%" B_PRIdDEV ", %" B_PRIdINO ">\n", fVnode,
|
||||||
fDevice, fInode);
|
fDevice, fInode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMVnodeCache::DeleteObject()
|
||||||
|
{
|
||||||
|
object_cache_delete(gVnodeCacheObjectCache, this);
|
||||||
|
}
|
||||||
|
|||||||
+4
-1
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -48,6 +48,9 @@ public:
|
|||||||
|
|
||||||
void VnodeDeleted() { fVnodeDeleted = true; }
|
void VnodeDeleted() { fVnodeDeleted = true; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DeleteObject();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct vnode* fVnode;
|
struct vnode* fVnode;
|
||||||
file_cache_ref* fFileCacheRef;
|
file_cache_ref* fFileCacheRef;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Zhao Shuai, upczhsh@163.com.
|
* Copyright 2008, Zhao Shuai, upczhsh@163.com.
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -846,6 +846,13 @@ VMAnonymousCache::Merge(VMCache* _source)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMAnonymousCache::DeleteObject()
|
||||||
|
{
|
||||||
|
object_cache_delete(gAnonymousCacheObjectCache, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
VMAnonymousCache::_SwapBlockBuild(off_t startPageIndex,
|
VMAnonymousCache::_SwapBlockBuild(off_t startPageIndex,
|
||||||
swap_addr_t startSlotIndex, uint32 count)
|
swap_addr_t startSlotIndex, uint32 count)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -64,6 +64,9 @@ public:
|
|||||||
|
|
||||||
virtual void Merge(VMCache* source);
|
virtual void Merge(VMCache* source);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DeleteObject();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class WriteCallback;
|
class WriteCallback;
|
||||||
friend class WriteCallback;
|
friend class WriteCallback;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
#include <arch_config.h>
|
#include <arch_config.h>
|
||||||
#include <heap.h>
|
#include <heap.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
#include <slab/Slab.h>
|
||||||
#include <vm/vm_priv.h>
|
#include <vm/vm_priv.h>
|
||||||
#include <vm/VMAddressSpace.h>
|
#include <vm/VMAddressSpace.h>
|
||||||
|
|
||||||
@@ -183,3 +184,10 @@ VMAnonymousNoSwapCache::MergeStore(VMCache* _source)
|
|||||||
committed_size = actualSize;
|
committed_size = actualSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMAnonymousNoSwapCache::DeleteObject()
|
||||||
|
{
|
||||||
|
object_cache_delete(gAnonymousNoSwapCacheObjectCache, this);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -37,6 +37,9 @@ public:
|
|||||||
|
|
||||||
virtual void MergeStore(VMCache* source);
|
virtual void MergeStore(VMCache* source);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DeleteObject();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool fCanOvercommit;
|
bool fCanOvercommit;
|
||||||
bool fHasPrecommitted;
|
bool fHasPrecommitted;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <heap.h>
|
#include <heap.h>
|
||||||
#include <int.h>
|
#include <int.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
|
#include <slab/Slab.h>
|
||||||
#include <smp.h>
|
#include <smp.h>
|
||||||
#include <tracing.h>
|
#include <tracing.h>
|
||||||
#include <util/khash.h>
|
#include <util/khash.h>
|
||||||
@@ -32,6 +33,13 @@
|
|||||||
#include <vm/VMAddressSpace.h>
|
#include <vm/VMAddressSpace.h>
|
||||||
#include <vm/VMArea.h>
|
#include <vm/VMArea.h>
|
||||||
|
|
||||||
|
// needed for the factory only
|
||||||
|
#include "VMAnonymousCache.h"
|
||||||
|
#include "VMAnonymousNoSwapCache.h"
|
||||||
|
#include "VMDeviceCache.h"
|
||||||
|
#include "VMNullCache.h"
|
||||||
|
#include "../cache/vnode_store.h"
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_VM_CACHE
|
//#define TRACE_VM_CACHE
|
||||||
#ifdef TRACE_VM_CACHE
|
#ifdef TRACE_VM_CACHE
|
||||||
@@ -47,6 +55,13 @@ VMCache* gDebugCacheList;
|
|||||||
static mutex sCacheListLock = MUTEX_INITIALIZER("global VMCache list");
|
static mutex sCacheListLock = MUTEX_INITIALIZER("global VMCache list");
|
||||||
// The lock is also needed when the debug feature is disabled.
|
// The lock is also needed when the debug feature is disabled.
|
||||||
|
|
||||||
|
ObjectCache* gCacheRefObjectCache;
|
||||||
|
ObjectCache* gAnonymousCacheObjectCache;
|
||||||
|
ObjectCache* gAnonymousNoSwapCacheObjectCache;
|
||||||
|
ObjectCache* gVnodeCacheObjectCache;
|
||||||
|
ObjectCache* gDeviceCacheObjectCache;
|
||||||
|
ObjectCache* gNullCacheObjectCache;
|
||||||
|
|
||||||
|
|
||||||
struct VMCache::PageEventWaiter {
|
struct VMCache::PageEventWaiter {
|
||||||
Thread* thread;
|
Thread* thread;
|
||||||
@@ -465,6 +480,30 @@ command_cache_stack(int argc, char** argv)
|
|||||||
status_t
|
status_t
|
||||||
vm_cache_init(kernel_args* args)
|
vm_cache_init(kernel_args* args)
|
||||||
{
|
{
|
||||||
|
// Create object caches for the structures we allocate here.
|
||||||
|
gCacheRefObjectCache = create_object_cache("cache refs", sizeof(VMCacheRef),
|
||||||
|
0, NULL, NULL, NULL);
|
||||||
|
gAnonymousCacheObjectCache = create_object_cache("anon caches",
|
||||||
|
sizeof(VMAnonymousCache), 0, NULL, NULL, NULL);
|
||||||
|
gAnonymousNoSwapCacheObjectCache = create_object_cache(
|
||||||
|
"anon no-swap caches", sizeof(VMAnonymousNoSwapCache), 0, NULL, NULL,
|
||||||
|
NULL);
|
||||||
|
gVnodeCacheObjectCache = create_object_cache("vnode caches",
|
||||||
|
sizeof(VMVnodeCache), 0, NULL, NULL, NULL);
|
||||||
|
gDeviceCacheObjectCache = create_object_cache("device caches",
|
||||||
|
sizeof(VMDeviceCache), 0, NULL, NULL, NULL);
|
||||||
|
gNullCacheObjectCache = create_object_cache("null caches",
|
||||||
|
sizeof(VMNullCache), 0, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
if (gCacheRefObjectCache == NULL || gAnonymousCacheObjectCache == NULL
|
||||||
|
|| gAnonymousNoSwapCacheObjectCache == NULL
|
||||||
|
|| gVnodeCacheObjectCache == NULL
|
||||||
|
|| gDeviceCacheObjectCache == NULL
|
||||||
|
|| gNullCacheObjectCache == NULL) {
|
||||||
|
panic("vm_cache_init(): Failed to create object caches!");
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,9 +597,8 @@ VMCacheRef::VMCacheRef(VMCache* cache)
|
|||||||
bool
|
bool
|
||||||
VMCache::_IsMergeable() const
|
VMCache::_IsMergeable() const
|
||||||
{
|
{
|
||||||
return (areas == NULL && temporary
|
return areas == NULL && temporary && !consumers.IsEmpty()
|
||||||
&& !list_is_empty(const_cast<list*>(&consumers))
|
&& consumers.Head() == consumers.Tail();
|
||||||
&& consumers.link.next == consumers.link.prev);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -573,7 +611,7 @@ VMCache::VMCache()
|
|||||||
|
|
||||||
VMCache::~VMCache()
|
VMCache::~VMCache()
|
||||||
{
|
{
|
||||||
delete fCacheRef;
|
object_cache_delete(gCacheRefObjectCache, fCacheRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -582,10 +620,6 @@ VMCache::Init(uint32 cacheType, uint32 allocationFlags)
|
|||||||
{
|
{
|
||||||
mutex_init(&fLock, "VMCache");
|
mutex_init(&fLock, "VMCache");
|
||||||
|
|
||||||
VMCache dummyCache;
|
|
||||||
list_init_etc(&consumers, offset_of_member(dummyCache, consumer_link));
|
|
||||||
// TODO: This is disgusting! Use DoublyLinkedList!
|
|
||||||
|
|
||||||
areas = NULL;
|
areas = NULL;
|
||||||
fRefCount = 1;
|
fRefCount = 1;
|
||||||
source = NULL;
|
source = NULL;
|
||||||
@@ -604,7 +638,7 @@ VMCache::Init(uint32 cacheType, uint32 allocationFlags)
|
|||||||
// initialize in case the following fails
|
// initialize in case the following fails
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fCacheRef = new(malloc_flags(allocationFlags)) VMCacheRef(this);
|
fCacheRef = new(gCacheRefObjectCache, allocationFlags) VMCacheRef(this);
|
||||||
if (fCacheRef == NULL)
|
if (fCacheRef == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -628,7 +662,7 @@ VMCache::Delete()
|
|||||||
{
|
{
|
||||||
if (areas != NULL)
|
if (areas != NULL)
|
||||||
panic("cache %p to be deleted still has areas", this);
|
panic("cache %p to be deleted still has areas", this);
|
||||||
if (!list_is_empty(&consumers))
|
if (!consumers.IsEmpty())
|
||||||
panic("cache %p to be deleted still has consumers", this);
|
panic("cache %p to be deleted still has consumers", this);
|
||||||
|
|
||||||
T(Delete(this));
|
T(Delete(this));
|
||||||
@@ -672,7 +706,7 @@ VMCache::Delete()
|
|||||||
|
|
||||||
mutex_unlock(&sCacheListLock);
|
mutex_unlock(&sCacheListLock);
|
||||||
|
|
||||||
delete this;
|
DeleteObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -680,7 +714,7 @@ void
|
|||||||
VMCache::Unlock(bool consumerLocked)
|
VMCache::Unlock(bool consumerLocked)
|
||||||
{
|
{
|
||||||
while (fRefCount == 1 && _IsMergeable()) {
|
while (fRefCount == 1 && _IsMergeable()) {
|
||||||
VMCache* consumer = (VMCache*)list_get_first_item(&consumers);
|
VMCache* consumer = consumers.Head();
|
||||||
if (consumerLocked) {
|
if (consumerLocked) {
|
||||||
_MergeWithOnlyConsumer();
|
_MergeWithOnlyConsumer();
|
||||||
} else if (consumer->TryLock()) {
|
} else if (consumer->TryLock()) {
|
||||||
@@ -698,7 +732,7 @@ VMCache::Unlock(bool consumerLocked)
|
|||||||
|
|
||||||
if (consumerLockedTemp) {
|
if (consumerLockedTemp) {
|
||||||
if (fRefCount == 1 && _IsMergeable()
|
if (fRefCount == 1 && _IsMergeable()
|
||||||
&& consumer == list_get_first_item(&consumers)) {
|
&& consumer == consumers.Head()) {
|
||||||
// nothing has changed in the meantime -- merge
|
// nothing has changed in the meantime -- merge
|
||||||
_MergeWithOnlyConsumer();
|
_MergeWithOnlyConsumer();
|
||||||
}
|
}
|
||||||
@@ -901,7 +935,7 @@ VMCache::AddConsumer(VMCache* consumer)
|
|||||||
T(AddConsumer(this, consumer));
|
T(AddConsumer(this, consumer));
|
||||||
|
|
||||||
consumer->source = this;
|
consumer->source = this;
|
||||||
list_add_item(&consumers, consumer);
|
consumers.Add(consumer);
|
||||||
|
|
||||||
AcquireRefLocked();
|
AcquireRefLocked();
|
||||||
AcquireStoreRef();
|
AcquireStoreRef();
|
||||||
@@ -1312,9 +1346,8 @@ VMCache::Dump(bool showPages) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
kprintf(" consumers:\n");
|
kprintf(" consumers:\n");
|
||||||
VMCache* consumer = NULL;
|
for (ConsumerList::ConstIterator it = consumers.GetIterator();
|
||||||
while ((consumer = (VMCache*)list_get_next_item((list*)&consumers,
|
VMCache* consumer = it.Next();) {
|
||||||
consumer)) != NULL) {
|
|
||||||
kprintf("\t%p\n", consumer);
|
kprintf("\t%p\n", consumer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1365,7 +1398,7 @@ VMCache::_NotifyPageEvents(vm_page* page, uint32 events)
|
|||||||
void
|
void
|
||||||
VMCache::_MergeWithOnlyConsumer()
|
VMCache::_MergeWithOnlyConsumer()
|
||||||
{
|
{
|
||||||
VMCache* consumer = (VMCache*)list_remove_head_item(&consumers);
|
VMCache* consumer = consumers.RemoveHead();
|
||||||
|
|
||||||
TRACE(("merge vm cache %p (ref == %ld) with vm cache %p\n",
|
TRACE(("merge vm cache %p (ref == %ld) with vm cache %p\n",
|
||||||
this, this->fRefCount, consumer));
|
this, this->fRefCount, consumer));
|
||||||
@@ -1381,8 +1414,8 @@ VMCache::_MergeWithOnlyConsumer()
|
|||||||
|
|
||||||
newSource->Lock();
|
newSource->Lock();
|
||||||
|
|
||||||
list_remove_item(&newSource->consumers, this);
|
newSource->consumers.Remove(this);
|
||||||
list_add_item(&newSource->consumers, consumer);
|
newSource->consumers.Add(consumer);
|
||||||
consumer->source = newSource;
|
consumer->source = newSource;
|
||||||
source = NULL;
|
source = NULL;
|
||||||
|
|
||||||
@@ -1416,7 +1449,7 @@ VMCache::_RemoveConsumer(VMCache* consumer)
|
|||||||
|
|
||||||
// remove the consumer from the cache, but keep its reference until later
|
// remove the consumer from the cache, but keep its reference until later
|
||||||
Lock();
|
Lock();
|
||||||
list_remove_item(&consumers, consumer);
|
consumers.Remove(consumer);
|
||||||
consumer->source = NULL;
|
consumer->source = NULL;
|
||||||
|
|
||||||
ReleaseRefAndUnlock();
|
ReleaseRefAndUnlock();
|
||||||
@@ -1427,15 +1460,6 @@ VMCache::_RemoveConsumer(VMCache* consumer)
|
|||||||
// TODO: Move to own source file!
|
// TODO: Move to own source file!
|
||||||
|
|
||||||
|
|
||||||
#include <heap.h>
|
|
||||||
|
|
||||||
#include "VMAnonymousCache.h"
|
|
||||||
#include "VMAnonymousNoSwapCache.h"
|
|
||||||
#include "VMDeviceCache.h"
|
|
||||||
#include "VMNullCache.h"
|
|
||||||
#include "../cache/vnode_store.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*static*/ status_t
|
/*static*/ status_t
|
||||||
VMCacheFactory::CreateAnonymousCache(VMCache*& _cache, bool canOvercommit,
|
VMCacheFactory::CreateAnonymousCache(VMCache*& _cache, bool canOvercommit,
|
||||||
int32 numPrecommittedPages, int32 numGuardPages, bool swappable,
|
int32 numPrecommittedPages, int32 numGuardPages, bool swappable,
|
||||||
@@ -1449,7 +1473,7 @@ VMCacheFactory::CreateAnonymousCache(VMCache*& _cache, bool canOvercommit,
|
|||||||
#if ENABLE_SWAP_SUPPORT
|
#if ENABLE_SWAP_SUPPORT
|
||||||
if (swappable) {
|
if (swappable) {
|
||||||
VMAnonymousCache* cache
|
VMAnonymousCache* cache
|
||||||
= new(malloc_flags(allocationFlags)) VMAnonymousCache;
|
= new(gAnonymousCacheObjectCache, allocationFlags) VMAnonymousCache;
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -1468,7 +1492,8 @@ VMCacheFactory::CreateAnonymousCache(VMCache*& _cache, bool canOvercommit,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
VMAnonymousNoSwapCache* cache
|
VMAnonymousNoSwapCache* cache
|
||||||
= new(malloc_flags(allocationFlags)) VMAnonymousNoSwapCache;
|
= new(gAnonymousNoSwapCacheObjectCache, allocationFlags)
|
||||||
|
VMAnonymousNoSwapCache;
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -1493,7 +1518,8 @@ VMCacheFactory::CreateVnodeCache(VMCache*& _cache, struct vnode* vnode)
|
|||||||
| HEAP_DONT_LOCK_KERNEL_SPACE;
|
| HEAP_DONT_LOCK_KERNEL_SPACE;
|
||||||
// Note: Vnode cache creation is never VIP.
|
// Note: Vnode cache creation is never VIP.
|
||||||
|
|
||||||
VMVnodeCache* cache = new(malloc_flags(allocationFlags)) VMVnodeCache;
|
VMVnodeCache* cache
|
||||||
|
= new(gVnodeCacheObjectCache, allocationFlags) VMVnodeCache;
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -1517,7 +1543,8 @@ VMCacheFactory::CreateDeviceCache(VMCache*& _cache, addr_t baseAddress)
|
|||||||
| HEAP_DONT_LOCK_KERNEL_SPACE;
|
| HEAP_DONT_LOCK_KERNEL_SPACE;
|
||||||
// Note: Device cache creation is never VIP.
|
// Note: Device cache creation is never VIP.
|
||||||
|
|
||||||
VMDeviceCache* cache = new(malloc_flags(allocationFlags)) VMDeviceCache;
|
VMDeviceCache* cache
|
||||||
|
= new(gDeviceCacheObjectCache, allocationFlags) VMDeviceCache;
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
@@ -1542,7 +1569,8 @@ VMCacheFactory::CreateNullCache(int priority, VMCache*& _cache)
|
|||||||
if (priority >= VM_PRIORITY_VIP)
|
if (priority >= VM_PRIORITY_VIP)
|
||||||
allocationFlags |= HEAP_PRIORITY_VIP;
|
allocationFlags |= HEAP_PRIORITY_VIP;
|
||||||
|
|
||||||
VMNullCache* cache = new(malloc_flags(allocationFlags)) VMNullCache;
|
VMNullCache* cache
|
||||||
|
= new(gNullCacheObjectCache, allocationFlags) VMNullCache;
|
||||||
if (cache == NULL)
|
if (cache == NULL)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include "VMDeviceCache.h"
|
#include "VMDeviceCache.h"
|
||||||
|
|
||||||
|
#include <slab/Slab.h>
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
VMDeviceCache::Init(addr_t baseAddress, uint32 allocationFlags)
|
VMDeviceCache::Init(addr_t baseAddress, uint32 allocationFlags)
|
||||||
@@ -34,3 +36,10 @@ VMDeviceCache::Write(off_t offset, const iovec* vecs, size_t count,
|
|||||||
// no place to write, this will cause the page daemon to skip this store
|
// no place to write, this will cause the page daemon to skip this store
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMDeviceCache::DeleteObject()
|
||||||
|
{
|
||||||
|
object_cache_delete(gDeviceCacheObjectCache, this);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -25,6 +25,9 @@ public:
|
|||||||
size_t count, uint32 flags,
|
size_t count, uint32 flags,
|
||||||
size_t* _numBytes);
|
size_t* _numBytes);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DeleteObject();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
addr_t fBaseAddress;
|
addr_t fBaseAddress;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,14 +1,24 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "VMNullCache.h"
|
#include "VMNullCache.h"
|
||||||
|
|
||||||
|
#include <slab/Slab.h>
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
VMNullCache::Init(uint32 allocationFlags)
|
VMNullCache::Init(uint32 allocationFlags)
|
||||||
{
|
{
|
||||||
return VMCache::Init(CACHE_TYPE_NULL, allocationFlags);
|
return VMCache::Init(CACHE_TYPE_NULL, allocationFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
VMNullCache::DeleteObject()
|
||||||
|
{
|
||||||
|
object_cache_delete(gNullCacheObjectCache, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2010, Ingo Weinhold, ingo_weinhold@gmx.de.
|
* Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
||||||
* Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
|
* Copyright 2005-2007, Axel Dörfler, axeld@pinc-software.de.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*
|
*
|
||||||
@@ -16,6 +16,9 @@
|
|||||||
class VMNullCache : public VMCache {
|
class VMNullCache : public VMCache {
|
||||||
public:
|
public:
|
||||||
status_t Init(uint32 allocationFlags);
|
status_t Init(uint32 allocationFlags);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void DeleteObject();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+10
-13
@@ -618,7 +618,7 @@ cut_area(VMAddressSpace* addressSpace, VMArea* area, addr_t address,
|
|||||||
|
|
||||||
// If no one else uses the area's cache, we can resize it, too.
|
// If no one else uses the area's cache, we can resize it, too.
|
||||||
if (cache->areas == area && area->cache_next == NULL
|
if (cache->areas == area && area->cache_next == NULL
|
||||||
&& list_is_empty(&cache->consumers)
|
&& cache->consumers.IsEmpty()
|
||||||
&& cache->type == CACHE_TYPE_RAM) {
|
&& cache->type == CACHE_TYPE_RAM) {
|
||||||
// Since VMCache::Resize() can temporarily drop the lock, we must
|
// Since VMCache::Resize() can temporarily drop the lock, we must
|
||||||
// unlock all lower caches to prevent locking order inversion.
|
// unlock all lower caches to prevent locking order inversion.
|
||||||
@@ -2442,7 +2442,7 @@ vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
|
|||||||
// Make sure the area (respectively, if we're going to call
|
// Make sure the area (respectively, if we're going to call
|
||||||
// vm_copy_on_write_area(), all areas of the cache) doesn't have any
|
// vm_copy_on_write_area(), all areas of the cache) doesn't have any
|
||||||
// wired ranges.
|
// wired ranges.
|
||||||
if (!isWritable && becomesWritable && !list_is_empty(&cache->consumers)) {
|
if (!isWritable && becomesWritable && !cache->consumers.IsEmpty()) {
|
||||||
for (VMArea* otherArea = cache->areas; otherArea != NULL;
|
for (VMArea* otherArea = cache->areas; otherArea != NULL;
|
||||||
otherArea = otherArea->cache_next) {
|
otherArea = otherArea->cache_next) {
|
||||||
if (wait_if_area_is_wired(otherArea, &locker, &cacheLocker)) {
|
if (wait_if_area_is_wired(otherArea, &locker, &cacheLocker)) {
|
||||||
@@ -2490,7 +2490,7 @@ vm_set_area_protection(team_id team, area_id areaID, uint32 newProtection,
|
|||||||
} else if (!isWritable && becomesWritable) {
|
} else if (!isWritable && becomesWritable) {
|
||||||
// !writable -> writable
|
// !writable -> writable
|
||||||
|
|
||||||
if (!list_is_empty(&cache->consumers)) {
|
if (!cache->consumers.IsEmpty()) {
|
||||||
// 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;
|
||||||
@@ -2885,9 +2885,8 @@ dump_cache_tree_recursively(VMCache* cache, int level,
|
|||||||
kprintf("%p\n", cache);
|
kprintf("%p\n", cache);
|
||||||
|
|
||||||
// recursively print its consumers
|
// recursively print its consumers
|
||||||
VMCache* consumer = NULL;
|
for (VMCache::ConsumerList::Iterator it = cache->consumers.GetIterator();
|
||||||
while ((consumer = (VMCache*)list_get_next_item(&cache->consumers,
|
VMCache* consumer = it.Next();) {
|
||||||
consumer)) != NULL) {
|
|
||||||
dump_cache_tree_recursively(consumer, level + 1, highlightCache);
|
dump_cache_tree_recursively(consumer, level + 1, highlightCache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2947,9 +2946,8 @@ update_cache_info_recursively(VMCache* cache, cache_info& info)
|
|||||||
info.committed += cache->committed_size;
|
info.committed += cache->committed_size;
|
||||||
|
|
||||||
// recurse
|
// recurse
|
||||||
VMCache* consumer = NULL;
|
for (VMCache::ConsumerList::Iterator it = cache->consumers.GetIterator();
|
||||||
while ((consumer = (VMCache*)list_get_next_item(&cache->consumers,
|
VMCache* consumer = it.Next();) {
|
||||||
consumer)) != NULL) {
|
|
||||||
update_cache_info_recursively(consumer, info);
|
update_cache_info_recursively(consumer, info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3012,9 +3010,8 @@ dump_caches_recursively(VMCache* cache, cache_info& info, int level)
|
|||||||
kputs("\n");
|
kputs("\n");
|
||||||
|
|
||||||
// recurse
|
// recurse
|
||||||
VMCache* consumer = NULL;
|
for (VMCache::ConsumerList::Iterator it = cache->consumers.GetIterator();
|
||||||
while ((consumer = (VMCache*)list_get_next_item(&cache->consumers,
|
VMCache* consumer = it.Next();) {
|
||||||
consumer)) != NULL) {
|
|
||||||
dump_caches_recursively(consumer, info, level + 1);
|
dump_caches_recursively(consumer, info, level + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3687,7 +3684,7 @@ vm_init(kernel_args* args)
|
|||||||
// initialize the free page list and physical page mapper
|
// initialize the free page list and physical page mapper
|
||||||
vm_page_init(args);
|
vm_page_init(args);
|
||||||
|
|
||||||
// initialize the hash table that stores the pages mapped to caches
|
// initialize the cache allocators
|
||||||
vm_cache_init(args);
|
vm_cache_init(args);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user