diff --git a/src/kernel/vm2/Jamfile b/src/kernel/vm2/Jamfile index 6da6705b06..6491ae4e43 100644 --- a/src/kernel/vm2/Jamfile +++ b/src/kernel/vm2/Jamfile @@ -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 ; diff --git a/src/kernel/vm2/area.C b/src/kernel/vm2/area.C index 9f50e47dd7..6acc6e625a 100644 --- a/src/kernel/vm2/area.C +++ b/src/kernel/vm2/area.C @@ -9,29 +9,24 @@ extern vmHeaderBlock *vmBlock; -bool vpageIsLessThan(void *a,void *b) -{ - return (((reinterpret_cast(a))->getStartAddress()) < (reinterpret_cast(b))->getStartAddress()); -} +ulong vpageHash (node &vp) {return reinterpret_cast (vp).hash();} +bool vpageisEqual (node &vp,node &vp2) {return reinterpret_cast (vp)==reinterpret_cast (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;ivpagePool->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(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;ivpagePool->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;inext;cur=cur->next); // INTENTIONAL - find the last one; - oldPage=(vpage *)cur; + for (int i=0;i(cur))->getStartAddress()) > maxAddress) { + maxAddress=curAddress; + max=cur; + } + oldPage=reinterpret_cast(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 (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; diff --git a/src/kernel/vm2/area.h b/src/kernel/vm2/area.h index abd5349a5d..d92a64b5b9 100644 --- a/src/kernel/vm2/area.h +++ b/src/kernel/vm2/area.h @@ -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 ((endend_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 ((endend_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 diff --git a/src/kernel/vm2/areaManager.C b/src/kernel/vm2/areaManager.C index f2b52bff26..2b92b2eee1 100644 --- a/src/kernel/vm2/areaManager.C +++ b/src/kernel/vm2/areaManager.C @@ -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(); } diff --git a/src/kernel/vm2/areaManager.h b/src/kernel/vm2/areaManager.h index a34b36db5a..be2f097e6d 100644 --- a/src/kernel/vm2/areaManager.h +++ b/src/kernel/vm2/areaManager.h @@ -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 diff --git a/src/kernel/vm2/areaPool.h b/src/kernel/vm2/areaPool.h index 36c587cfae..f8840a91ab 100644 --- a/src/kernel/vm2/areaPool.h +++ b/src/kernel/vm2/areaPool.h @@ -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); diff --git a/src/kernel/vm2/cacheManager.C b/src/kernel/vm2/cacheManager.C index 2ca2896387..f2d29f33ba 100644 --- a/src/kernel/vm2/cacheManager.C +++ b/src/kernel/vm2/cacheManager.C @@ -3,49 +3,49 @@ #include #include "vmHeaderBlock.h" -bool cacheMemberIsLessThan(void *a,void *b) -{ - vnode *v1 = reinterpret_cast(a)->vn; - vnode *v2 = reinterpret_cast(b)->vn; - if (v1->fd < v2->fd) - return true; - if ((v1->fd==v2->fd) && (v1->offsetoffset)) - return true; - return false; -} +ulong vnodeHash (node &vp) {vnode &vn=reinterpret_cast (vp); return vn.offset+vn.fd;} +bool vnodeisEqual (node &vp,node &vp2) { + vnode &vn=reinterpret_cast (vp); + vnode &vn2=reinterpret_cast (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(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(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 (vpages.rock));!foundSpot && cur;cur=reinterpret_cast (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); diff --git a/src/kernel/vm2/cacheManager.h b/src/kernel/vm2/cacheManager.h index 3ba9652e60..888169810d 100644 --- a/src/kernel/vm2/cacheManager.h +++ b/src/kernel/vm2/cacheManager.h @@ -2,7 +2,7 @@ #include #include #include -#include +#include 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 }; diff --git a/src/kernel/vm2/error.C b/src/kernel/vm2/error.C index 315f45a4c3..81c04ab8e2 100644 --- a/src/kernel/vm2/error.C +++ b/src/kernel/vm2/error.C @@ -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); diff --git a/src/kernel/vm2/hashTable.h b/src/kernel/vm2/hashTable.h index 65e42c3454..5020ae5c35 100644 --- a/src/kernel/vm2/hashTable.h +++ b/src/kernel/vm2/hashTable.h @@ -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;irock;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;iensureSane(); - 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;irock;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;iensureSane(); + 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 && buckettop(); + 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 diff --git a/src/kernel/vm2/hashTest.C b/src/kernel/vm2/hashTest.C index 6778b8e85e..0498457367 100644 --- a/src/kernel/vm2/hashTest.C +++ b/src/kernel/vm2/hashTest.C @@ -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; } diff --git a/src/kernel/vm2/list.h b/src/kernel/vm2/list.h index cbcb8424cd..43898f9c69 100644 --- a/src/kernel/vm2/list.h +++ b/src/kernel/vm2/list.h @@ -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 diff --git a/src/kernel/vm2/olist.h b/src/kernel/vm2/olist.h index 58dd075ac2..f12fc9b7cd 100644 --- a/src/kernel/vm2/olist.h +++ b/src/kernel/vm2/olist.h @@ -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; diff --git a/src/kernel/vm2/page.h b/src/kernel/vm2/page.h index 1ba523d017..704353a31f 100644 --- a/src/kernel/vm2/page.h +++ b/src/kernel/vm2/page.h @@ -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 diff --git a/src/kernel/vm2/pageManTest.C b/src/kernel/vm2/pageManTest.C new file mode 100644 index 0000000000..86bf52062c --- /dev/null +++ b/src/kernel/vm2/pageManTest.C @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#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); +} diff --git a/src/kernel/vm2/pageManager.C b/src/kernel/vm2/pageManager.C index 5cc6028fb3..1270db2c00 100644 --- a/src/kernel/vm2/pageManager.C +++ b/src/kernel/vm2/pageManager.C @@ -3,26 +3,19 @@ #include #include -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;isetup(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 (countgetAddress(); - 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; diff --git a/src/kernel/vm2/pageManager.h b/src/kernel/vm2/pageManager.h index e5fe7ef08c..aeab133ce9 100644 --- a/src/kernel/vm2/pageManager.h +++ b/src/kernel/vm2/pageManager.h @@ -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; diff --git a/src/kernel/vm2/pools.h b/src/kernel/vm2/pools.h index dd8d4ed847..b11164baa1 100644 --- a/src/kernel/vm2/pools.h +++ b/src/kernel/vm2/pools.h @@ -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); } - }; */ diff --git a/src/kernel/vm2/simpleTest.C b/src/kernel/vm2/simpleTest.C new file mode 100644 index 0000000000..a48672a182 --- /dev/null +++ b/src/kernel/vm2/simpleTest.C @@ -0,0 +1,57 @@ +#include "vmInterface.h" +#include +#include +#include +#include +#include + +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;iloopSnooze); } } + 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)); diff --git a/src/kernel/vm2/vm.h b/src/kernel/vm2/vm.h index 5613ad783b..9b1ecdc46b 100644 --- a/src/kernel/vm2/vm.h +++ b/src/kernel/vm2/vm.h @@ -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; diff --git a/src/kernel/vm2/vmInterface.C b/src/kernel/vm2/vmInterface.C index 42e0747d80..3e4e87d478 100644 --- a/src/kernel/vm2/vmInterface.C +++ b/src/kernel/vm2/vmInterface.C @@ -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); -} diff --git a/src/kernel/vm2/vmInterface.h b/src/kernel/vm2/vmInterface.h index ce61801b30..e6e17d199e 100644 --- a/src/kernel/vm2/vmInterface.h +++ b/src/kernel/vm2/vmInterface.h @@ -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; }; diff --git a/src/kernel/vm2/vnodeManager.C b/src/kernel/vm2/vnodeManager.C new file mode 100644 index 0000000000..68a093b246 --- /dev/null +++ b/src/kernel/vm2/vnodeManager.C @@ -0,0 +1,18 @@ +#include + +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); +} diff --git a/src/kernel/vm2/vnodeManager.h b/src/kernel/vm2/vnodeManager.h new file mode 100644 index 0000000000..da197b8cff --- /dev/null +++ b/src/kernel/vm2/vnodeManager.h @@ -0,0 +1,33 @@ +#include + +// 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; +} diff --git a/src/kernel/vm2/vpage.C b/src/kernel/vm2/vpage.C index 07b187ccdd..f15e23d6c8 100644 --- a/src/kernel/vm2/vpage.C +++ b/src/kernel/vm2/vpage.C @@ -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; diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h index 00b1825ab1..d73ef8cf63 100644 --- a/src/kernel/vm2/vpage.h +++ b/src/kernel/vm2/vpage.h @@ -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(); diff --git a/src/kernel/vm2/vpagePool.h b/src/kernel/vm2/vpagePool.h index 6d3a5c9a1b..3a04c824fb 100644 --- a/src/kernel/vm2/vpagePool.h +++ b/src/kernel/vm2/vpagePool.h @@ -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);