Files
beaglefw/pagecache.cc
Matthias Blankertz 76cc09a168 - WIP: OMAP35x SD/MMC controller driver
- WIP: Pagecache
- Added sleep() and usleep() functions
2013-07-19 19:51:40 +02:00

167 lines
3.6 KiB
C++

#include <cassert>
#include <cstdio>
#include "mm.hh"
#include "phys_mm.hh"
#include "pagecache.hh"
PageCache::PageCache(int maxPages) : maxPages_(maxPages), curPages_(0) {
}
PageCache::~PageCache() {
for(auto& devEntry : allocs_) { // For each known device
for(auto& allocEntry : devEntry.second) {
freeAlloc(allocEntry);
}
}
}
PageCache::Handle PageCache::readAllocate(IBlockDevice& dev, unsigned pos, unsigned count) {
ScopedLock<Mutex> lock(mutex_);
_allocInfo *alloc = searchAlloc(&dev, pos, count);
if(!alloc) {
_allocInfo newAlloc;
buildAlloc(newAlloc, count);
newAlloc.dev = &dev;
newAlloc.start = pos;
try {
dev.read(newAlloc.start, newAlloc.virtMem, newAlloc.len);
allocs_[&dev].push_back(newAlloc);
alloc = &allocs_[&dev].back();
} catch(...) {
freeAlloc(newAlloc);
throw;
}
curPages_ += count;
}
return Handle(alloc, (pos - alloc->start));
}
PageCache::Handle PageCache::writeAllocate(IBlockDevice& dev, unsigned pos, unsigned count) {
ScopedLock<Mutex> lock(mutex_);
_allocInfo *alloc = searchAlloc(&dev, pos, count);
if(!alloc) {
_allocInfo newAlloc;
buildAlloc(newAlloc, count);
newAlloc.dev = &dev;
newAlloc.start = pos;
try {
allocs_[&dev].push_back(newAlloc);
alloc = &allocs_[&dev].back();
} catch(...) {
freeAlloc(newAlloc);
throw;
}
curPages_ += count;
}
return Handle(alloc, (pos - alloc->start));
}
void PageCache::eject(int lengthHint) {
ScopedLock<Mutex> lock(mutex_);
_eject(lengthHint);
}
void PageCache::freeAlloc(_allocInfo& alloc) {
assert(!alloc.refs);
if(alloc.dirty && alloc.dev)
alloc.dev->write(alloc.start, alloc.virtMem, alloc.len);
if(alloc.virtMem) {
cortexa8::unmap_pages((uintptr_t)alloc.virtMem, alloc.len);
mm::virtfree_pc((uintptr_t)alloc.virtMem);
}
if(alloc.physMem)
phys_mm::free(alloc.physMem);
}
void PageCache::buildAlloc(_allocInfo& alloc, unsigned len) {
if((maxPages_ > 0) && (curPages_ + len > (unsigned)maxPages_)) {
_eject(curPages_+len-maxPages_);
if(curPages_ + len > (unsigned)maxPages_)
throw ex::bad_alloc{};
}
alloc.dirty = false;
alloc.len = len;
alloc.dev = nullptr;
alloc.physMem = 0;
alloc.virtMem = nullptr;
alloc.refs = 0;
bool retry = true;
while(true) {
try {
if(!alloc.physMem)
alloc.physMem = phys_mm::alloc(len);
if(!alloc.virtMem)
alloc.virtMem = (char*)mm::virtalloc_pc(len);
cortexa8::map_pages((uintptr_t)alloc.virtMem, alloc.physMem, len);
break;
} catch(ex::bad_alloc &ex) {
if(retry) {
_eject(len);
retry = false;
} else {
freeAlloc(alloc);
throw;
}
}
}
}
PageCache::_allocInfo* PageCache::searchAlloc(IBlockDevice* dev, unsigned start, unsigned len) {
auto it = allocs_.find(dev);
if(it == allocs_.end())
return nullptr;
for(auto& allocEntry : it->second) {
if((allocEntry.start <= start) &&
((allocEntry.start + allocEntry.len) >= (start + len)))
return &allocEntry;
}
return nullptr;
}
void PageCache::_eject(int lengthHint) {
printf("NYI: PageCache::_eject\n");
}
PageCache::Handle::Handle(_allocInfo* alloc, int ofs) : alloc_(alloc), ofs_(ofs) {
++alloc_->refs;
}
PageCache::Handle::Handle(Handle const& copy) : alloc_(copy.alloc_), ofs_(copy.ofs_) {
++alloc_->refs;
}
PageCache::Handle& PageCache::Handle::operator=(Handle const& copy) {
if(alloc_)
--alloc_->refs;
alloc_ = copy.alloc_;
ofs_ = copy.ofs_;
if(alloc_)
++alloc_->refs;
return *this;
}
PageCache::Handle::~Handle() {
--alloc_->refs;
}