First steps towards being able of collapse vm_cache objects after forking:
* a vm_cache now maintains a list of its "consumer" caches. * introduced to new functions that add/remove consumer to a cache (instead of only maintaining the vm_cache::source field). * fixed the incorrect reference counting when doing copy-on-write; we kept one ref too many of the lower cache. * minor cleanup. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19035 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
6177d112d4
commit
d593e74a27
@ -27,6 +27,8 @@ void vm_cache_release_ref(vm_cache_ref *cache_ref);
|
||||
vm_page *vm_cache_lookup_page(vm_cache_ref *cacheRef, off_t page);
|
||||
void vm_cache_insert_page(vm_cache_ref *cacheRef, vm_page *page, off_t offset);
|
||||
void vm_cache_remove_page(vm_cache_ref *cacheRef, vm_page *page);
|
||||
void vm_cache_remove_consumer(vm_cache_ref *cacheRef, vm_cache *consumer);
|
||||
void vm_cache_add_consumer(vm_cache_ref *cacheRef, vm_cache *consumer);
|
||||
status_t vm_cache_write_modified(vm_cache_ref *ref, bool fsReenter);
|
||||
status_t vm_cache_set_minimal_commitment(vm_cache_ref *ref, off_t commitment);
|
||||
status_t vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize);
|
||||
|
@ -68,6 +68,9 @@ typedef struct vm_cache_ref {
|
||||
|
||||
// vm_cache
|
||||
typedef struct vm_cache {
|
||||
struct list_link consumer_link;
|
||||
struct list consumers;
|
||||
// list of caches that use this cache as a source
|
||||
vm_page *page_list;
|
||||
vm_cache_ref *ref;
|
||||
struct vm_cache *source;
|
||||
|
@ -552,11 +552,10 @@ map_backing_store(vm_address_space *addressSpace, vm_store *store, void **_virtu
|
||||
newCache->temporary = 1;
|
||||
newCache->scan_skip = cache->scan_skip;
|
||||
|
||||
newCache->source = cache;
|
||||
vm_cache_acquire_ref(cacheRef);
|
||||
vm_cache_add_consumer(cacheRef, newCache);
|
||||
|
||||
cache = newCache;
|
||||
cacheRef = cache->ref;
|
||||
cacheRef = newCache->ref;
|
||||
store = newStore;
|
||||
cache->virtual_size = offset + size;
|
||||
}
|
||||
@ -1479,13 +1478,12 @@ vm_copy_on_write_area(vm_area *area)
|
||||
upperCache->temporary = 1;
|
||||
upperCache->scan_skip = lowerCache->scan_skip;
|
||||
upperCache->source = lowerCache;
|
||||
list_add_item(&lowerCache->consumers, upperCache);
|
||||
upperCache->ref = upperCacheRef;
|
||||
upperCacheRef->cache = upperCache;
|
||||
|
||||
// we need to manually alter the ref_count
|
||||
// ToDo: investigate a bit deeper if this is really correct
|
||||
// (doesn't look like it, but it works)
|
||||
lowerCacheRef->ref_count = upperCacheRef->ref_count;
|
||||
// we need to manually alter the ref_count (divide it between the two)
|
||||
lowerCacheRef->ref_count = upperCacheRef->ref_count - 1;
|
||||
upperCacheRef->ref_count = 1;
|
||||
|
||||
// grab a ref to the cache object we're now linked to as a source
|
||||
|
@ -20,7 +20,8 @@
|
||||
#include <smp.h>
|
||||
#include <arch/cpu.h>
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
//#define TRACE_VM_CACHE
|
||||
#ifdef TRACE_VM_CACHE
|
||||
@ -73,11 +74,9 @@ page_hash_func(void *_p, const void *_key, uint32 range)
|
||||
|
||||
|
||||
status_t
|
||||
vm_cache_init(kernel_args *ka)
|
||||
vm_cache_init(kernel_args *args)
|
||||
{
|
||||
vm_page p;
|
||||
|
||||
page_cache_table = hash_init(PAGE_TABLE_SIZE, (int)&p.hash_next - (int)&p,
|
||||
page_cache_table = hash_init(PAGE_TABLE_SIZE, offsetof(vm_page, hash_next),
|
||||
&page_compare_func, &page_hash_func);
|
||||
if (!page_cache_table)
|
||||
panic("vm_cache_init: cannot allocate memory for page cache hash table\n");
|
||||
@ -101,6 +100,7 @@ vm_cache_create(vm_store *store)
|
||||
if (cache == NULL)
|
||||
return NULL;
|
||||
|
||||
list_init(&cache->consumers);
|
||||
cache->page_list = NULL;
|
||||
cache->ref = NULL;
|
||||
cache->source = NULL;
|
||||
@ -211,7 +211,7 @@ vm_cache_release_ref(vm_cache_ref *cache_ref)
|
||||
|
||||
// remove the ref to the source
|
||||
if (cache_ref->cache->source)
|
||||
vm_cache_release_ref(cache_ref->cache->source->ref);
|
||||
vm_cache_remove_consumer(cache_ref->cache->source->ref, cache_ref->cache);
|
||||
|
||||
mutex_destroy(&cache_ref->lock);
|
||||
free(cache_ref->cache);
|
||||
@ -391,6 +391,56 @@ vm_cache_resize(vm_cache_ref *cacheRef, off_t newSize)
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Removes the \a consumer from the \a cacheRef's cache.
|
||||
It will also release the reference to the cacheRef owned by the consumer.
|
||||
*/
|
||||
void
|
||||
vm_cache_remove_consumer(vm_cache_ref *cacheRef, vm_cache *consumer)
|
||||
{
|
||||
vm_cache *cache = cacheRef->cache;
|
||||
TRACE(("remove consumer vm cache %p from cache %p\n", consumer, cache));
|
||||
|
||||
mutex_lock(&cacheRef->lock);
|
||||
|
||||
list_remove_item(&cache->consumers, consumer);
|
||||
consumer->source = NULL;
|
||||
|
||||
if (cacheRef->areas == NULL && cache->source != NULL
|
||||
&& !list_is_empty(&cache->consumers)
|
||||
&& cache->consumers.link.next == cache->consumers.link.prev) {
|
||||
// The cache is not really needed anymore - it can be merged with its only
|
||||
// consumer left.
|
||||
// TODO!
|
||||
TRACE(("merge vm cache %p (ref == %ld) with vm cache %p\n",
|
||||
cache, cacheRef->ref_count, cache->consumers.link.next));
|
||||
}
|
||||
|
||||
mutex_unlock(&cacheRef->lock);
|
||||
vm_cache_release_ref(cacheRef);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
Marks the \a cacheRef's cache as source of the \a consumer cache,
|
||||
and adds the \a consumer to its list.
|
||||
This also grabs a reference to the source cache.
|
||||
*/
|
||||
void
|
||||
vm_cache_add_consumer(vm_cache_ref *cacheRef, vm_cache *consumer)
|
||||
{
|
||||
TRACE(("add consumer vm cache %p to cache %p\n", consumer, cacheRef->cache));
|
||||
mutex_lock(&cacheRef->lock);
|
||||
|
||||
consumer->source = cacheRef->cache;
|
||||
list_add_item(&cacheRef->cache->consumers, consumer);
|
||||
|
||||
mutex_unlock(&cacheRef->lock);
|
||||
|
||||
vm_cache_acquire_ref(cacheRef);
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
vm_cache_insert_area(vm_cache_ref *cache_ref, vm_area *area)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user