Many bug fixes and changes.

Also added "locked list" - a semaphore protected list derived from list.h.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2851 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Phipps 2003-02-27 04:41:44 +00:00
parent 7c9135c008
commit a48062f5fa
18 changed files with 100 additions and 77 deletions

View File

@ -180,42 +180,35 @@ status_t area::getInfo(area_info *dest) {
bool area::contains(const 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)));
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));
}
// Resize an area.
status_t area::resize(size_t newSize) {
size_t oldSize =end_address-start_address;
size_t oldSize =end_address-start_address+1;
// Duh. Nothing to do.
if (newSize==oldSize)
return B_OK;
// Grow the area. Figure out how many pages, allocate them and set them up
if (newSize>oldSize) {
int pageCount = (newSize - oldSize + PAGE_SIZE - 1) / PAGE_SIZE;
error ("Old size = %d, new size = %d, pageCount = %d\n",oldSize,newSize,pageCount);
vpage *newPage;
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;
dump();
}
else { // Ewww. Shrinking. This is ugly right now.
int pageCount = (oldSize - newSize + PAGE_SIZE - 1) / PAGE_SIZE;
size_t newFinalAddress=start_address+newSize;
vpage *oldPage;
struct node *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;
}
// Found the right one to removei; waste it, pool it, and move on
oldPage=reinterpret_cast<vpage *>(max);
for (hashIterate hi(vpages);node *cur=hi.get();) {
oldPage=reinterpret_cast<vpage *>(cur);
if (oldPage->getStartAddress() > (reinterpret_cast<void *> (newFinalAddress))) {
vpages.remove(cur);
if (finalWrite)
oldPage->flush();
@ -223,6 +216,8 @@ status_t area::resize(size_t newSize) {
vmBlock->vpagePool->put(oldPage);
}
}
}
end_address=start_address+newSize;
return B_OK;
}
@ -238,6 +233,7 @@ status_t area::setProtection(protectType prot) {
vpage *area::findVPage(unsigned long address) {
vpage findMe(address);
// error ("area::findVPage: finding %ld\n",address);
return reinterpret_cast <vpage *>(vpages.find(&findMe));
}
@ -273,9 +269,12 @@ int area::getInt(unsigned long address) { // This is for testing only
}
void area::setInt(unsigned long address,int value) { // This is for testing only
// error ("area::setInt - start\n");
vpage *page=findVPage(address);
// error ("area::setInt - page = %x\n",page);
if (page)
page->setInt(address,value,manager);
// error ("area::setInt - done\n");
}
// For every one of our vpages, call the vpage's pager

View File

@ -2,7 +2,7 @@
#define _AREA_H
#include "OS.h"
#include "vm.h"
#include "list.h"
#include "lockedList.h"
#include "hashTable.h"
class areaManager;
@ -51,6 +51,7 @@ class area : public node
areaManager *getAreaManager(void) {return manager;}
unsigned long getEndAddress(void) {return end_address;}
unsigned long getStartAddress(void) {return start_address;}
const char *getName(void) {return name;}
// Debugging
void dump(void);

View File

@ -39,8 +39,9 @@ unsigned long areaManager::getNextAddress(int pages, unsigned long start) {
}
// Remove the area from our list, put it on the area pool and move on
void areaManager::freeArea(area_id areaID) {
status_t areaManager::freeArea(area_id areaID) {
//error ("areaManager::freeArea: begin\n");
status_t retVal=B_OK;
lock();
area *oldArea=findArea(areaID);
//error ("areaManager::freeArea: found area %x\n",oldArea);
@ -55,9 +56,13 @@ void areaManager::freeArea(area_id areaID) {
// error ("areaManager::freeArea: freeArea complete \n");
vmBlock->areaPool->put(oldArea);
}
else
else {
retVal=B_ERROR;
error ("areaManager::freeArea: unable to find requested area\n");
}
unlock();
// error ("areaManager::freeArea: final unlock complete\n");
return retVal;
}
area *areaManager::findAreaLock(void *address) {
@ -93,7 +98,7 @@ area *areaManager::findArea(const void *address) {
if (myArea->contains(address))
return myArea;
}
error ("areaManager::findArea is giving up\n");
// error ("areaManager::findArea is giving up\n");
return NULL;
}
@ -137,14 +142,14 @@ long areaManager::nextAreaID=0;
// Create an area; get a new structure, call setup, create the guts, set its ID, add it to our list
int areaManager::createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect) {
error ("areaManager::createArea - Creating an area\n");
// error ("areaManager::createArea - 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");
int retVal = 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");
if (retVal==B_OK) {
atomic_add(&nextAreaID,1);
newArea->setAreaID(nextAreaID);
@ -152,6 +157,7 @@ int areaManager::createArea(char *AreaName,int pageCount,void **address, address
addArea(newArea);
//error ("areaManager::createArea - new area added to list\n");
retVal=newArea->getAreaID();
// error ("areaManager::createArea - getAreaID=%d\n",retVal);
//error ("areaManager::createArea - new area id found\n");
}
unlock();
@ -243,16 +249,21 @@ void areaManager::setByte(unsigned long address,char value) {
}
void areaManager::setInt(unsigned long address,int value) {
error ("areaManager::setInt starting to set on address %lx, value = %d\n",address,value);
area *myArea;
lock();
error ("areaManager::setInt locked\n");
myArea=findArea((void *)address);
error ("areaManager::setInt area %s found\n",((myArea)?"":" not "));
if (myArea)
myArea->setInt(address,value);
else {
char temp[1000];
sprintf (temp,"Unable to find an area for address %d\n",address);
unlock();
throw (temp);
}
error ("areaManager::setInt unlocking\n");
unlock();
}

View File

@ -13,7 +13,7 @@ class areaManager // One of these per process
areaManager ();
void addArea(area *newArea) {areas.add(newArea);}
void removeArea(area *oldArea) {areas.remove(oldArea); }
void freeArea(area_id area);
status_t 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);

View File

@ -1,5 +1,5 @@
#include <OS.h>
#include "list.h"
#include "lockedList.h"
class area;
class poolarea
{

View File

@ -1,4 +1,4 @@
#include <list.h>
#include <lockedList.h>
#include <vm.h>
#include <vpage.h>
#include <area.h>

View File

@ -1,6 +1,6 @@
#ifndef _HASH_H
#define _HASH_H
#include "list.h"
#include "lockedList.h"
#include "vm.h"
#include "page.h"
#include "pageManager.h"

View File

@ -0,0 +1,19 @@
#ifndef _LOCKED_LIST_H
#define _LOCKED_LIST_H
#include <OS.h>
#include <list.h>
class lockedList: public list
{
public:
lockedList(void) {myLock=create_sem(1,"lockedListSem");}
void add(node *newNode) {lock();list::add(newNode);unlock();}
node *next(void) {lock();node *retVal=list::next();unlock();return retVal;}
void remove(node *newNode) {lock();list::remove(newNode);unlock();}
void dump() {lock();list::dump();unlock();}
bool ensureSane(void) {lock();bool retVal=list::ensureSane();unlock();return retVal;}
void lock() { acquire_sem(myLock);}
void unlock() { release_sem(myLock);}
private:
sem_id myLock;
};
#endif

View File

@ -1,7 +1,7 @@
#ifndef _PAGE_H
#define _PAGE_H
#include "vm.h"
#include "list.h"
#include "lockedList.h"
class page : public node {
private:
void *cpuSpecific;

View File

@ -21,9 +21,6 @@ void pageManager::setup(void *area,int pages) {
unused.add(newPage);
}
cleanLock=create_sem (1,"clean_lock");
unusedLock=create_sem (1,"unused_lock");
inUseLock=create_sem (1,"inuse_lock");
totalPages=pages;
//error ("pageManager::setup - %d pages ready to rock and roll\n",unused.count());
}
@ -34,22 +31,16 @@ page *pageManager::getPage(void) {
while (!ret)
{
if (clean.count()) {
acquire_sem(cleanLock);
ret=(page *)clean.next();
release_sem(cleanLock);
} // This could fail if someone swooped in and stole our page.
if (!ret && unused.count()) {
acquire_sem(unusedLock);
ret=(page *)unused.next();
release_sem(unusedLock);
if (ret)
ret->zero();
} // This could fail if someone swooped in and stole our page.
}
//error ("pageManager::getPage - returning page %x, clean = %d, unused = %d, inuse = %x\n",ret,clean.count(),unused.count(),inUse.count());
acquire_sem(inUseLock);
inUse.add(ret);
release_sem(inUseLock);
ret->count++;
if (!ret)
throw ("Out of physical pages!");
@ -60,15 +51,11 @@ page *pageManager::getPage(void) {
void pageManager::freePage(page *toFree) {
//error ("pageManager::freePage; count = %d, address = %p\n",toFree->count,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);
// inUse.dump();
release_sem(inUseLock);
acquire_sem(unusedLock);
unused.add(toFree);
// unused.dump();
release_sem(unusedLock);
}
}
@ -83,14 +70,10 @@ void pageManager::cleaner(void) {
// Find a page that needs cleaning. Take it from the "unused" list, clean it and put it on the clean list.
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);
}
}
}
@ -104,27 +87,27 @@ int pageManager::desperation(void) { // Formula to determine how desperate syste
void pageManager::dump(void) {
error ("Dumping the unused list (%d entries)\n",getUnusedCount());
acquire_sem(unusedLock);
unused.lock();
for (struct node *cur=unused.rock;cur;) {
page *thisPage=(page *)cur;
thisPage->dump();
cur=cur->next;
}
release_sem(unusedLock);
unused.unlock();
error ("Dumping the clean list (%d entries)\n",getCleanCount());
acquire_sem(cleanLock);
clean.lock();
for (struct node *cur=clean.rock;cur;) {
page *thisPage=(page *)cur;
thisPage->dump();
cur=cur->next;
}
error ("Dumping the inuse list (%d entries)\n",getInUseCount());
release_sem(cleanLock);
acquire_sem(inUseLock);
clean.unlock();
inUse.lock();
for (struct node *cur=inUse.rock;cur;) {
page *thisPage=(page *)cur;
thisPage->dump();
cur=cur->next;
}
release_sem(inUseLock);
inUse.unlock();
}

View File

@ -1,7 +1,7 @@
#ifndef _PAGE_MANAGER_H
#define _PAGE_MANAGER_H
#include "/boot/develop/headers/be/kernel/OS.h"
#include "list.h"
#include "lockedList.h"
#include "page.h"
class pageManager {
@ -28,8 +28,7 @@ class pageManager {
int getUnusedCount(void) {return unused.count();}
int getInUseCount(void) {return inUse.count();}
private:
list clean,unused,inUse;
sem_id cleanLock,unusedLock,inUseLock;
lockedList clean,unused,inUse;
int totalPages;
};
#endif

View File

@ -1,4 +1,4 @@
#include "list.h"
#include "lockedList.h"
#ifndef _VM_TYPES
#define _VM_TYPES

View File

@ -10,7 +10,7 @@ class pageManager;
class swapFileManager;
class cacheManager;
class vnodeManager;
class list;
class lockedList;
#endif
struct vmHeaderBlock
@ -22,7 +22,7 @@ struct vmHeaderBlock
swapFileManager *swapMan;
cacheManager *cacheMan;
vnodeManager *vnodeMan;
list areas;
lockedList areas;
};
#endif

View File

@ -1,5 +1,6 @@
#include <new.h>
#include "mman.h"
#include "lockedList.h"
#include "area.h"
#include "areaPool.h"
#include "vpagePool.h"
@ -145,7 +146,7 @@ status_t vmInterface::resizeArea(int Area,size_t size)
int vmInterface::createArea(char *AreaName,int pageCount,void **address, addressSpec addType,pageState state,protectType protect)
{
int retVal;
error ("vmInterface::createArea: Creating an area!\n");
// error ("vmInterface::createArea: Creating an area!\n");
if (!AreaName)
return B_BAD_ADDRESS;
if (!address)
@ -161,19 +162,20 @@ int vmInterface::createArea(char *AreaName,int pageCount,void **address, address
if (protect>copyOnWrite || protect < none)
return B_BAD_VALUE;
retVal = getAM()->createArea(AreaName,pageCount,address,addType,state,protect);
//error ("vmInterface::createArea: Done creating an area!\n");
// error ("vmInterface::createArea: Done creating an area! ID = %d\n",retVal);
return retVal;
}
void vmInterface::freeArea(int area)
status_t vmInterface::delete_area(int area)
{
getAM()->freeArea(area);
return getAM()->freeArea(area);
}
status_t vmInterface::getAreaInfo(int Area,area_info *dest)
{
status_t retVal;
//error ("vmInterface::getAreaInfo: Getting info about an area!\n");
if (!dest) return B_ERROR;
retVal = getAM()->getAreaInfo(Area,dest);
//error ("vmInterface::getAreaInfo: Done getting info about an area!\n");
return retVal;
@ -189,8 +191,15 @@ status_t vmInterface::getNextAreaInfo(int process,int32 *cookie,area_info *dest
int vmInterface::getAreaByName(char *name)
{
int retVal;
retVal = getAM()->getAreaByName(name);
int retVal=B_NAME_NOT_FOUND;
vmBlock->areas.lock();
for (struct node *cur=vmBlock->areas.rock;cur && retVal==B_NAME_NOT_FOUND;cur=cur->next) {
area *myArea=(area *)cur;
error ("vmInterface::getAreaByName comapring %s to passed in %s\n",myArea->getName(),name);
if (myArea->nameMatch(name))
retVal=myArea->getAreaID();
}
vmBlock->areas.unlock();
return retVal;
}

View File

@ -11,7 +11,7 @@ class vmInterface // This is the class that "owns" all of the managers.
int createArea(char *AreaName,int pageCount,void **address,
addressSpec addType=ANY,
pageState state=NO_LOCK,protectType protect=writable);
void freeArea(int Area);
status_t delete_area(int Area);
status_t getAreaInfo(int Area,area_info *dest);
status_t getNextAreaInfo(int process,int32 *cookie,area_info *dest);
int getAreaByName(char *name);
@ -40,6 +40,6 @@ class vmInterface // This is the class that "owns" all of the managers.
char getByte(unsigned long offset) {return getAM()->getByte(offset);} // This is for testing only
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 setInt(unsigned long offset,int value) {getAM()->setInt(offset,value);} // This is for testing only
thread_id tid_cleaner,tid_saver,tid_pager;
};

View File

@ -1,5 +1,5 @@
#include <OS.h>
#include "list.h"
#include "lockedList.h"
class area;
class vnode;
class poolvnode

View File

@ -86,7 +86,7 @@ void vpage::setup(unsigned long start,vnode *backing, page *physMem,protectType
// If there is no physical page already and we can't wait to get one, then get one now
if (!physPage && (state!=LAZY) && (state!=NO_LOCK)) {
physPage=vmBlock->pageMan->getPage();
error ("vpage::setup, state = %d, allocated page %x\n",state,physPage);
// error ("vpage::setup, state = %d, allocated page %x\n",state,physPage);
}
else { // We either don't need it or we already have it.
if (physPage)
@ -120,14 +120,14 @@ void vpage::setProtection(protectType prot) {
// This is dispatched by the real interrupt handler, who locates us
// true = OK, false = panic.
bool vpage::fault(void *fault_address, bool writeError, int &in_count) {
// error ("vpage::fault: virtual address = %lx, write = %s\n",(unsigned long) fault_address,((writeError)?"true":"false"));
error ("vpage::fault: virtual address = %lx, write = %s\n",(unsigned long) fault_address,((writeError)?"true":"false"));
if (writeError && protection != copyOnWrite && protection != writable)
return false;
if (writeError && physPage) { // If we already have a page and this is a write, it is either a copy on write or a "dirty" notice
dirty=true;
if (protection==copyOnWrite) { // Else, this was just a "let me know when I am dirty"...
page *newPhysPage=vmBlock->pageMan->getPage();
// error ("vpage::fault - copy on write allocated page %x\n",newPhysPage);
error ("vpage::fault - copy on write allocated page %x\n",newPhysPage);
memcpy((void *)(newPhysPage->getAddress()),(void *)(physPage->getAddress()),PAGE_SIZE);
physPage=newPhysPage;
protection=writable;
@ -140,10 +140,10 @@ bool vpage::fault(void *fault_address, bool writeError, int &in_count) {
}
// Guess this is the real deal. Get a physical page.
physPage=vmBlock->pageMan->getPage();
// error ("vpage::fault - regular - allocated page %x\n",physPage);
error ("vpage::fault - regular - allocated page %x\n",physPage);
if (!physPage) // No room at the inn
return false;
// error ("vpage::fault: New page allocated! new physical address = %x vnode.fd=%d, vnode.offset=%d, \n",physPage->getAddress(),((backingNode)?backingNode->fd:0),((backingNode)?backingNode->offset:0));
error ("vpage::fault: New page allocated! new physical address = %x vnode.fd=%d, vnode.offset=%d, \n",physPage->getAddress(),((backingNode)?backingNode->fd:0),((backingNode)?backingNode->offset:0));
// Update the architecture specific stuff here...
// This refresh is unneeded if the data was never written out...
// dump();
@ -201,10 +201,12 @@ int vpage::getInt(unsigned long address,areaManager *manager) {
}
void vpage::setInt(unsigned long address,int value,areaManager *manager) {
error ("vpage::setInt: here I am!\n");
if (!physPage)
if (!manager->fault((void *)(address),true))
throw ("vpage::setInt");
*((int *)(address-start_address+physPage->getAddress()))=value;
error ("vpage::setInt: leaving!\n");
}
// Swaps pages out where necessary.

View File

@ -1,5 +1,5 @@
#include <OS.h>
#include "list.h"
#include "lockedList.h"
class vpage;
class poolvpage
{