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:
parent
c773cf76b7
commit
bc6600175c
@ -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 ;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
102
src/kernel/vm2/pageManTest.C
Normal file
102
src/kernel/vm2/pageManTest.C
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
};
|
||||
*/
|
||||
|
57
src/kernel/vm2/simpleTest.C
Normal file
57
src/kernel/vm2/simpleTest.C
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
|
18
src/kernel/vm2/vnodeManager.C
Normal file
18
src/kernel/vm2/vnodeManager.C
Normal 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=⌖
|
||||
mv->pages.add(&vp);
|
||||
}
|
33
src/kernel/vm2/vnodeManager.h
Normal file
33
src/kernel/vm2/vnodeManager.h
Normal 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;
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user