From 3dcf5034e5767027ed25eb072e728db53428a970 Mon Sep 17 00:00:00 2001 From: Michael Phipps Date: Sat, 26 Oct 2002 18:55:44 +0000 Subject: [PATCH] Checkpoint - more work done. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@1685 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/kernel/vm2/hashTable.h | 87 +++++++++++++++++---------- src/kernel/vm2/hashTest.C | 107 ++++++++++++++++++++++++++++++++++ src/kernel/vm2/list.h | 43 ++++++++------ src/kernel/vm2/pageManager.C | 36 ++++++++++++ src/kernel/vm2/pageManager.h | 1 + src/kernel/vm2/vpage.h | 1 + src/kernel/vm2/vpageManager.h | 1 + 7 files changed, 226 insertions(+), 50 deletions(-) create mode 100644 src/kernel/vm2/hashTest.C diff --git a/src/kernel/vm2/hashTable.h b/src/kernel/vm2/hashTable.h index ac0f5d8a1b..65e42c3454 100644 --- a/src/kernel/vm2/hashTable.h +++ b/src/kernel/vm2/hashTable.h @@ -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 -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;igetAddress()+(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;pageCountpageMan->getPage(); + if (!newPage) + throw ("Out of pages to allocate a pool!"); + for (int i=0;igetAddress()+(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;inext) - 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;iensureSane(); + 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 diff --git a/src/kernel/vm2/hashTest.C b/src/kernel/vm2/hashTest.C new file mode 100644 index 0000000000..6778b8e85e --- /dev/null +++ b/src/kernel/vm2/hashTest.C @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#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(a); + return a1.value; +} + +bool isEqual (node &a,node &b) { + hashTest &a1=reinterpret_cast(a); + hashTest &b1=reinterpret_cast(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; +} diff --git a/src/kernel/vm2/list.h b/src/kernel/vm2/list.h index 56b8a1249d..cbcb8424cd 100644 --- a/src/kernel/vm2/list.h +++ b/src/kernel/vm2/list.h @@ -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: diff --git a/src/kernel/vm2/pageManager.C b/src/kernel/vm2/pageManager.C index ce8cc706d4..5cc6028fb3 100644 --- a/src/kernel/vm2/pageManager.C +++ b/src/kernel/vm2/pageManager.C @@ -1,6 +1,7 @@ #include "pageManager.h" #include #include +#include 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 (countgetAddress(); + 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); diff --git a/src/kernel/vm2/pageManager.h b/src/kernel/vm2/pageManager.h index d5125f734b..e5fe7ef08c 100644 --- a/src/kernel/vm2/pageManager.h +++ b/src/kernel/vm2/pageManager.h @@ -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); diff --git a/src/kernel/vm2/vpage.h b/src/kernel/vm2/vpage.h index 4e1e6a89bc..00b1825ab1 100644 --- a/src/kernel/vm2/vpage.h +++ b/src/kernel/vm2/vpage.h @@ -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); diff --git a/src/kernel/vm2/vpageManager.h b/src/kernel/vm2/vpageManager.h index faee29782b..8789febb35 100644 --- a/src/kernel/vm2/vpageManager.h +++ b/src/kernel/vm2/vpageManager.h @@ -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); }