Checkpoint - more work done.

git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1685 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Phipps 2002-10-26 18:55:44 +00:00
parent 4b8670624a
commit 3dcf5034e5
7 changed files with 226 additions and 50 deletions

View File

@ -1,64 +1,89 @@
#ifndef _HASH_H
#define _HASH_H
#include "list.h"
#include "vm.h"
#include "page.h"
#include "pageManager.h"
#include "vmHeaderBlock.h"
#include <new.h>
static bool throwException (node &foo)
{ throw ("Attempting to use an hash table without setting up a 'hash' function"); }
extern vmHeaderBlock *vmBlock;
class hashTable : public list
{
public:
hashTable(int size)
{
hashTable(int size) {
nodeCount=0;
numRocks=size;
int pageCount=PAGE_SIZE*size/sizeof(list);
if (size*sizeof (list *)>PAGE_SIZE)
throw ("Hash table too big!");
page *newPage=vmBlock->pageMan->getPage();
if (!newPage)
throw ("Out of pages to allocate a pool!");
int newCount=PAGE_SIZE/sizeof(area);
acquire_sem(inUse);
//error ("poolarea::get: Adding %d new elements to the pool!\n",newCount);
for (int i=0;i<newCount;i++)
unused.add(((node *)(newPage->getAddress()+(i*sizeof(area)))));
release_sem(inUse);
rocks=(list **)(newPage->getAddress());
int listsPerPage=PAGE_SIZE/sizeof(list);
int pages=(size+(listsPerPage-1))/listsPerPage;
for (int pageCount=0;pageCount<pages;pageCount++)
{
page *newPage=vmBlock->pageMan->getPage();
if (!newPage)
throw ("Out of pages to allocate a pool!");
for (int i=0;i<listsPerPage;i++)
rocks[i]=new ((list *)(newPage->getAddress()+(i*sizeof(list)))) list;
}
}
void setHash (ulong (*hash_in)(node &)) { hash=hash_in; }
void setIsEqual (ulong (*isEqual_in)(node &,node &)) { isEqual=isEqual_in; }
void setIsEqual (bool (*isEqual_in)(node &,node &)) { isEqual=isEqual_in; }
int count(void) {return nodeCount;}
void add (node *newNode) {
unsigned long hashValue=hash(*newNode)%numRocks;
// Note - no looking for duplicates; no ordering.
rocks[hashValue].add(newNode);
}
node *next(void) { return NULL; // This operation doesn't make sense for this class}
void remove(node *toNuke)
{
unsigned long hashValue=hash(*findNode)%numRocks;
rocks[hashValue].remove(newNode);
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
unsigned long hashValue=hash(*newNode)%numRocks;
// Note - no looking for duplicates; no ordering.
rocks[hashValue]->add(newNode);
}
void dump(void)
{
node *next(void) {throw ("Next is invalid in a hash table!");} // This operation doesn't make sense for this class
void remove(node *toNuke) {
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
unsigned long hashValue=hash(*toNuke)%numRocks;
rocks[hashValue]->remove(toNuke);
}
void dump(void) {
for (int i=0;i<numRocks;i++)
for (struct node *cur=rocks[hashValue].rock;cur && !done;cur=cur->next)
error ("hashTable::dump: At %p, next = %p\n",cur,cur->next);
for (struct node *cur=rocks[i]->rock;cur;cur=cur->next)
error ("hashTable::dump: On bucket %d of %d, At %p, next = %p\n",i,numRocks,cur,cur->next);
}
node *find(node *findNode)
{
bool ensureSane (void) {
bool ok=true;
for (int i=0;i<numRocks;i++)
ok|=rocks[i]->ensureSane();
return ok;
}
node *find(node *findNode) {
if (!hash)
throw ("Attempting to use a hash table without setting up a 'hash' function");
if (!isEqual)
throw ("Attempting to use a hash table without setting up an 'isEqual' function");
unsigned long hashValue=hash(*findNode)%numRocks;
for (struct node *cur=rocks[hashValue].rock;cur && !done;cur=cur->next)
for (struct node *cur=rocks[hashValue]->rock;cur ;cur=cur->next)
if (isEqual(*findNode,*cur))
return cur;
return NULL;
}
private:
ulong (*hash)(node &a);
bool (*isEqual)(node &a,node &b);
list *rocks;
list **rocks;
int numRocks;
};
#endif

107
src/kernel/vm2/hashTest.C Normal file
View File

@ -0,0 +1,107 @@
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "hashTable.h"
#include "OS.h"
#include "vmInterface.h"
vmInterface vm(30);
struct hashTest : public node {
hashTest(int i) {value=i;}
int value;
};
ulong hash(node &a) {
hashTest &a1=reinterpret_cast<hashTest &>(a);
return a1.value;
}
bool isEqual (node &a,node &b) {
hashTest &a1=reinterpret_cast<hashTest &>(a);
hashTest &b1=reinterpret_cast<hashTest &>(b);
return (a1.value==b1.value);
}
int main(int argc,char **argv) {
// Test 1 - Try to add to foo without setting an isLessThan function
try {
hashTable foo(10);
node tmp;
foo.add(&tmp);
}
catch (const char *badness)
{
if (strcmp(badness,"Attempting to use a hash table without setting up a 'hash' function"))
error ("Failure on adding with no hash, error = %s\n", badness);
error ("Success on adding with no hash, \n" );
}
catch(...)
{
error ("Failure on adding with no hash, unknown exception\n");
}
hashTable foo(20);
foo.setHash(hash);
foo.setIsEqual(isEqual);
error ("Add the first couple, in order (easy)\n");
hashTest first(1);
foo.add(&first);
hashTest second(2);
foo.add(&second);
foo.dump();
error ("Add the next three, not in order (harder)\n");
hashTest third(3);
hashTest fourth(4);
hashTest fifth(5);
foo.add(&fourth);
foo.add(&third);
foo.add(&fifth);
foo.dump();
error ("Create bar, populated with 1000 values");
hashTable bar(200);
bar.setHash(hash);
bar.setIsEqual(isEqual);
for (int a=0;a<100;a++)
bar.add(new hashTest(a));
for (int a=1000;a>=100;a--)
bar.add(new hashTest(a));
bar.dump();
error ("Removing simple case: remove 1,leave 2,3,4,5 \n");
foo.remove(&first);
foo.dump();
error ("Removing simple case: remove 2,leave 3,4,5 \n");
foo.remove(&second);
foo.dump();
error ("Setting up middle case (readding 1 and 2)\n");
foo.add(&first);
foo.add(&second);
foo.dump();
error ("Removing middle case (removing 2)\n");
foo.remove(&second);
foo.dump();
error ("Removing middle case (removing 1)\n");
foo.remove(&first);
foo.dump();
error ("Finding 1\n");
hashTest findOne(1);
hashTest *found=(hashTest *)bar.find(&findOne);
error ("found value = %d\n",found->value);
error ("Finding 77\n");
hashTest findSeventySeven(77);
hashTest *found77=(hashTest *)bar.find(&findSeventySeven);
error ("found value = %d\n",found77->value);
error ("ensuringSane on smaller (foo) = %s\n",((foo.ensureSane())?"OK":"BAD!"));
error ("ensuringSane on larger (bar) = %s\n",((bar.ensureSane())?"OK":"BAD!"));
return 0;
}

View File

@ -13,41 +13,34 @@ struct node
class list {
public:
list(void){nodeCount=0;rock=NULL;}
void add (node *newNode)
{
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)
{
node *next(void) {
//dump();
node *n=rock;
if (rock)
{
if (rock) {
rock=rock->next;
nodeCount--;
}
//dump();
return n;
}
void remove(node *toNuke)
{
void remove(node *toNuke) {
//error ("list::remove starting: nuking %x \n",toNuke);
//dump();
if (rock==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;
@ -56,13 +49,25 @@ class list {
//error ("list::remove ending: \n");
//dump();
}
void dump(void)
{
void dump(void) {
for (struct node *cur=rock;cur;cur=cur->next)
{
error ("list::dump: At %p, next = %p\n",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
if (temp<0) {
error ("list::ensureSane: found too many records!\n");
return false;
}
if (temp>0) {
error ("list::ensureSane: found too few records!\n");
return false;
}
return true;
}
struct node *rock;
int nodeCount;
private:

View File

@ -1,6 +1,7 @@
#include "pageManager.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void *addOffset(void *base,unsigned long offset)
{
@ -74,6 +75,41 @@ page *pageManager::getPage(void)
return ret;
}
bool pageManager::getContiguousPages(int pages,page **location)
{
unsigned long current, start=0, next;
page *curPage;
int count=0;
while (count<pages)
{
curPage=getPage();
current=curPage->getAddress();
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
{
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)
{
freePage(location[count]);
location[count]=NULL;
}
}
}
return true;
}
void pageManager::freePage(page *toFree)
{
error ("pageManager::freePage; old value = %d\n",toFree->count);

View File

@ -9,6 +9,7 @@ class pageManager {
pageManager(void);
void setup(void *memory,int pages);
page *getPage(void);
bool getContiguousPages(int pages,page **location);
void freePage(page *);
void cleaner(void);
int desperation(void);

View File

@ -21,6 +21,7 @@ class vpage : public node
void flush(void); // write page to vnode, if necessary
void refresh(void); // Read page back in from vnode
vpage(void);
// 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);
void setProtection(protectType prot);

View File

@ -14,6 +14,7 @@ class vpageManager
private:
public:
vpage *getVpage(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state);
vpage *getVpage(vnode &vn);
void putVpage(vpage &vp);
}