Files
haiku-beta6/src/kernel/vm2/cacheManager.C
T

79 lines
2.8 KiB
C++
Raw Normal View History

#include <new.h>
#include <cacheManager.h>
#include <vpagePool.h>
#include "vmHeaderBlock.h"
2002-11-19 04:05:16 +00:00
ulong vnodeHash (node &vp) {vnode &vn=reinterpret_cast <vnode &>(vp); return vn.offset+vn.fd;}
bool vnodeisEqual (node &vp,node &vp2) {
vnode &vn=reinterpret_cast <vnode &>(vp);
vnode &vn2=reinterpret_cast <vnode &>(vp2);
return vn.fd==vn2.fd && vn.offset==vn2.offset;
}
2002-09-14 17:03:16 +00:00
extern vmHeaderBlock *vmBlock;
// TODO - we need to (somehow) make sure that the same vnodes here are shared with mmap.
// Maybe a vnode manager...
2002-11-19 04:05:16 +00:00
cacheManager::cacheManager(void) : area (),cacheMembers(30) {
myLock=create_sem(1,"Cache Manager Semaphore");
2002-11-19 04:05:16 +00:00
cacheMembers.setHash(vnodeHash);
cacheMembers.setIsEqual(vnodeisEqual);
}
2002-11-19 04:05:16 +00:00
void *cacheManager::findBlock(vnode *target,bool readOnly) {
cacheMember *candidate=reinterpret_cast<cacheMember *>(cacheMembers.find(target));
if (!candidate || readOnly || candidate->vp->getProtection()>=writable)
return candidate;
// At this point, we have the first one in the hahs bucket. Loop over the hash bucket from now on,
// looking for an equality and writability match...
for (struct cacheMember *cur=candidate;cur;cur=reinterpret_cast<cacheMember *>(cur->next)) {
if ((target==cur->vn) && (readOnly || (cur->vp->getProtection()>=writable)))
return (cur->vp->getStartAddress());
}
2002-11-19 04:05:16 +00:00
// We didn't find one, but to get here, there has to be one that is READ ONLY. So let's make a copy
// of that one, but readable...
return createBlock(target,false);
}
2002-11-19 04:05:16 +00:00
void *cacheManager::createBlock(vnode *target,bool readOnly, cacheMember *candidate) {
bool foundSpot=false;
vpage *prev=NULL,*cur=NULL;
unsigned long begin=CACHE_BEGIN;
2002-09-14 17:03:16 +00:00
// Find a place in the cache's virtual space to put this vnode...
2002-11-19 04:05:16 +00:00
if (vpages.rock)
for (cur=(reinterpret_cast <vpage *>(vpages.rock));!foundSpot && cur;cur=reinterpret_cast <vpage *>(cur->next))
if (cur->getStartAddress()!=(void *)begin)
foundSpot=true;
2002-11-19 04:05:16 +00:00
else { // no joy
begin+=PAGE_SIZE;
prev=cur;
}
lock();
// Create a vnode here
vpage *newPage = new (vmBlock->vpagePool->get()) vpage;
newPage->setup(begin,target,NULL,((readOnly)?readable:writable),NO_LOCK);
vpages.add(newPage);
cacheMembers.add(newPage);
2002-11-19 04:05:16 +00:00
// While this may not seem like a good idea (since this only happens on a write),
// it is because someone may only write to part of the file/page...
if (candidate)
memcpy(newPage->getStartAddress(),candidate->vp->getStartAddress(),PAGE_SIZE);
unlock();
// return address from this vnode
return (void *)begin;
}
2002-11-19 04:05:16 +00:00
void *cacheManager::readBlock(vnode *target) {
void *destination=findBlock(target,true);
if (destination) return destination;
return createBlock(target,true);
}
2002-11-19 04:05:16 +00:00
void *cacheManager::writeBlock(vnode *target) {
void *destination=findBlock(target,false);
if (destination) return destination;
return createBlock(target,false);
}