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:
+56
-31
@@ -1,64 +1,89 @@
|
|||||||
#ifndef _HASH_H
|
#ifndef _HASH_H
|
||||||
#define _HASH_H
|
#define _HASH_H
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "vm.h"
|
||||||
|
#include "page.h"
|
||||||
|
#include "pageManager.h"
|
||||||
|
#include "vmHeaderBlock.h"
|
||||||
|
#include <new.h>
|
||||||
|
|
||||||
static bool throwException (node &foo)
|
extern vmHeaderBlock *vmBlock;
|
||||||
{ throw ("Attempting to use an hash table without setting up a 'hash' function"); }
|
|
||||||
|
|
||||||
class hashTable : public list
|
class hashTable : public list
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
hashTable(int size)
|
hashTable(int size) {
|
||||||
{
|
|
||||||
nodeCount=0;
|
nodeCount=0;
|
||||||
numRocks=size;
|
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();
|
page *newPage=vmBlock->pageMan->getPage();
|
||||||
if (!newPage)
|
if (!newPage)
|
||||||
throw ("Out of pages to allocate a pool!");
|
throw ("Out of pages to allocate a pool!");
|
||||||
int newCount=PAGE_SIZE/sizeof(area);
|
rocks=(list **)(newPage->getAddress());
|
||||||
acquire_sem(inUse);
|
|
||||||
//error ("poolarea::get: Adding %d new elements to the pool!\n",newCount);
|
int listsPerPage=PAGE_SIZE/sizeof(list);
|
||||||
for (int i=0;i<newCount;i++)
|
int pages=(size+(listsPerPage-1))/listsPerPage;
|
||||||
unused.add(((node *)(newPage->getAddress()+(i*sizeof(area)))));
|
for (int pageCount=0;pageCount<pages;pageCount++)
|
||||||
release_sem(inUse);
|
{
|
||||||
|
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 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;}
|
int count(void) {return nodeCount;}
|
||||||
void add (node *newNode) {
|
void add (node *newNode) {
|
||||||
unsigned long hashValue=hash(*newNode)%numRocks;
|
if (!hash)
|
||||||
// Note - no looking for duplicates; no ordering.
|
throw ("Attempting to use a hash table without setting up a 'hash' function");
|
||||||
rocks[hashValue].add(newNode);
|
unsigned long hashValue=hash(*newNode)%numRocks;
|
||||||
}
|
// Note - no looking for duplicates; no ordering.
|
||||||
node *next(void) { return NULL; // This operation doesn't make sense for this class}
|
rocks[hashValue]->add(newNode);
|
||||||
void remove(node *toNuke)
|
|
||||||
{
|
|
||||||
unsigned long hashValue=hash(*findNode)%numRocks;
|
|
||||||
rocks[hashValue].remove(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 (int i=0;i<numRocks;i++)
|
||||||
for (struct node *cur=rocks[hashValue].rock;cur && !done;cur=cur->next)
|
for (struct node *cur=rocks[i]->rock;cur;cur=cur->next)
|
||||||
error ("hashTable::dump: At %p, next = %p\n",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;
|
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))
|
if (isEqual(*findNode,*cur))
|
||||||
return cur;
|
return cur;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ulong (*hash)(node &a);
|
ulong (*hash)(node &a);
|
||||||
bool (*isEqual)(node &a,node &b);
|
bool (*isEqual)(node &a,node &b);
|
||||||
list *rocks;
|
list **rocks;
|
||||||
int numRocks;
|
int numRocks;
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
+24
-19
@@ -13,41 +13,34 @@ struct node
|
|||||||
class list {
|
class list {
|
||||||
public:
|
public:
|
||||||
list(void){nodeCount=0;rock=NULL;}
|
list(void){nodeCount=0;rock=NULL;}
|
||||||
void add (node *newNode)
|
void add (node *newNode) {
|
||||||
{
|
|
||||||
newNode->next=rock;
|
newNode->next=rock;
|
||||||
rock=newNode;
|
rock=newNode;
|
||||||
nodeCount++;
|
nodeCount++;
|
||||||
}
|
}
|
||||||
//int count(void) {error ("list::count: About to return %d\n",nodeCount);return nodeCount;}
|
//int count(void) {error ("list::count: About to return %d\n",nodeCount);return nodeCount;}
|
||||||
int count(void) {return nodeCount;}
|
int count(void) {return nodeCount;}
|
||||||
node *next(void)
|
node *next(void) {
|
||||||
{
|
|
||||||
//dump();
|
//dump();
|
||||||
node *n=rock;
|
node *n=rock;
|
||||||
if (rock)
|
if (rock) {
|
||||||
{
|
|
||||||
rock=rock->next;
|
rock=rock->next;
|
||||||
nodeCount--;
|
nodeCount--;
|
||||||
}
|
}
|
||||||
//dump();
|
//dump();
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
void remove(node *toNuke)
|
void remove(node *toNuke) {
|
||||||
{
|
|
||||||
//error ("list::remove starting: nuking %x \n",toNuke);
|
//error ("list::remove starting: nuking %x \n",toNuke);
|
||||||
//dump();
|
//dump();
|
||||||
if (rock==toNuke)
|
if (rock==toNuke) {
|
||||||
{
|
|
||||||
rock=rock->next;
|
rock=rock->next;
|
||||||
nodeCount--;
|
nodeCount--;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
|
||||||
bool done=false;
|
bool done=false;
|
||||||
for (struct node *cur=rock;!done && cur->next;cur=cur->next)
|
for (struct node *cur=rock;!done && cur->next;cur=cur->next)
|
||||||
if (cur->next==toNuke)
|
if (cur->next==toNuke) {
|
||||||
{
|
|
||||||
cur->next=toNuke->next;
|
cur->next=toNuke->next;
|
||||||
nodeCount--;
|
nodeCount--;
|
||||||
done=true;
|
done=true;
|
||||||
@@ -56,13 +49,25 @@ class list {
|
|||||||
//error ("list::remove ending: \n");
|
//error ("list::remove ending: \n");
|
||||||
//dump();
|
//dump();
|
||||||
}
|
}
|
||||||
void dump(void)
|
void dump(void) {
|
||||||
{
|
|
||||||
for (struct node *cur=rock;cur;cur=cur->next)
|
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;
|
struct node *rock;
|
||||||
int nodeCount;
|
int nodeCount;
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include "pageManager.h"
|
#include "pageManager.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
void *addOffset(void *base,unsigned long offset)
|
void *addOffset(void *base,unsigned long offset)
|
||||||
{
|
{
|
||||||
@@ -74,6 +75,41 @@ page *pageManager::getPage(void)
|
|||||||
return ret;
|
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)
|
void pageManager::freePage(page *toFree)
|
||||||
{
|
{
|
||||||
error ("pageManager::freePage; old value = %d\n",toFree->count);
|
error ("pageManager::freePage; old value = %d\n",toFree->count);
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ class pageManager {
|
|||||||
pageManager(void);
|
pageManager(void);
|
||||||
void setup(void *memory,int pages);
|
void setup(void *memory,int pages);
|
||||||
page *getPage(void);
|
page *getPage(void);
|
||||||
|
bool getContiguousPages(int pages,page **location);
|
||||||
void freePage(page *);
|
void freePage(page *);
|
||||||
void cleaner(void);
|
void cleaner(void);
|
||||||
int desperation(void);
|
int desperation(void);
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class vpage : public node
|
|||||||
void flush(void); // write page to vnode, if necessary
|
void flush(void); // write page to vnode, if necessary
|
||||||
void refresh(void); // Read page back in from vnode
|
void refresh(void); // Read page back in from vnode
|
||||||
vpage(void);
|
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 setup(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state); // backing and/or physMem can be NULL/0.
|
||||||
void cleanup(void);
|
void cleanup(void);
|
||||||
void setProtection(protectType prot);
|
void setProtection(protectType prot);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ class vpageManager
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
vpage *getVpage(unsigned long start,vnode *backing, page *physMem,protectType prot,pageState state);
|
||||||
vpage *getVpage(vnode &vn);
|
vpage *getVpage(vnode &vn);
|
||||||
void putVpage(vpage &vp);
|
void putVpage(vpage &vp);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user