Mega changes. Using hash tables.

Many bug fixes
Some formatting changes.
Introduction of vnodeManager - to allow cached, opened and mmapped files to
work together in love, peace and harmony.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2012 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Phipps 2002-11-19 04:05:16 +00:00
parent c773cf76b7
commit bc6600175c
29 changed files with 684 additions and 456 deletions

View File

@ -1,6 +1,9 @@
SubDir OBOS_TOP src kernel vm2 ;
BinCommand vmTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C test.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C : root be ;
BinCommand vmTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C test.C : root be ;
BinCommand simpleTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C simpleTest.C : root be ;
BinCommand hashTest : error.C area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C vmInterface.C vpage.C areaPool.C vnodePool.C vpagePool.C hashTest.C : root be ;
BinCommand olTest : error.C olTest.C : root be ;
BinCommand pmTest : error.C pageManager.C pageManTest.C page.C : root be ;

View File

@ -9,29 +9,24 @@
extern vmHeaderBlock *vmBlock;
bool vpageIsLessThan(void *a,void *b)
{
return (((reinterpret_cast<vpage *>(a))->getStartAddress()) < (reinterpret_cast<vpage *>(b))->getStartAddress());
}
ulong vpageHash (node &vp) {return reinterpret_cast <vpage &>(vp).hash();}
bool vpageisEqual (node &vp,node &vp2) {return reinterpret_cast <vpage &>(vp)==reinterpret_cast <vpage &>(vp2);}
area::area(void)
{
vpages.setIsLessThan(vpageIsLessThan);
area::area(void) : vpages(AREA_HASH_TABLE_SIZE) {
vpages.setHash(vpageHash);
vpages.setIsEqual(vpageisEqual);
}
void area::setup (areaManager *myManager)
{
void area::setup (areaManager *myManager) {
//error ("area::setup setting up new area\n");
manager=myManager;
//error ("area::setup done setting up new area\n");
}
unsigned long area::mapAddressSpecToAddress(addressSpec type,void * req,int pageCount)
{
unsigned long area::mapAddressSpecToAddress(addressSpec type,void * req,int pageCount) {
// We will lock in the callers
unsigned long base,requested=(unsigned long)req;
switch (type)
{
switch (type) {
case EXACT:
base=manager->getNextAddress(pageCount,requested);
if (base!=requested)
@ -54,8 +49,9 @@ unsigned long area::mapAddressSpecToAddress(addressSpec type,void * req,int page
return base;
}
status_t area::createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea=NULL /* For clone only*/)
{
status_t area::createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea=NULL /* For clone only*/) {
error ("area::createAreaGuts : name = %s, pageCount = %d, address = %ld, addressSpec = %d, pageState = %d, protection = %d, inFinalWrite = %d, fd = %d, offset = %d,originalArea=%ld\n",
inName,pageCount,address,type,inState,protect,inFinalWrite,fd,offset,originalArea);
strcpy(name,inName);
vpage *newPage;
@ -67,53 +63,50 @@ status_t area::createAreaGuts( char *inName, int pageCount, void **address, addr
end_address=base+(pageCount*PAGE_SIZE)-1;
*address=(void *)base;
finalWrite=inFinalWrite;
if (!originalArea)
for (int i=0;i<pageCount;i++)
{
if (originalArea==NULL) // Not for cloning
for (int i=0;i<pageCount;i++) {
newPage=new (vmBlock->vpagePool->get()) vpage;
if (fd)
{
vnode *newVnode=new (vmBlock->vnodePool->get()) vnode;
if (fd) {
// vnode *newVnode=new (vmBlock->vnodePool->get()) vnode;
void *currentMemoryLocation;
// A future implementation vnode *newVnode=vmBlock->vnodePool->getNode(fd,offset,PAGE_SIZE*i,true,currentMemoryLocation);
vnode *newVnode=vmBlock->vnodePool->get();
newVnode->fd=fd;
newVnode->offset=offset+PAGE_SIZE*i;
newVnode->valid=true;
newVnode->offset=offset;
newPage->setup(base+PAGE_SIZE*i,newVnode,NULL,protect,inState);
}
else
newPage->setup(base+PAGE_SIZE*i,NULL,NULL,protect,inState);
vpages.add(newPage);
}
else
for (struct node *cur=originalArea->vpages.rock;cur;cur=cur->next)
{
else // cloned
// Need to lock other area, here, just in case...
for (hashIterate hi(vpages);node *cur=hi.get();) {
vpage *page=(vpage *)cur;
newPage=new (vmBlock->vpagePool->get()) vpage;
newPage->setup(base,page->getBacking(),page->getPhysPage(),protect,inState);// Cloned area has the same physical page and backing store...
vpages.add(newPage);
base+=PAGE_SIZE;
}
dump();
return B_OK;
}
status_t area::createAreaMappingFile(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect,int fd,size_t offset)
{
status_t area::createAreaMappingFile(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect,int fd,size_t offset) {
return createAreaGuts(inName,pageCount,address,type,inState,protect,true,fd,offset);
}
status_t area::createArea(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect)
{
status_t area::createArea(char *inName, int pageCount,void **address, addressSpec type,pageState inState,protectType protect) {
return createAreaGuts(inName,pageCount,address,type,inState,protect,false,0,0);
}
status_t area::cloneArea(area *origArea, char *inName, void **address, addressSpec type,pageState inState,protectType protect)
{
if (type==CLONE)
{
status_t area::cloneArea(area *origArea, char *inName, void **address, addressSpec type,pageState inState,protectType protect) {
if (type==CLONE) {
*address=(void *)(origArea->getStartAddress());
type=EXACT;
}
if (origArea->getAreaManager()!=manager)
{
if (origArea->getAreaManager()!=manager) {
origArea->getAreaManager()->lock(); // This is just begging for a deadlock...
status_t retVal = createAreaGuts(inName,origArea->getPageCount(),address,type,inState,protect,false,0,0,origArea);
origArea->getAreaManager()->unlock();
@ -123,14 +116,12 @@ status_t area::cloneArea(area *origArea, char *inName, void **address, addressSp
return createAreaGuts(inName,origArea->getPageCount(),address,type,inState,protect,false,0,0,origArea);
}
void area::freeArea(void)
{
void area::freeArea(void) {
//error ("area::freeArea: starting \n");
// vpages.dump();
node *cur;
while ((cur=vpages.next())!=NULL)
{
for (hashIterate hi(vpages);node *cur=hi.get();) {
//error ("area::freeArea: wasting a page: %x\n",cur);
vpage *page=reinterpret_cast<vpage *>(cur);
if (finalWrite)
@ -144,8 +135,7 @@ void area::freeArea(void)
//error ("area::freeArea: ending \n");
}
status_t area::getInfo(area_info *dest)
{
status_t area::getInfo(area_info *dest) {
dest->area=areaID;
strcpy(dest->name,name);
dest->size=end_address-start_address;
@ -156,8 +146,7 @@ status_t area::getInfo(area_info *dest)
dest->in_count=0;
dest->out_count=0;
dest->copy_count=0;
for (struct node *cur=vpages.rock;cur;cur=cur->next)
{
for (hashIterate hi(vpages);node *cur=hi.get();) {
vpage *page=(vpage *)cur;
if (page->isMapped())
dest->ram_size+=PAGE_SIZE;
@ -169,40 +158,40 @@ status_t area::getInfo(area_info *dest)
return B_OK;
}
bool area::contains(void *address)
{
bool area::contains(void *address) {
unsigned long base=(unsigned long)(address);
// error ("area::contains: looking for %d in %d -- %d, value = %d\n",base,start_address,end_address, ((start_address<=base) && (end_address>=base)));
return ((start_address<=base) && (base<=end_address));
}
status_t area::resize(size_t newSize)
{
status_t area::resize(size_t newSize) {
size_t oldSize =end_address-start_address;
if (newSize==oldSize)
return B_OK;
if (newSize>oldSize)
{
if (newSize>oldSize) {
int pageCount = (newSize - oldSize + PAGE_SIZE - 1) / PAGE_SIZE;
vpage *newPage;
for (int i=0;i<pageCount;i++)
{
for (int i=0;i<pageCount;i++) {
newPage=new (vmBlock->vpagePool->get()) vpage;
newPage->setup(end_address+PAGE_SIZE*i-1,NULL,NULL,protection,state);
vpages.add(newPage);
}
end_address+=start_address+newSize;
}
else
{
else {
int pageCount = (oldSize - newSize + PAGE_SIZE - 1) / PAGE_SIZE;
vpage *oldPage;
struct node *cur;
for (int i=0;i<pageCount;i++) // This is probably really slow. Adding an "end" to list would be faster.
{
for (cur=vpages.rock;cur->next;cur=cur->next); // INTENTIONAL - find the last one;
oldPage=(vpage *)cur;
for (int i=0;i<pageCount;i++) { // This is probably really slow. OTOH, how often do people shrink their allocations?
node *max;
void *maxAddress=NULL,*curAddress;
for (hashIterate hi(vpages);node *cur=hi.get();)
if ((curAddress=(reinterpret_cast<vpage *>(cur))->getStartAddress()) > maxAddress) {
maxAddress=curAddress;
max=cur;
}
oldPage=reinterpret_cast<vpage *>(max);
vpages.remove(cur);
if (finalWrite)
oldPage->flush();
@ -213,10 +202,8 @@ status_t area::resize(size_t newSize)
return B_OK;
}
status_t area::setProtection(protectType prot)
{
for (struct node *cur=vpages.rock;cur;cur=cur->next)
{
status_t area::setProtection(protectType prot) {
for (hashIterate hi(vpages);node *cur=hi.get();) {
vpage *page=(vpage *)cur;
page->setProtection(prot);
}
@ -224,21 +211,12 @@ status_t area::setProtection(protectType prot)
return B_OK;
}
vpage *area::findVPage(unsigned long address)
{
for (struct node *cur=vpages.rock;cur;cur=cur->next)
{
vpage *page=(vpage *)cur;
//error ("Examining following vpage, looking for address %lx\n",address);
//page->dump();
if (page->contains(address))
return page;
}
return NULL;
vpage *area::findVPage(unsigned long address) {
vpage findMe(address);
return reinterpret_cast <vpage *>(vpages.find(&findMe));
}
bool area::fault(void *fault_address, bool writeError) // true = OK, false = panic.
{
bool area::fault(void *fault_address, bool writeError) { // true = OK, false = panic.
vpage *page=findVPage((unsigned long)fault_address);
if (page)
return page->fault(fault_address,writeError);
@ -246,8 +224,7 @@ bool area::fault(void *fault_address, bool writeError) // true = OK, false = pan
return false;
}
char area::getByte(unsigned long address) // This is for testing only
{
char area::getByte(unsigned long address) { // This is for testing only
vpage *page=findVPage(address);
if (page)
return page->getByte(address,manager);
@ -255,15 +232,13 @@ char area::getByte(unsigned long address) // This is for testing only
return 0;
}
void area::setByte(unsigned long address,char value) // This is for testing only
{
void area::setByte(unsigned long address,char value) { // This is for testing only
vpage *page=findVPage(address);
if (page)
page->setByte(address,value,manager);
}
int area::getInt(unsigned long address) // This is for testing only
{
int area::getInt(unsigned long address) { // This is for testing only
vpage *page=findVPage(address);
if (page)
return page->getInt(address,manager);
@ -271,36 +246,30 @@ int area::getInt(unsigned long address) // This is for testing only
return 0;
}
void area::setInt(unsigned long address,int value) // This is for testing only
{
void area::setInt(unsigned long address,int value) { // This is for testing only
vpage *page=findVPage(address);
if (page)
page->setInt(address,value,manager);
}
void area::pager(int desperation)
{
for (struct node *cur=vpages.rock;cur;cur=cur->next)
{
void area::pager(int desperation) {
for (hashIterate hi(vpages);node *cur=hi.get();) {
vpage *page=(vpage *)cur;
page->pager(desperation);
}
}
void area::saver(void)
{
for (struct node *cur=vpages.rock;cur;cur=cur->next)
{
void area::saver(void) {
for (hashIterate hi(vpages);node *cur=hi.get();) {
vpage *page=(vpage *)cur;
page->saver();
}
}
void area::dump(void)
{
void area::dump(void) {
error ("area::dump: size = %ld, lock = %d, address = %lx\n",end_address-start_address,state,start_address);
for (struct node *cur=vpages.rock;cur;)
{
vpages.dump();
for (hashIterate hi(vpages);node *cur=hi.get();) {
vpage *page=(vpage *)cur;
page->dump();
cur=cur->next;

View File

@ -3,7 +3,7 @@
#include "OS.h"
#include "vm.h"
#include "list.h"
#include "olist.h"
#include "hashTable.h"
class areaManager;
class vpage;
@ -11,7 +11,7 @@ class vpage;
class area : public node
{
protected:
orderedList vpages;
hashTable vpages;
char name[B_OS_NAME_LENGTH];
pageState state;
protectType protection;
@ -25,36 +25,47 @@ class area : public node
unsigned long end_address;
vpage *findVPage(unsigned long);
public:
// Constructors and Destructors and related
area(void);
void setup(areaManager *myManager);
bool nameMatch(char *matchName) {return (strcmp(matchName,name)==0);}
unsigned long mapAddressSpecToAddress(addressSpec type,void *requested,int pageCount);
void freeArea(void);
status_t createAreaGuts( char *inName, int pageCount, void **address, addressSpec type, pageState inState, protectType protect, bool inFinalWrite, int fd, size_t offset, area *originalArea=NULL /* For clone only*/);
status_t createAreaMappingFile(char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect,int fd,size_t offset);
status_t createArea (char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect);
status_t cloneArea(area *area, char *inName, void **address, addressSpec type,pageState inState,protectType protect);
int getAreaID(void) {return areaID;}
unsigned long mapAddressSpecToAddress(addressSpec type,void *requested,int pageCount);
// Mutators
void setAreaID(int id) {areaID=id;}
void freeArea(void);
status_t getInfo(area_info *dest);
bool contains(void *address);
status_t resize(size_t newSize);
status_t setProtection(protectType prot);
bool couldAdd(unsigned long start,unsigned long end) { return ((end<start_address) || (start>end_address));}
unsigned long getEndAddress(void) {return end_address;}
unsigned long getStartAddress(void) {return start_address;}
void pager(int desperation);
void saver(void);
status_t resize(size_t newSize);
// Accessors
status_t getInfo(area_info *dest);
int getAreaID(void) {return areaID;}
unsigned long getSize(void) {return getEndAddress()-getStartAddress();}
unsigned long getPageCount(void) {return (getEndAddress()-getStartAddress())/PAGE_SIZE;}
areaManager *getAreaManager(void) {return manager;}
unsigned long getEndAddress(void) {return end_address;}
unsigned long getStartAddress(void) {return start_address;}
// Debugging
void dump(void);
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
char getByte(unsigned long ); // This is for testing only
void setByte(unsigned long ,char value); // This is for testing only
int getInt(unsigned long ); // This is for testing only
void setInt(unsigned long ,int value); // This is for testing only
// Comparisson with others
bool nameMatch(char *matchName) {return (strcmp(matchName,name)==0);}
bool couldAdd(unsigned long start,unsigned long end) { return ((end<start_address) || (start>end_address));}
bool contains(void *address);
// External methods for "server" type calls
void pager(int desperation);
void saver(void);
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
};
#endif

View File

@ -86,11 +86,11 @@ area *areaManager::findArea(char *address)
area *areaManager::findArea(void *address)
{
// THIS DOES NOT HAVE LOCKING - all callers must lock.
//error ("Finding area by void * address\n");
// error ("Finding area by void * address\n");
for (struct node *cur=areas.rock;cur;cur=cur->next)
{
area *myArea=(area *)cur;
// error ("areaManager::findArea: Looking for %x between %x and %x\n",address,myArea->getStartAddress(),myArea->getEndAddress());
//error ("areaManager::findArea: Looking for %x between %x and %x\n",address,myArea->getStartAddress(),myArea->getEndAddress());
if (myArea->contains(address))
return myArea;
}
@ -142,20 +142,20 @@ int areaManager::createArea(char *AreaName,int pageCount,void **address, address
error ("Creating an area\n");
lock();
area *newArea = new (vmBlock->areaPool->get()) area;
// error ("areaManager::createArea - got a new area (%p) from the areaPool\n",newArea);
error ("areaManager::createArea - got a new area (%p) from the areaPool\n",newArea);
newArea->setup(this);
// error ("areaManager::createArea - setup complete\n");
error ("areaManager::createArea - setup complete\n");
newArea->createArea(AreaName,pageCount,address,addType,state,protect);
// error ("areaManager::createArea - new area's createArea called\n");
error ("areaManager::createArea - new area's createArea called\n");
atomic_add(&nextAreaID,1);
newArea->setAreaID(nextAreaID);
// error ("areaManager::createArea - new area's setAreaID called\n");
error ("areaManager::createArea - new area's setAreaID called\n");
addArea(newArea);
// error ("areaManager::createArea - new area added to list\n");
error ("areaManager::createArea - new area added to list\n");
int retVal=newArea->getAreaID();
// error ("areaManager::createArea - new area id found\n");
error ("areaManager::createArea - new area id found\n");
unlock();
//error ("Done Creating an area\n");
error ("Done Creating an area\n");
return retVal;
}
@ -184,13 +184,18 @@ int areaManager::cloneArea(int newAreaID,char *AreaName,void **address, addressS
char areaManager::getByte(unsigned long address)
{
area *myArea;
// error ("areaManager::getByte : starting\n");
int retVal;
lock();
myArea=findArea((void *)address);
if (myArea)
retVal=myArea->getByte(address);
else
retVal= 0;
{
char temp[1000];
sprintf (temp,"Unable to find an area for address %d\n",address);
throw (temp);
}
unlock();
return retVal;
}
@ -204,18 +209,29 @@ int areaManager::getInt(unsigned long address)
if (myArea)
retVal=myArea->getInt(address);
else
retVal= 0;
{
char temp[1000];
sprintf (temp,"Unable to find an area for address %d\n",address);
throw (temp);
}
unlock();
return retVal;
}
void areaManager::setByte(unsigned long address,char value)
{
// error ("areaManager::setByte : starting\n");
area *myArea;
lock();
myArea=findArea((void *)address);
if (myArea)
myArea->setByte(address,value);
else
{
char temp[1000];
sprintf (temp,"Unable to find an area for address %d\n",address);
throw (temp);
}
unlock();
}
@ -226,6 +242,12 @@ void areaManager::setInt(unsigned long address,int value)
myArea=findArea((void *)address);
if (myArea)
myArea->setInt(address,value);
else
{
char temp[1000];
sprintf (temp,"Unable to find an area for address %d\n",address);
throw (temp);
}
unlock();
}

View File

@ -9,43 +9,18 @@ class areaManager // One of these per process
sem_id myLock;
static long nextAreaID;
public:
// Constructors and Destructors and related
areaManager ();
void addArea(area *newArea) {areas.add(newArea);}
void removeArea(area *oldArea) {areas.remove(oldArea); }
void freeArea(area_id area);
int createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect) ;
int cloneArea(int newAreaID,char *AreaName,void **address, addressSpec addType=ANY, pageState state=NO_LOCK, protectType prot=writable);
// Accessors
team_id getTeam(void) {return team;}
unsigned long getNextAddress(int pages,unsigned long minimum=USER_BASE);
area *findArea(void *address);
area *findAreaLock(void *address);
area *findArea(char *address);
area *findArea(area_id id);
area *findAreaLock(area_id id);
status_t setProtection(int areaID,protectType prot)
{
status_t retVal;
lock();
area *myArea=findArea(areaID);
if (myArea)
retVal= myArea->setProtection(prot);
else
retVal= B_ERROR;
unlock();
return retVal;
}
status_t resizeArea(int Area,size_t size)
{
status_t retVal;
lock();
area *oldArea=findArea(Area);
if (oldArea)
retVal= oldArea->resize(size);
else
retVal= B_ERROR;
unlock();
return retVal;
}
status_t getAreaInfo(int areaID,area_info *dest)
{
status_t getAreaInfo(int areaID,area_info *dest) {
status_t retVal;
lock();
area *oldArea=findArea(areaID);
@ -56,8 +31,49 @@ class areaManager // One of these per process
unlock();
return retVal;
}
status_t getInfoAfter(int32 & areaID,area_info *dest)
{
int getAreaByName(char *name) {
int retVal;
lock();
area *oldArea=findArea(name);
if (oldArea)
retVal= oldArea->getAreaID();
else
retVal= B_ERROR;
unlock();
return retVal;
}
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
status_t munmap(void *addr,size_t len);
// Mutators
area *findArea(void *address);
area *findAreaLock(void *address);
area *findArea(char *address);
area *findArea(area_id id);
area *findAreaLock(area_id id);
status_t setProtection(int areaID,protectType prot) {
status_t retVal;
lock();
area *myArea=findArea(areaID);
if (myArea)
retVal= myArea->setProtection(prot);
else
retVal= B_ERROR;
unlock();
return retVal;
}
status_t resizeArea(int Area,size_t size) {
status_t retVal;
lock();
area *oldArea=findArea(Area);
if (oldArea)
retVal= oldArea->resize(size);
else
retVal= B_ERROR;
unlock();
return retVal;
}
status_t getInfoAfter(int32 & areaID,area_info *dest) {
status_t retVal;
lock();
area *oldArea=findArea(areaID);
@ -72,29 +88,15 @@ class areaManager // One of these per process
unlock();
return retVal;
}
int getAreaByName(char *name)
{
int retVal;
lock();
area *oldArea=findArea(name);
if (oldArea)
retVal= oldArea->getAreaID();
else
retVal= B_ERROR;
unlock();
return retVal;
}
int createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect) ;
void pager(int desperation);
void saver(void);
void lock() { acquire_sem(myLock); }
void unlock() {release_sem(myLock);}
void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
status_t munmap(void *addr,size_t len);
int cloneArea(int newAreaID,char *AreaName,void **address, addressSpec addType=ANY, pageState state=NO_LOCK, protectType prot=writable);
// External methods for "server" type calls
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
void pager(int desperation);
void saver(void);
// Debugging
char getByte(unsigned long offset); // This is for testing only
void setByte(unsigned long offset,char value); // This is for testing only
int getInt(unsigned long offset); // This is for testing only

View File

@ -7,13 +7,14 @@ class poolarea
list unused;
sem_id inUse;
public:
poolarea(void)
{
// Constructors and Destructors and related
poolarea(void) {
inUse = create_sem(1,"areapool");
}
// Mutators
area *get(void);
void put(area *in)
{
void put(area *in) {
acquire_sem(inUse);
unused.add((node *)in);
release_sem(inUse);

View File

@ -3,49 +3,49 @@
#include <vpagePool.h>
#include "vmHeaderBlock.h"
bool cacheMemberIsLessThan(void *a,void *b)
{
vnode *v1 = reinterpret_cast<cacheMember *>(a)->vn;
vnode *v2 = reinterpret_cast<cacheMember *>(b)->vn;
if (v1->fd < v2->fd)
return true;
if ((v1->fd==v2->fd) && (v1->offset<v2->offset))
return true;
return false;
}
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;
}
extern vmHeaderBlock *vmBlock;
// TODO - we need to (somehow) make sure that the same vnodes here are shared with mmap.
// Maybe a vnode manager...
cacheManager::cacheManager(void) : area ()
{
cacheManager::cacheManager(void) : area (),cacheMembers(30) {
myLock=create_sem(1,"Cache Manager Semaphore");
cacheMembers.setHash(vnodeHash);
cacheMembers.setIsEqual(vnodeisEqual);
}
void *cacheManager::findBlock(vnode *target,bool readOnly)
{
if (!cacheMembers.rock)
return NULL;
for (struct cacheMember *cur=((cacheMember *)cacheMembers.rock);cur;cur=((cacheMember *)cur->next))
{
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());
}
return NULL;
// 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);
}
void *cacheManager::createBlock(vnode *target,bool readOnly)
{
void *cacheManager::createBlock(vnode *target,bool readOnly, cacheMember *candidate) {
bool foundSpot=false;
vpage *prev=NULL,*cur=NULL;
unsigned long begin=CACHE_BEGIN;
// Find a place in the cache's virtual space to put this vnode...
if (vpages.rock)
for (cur=((vpage *)(vpages.rock));!foundSpot && cur;cur=(vpage *)(cur->next))
if (cur->getStartAddress()!=(void *)begin)
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;
else // no joy
{
else { // no joy
begin+=PAGE_SIZE;
prev=cur;
}
@ -55,21 +55,23 @@ void *cacheManager::createBlock(vnode *target,bool readOnly)
newPage->setup(begin,target,NULL,((readOnly)?readable:writable),NO_LOCK);
vpages.add(newPage);
cacheMembers.add(newPage);
// 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;
}
void *cacheManager::readBlock(vnode *target)
{
void *cacheManager::readBlock(vnode *target) {
void *destination=findBlock(target,true);
if (destination) return destination;
return createBlock(target,true);
}
void *cacheManager::writeBlock(vnode *target)
{
void *cacheManager::writeBlock(vnode *target) {
void *destination=findBlock(target,false);
if (destination) return destination;
return createBlock(target,false);

View File

@ -2,7 +2,7 @@
#include <vm.h>
#include <vpage.h>
#include <area.h>
#include <olist.h>
#include <hashTable.h>
struct cacheMember : public node
{
@ -13,20 +13,24 @@ struct cacheMember : public node
class cacheManager : public area
{
private:
orderedList cacheMembers; // Yes, this is slow and should be a hash table. This should be done prior to
// moving into the kernel, so we can test it better.
// While this very much mirrors the area's vpage list, it won't when it is a hash table...
hashTable cacheMembers;
void *findBlock (vnode *target,bool readOnly);
void *createBlock (vnode *target,bool readOnly);
void *createBlock (vnode *target,bool readOnly, cacheMember *candidate=NULL);
sem_id myLock;
public:
// For these two, the VFS passes in the target vnode
// Return value is the address. Note that the paging daemon does the actual loading
// Constructors and Destructors and related
cacheManager(void);
// Mutators
void *readBlock (vnode *target);
void *writeBlock (vnode *target);
void pager(int desperation); // override, as we should blow away useless nodes, not just free blocks.
void saver(void); // Override - not sure why
void lock() {acquire_sem(myLock);}
void unlock() {release_sem(myLock);}
// External methods for "server" type calls
void pager(int desperation); // override, as we should blow away useless nodes, not just free blocks.
void saver(void); // Override - not sure why
};

View File

@ -10,7 +10,7 @@ void error(char *fmt, ...)
errorPrinting=create_sem(1,"error_printing");
acquire_sem(errorPrinting);
va_list argp;
char tmp[1000];
char tmp[2000];
sprintf(tmp, "[%lld] error: %s",real_time_clock_usecs(),fmt);
va_start(argp, tmp);
vfprintf(stderr,tmp,argp);

View File

@ -9,19 +9,27 @@
extern vmHeaderBlock *vmBlock;
class hashIterate;
class hashTable : public list
{
friend hashIterate;
public:
// Constructors and Destructors and related
hashTable(int size) {
nodeCount=0;
numRocks=size;
error ("Starting to initalize hash table\n");
if (size*sizeof (list *)>PAGE_SIZE)
throw ("Hash table too big!");
error ("Getting Page\n");
page *newPage=vmBlock->pageMan->getPage();
error ("Got Page\n");
if (!newPage)
throw ("Out of pages to allocate a pool!");
rocks=(list **)(newPage->getAddress());
error ("Got rocks\n");
int listsPerPage=PAGE_SIZE/sizeof(list);
int pages=(size+(listsPerPage-1))/listsPerPage;
@ -35,10 +43,9 @@ class hashTable : public list
}
}
// Mutators
void setHash (ulong (*hash_in)(node &)) { hash=hash_in; }
void setIsEqual (bool (*isEqual_in)(node &,node &)) { isEqual=isEqual_in; }
int count(void) {return nodeCount;}
void add (node *newNode) {
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
@ -47,27 +54,8 @@ class hashTable : public list
rocks[hashValue]->add(newNode);
}
node *next(void) {throw ("Next is invalid in a hash table!");} // This operation doesn't make sense for this class
void remove(node *toNuke) {
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
unsigned long hashValue=hash(*toNuke)%numRocks;
rocks[hashValue]->remove(toNuke);
}
void dump(void) {
for (int i=0;i<numRocks;i++)
for (struct node *cur=rocks[i]->rock;cur;cur=cur->next)
error ("hashTable::dump: On bucket %d of %d, At %p, next = %p\n",i,numRocks,cur,cur->next);
}
bool ensureSane (void) {
bool ok=true;
for (int i=0;i<numRocks;i++)
ok|=rocks[i]->ensureSane();
return ok;
}
// Accessors
int count(void) {return nodeCount;}
node *find(node *findNode) {
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
@ -79,6 +67,26 @@ class hashTable : public list
return cur;
return NULL;
}
node *next(void) {throw ("Next is invalid in a hash table!");} // This operation doesn't make sense for this class
void remove(node *toNuke) {
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
unsigned long hashValue=hash(*toNuke)%numRocks;
rocks[hashValue]->remove(toNuke);
}
// Debugging
void dump(void) {
for (int i=0;i<numRocks;i++)
for (struct node *cur=rocks[i]->rock;cur;cur=cur->next)
error ("hashTable::dump: On bucket %d of %d, At %p, next = %p\n",i,numRocks,cur,cur->next);
}
bool ensureSane (void) {
bool ok=true;
for (int i=0;i<numRocks;i++)
ok|=rocks[i]->ensureSane();
return ok;
}
private:
ulong (*hash)(node &a);
@ -86,4 +94,27 @@ class hashTable : public list
list **rocks;
int numRocks;
};
class hashIterate {
private:
int bucket;
node *current;
hashTable &table;
public:
hashIterate(hashTable *in) : bucket(0),current(NULL),table(*in) {}
hashIterate(hashTable &in) : bucket(0),current(NULL),table(in) {}
node *get(void)
{
while (!current && bucket<table.numRocks)
current=table.rocks[bucket++]->top();
if (!current)
return NULL; // No more in the hash table
node *retVal=current; // Store the current and get then next in preperation
current=current->next;
return retVal;
}
};
#endif

View File

@ -27,7 +27,7 @@ bool isEqual (node &a,node &b) {
int main(int argc,char **argv) {
// Test 1 - Try to add to foo without setting an isLessThan function
try {
hashTable foo(10);
hashTable foo(40);
node tmp;
foo.add(&tmp);
}
@ -68,7 +68,7 @@ int main(int argc,char **argv) {
bar.setIsEqual(isEqual);
for (int a=0;a<100;a++)
bar.add(new hashTest(a));
for (int a=1000;a>=100;a--)
for (int a=999;a>=100;a--)
bar.add(new hashTest(a));
bar.dump();
@ -79,7 +79,7 @@ int main(int argc,char **argv) {
foo.remove(&second);
foo.dump();
error ("Setting up middle case (readding 1 and 2)\n");
error ("Setting up middle case (reading 1 and 2)\n");
foo.add(&first);
foo.add(&second);
foo.dump();
@ -103,5 +103,16 @@ int main(int argc,char **argv) {
error ("ensuringSane on smaller (foo) = %s\n",((foo.ensureSane())?"OK":"BAD!"));
error ("ensuringSane on larger (bar) = %s\n",((bar.ensureSane())?"OK":"BAD!"));
int count=0;
for (hashIterate hi(bar);node *next=hi.get();) {
count++;
if (next==NULL)
error ("Found a NULL at %d\n",count);
}
if (count==1000)
error ("found 1000, as expected!\n");
else
error ("did NOT find 1000, as expected, found %d!\n",count);
return 0;
}

View File

@ -12,14 +12,15 @@ struct node
class list {
public:
// Constructors and Destructors and related
list(void){nodeCount=0;rock=NULL;}
// Mutators
void add (node *newNode) {
newNode->next=rock;
rock=newNode;
nodeCount++;
}
//int count(void) {error ("list::count: About to return %d\n",nodeCount);return nodeCount;}
int count(void) {return nodeCount;}
node *next(void) {
//dump();
node *n=rock;
@ -49,11 +50,16 @@ class list {
//error ("list::remove ending: \n");
//dump();
}
// Accessors
int count(void) {return nodeCount;}
node *top(void) {return rock;} // Intentionally non-destructive ; works like peek() on a queue
// Debugging
void dump(void) {
for (struct node *cur=rock;cur;cur=cur->next)
{ error ("list::dump: At %p, next = %p\n",cur,cur->next); }
}
bool ensureSane (void) {
int temp=nodeCount;
for (struct node *cur=rock;cur && --temp;cur=cur->next) ; // Intentional to have no body

View File

@ -10,27 +10,24 @@ static bool throwException (void *foo, void *bar)
class orderedList : public list
{
public:
// Constructors and Destructors and related
orderedList(void) {nodeCount=0;rock=NULL; isLessThan=throwException; }
// Mutators
void setIsLessThan (bool (*iLT)(void *,void *)) { isLessThan=iLT; }
void add(node *in)
{
void add(node *in) {
nodeCount++;
//error ("orderedList::add starting\n");
if (!rock || isLessThan(in,rock))
{ // special case - this will be the first one
if (!rock || isLessThan(in,rock)) { // special case - this will be the first one
//error ("orderedList::specialCase starting\n");
in->next=rock;
rock=in;
}
else
{
else {
//error ("orderedList::Normal Case starting\n");
bool done=false;
for (struct node *cur=rock;cur && !done;cur=cur->next)
if (!(cur->next) || isLessThan(in,cur->next))
{ // If we have found our niche, *OR* this is the last element, insert here.
if (!(cur->next) || isLessThan(in,cur->next)) { // If we have found our niche, *OR* this is the last element, insert here.
//error ("orderedList::Normal Case Adding Start\n");
in->next=cur->next;
cur->next=in;
@ -40,20 +37,15 @@ class orderedList : public list
//error ("orderedList::Normal Case ending\n");
}
}
void remove(node *toNuke)
{
if (rock==toNuke)
{
void remove(node *toNuke) {
if (rock==toNuke) {
rock=rock->next;
nodeCount--;
}
else
{
else {
bool done=false;
for (struct node *cur=rock;!done && (cur->next);cur=cur->next)
if (cur->next==toNuke)
{
if (cur->next==toNuke) {
cur->next=toNuke->next;
nodeCount--;
done=true;

View File

@ -7,11 +7,19 @@ class page : public node {
void *cpuSpecific;
void *physicalAddress;
public:
long count; // Yes, this is large. However, the only atomic add that I have in userland works on int32's. In kernel land, we could shrink this
// Constructors and Destructors and related
page(void) {cpuSpecific=NULL;physicalAddress=NULL;};
void setup (void *address) {count=0;physicalAddress=address;};
void zero(void);
// Accessors
unsigned long getAddress(void) {return (unsigned long)physicalAddress;}
// Debugging
void dump(void) { error ("page::dump: Page %p, physicalAddress = %lx\n",this,getAddress()); }
// External methods for "server" type calls
void zero(void);
long count; // Yes, this is large. However, the only atomic add that I have in userland works on int32's. In kernel land, we could shrink this
};
#endif

View File

@ -0,0 +1,102 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "pageManager.h"
#include "OS.h"
enum testType {clean,unused,inuse};
pageManager pm;
char *testName;
bool testCount (int expected, testType type)
{
int found;
switch (type) {
case clean:
if (found=pm.getCleanCount()!=expected) {
error ("%s, invalid cleanCount of %d, expected: %d\n",testName,found,expected);
return false;
}
break;
case unused:
if (found=pm.getUnusedCount()!=expected) {
error ("%s, invalid unusedCount of %d, expected: %d\n",testName,found,expected);
return false;
}
break;
case inuse:
if (found=pm.getInUseCount()!=expected) {
error ("%s, invalid InUseCount of %d, expected: %d\n",testName,found,expected);
return false;
}
break;
}
return true;
}
int main(int argc,char **argv)
{
testName="Setup";
pm.setup(malloc(PAGE_SIZE*100),100);
if (!(testCount(99,unused) || testCount (0,clean) || testCount (0,inuse))) {
pm.dump();
exit(1);
}
testName="Get One";
page *gotten = pm.getPage();
if (!(testCount(98,unused) || testCount (0,clean) || testCount (1,inuse))) {
pm.dump();
exit(1);
}
testName="Put One";
pm.freePage(gotten);
if (!(testCount(99,unused) || testCount (0,clean) || testCount (0,inuse))) {
pm.dump();
exit(1);
}
testName="Clean One";
pm.cleanOnePage();
if (!(testCount(98,unused) || testCount (1,clean) || testCount (0,inuse))) {
pm.dump();
exit(1);
}
testName="Get One Cleaned";
gotten = pm.getPage();
if (!(testCount(98,unused) || testCount (0,clean) || testCount (1,inuse))) {
pm.dump();
exit(1);
}
testName="Put One Cleaned";
pm.freePage(gotten);
if (!(testCount(99,unused) || testCount (0,clean) || testCount (0,inuse))) {
pm.dump();
exit(1);
}
testName="Get them all";
page *pages[100];
for (int i=0;i<99;i++)
pages[i]=pm.getPage();
if (!(testCount(0,unused) || testCount (0,clean) || testCount (99,inuse))) {
pm.dump();
exit(1);
}
testName="Free them all";
for (int i=0;i<99;i++)
pm.freePage(pages[i]);
if (!(testCount(99,unused) || testCount (0,clean) || testCount (0,inuse))) {
pm.dump();
exit(1);
}
exit(0);
}

View File

@ -3,26 +3,19 @@
#include <stdlib.h>
#include <string.h>
void *addOffset(void *base,unsigned long offset)
{
void *addOffset(void *base,unsigned long offset) {
return (void *)(((unsigned long)base+offset));
}
pageManager::pageManager(void)
{
pageManager::pageManager(void) {
}
void pageManager::setup(void *area,int pages)
{
void pageManager::setup(void *area,int pages) {
// Calculate the number of pages that we will need to hold the page structures
int pageOverhead=((pages*sizeof(page))+(PAGE_SIZE-1))/PAGE_SIZE;
for (int i=0;i<pages-pageOverhead;i++)
{
for (int i=0;i<pages-pageOverhead;i++) {
page *newPage=(page *)(addOffset(area,i*sizeof(page)));
newPage->setup(addOffset(area,(i+pageOverhead)*PAGE_SIZE));
//error ("newPage = %x, setup = %x\n",newPage,addOffset(area,(i+pageOverhead)*PAGE_SIZE));
//error ("i = %d, sizeof(page) = %x, pageOverhead = %d\n",i,sizeof(page),pageOverhead);
//newPage->dump();
unused.add(newPage);
}
@ -30,39 +23,21 @@ void pageManager::setup(void *area,int pages)
unusedLock=create_sem (1,"unused_lock");
inUseLock=create_sem (1,"inuse_lock");
totalPages=pages;
/*
error ("pageManager::pageManager: About to dump the clean pages (should be 0):\n\n");
clean.dump();
error ("pageManager::pageManager: About to dump the unused pages (should not be 0):\n\n");
unused.dump();
*/
}
page *pageManager::getPage(void)
{
page *pageManager::getPage(void) {
page *ret=NULL;
// error ("pageManager::getPage: Checking clean\n");
//error ("pageManager::getPage:cleanCount = %d\n", clean.nodeCount);
while (!ret)
{
if (clean.count())
{
//error ("pageManager::getPage:locking clean\n");
if (clean.count()) {
acquire_sem(cleanLock);
//error ("pageManager::getPage:locked clean\n");
ret=(page *)clean.next();
//error ("pageManager::getPage:got next clean\n");
release_sem(cleanLock);
//error ("pageManager::getPage:unlocked clean\n");
} // This could fail if someone swooped in and stole our page.
if (!ret && unused.count())
{
//error ("pageManager::getPage:Checking unused\n");
if (!ret && unused.count()) {
acquire_sem(unusedLock);
ret=(page *)unused.next();
//error ("pageManager::getPage:got next unused\n");
release_sem(unusedLock);
//error ("pageManager::getPage:next unused = %x\n",ret);
if (ret)
ret->zero();
} // This could fail if someone swooped in and stole our page.
@ -71,37 +46,30 @@ page *pageManager::getPage(void)
inUse.add(ret);
release_sem(inUseLock);
ret->count++;
// error ("pageManager::getPage:leaving with page = %x\n", ret->getAddress());
return ret;
}
bool pageManager::getContiguousPages(int pages,page **location)
{
bool pageManager::getContiguousPages(int pages,page **location) {
unsigned long current, start=0, next;
page *curPage;
int count=0;
while (count<pages)
{
while (count<pages) {
curPage=getPage();
current=curPage->getAddress();
if (start==0)
{
if (start==0) {
start=current;
location[count++]=curPage;
}
else if (current==start+PAGE_SIZE*count) // This is the next one in line
location[count++]=curPage;
else if (current==start-PAGE_SIZE) // Found the one directly previous
{
else if (current==start-PAGE_SIZE) { // Found the one directly previous
memmove(location[1],location[0],count*sizeof(page *));
start=current;
location[0]=curPage;
count++;
}
else // Forget this series - it doesn't seem to be going anywhere...
{
while (--count>=0)
{
else { // Forget this series - it doesn't seem to be going anywhere...
while (--count>=0) {
freePage(location[count]);
location[count]=NULL;
}
@ -110,11 +78,8 @@ bool pageManager::getContiguousPages(int pages,page **location)
return true;
}
void pageManager::freePage(page *toFree)
{
error ("pageManager::freePage; old value = %d\n",toFree->count);
if (atomic_add(&(toFree->count),-1)==1) // atomic_add returns the *PREVIOUS* value. So we need to check to see if the one we are wasting was the last one.
{
void pageManager::freePage(page *toFree) {
if (atomic_add(&(toFree->count),-1)==1) { // atomic_add returns the *PREVIOUS* value. So we need to check to see if the one we are wasting was the last one.
acquire_sem(inUseLock);
inUse.remove(toFree);
release_sem(inUseLock);
@ -122,63 +87,55 @@ void pageManager::freePage(page *toFree)
unused.add(toFree);
release_sem(unusedLock);
}
error ("pageManager::freePage:new value = %d, page = %x\n",toFree->count,toFree->getAddress());
}
void pageManager::cleaner(void)
{
while (1)
{
void pageManager::cleaner(void) {
while (1) {
snooze(250000);
if (unused.count())
{
//error ("pageManager::cleaner: About to vacuum a page\n");
acquire_sem(unusedLock);
page *first=(page *)unused.next();
release_sem(unusedLock);
if (first)
{
first->zero();
acquire_sem(cleanLock);
clean.add(first);
release_sem(cleanLock);
}
//error ("pageManager::cleaner: All done with vacuum a page\n");
cleanOnePage();
}
}
void pageManager::cleanOnePage(void) {
if (unused.count()) {
acquire_sem(unusedLock);
page *first=(page *)unused.next();
release_sem(unusedLock);
if (first) {
first->zero();
acquire_sem(cleanLock);
clean.add(first);
release_sem(cleanLock);
}
}
}
int pageManager::desperation(void)
{ // Formula to determine how desperate system is to get pages back...
int pageManager::desperation(void) { // Formula to determine how desperate system is to get pages back...
int percentClean=(unused.count()+clean.count())*100/totalPages;
if (percentClean>30) return 1;
return (35-percentClean)/7;
}
void pageManager::dump(void)
{
error ("Dumping the unused list\n");
void pageManager::dump(void) {
error ("Dumping the unused list (%d entries)\n",getUnusedCount());
acquire_sem(unusedLock);
for (struct node *cur=unused.rock;cur;)
{
for (struct node *cur=unused.rock;cur;) {
page *thisPage=(page *)cur;
thisPage->dump();
cur=cur->next;
}
release_sem(unusedLock);
error ("Dumping the clean list\n");
error ("Dumping the clean list (%d entries)\n",getCleanCount());
acquire_sem(cleanLock);
for (struct node *cur=clean.rock;cur;)
{
for (struct node *cur=clean.rock;cur;) {
page *thisPage=(page *)cur;
thisPage->dump();
cur=cur->next;
}
error ("Dumping the inuse list\n");
error ("Dumping the inuse list (%d entries)\n",getInUseCount());
release_sem(cleanLock);
acquire_sem(inUseLock);
for (struct node *cur=inUse.rock;cur;)
{
for (struct node *cur=inUse.rock;cur;) {
page *thisPage=(page *)cur;
thisPage->dump();
cur=cur->next;

View File

@ -6,14 +6,27 @@
class pageManager {
public:
// Constructors and Destructors and related
pageManager(void);
void setup(void *memory,int pages);
void freePage(page *);
// Mutators
page *getPage(void);
bool getContiguousPages(int pages,page **location);
void freePage(page *);
void cleaner(void);
// Accessors
int desperation(void);
// External methods for "server" type calls
void cleaner(void);
void cleanOnePage(void);
// Debugging
void dump(void);
int getCleanCount(void) {return clean.count();}
int getUnusedCount(void) {return unused.count();}
int getInUseCount(void) {return inUse.count();}
private:
list clean,unused,inUse;
sem_id cleanLock,unusedLock,inUseLock;

View File

@ -12,27 +12,21 @@ class poolTYPE
list unused;
sem_id inUse;
public:
poolTYPE(void)
{
inUse = create_sem(1,"TYPEpool");
poolTYPE(void) { inUse = create_sem(1,"TYPEpool");
}
TYPE *get(void)
{
TYPE *get(void) {
TYPE *ret=NULL;
if (unused.count())
{
if (unused.count()) {
error ("poolTYPE::get: Getting an unused one!\n");
acquire_sem(inUse);
ret=(TYPE *)unused.next();
release_sem(inUse);
}
if (ret)
{
if (ret) {
error ("poolTYPE::get: Returning address:%x \n",ret);
return ret;
}
else
{
else {
error ("poolTYPE::get: Getting a new page!\n");
page *newPage=vmBlock->pageMan->getPage();
if (!newPage)
@ -46,12 +40,11 @@ class poolTYPE
return (get()); // A little cheat - call self again to get the first one from stack...
}
}
void put(TYPE *in)
{
void put(TYPE *in) {
acquire_sem(inUse);
unused.add(in);
release_sem(inUse);
}
};
*/

View File

@ -0,0 +1,57 @@
#include "vmInterface.h"
#include <stdio.h>
#include <unistd.h>
#include <mman.h>
#include <errno.h>
#include <string.h>
vmInterface vm(30);
void writeByte(unsigned long addr,unsigned int offset, char value) { vm.setByte(addr+offset,value); }
unsigned char readByte(unsigned long addr,unsigned int offset ) { char value=vm.getByte(addr+offset); return value; }
int createFillAndTest(int pages,char *name)
{
try{
unsigned long addr;
int area1;
error ("%s: createFillAndTest: about to create \n",name);
area1=vm.createArea(name,pages,(void **)(&addr));
error ("%s: createFillAndTest: create done\n",name);
for (int i=0;i<pages*PAGE_SIZE;i++)
{
if (!(i%9024) )
error ("Writing to byte %d of area %s\n",i,name);
writeByte(addr,i,i%256);
}
error ("%s: createFillAndTest: writing done\n",name);
for (int i=0;i<pages*PAGE_SIZE;i++)
{
if (!(i%9024) )
error ("Reading from byte %d of area %s\n",i,name);
if (i%256!=readByte(addr,i))
error ("ERROR! Byte at offset %d does not match: expected: %d, found: %d\n",i,i%256,readByte(addr,i));
}
error ("%s: createFillAndTest: reading done\n",name);
return area1;
}
catch (const char *t)
{
error ("Exception thrown! %s\n",t);
exit(1);
}
catch (...)
{
error ("Exception thrown!\n");
exit(1);
}
return 0;
}
int main(int argc,char **argv)
{
error ("Starting Threads!\n");
createFillAndTest(1,"myTest");
return 0;
}

View File

@ -13,13 +13,18 @@ class swapFileManager {
sem_id lockFreeList;
public:
// Constructors and Destructors and related
swapFileManager (void);
vnode &findNode(void); // Get an unused node
void freeVNode(vnode &); // Free a node
// Mutators
vnode &findNode(void); // Get an unused node
void write_block(vnode &node,void *loc,unsigned long size);
void read_block(vnode &node,void *loc,unsigned long size);
void lock() {acquire_sem(lockFreeList);}
void unlock() {release_sem(lockFreeList);}
// Accessors
int getFD(void) {return swapFile;}
};
#endif

View File

@ -39,18 +39,8 @@ int createFillAndTest(int pages,char *name)
}
catch (const char *t)
{
vm.suspendAll();
thread_id me=find_thread(NULL);
suspend_thread(clone1);
suspend_thread(mmap1);
suspend_thread(info1);
if (loop1!=me)
suspend_thread(loop1);
if (loop2!=me)
suspend_thread(loop2);
if (loop3!=me)
suspend_thread(loop3);
debugger(t);
error ("Exception thrown! %s\n",t);
exit(1);
}
catch (...)
{
@ -87,6 +77,11 @@ int32 loopTest(void *parameters)
snooze(params->loopSnooze);
}
}
catch (const char *t)
{
error ("Exception thrown! %s\n",t);
exit(1);
}
catch (...)
{
error ("Exception thrown!\n");
@ -125,6 +120,11 @@ int32 getInfoTest(void *parameters)
snooze(params->loopSnooze);
}
}
catch (const char *t)
{
error ("Exception thrown! %s\n",t);
exit(1);
}
catch (...)
{
error ("Exception thrown!\n");
@ -160,6 +160,11 @@ int32 mmapTest (void *parameters)
error ("Closed file, fd = %d\n",fd);
}
}
catch (const char *t)
{
error ("Exception thrown! %s\n",t);
exit(1);
}
catch (...)
{
error ("Exception thrown!\n");
@ -207,9 +212,10 @@ int main(int argc,char **argv)
loopTestParameters mmap1Params={"mmap",500000,8192,400000,1000000};
loopTestParameters clone1Params={"clone1",200000,2,300000,400000};
resume_thread(loop1=spawn_thread(loopTest,"area test 1",0,&area1Params));
resume_thread(loop2=spawn_thread(loopTest,"area test 2",0,&area2Params));
resume_thread(loop3=spawn_thread(loopTest,"area test 3",0,&area3Params));
error ("Starting Threads!\n");
//resume_thread(loop1=spawn_thread(loopTest,"area test 1",0,&area1Params));
//resume_thread(loop2=spawn_thread(loopTest,"area test 2",0,&area2Params));
//resume_thread(loop3=spawn_thread(loopTest,"area test 3",0,&area3Params));
resume_thread(info1=spawn_thread(getInfoTest,"info test 1",0,&info1Params));
//resume_thread(mmap1=spawn_thread(mmapTest,"mmap test 1",0,&mmap1Params));
//resume_thread(clone1=spawn_thread(cloneTest,"clone test 1",0,&clone1Params));

View File

@ -3,6 +3,8 @@
#ifndef _VM_TYPES
#define _VM_TYPES
const int PAGE_SIZE = 4096;
const int BITS_IN_PAGE_SIZE = 12;
const int AREA_HASH_TABLE_SIZE = 40;
struct vnode : public node
{
int fd;

View File

@ -73,7 +73,7 @@ vmInterface::vmInterface(int pages)
error ("pageManager::pageManager: No memory!\n");
exit(1);
}
//error ("Allocated an area. Address = %x\n",vmBlock);
error ("Allocated an area. Address = %x\n",vmBlock);
// Figure out how many pages we need
int pageCount = (sizeof(poolarea)+sizeof(poolvpage)+sizeof(poolvnode)+sizeof(pageManager)+sizeof(swapFileManager)+sizeof(cacheManager)+sizeof(vmHeaderBlock)+PAGE_SIZE-1)/PAGE_SIZE;
if (pageCount >=pages)
@ -81,24 +81,29 @@ vmInterface::vmInterface(int pages)
error ("Hey! Go buy some ram! Trying to create a VM with fewer pages than the setup will take!\n");
exit(1);
}
//error ("Need %d pages, creation calls for %d\n",pageCount,pages);
error ("Need %d pages, creation calls for %d\n",pageCount,pages);
void *currentAddress = addToPointer(vmBlock,sizeof(struct vmHeaderBlock));
vmBlock->pageMan = new (currentAddress) pageManager;
currentAddress=addToPointer(currentAddress,sizeof(pageManager));
vmBlock->pageMan->setup(addToPointer(vmBlock,PAGE_SIZE*pageCount),pages-pageCount);
error ("Set up Page Man\n");
vmBlock->areaPool = new (currentAddress) poolarea;
currentAddress=addToPointer(currentAddress,sizeof(poolarea));
vmBlock->vpagePool = new (currentAddress) poolvpage;
currentAddress=addToPointer(currentAddress,sizeof(poolvpage));
vmBlock->vnodePool = new (currentAddress) poolvnode;
currentAddress=addToPointer(currentAddress,sizeof(poolvnode));
vmBlock->pageMan = new (currentAddress) pageManager;
currentAddress=addToPointer(currentAddress,sizeof(pageManager));
vmBlock->swapMan = new (currentAddress) swapFileManager;
currentAddress=addToPointer(currentAddress,sizeof(swapFileManager));
vmBlock->cacheMan = new (currentAddress) cacheManager;
currentAddress=addToPointer(currentAddress,sizeof(cacheManager));
//error ("Need %d pages, creation calls for %d\n",pageCount,pages);
//error ("vmBlock is at %x, end of structures is at %x, pageMan called with address %x, pages = %d\n",vmBlock,currentAddress,addToPointer(vmBlock,PAGE_SIZE*pageCount),pages-pageCount);
vmBlock->pageMan->setup(addToPointer(vmBlock,PAGE_SIZE*pageCount),pages-pageCount);
error ("Need %d pages, creation calls for %d\n",pageCount,pages);
error ("vmBlock is at %x, end of structures is at %x, pageMan called with address %x, pages = %d\n",vmBlock,currentAddress,addToPointer(vmBlock,PAGE_SIZE*pageCount),pages-pageCount);
}
else
{
error ("Area found!\n");
}
resume_thread(tid_cleaner=spawn_thread(cleanerThread,"cleanerThread",0,(vmBlock->pageMan)));
resume_thread(tid_saver=spawn_thread(saverThread,"saverThread",0,getAM()));
@ -214,10 +219,3 @@ status_t vmInterface::munmap(void *addr, size_t len)
retVal = getAM()->munmap(addr,len);
return retVal;
}
void vmInterface::suspendAll(void)
{
suspend_thread(tid_cleaner);
suspend_thread(tid_saver);
suspend_thread(tid_pager);
}

View File

@ -33,6 +33,5 @@ class vmInterface // This is the class that "owns" all of the managers.
void setByte(unsigned long offset,char value) {getAM()->setByte(offset,value);} // This is for testing only
int getInt(unsigned long offset) {return getAM()->getInt(offset);} // This is for testing only
void setInt(unsigned long offset,int value) {getAM()->setByte(offset,value);} // This is for testing only
void suspendAll(void);
thread_id tid_cleaner,tid_saver,tid_pager;
};

View File

@ -0,0 +1,18 @@
#include <vnodeManager.h>
vpage *vnodeManager::findVnode(vnode &target)
{
managedVnode *found=vnodes.find(&target);
if (found==NULL)
return NULL;
else
return found->pages.peek();
}
void vnodeManager::addVnode(vnode &target,vpage &vp)
{
// Allocate space for a managed vnode
managedVnode *mv = NULL; // Fill this in later - maybe another pool?
mv->node=&target;
mv->pages.add(&vp);
}

View File

@ -0,0 +1,33 @@
#include <hashTable.h>
// vnode manager tracks which vnodes are already mapped to pages
// and facilitates sharing of memory containing the same disk space.
struct managedVnode
{
vnode *node;
list pages; // Hold the list of vpages that this vnode points to
};
ulong mnHash (node &vnodule) { return ((managedNode &)vnodule).node->fd; }
bool mnIsEqual (node &vnodule1,&vnodule2) {
managedNode &v1= ((managedNode &)vnodule1);
managedNode &v2= ((managedNode &)vnodule2);
return v1.node->fd==v2.node->fd && v1.node->offset==v2.node->offset;
}
class vnodeManager
{
public:
vnodeManager(void) : vnodes(20)
{
vnodes.setHash(mnHash);
vnodes.setIsEqual(mnIsEqual);
}
vpage *findVnode(vnode &target); // pass in a vnode, get back the "master" vpage
void addVnode (vnode &target, vpage &vp);
private:
hashTable vnodes;
}

View File

@ -8,10 +8,8 @@
extern vmHeaderBlock *vmBlock;
void vpage::flush(void)
{
if (protection==writable && dirty)
{
void vpage::flush(void) {
if (protection==writable && dirty) {
//error (vpage::write_block: writing, backingNode->fd = %d, backingNode->offset = %d, address = %x\n",backingNode->fd, backingNode->offset,loc);
if (-1==lseek(backingNode->fd,backingNode->offset,SEEK_SET))
error ("vpage::flush:seek failed, fd = %d, errno = %d, %s\n",backingNode->fd,errno,strerror(errno));
@ -22,8 +20,7 @@ void vpage::flush(void)
}
}
void vpage::refresh(void)
{
void vpage::refresh(void) {
if (backingNode->valid==false)
return; // Do nothing. This prevents "garbage" data on disk from being read in...
//error ("vpage::refresh: reading, backingNode->fd = %d, backingNode->offset = %d into %x\n",backingNode->fd, backingNode->offset,loc);
@ -33,27 +30,19 @@ void vpage::refresh(void)
error ("vpage::refresh: failed, fd = %d, errno = %d, %s\n",backingNode->fd,errno,strerror(errno));
}
vpage::vpage(void)
vpage::vpage(void) : physPage(NULL),backingNode(NULL),protection(none),dirty(false),swappable(false),start_address(0),end_address(0)
{
physPage=NULL;
backingNode=NULL;
protection=none;
dirty=false;
swappable=false;
start_address=end_address=0;
}
// backing and/or physMem can be NULL/0.
void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state)
{
//error ("vpage::vpage: start = %x, vnode.fd=%d, vnode.offset=%d, physMem = %x\n",start,((backing)?backing->fd:0),((backing)?backing->offset:0), ((physMem)?(physMem->getAddress()):0));
void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state) {
error ("vpage::setup: start = %x, vnode.fd=%d, vnode.offset=%d, physMem = %x\n",start,((backing)?backing->fd:0),((backing)?backing->offset:0), ((physMem)?(physMem->getAddress()):0));
start_address=start;
end_address=start+PAGE_SIZE-1;
protection=prot;
swappable=(state==NO_LOCK);
if (backing)
{
if (backing) {
backingNode=backing;
atomic_add(&(backing->count),1);
}
@ -61,47 +50,40 @@ void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType
backingNode=&(vmBlock->swapMan->findNode());
if (!physMem && (state!=LAZY) && (state!=NO_LOCK))
physPage=vmBlock->pageMan->getPage();
else
{
else {
if (physMem)
atomic_add(&(physMem->count),1);
physPage=physMem;
}
dirty=false;
//error ("vpage::vpage: ended : start = %x, vnode.fd=%d, vnode.offset=%d, physMem = %x\n",start,((backing)?backing->fd:0),((backing)?backing->offset:0), ((physMem)?(physMem->getAddress()):0));
error ("vpage::setup: ended : start = %x, vnode.fd=%d, vnode.offset=%d, physMem = %x\n",start,((backing)?backing->fd:0),((backing)?backing->offset:0), ((physMem)?(physMem->getAddress()):0));
}
void vpage::cleanup(void)
{
void vpage::cleanup(void) {
if (physPage) // Note that free means release one reference
vmBlock->pageMan->freePage(physPage);
if (backingNode)
{
if (backingNode) {
if (backingNode->fd)
if (backingNode->fd==vmBlock->swapMan->getFD())
vmBlock->swapMan->freeVNode(*backingNode);
else
{
if ( atomic_add(&(backingNode->count),-1)==1)
vmBlock->vnodePool->put(backingNode);
}
}
}
void vpage::setProtection(protectType prot)
{
void vpage::setProtection(protectType prot) {
protection=prot;
// Change the hardware
}
bool vpage::fault(void *fault_address, bool writeError) // true = OK, false = panic.
{ // This is dispatched by the real interrupt handler, who locates us
// This is dispatched by the real interrupt handler, who locates us
// true = OK, false = panic.
bool vpage::fault(void *fault_address, bool writeError) {
error ("vpage::fault: virtual address = %lx, write = %s\n",(unsigned long) fault_address,((writeError)?"true":"false"));
if (writeError && physPage)
{
if (writeError && physPage) {
dirty=true;
if (protection==copyOnWrite) // Else, this was just a "let me know when I am dirty"...
{
if (protection==copyOnWrite) { // Else, this was just a "let me know when I am dirty"...
page *newPhysPage=vmBlock->pageMan->getPage();
if (!newPhysPage) // No room at the inn
return false;
@ -128,18 +110,16 @@ bool vpage::fault(void *fault_address, bool writeError) // true = OK, false = pa
return true;
}
char vpage::getByte(unsigned long address,areaManager *manager)
{
//error ("vpage::getByte: address = %ld\n",address );
char vpage::getByte(unsigned long address,areaManager *manager) {
// error ("vpage::getByte: address = %ld\n",address );
if (!physPage)
if (!manager->fault((void *)(address),false))
throw ("vpage::getByte");
//error ("vpage::getByte: About to return %d\n", *((char *)(address-start_address+physPage->getAddress())));
// error ("vpage::getByte: About to return %d\n", *((char *)(address-start_address+physPage->getAddress())));
return *((char *)(address-start_address+physPage->getAddress()));
}
void vpage::setByte(unsigned long address,char value,areaManager *manager)
{
void vpage::setByte(unsigned long address,char value,areaManager *manager) {
// error ("vpage::setByte: address = %d, value = %d\n",address, value);
if (!physPage)
if (!manager->fault((void *)(address),true))
@ -148,8 +128,7 @@ void vpage::setByte(unsigned long address,char value,areaManager *manager)
// error ("vpage::setByte: physical address = %d, value = %d\n",physPage->getAddress(), *((char *)(physPage->getAddress())));
}
int vpage::getInt(unsigned long address,areaManager *manager)
{
int vpage::getInt(unsigned long address,areaManager *manager) {
error ("vpage::getInt: address = %ld\n",address );
if (!physPage)
if (!manager->fault((void *)(address),false))
@ -159,22 +138,19 @@ int vpage::getInt(unsigned long address,areaManager *manager)
return *((int *)(address-start_address+physPage->getAddress()));
}
void vpage::setInt(unsigned long address,int value,areaManager *manager)
{
void vpage::setInt(unsigned long address,int value,areaManager *manager) {
if (!physPage)
if (!manager->fault((void *)(address),true))
throw ("vpage::setInt");
*((int *)(address-start_address+physPage->getAddress()))=value;
}
void vpage::pager(int desperation)
{
void vpage::pager(int desperation) {
//error ("vpage::pager start desperation = %d\n",desperation);
if (!swappable)
return;
error ("vpage::pager swappable\n");
switch (desperation)
{
switch (desperation) {
case 1: return; break;
case 2: if (!physPage || protection!=readable) return;break;
case 3: if (!physPage || dirty) return;break;
@ -190,8 +166,7 @@ void vpage::pager(int desperation)
physPage=NULL;
}
void vpage::saver(void)
{
void vpage::saver(void) {
if (dirty)
flush();
dirty=false;

View File

@ -16,27 +16,37 @@ class vpage : public node
unsigned long start_address;
unsigned long end_address;
public:
bool isMapped(void) {return (physPage);}
bool contains(uint32 address) { return ((start_address<=address) && (end_address>=address)); }
void flush(void); // write page to vnode, if necessary
void refresh(void); // Read page back in from vnode
// Constructors and Destructors and related
vpage(void);
vpage(unsigned long address) {start_address=address-address%PAGE_SIZE;end_address=start_address+PAGE_SIZE-1;} // Only for lookups
// Setup should now only be called by the vpage manager...
void setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state); // backing and/or physMem can be NULL/0.
void cleanup(void);
// Mutators
void setProtection(protectType prot);
void flush(void); // write page to vnode, if necessary
void refresh(void); // Read page back in from vnode
// Accessors
protectType getProtection(void) {return protection;}
void *getStartAddress(void) {return (void *)start_address;}
page *getPhysPage(void) {return physPage;}
vnode *getBacking(void) {return backingNode;}
bool isMapped(void) {return (physPage);}
// Comparisson with others
ulong hash(void) {return start_address >> BITS_IN_PAGE_SIZE;}
bool operator==(vpage &rhs) {return rhs.start_address==start_address && rhs.end_address==end_address;}
bool contains(uint32 address) { return ((start_address<=address) && (end_address>=address)); }
// External methods for "server" type calls
bool fault(void *fault_address, bool writeError); // true = OK, false = panic.
void pager(int desperation);
void saver(void);
void dump(void)
{
// Debugging
void dump(void) {
error ("Dumping vpage %p, address = %lx, physPage: \n",this,start_address);
if (physPage)
physPage->dump();

View File

@ -7,13 +7,11 @@ class poolvpage
list unused;
sem_id inUse;
public:
poolvpage(void)
{
poolvpage(void) {
inUse = create_sem(1,"vpagepool");
}
vpage *get(void);
void put(vpage *in)
{
void put(vpage *in) {
acquire_sem(inUse);
unused.add((node *)in);
release_sem(inUse);