diff --git a/src/kernel/vm2/Jamfile b/src/kernel/vm2/Jamfile index 3c7d75dc5a..6428bd539f 100644 --- a/src/kernel/vm2/Jamfile +++ b/src/kernel/vm2/Jamfile @@ -1,9 +1,4 @@ SubDir OBOS_TOP src kernel vm2 ; -C++FLAGS += -g ; -CCFLAGS += -g ; - -Server vmTest : area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C test.C vmInterface.C vpage.C ; - -LinkSharedOSLibs vmTest : root be ; +BinCommand vmTest : area.C areaManager.C cacheManager.C page.C pageManager.C swapFileManager.C test.C vmInterface.C vpage.C : root be ; diff --git a/src/kernel/vm2/TODO b/src/kernel/vm2/TODO index 23acb7a292..e7e0ec548b 100644 --- a/src/kernel/vm2/TODO +++ b/src/kernel/vm2/TODO @@ -1,16 +1,16 @@ 1) Need to make the paging daemon load the pages in, using semaphores. 2) See how unresolvable page faults and permissions errors are handled - need to properly handle -3) Implment cloneArea -4) Tests are not done. +3) Tests are not done. Test: - getAreaInfo getNextAreaInfo cloneArea resizeArea setAreaProtection - mmap + mmap / munmap paging + disk caching -5) Improve locking (remains to be seen - works ok so far) -6) I use new and delete. I know that doesn't work in kernel land. Not too tough to change, though. -7) There is no arch-level integration. This is to be tested (to death) in user land first. * == can not be done in user land. +4) Improve locking (remains to be seen - works ok so far) +5) I use new and delete. I know that doesn't work in kernel land. Not too tough to change, though. + - Pooling is now used for everything but pages +6) There is no arch-level integration. This is to be tested (to death) in user land first. * == can not be done in user land. diff --git a/src/kernel/vm2/area.C b/src/kernel/vm2/area.C index 5003c3b658..62f705b858 100644 --- a/src/kernel/vm2/area.C +++ b/src/kernel/vm2/area.C @@ -1,8 +1,17 @@ #include "area.h" #include "areaManager.h" #include "vpage.h" +#include "vpagePool.h" +#include "vnodePool.h" -area::area (areaManager *myManager) +extern poolvpage vpagePool; +extern poolvnode vnodePool; + +area::area(void) + { + } + +void area::setup (areaManager *myManager) { manager=myManager; } @@ -43,11 +52,12 @@ status_t area::createAreaMappingFile(char *inName, int pageCount,void **address, unsigned long base=mapAddressSpecToAddress(type,requested,pageCount); for (int i=0;ifd=fd; newVnode->offset=offset+PAGE_SIZE*i; newVnode->valid=true; - newPage = new vpage(base+PAGE_SIZE*i,newVnode,NULL,protect,inState); + newPage=vpagePool.get(); + newPage->setup(base+PAGE_SIZE*i,newVnode,NULL,protect,inState); vpages.add(newPage); // printf ("New vnode with fd %d, offset = %d\n",fd,newVnode->offset); } @@ -76,7 +86,8 @@ status_t area::createArea(char *inName, int pageCount,void **address, addressSpe for (int i=0;isetup(base+PAGE_SIZE*i,NULL,NULL,protect,inState); vpages.add(newPage); } manager->unlock(); @@ -107,7 +118,8 @@ status_t area::cloneArea(area *origArea, char *inName, void **address, addressSp { vpage *newPage,*page=(vpage *)cur; // Cloned area has the same physical page and backing store... - newPage = new vpage(base,page->getBacking(),page->getPhysPage(),protect,inState); + newPage=vpagePool.get(); + newPage->setup(base,page->getBacking(),page->getPhysPage(),protect,inState); vpages.add(newPage); base+=PAGE_SIZE; cur=cur->next; @@ -124,23 +136,25 @@ status_t area::cloneArea(area *origArea, char *inName, void **address, addressSp void area::freeArea(void) { - //printf ("area::freeArea: starting \n"); +//printf ("area::freeArea: starting \n"); manager->lock(); // vpages.dump(); - for (struct node *cur=vpages.rock;cur;) + node *cur; + while (cur=vpages.next()) { - //printf ("area::freeArea: wasting a page: %x\n",cur); - vpage *page=(vpage *)cur; +//printf ("area::freeArea: wasting a page: %x\n",cur); + vpage *page=reinterpret_cast(cur); if (finalWrite) page->flush(); - //printf ("area::freeArea: flushed a page \n"); - cur=cur->next; - delete page; // Probably need to add a destructor +//printf ("area::freeArea: flushed a page \n"); + page->cleanup(); + //page->next=NULL; + vpagePool.put(page); } - //printf ("area::freeArea: unlocking \n"); +//printf ("area::freeArea: unlocking \n"); manager->unlock(); - //printf ("area::freeArea: ending \n"); +//printf ("area::freeArea: ending \n"); } status_t area::getInfo(area_info *dest) @@ -188,7 +202,8 @@ status_t area::resize(size_t newSize) vpage *newPage; for (int i=0;isetup(end_address+PAGE_SIZE*i-1,NULL,NULL,protection,state); vpages.add(newPage); } end_address+=start_address+newSize; @@ -203,7 +218,8 @@ status_t area::resize(size_t newSize) { for (cur=vpages.rock;cur->next;cur=cur->next); // INTENTIONAL - find the last one; vpage *oldPage=(vpage *)cur; - delete oldPage; + oldPage->cleanup(); + vpagePool.put(oldPage); } } manager->unlock(); diff --git a/src/kernel/vm2/area.h b/src/kernel/vm2/area.h index 3e47d94dc0..ad143b711c 100644 --- a/src/kernel/vm2/area.h +++ b/src/kernel/vm2/area.h @@ -24,7 +24,8 @@ class area : public node unsigned long end_address; vpage *findVPage(unsigned long); public: - area(areaManager *myManager); + area(void); + void setup(areaManager *myManager); bool nameMatch(char *matchName) {return (strcmp(matchName,name)==0);} unsigned long mapAddressSpecToAddress(addressSpec type,unsigned long requested,int pageCount); status_t createAreaMappingFile(char *name, int pageCount,void **address, addressSpec type,pageState state,protectType protect,int fd,size_t offset); diff --git a/src/kernel/vm2/areaPool.h b/src/kernel/vm2/areaPool.h new file mode 100644 index 0000000000..4e8eeb6ea8 --- /dev/null +++ b/src/kernel/vm2/areaPool.h @@ -0,0 +1,51 @@ +#include "pageManager.h" + +extern pageManager pageMan; +class poolarea +{ + private: + list unused; + sem_id inUse; + public: + poolarea(void) + { + inUse = create_sem(1,"areapool"); + } + area *get(void) + { + area *ret=NULL; + if (unused.count()) + { + //printf ("poolarea::get: Getting an unused one!\n"); + acquire_sem(inUse); + ret=(area *)unused.next(); + release_sem(inUse); + } + if (ret) + { + //printf ("poolarea::get: Returning address:%x \n",ret); + return ret; + } + else + { + //printf ("poolarea::get: Getting a new page!\n"); + page *newPage=pageMan.getPage(); + if (!newPage) + throw ("Out of pages to allocate a pool!"); + int newCount=PAGE_SIZE/sizeof(area); + acquire_sem(inUse); + //printf ("poolarea::get: Adding %d new elements to the pool!\n",newCount); + for (int i=0;igetAddress()+(i*sizeof(area))))); + release_sem(inUse); + return (get()); // A little cheat - call self again to get the first one from stack... + } + } + void put(area *in) + { + acquire_sem(inUse); + unused.add(in); + release_sem(inUse); + } + +}; diff --git a/src/kernel/vm2/cacheManager.C b/src/kernel/vm2/cacheManager.C index d7f41a25c2..1ac64504d4 100644 --- a/src/kernel/vm2/cacheManager.C +++ b/src/kernel/vm2/cacheManager.C @@ -1,6 +1,9 @@ #include +#include -cacheManager::cacheManager(void) : area (NULL) +extern poolvpage vpagePool; + +cacheManager::cacheManager(void) : area () { myLock=create_sem(1,"Area Manager Semaphore"); // Should have team name in it. } @@ -33,7 +36,8 @@ void *cacheManager::createBlock(vnode *target,bool readOnly) } lock(); // Create a vnode here - vpage *newPage = new vpage(begin,target,NULL,((readOnly)?readable:writable),NO_LOCK); + vpage *newPage = vpagePool.get(); + newPage->setup(begin,target,NULL,((readOnly)?readable:writable),NO_LOCK); vpages.add(newPage); cacheMembers.add(newPage); unlock(); diff --git a/src/kernel/vm2/pools.h b/src/kernel/vm2/pools.h new file mode 100644 index 0000000000..b9b38b83ab --- /dev/null +++ b/src/kernel/vm2/pools.h @@ -0,0 +1,55 @@ +#include "pageManager.h" + +extern pageManager pageMan; +/* This is the template + * replace TYPE with the type you need a pool for + * +class poolTYPE +{ + private: + list unused; + sem_id inUse; + public: + poolTYPE(void) + { + inUse = create_sem(1,"TYPEpool"); + } + TYPE *get(void) + { + TYPE *ret=NULL; + if (unused.count()) + { + printf ("poolTYPE::get: Getting an unused one!\n"); + acquire_sem(inUse); + ret=(TYPE *)unused.next(); + release_sem(inUse); + } + if (ret) + { + printf ("poolTYPE::get: Returning address:%x \n",ret); + return ret; + } + else + { + printf ("poolTYPE::get: Getting a new page!\n"); + page *newPage=pageMan.getPage(); + if (!newPage) + throw ("Out of pages to allocate a pool!"); + int newCount=PAGE_SIZE/sizeof(TYPE); + acquire_sem(inUse); + printf ("poolTYPE::get: Adding %d new elements to the pool!\n",newCount); + for (int i=0;igetAddress()+(i*sizeof(TYPE))))); + release_sem(inUse); + return (get()); // A little cheat - call self again to get the first one from stack... + } + } + void put(TYPE *in) + { + acquire_sem(inUse); + unused.add(in); + release_sem(inUse); + } + +}; +*/ diff --git a/src/kernel/vm2/swapFileManager.C b/src/kernel/vm2/swapFileManager.C index f72fdffc0c..d51002900f 100644 --- a/src/kernel/vm2/swapFileManager.C +++ b/src/kernel/vm2/swapFileManager.C @@ -2,6 +2,9 @@ #include #include #include +#include + +extern poolvnode vnodePool; swapFileManager::swapFileManager(void) { @@ -44,7 +47,7 @@ vnode &swapFileManager::findNode(void) Unlock(); if (!newNode) { - newNode=new vnode; + newNode=vnodePool.get(); newNode->fd=swapFile; newNode->offset=maxNode+=PAGE_SIZE; //printf (" New One: %d\n",newNode->offset); diff --git a/src/kernel/vm2/swapFileManager.h b/src/kernel/vm2/swapFileManager.h index e70ea8178e..1b0331393a 100644 --- a/src/kernel/vm2/swapFileManager.h +++ b/src/kernel/vm2/swapFileManager.h @@ -1,3 +1,5 @@ +#ifndef _SWAPFILE_MANAGER +#define _SWAPFILE_MANAGER #include #include #include "vm.h" @@ -19,3 +21,4 @@ class swapFileManager { void Lock() {acquire_sem(lockFreeList);} void Unlock() {release_sem(lockFreeList);} }; +#endif diff --git a/src/kernel/vm2/test.C b/src/kernel/vm2/test.C index 4d62637790..c23ce611fe 100644 --- a/src/kernel/vm2/test.C +++ b/src/kernel/vm2/test.C @@ -94,8 +94,6 @@ int32 getInfoTest(void *parameters) int32 mmapTest (void *parameters) { void *map; - - loopTestParameters *params=((loopTestParameters *)parameters); int size=params->areaSize; // Note that this is in bytes, not in pages while (1) @@ -109,9 +107,11 @@ int32 mmapTest (void *parameters) printf ("mmap address = %x\n",map); for (int i=0;iloopSnooze); vm.munmap(map,size); close(fd); diff --git a/src/kernel/vm2/vmInterface.C b/src/kernel/vm2/vmInterface.C index c0481e7b2f..f9e0f3c48d 100644 --- a/src/kernel/vm2/vmInterface.C +++ b/src/kernel/vm2/vmInterface.C @@ -2,10 +2,16 @@ //#include "areaManager.h" #include "mman.h" #include "area.h" +#include "areaPool.h" +#include "vpagePool.h" +#include "vnodePool.h" areaManager am; swapFileManager swapMan; -pageManager pageMan(10); // Obviously this hard coded number is a hack... +poolarea areaPool; +poolvpage vpagePool; +poolvnode vnodePool; +pageManager pageMan(30); // Obviously this hard coded number is a hack... areaManager *vmInterface::getAM(void) { @@ -79,7 +85,8 @@ status_t vmInterface::resizeArea(int Area,size_t size) int vmInterface::createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect) { - area *newArea = new area(getAM()); + area *newArea = areaPool.get(); + newArea->setup(getAM()); newArea->createArea(AreaName,pageCount,address,addType,state,protect); newArea->setAreaID(nextAreaID++); // THIS IS NOT THREAD SAFE getAM()->addArea(newArea); @@ -93,14 +100,14 @@ void vmInterface::freeArea(int Area) //printf ("vmInterface::freeArea: found area %x\n",oldArea); if (oldArea) { - //printf ("vmInterface::freeArea: removing area %x from linked list\n",oldArea); - areaManager *foo=getAM(); - //printf ("vmInterface::freeArea: areaManager = %x \n",foo); - foo->removeArea(oldArea); - //printf ("vmInterface::freeArea: deleting area %x \n",oldArea); +// printf ("vmInterface::freeArea: removing area %x from linked list\n",oldArea); + areaManager *manager=getAM(); +// printf ("vmInterface::freeArea: areaManager = %x \n",manager); + manager->removeArea(oldArea); +// printf ("vmInterface::freeArea: deleting area %x \n",oldArea); oldArea->freeArea(); - //printf ("vmInterface::freeArea: freeArea complete \n"); - delete oldArea; +// printf ("vmInterface::freeArea: freeArea complete \n"); + areaPool.put(oldArea); } else printf ("vmInterface::freeArea: unable to find requested area\n"); @@ -132,8 +139,9 @@ int vmInterface::getAreaByName(char *name) int vmInterface::cloneArea(int newAreaID,char *AreaName,void **address, addressSpec addType=ANY, pageState state=NO_LOCK, protectType prot=writable) { - area *newArea = new area(getAM()); - area *oldArea=getAM()->findArea(newAreaID); + area *newArea = areaPool.get(); + newArea->setup(getAM()); + area *oldArea=getAM()->findArea(newAreaID); newArea->cloneArea(oldArea,AreaName,address,addType,state,prot); newArea->setAreaID(nextAreaID++); // THIS IS NOT THREAD SAFE getAM()->addArea(newArea); @@ -182,7 +190,8 @@ void *vmInterface::mmap(void *addr, size_t len, int prot, int flags, int fd, off return addr; } - area *newArea = new area(getAM()); + area *newArea = areaPool.get(); + newArea->setup(getAM()); //printf ("area = %x, start = %x\n",newArea, newArea->getStartAddress()); newArea->createAreaMappingFile(name,(int)((len+PAGE_SIZE-1)/PAGE_SIZE),&addr,addType,LAZY,protType,fd,offset); newArea->setAreaID(nextAreaID++); // THIS IS NOT THREAD SAFE diff --git a/src/kernel/vm2/vnodePool.h b/src/kernel/vm2/vnodePool.h new file mode 100644 index 0000000000..51c02a11e0 --- /dev/null +++ b/src/kernel/vm2/vnodePool.h @@ -0,0 +1,51 @@ +#include "pageManager.h" + +extern pageManager pageMan; +class poolvnode +{ + private: + list unused; + sem_id inUse; + public: + poolvnode(void) + { + inUse = create_sem(1,"vnodepool"); + } + vnode *get(void) + { + vnode *ret=NULL; + if (unused.count()) + { + //printf ("poolvnode::get: Getting an unused one!\n"); + acquire_sem(inUse); + ret=(vnode *)unused.next(); + release_sem(inUse); + } + if (ret) + { + //printf ("poolvnode::get: Returning address:%x \n",ret); + return ret; + } + else + { + //printf ("poolvnode::get: Getting a new page!\n"); + page *newPage=pageMan.getPage(); + if (!newPage) + throw ("Out of pages to allocate a pool!"); + int newCount=PAGE_SIZE/sizeof(vnode); + acquire_sem(inUse); + //printf ("poolvnode::get: Adding %d new elements to the pool!\n",newCount); + for (int i=0;igetAddress()+(i*sizeof(vnode))))); + release_sem(inUse); + return (get()); // A little cheat - call self again to get the first one from stack... + } + } + void put(vnode *in) + { + acquire_sem(inUse); + unused.add(in); + release_sem(inUse); + } + +}; diff --git a/src/kernel/vm2/vpage.C b/src/kernel/vm2/vpage.C index 8a0dd465a3..cc4a85b220 100644 --- a/src/kernel/vm2/vpage.C +++ b/src/kernel/vm2/vpage.C @@ -1,7 +1,9 @@ #include "vpage.h" +#include "vnodePool.h" extern swapFileManager swapMan; extern pageManager pageMan; + extern poolvnode vnodePool; void vpage::flush(void) { @@ -14,8 +16,12 @@ void vpage::refresh(void) swapMan.read_block(*backingNode,((void *)(physPage->getAddress())), PAGE_SIZE); } +vpage::vpage(void) +{ +} + // backing and/or physMem can be NULL/0. -vpage::vpage(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state) +void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state) { //printf ("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)); start_address=start; @@ -42,12 +48,16 @@ vpage::vpage(unsigned long start,vnode *backing, page *physMem,protectType prot, //printf ("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)); } -vpage::~vpage(void) +void vpage::cleanup(void) { if (physPage) // Note that free means release one reference pageMan.freePage(physPage); - if (backingNode->fd) - swapMan.freeVNode(*backingNode); + if (backingNode) + { + if (backingNode->fd) + swapMan.freeVNode(*backingNode); + vnodePool.put(backingNode); + } } void vpage::setProtection(protectType prot) @@ -130,7 +140,7 @@ void vpage::setInt(unsigned long address,int value) void vpage::pager(int desperation) { - printf ("vpage::pager start desperation = %d\n",desperation); + //printf ("vpage::pager start desperation = %d\n",desperation); if (!swappable) return; printf ("vpage::pager swappable\n"); diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h index 35f6a8d05e..3cdda93b7d 100644 --- a/src/kernel/vm2/vpage.h +++ b/src/kernel/vm2/vpage.h @@ -1,3 +1,5 @@ +#ifndef VPAGE_H +#define VPAGE_H #include #include #include @@ -17,8 +19,9 @@ class vpage : public node 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 - vpage(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state); // backing and/or physMem can be NULL/0. - ~vpage(void); + vpage(void); + void setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state); // backing and/or physMem can be NULL/0. + void cleanup(void); void setProtection(protectType prot); protectType getProtection(void) {return protection;} void *getStartAddress(void) {return (void *)start_address;} @@ -43,3 +46,4 @@ class vpage : public node int getInt(unsigned long offset); // This is for testing only void setInt(unsigned long offset,int value); // This is for testing only }; +#endif diff --git a/src/kernel/vm2/vpagePool.h b/src/kernel/vm2/vpagePool.h new file mode 100644 index 0000000000..cd3aa21325 --- /dev/null +++ b/src/kernel/vm2/vpagePool.h @@ -0,0 +1,52 @@ +#include "pageManager.h" +#include "vpage.h" + +extern pageManager pageMan; +class poolvpage +{ + private: + list unused; + sem_id inUse; + public: + poolvpage(void) + { + inUse = create_sem(1,"vpagepool"); + } + vpage *get(void) + { + vpage *ret=NULL; + if (unused.count()) + { + //printf ("poolvpage::get: Getting an unused one!\n"); + acquire_sem(inUse); + ret=(vpage *)unused.next(); + release_sem(inUse); + } + if (ret) + { + //printf ("poolvpage::get: Returning address:%x \n",ret); + return ret; + } + else + { + //printf ("poolvpage::get: Getting a new page!\n"); + page *newPage=pageMan.getPage(); + if (!newPage) + throw ("Out of pages to allocate a pool!"); + int newCount=PAGE_SIZE/sizeof(vpage); + acquire_sem(inUse); + //printf ("poolvpage::get: Adding %d new elements to the pool!\n",newCount); + for (int i=0;igetAddress()+(i*sizeof(vpage))))); + release_sem(inUse); + return (get()); // A little cheat - call self again to get the first one from stack... + } + } + void put(vpage *in) + { + acquire_sem(inUse); + unused.add(in); + release_sem(inUse); + } + +};