2002-08-28 01:34:19 +00:00
#include <new.h>
2002-07-19 03:55:07 +00:00
#include "area.h"
#include "areaManager.h"
#include "vpage.h"
2002-08-26 20:14:54 +00:00
#include "vnodePool.h"
2002-09-05 03:26:02 +00:00
#include "vpagePool.h"
#include "vmHeaderBlock.h"
2002-07-19 03:55:07 +00:00
2002-09-05 03:26:02 +00:00
extern vmHeaderBlock * vmBlock ;
2002-08-26 20:14:54 +00:00
2002-11-19 04:05:16 +00:00
ulong vpageHash ( node & vp ) { return reinterpret_cast < vpage &> ( vp ). hash ();}
bool vpageisEqual ( node & vp , node & vp2 ) { return reinterpret_cast < vpage &> ( vp ) == reinterpret_cast < vpage &> ( vp2 );}
2002-10-03 03:42:59 +00:00
2002-11-19 04:05:16 +00:00
area :: area ( void ) : vpages ( AREA_HASH_TABLE_SIZE ) {
vpages . setHash ( vpageHash );
vpages . setIsEqual ( vpageisEqual );
2002-08-26 20:14:54 +00:00
}
2002-11-19 04:05:16 +00:00
void area :: setup ( areaManager * myManager ) {
2002-09-16 03:14:44 +00:00
//error ("area::setup setting up new area\n");
2002-07-19 03:55:07 +00:00
manager = myManager ;
2002-09-16 03:14:44 +00:00
//error ("area::setup done setting up new area\n");
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
unsigned long area :: mapAddressSpecToAddress ( addressSpec type , void * req , int pageCount ) {
2002-07-25 01:27:00 +00:00
// We will lock in the callers
2002-10-03 03:42:59 +00:00
unsigned long base , requested = ( unsigned long ) req ;
2002-11-19 04:05:16 +00:00
switch ( type ) {
2002-07-19 03:55:07 +00:00
case EXACT :
base = manager -> getNextAddress ( pageCount , requested );
if ( base != requested )
2002-09-14 17:03:16 +00:00
return 0 ;
2002-07-19 03:55:07 +00:00
break ;
case BASE :
base = manager -> getNextAddress ( pageCount , requested );
break ;
case ANY :
base = manager -> getNextAddress ( pageCount , USER_BASE );
break ;
case ANY_KERNEL :
base = manager -> getNextAddress ( pageCount , KERNEL_BASE );
break ;
case CLONE : base = 0 ; break ; // Not sure what to do...
2002-09-14 17:03:16 +00:00
default : // should never happen
throw ( "Unknown type passed to mapAddressSpecToAddress" );
2002-07-19 03:55:07 +00:00
}
2002-09-16 03:14:44 +00:00
// error ("area::mapAddressSpecToAddress, in type: %s, address = %x, size = %d\n", ((type==EXACT)?"Exact":(type==BASE)?"BASE":(type==ANY)?"ANY":(type==CLONE)?"CLONE":"ANY_KERNEL"), requested,pageCount);
2002-07-19 03:55:07 +00:00
return base ;
}
2002-11-19 04:05:16 +00:00
status_t area :: createAreaGuts ( char * inName , int pageCount , void ** address , addressSpec type , pageState inState , protectType protect , bool inFinalWrite , int fd , size_t offset , area * originalArea = NULL /* For clone only*/ ) {
error ( "area::createAreaGuts : name = %s, pageCount = %d, address = %ld, addressSpec = %d, pageState = %d, protection = %d, inFinalWrite = %d, fd = %d, offset = %d,originalArea=%ld \n " ,
inName , pageCount , address , type , inState , protect , inFinalWrite , fd , offset , originalArea );
2002-08-16 01:09:45 +00:00
strcpy ( name , inName );
2002-07-19 03:55:07 +00:00
vpage * newPage ;
2002-08-16 01:09:45 +00:00
2002-10-03 03:42:59 +00:00
unsigned long base = mapAddressSpecToAddress ( type , * address , pageCount );
2002-09-14 17:03:16 +00:00
if ( base == 0 )
return B_ERROR ;
2002-07-19 03:55:07 +00:00
state = inState ;
2002-07-25 01:27:00 +00:00
start_address = base ;
2002-09-14 17:03:16 +00:00
end_address = base + ( pageCount * PAGE_SIZE ) - 1 ;
2002-08-16 01:09:45 +00:00
* address = ( void * ) base ;
2002-10-03 03:42:59 +00:00
finalWrite = inFinalWrite ;
2002-11-19 04:05:16 +00:00
if ( originalArea == NULL ) // Not for cloning
for ( int i = 0 ; i < pageCount ; i ++ ) {
2002-10-03 03:42:59 +00:00
newPage = new ( vmBlock -> vpagePool -> get ()) vpage ;
2002-11-19 04:05:16 +00:00
if ( fd ) {
// vnode *newVnode=new (vmBlock->vnodePool->get()) vnode;
void * currentMemoryLocation ;
// A future implementation vnode *newVnode=vmBlock->vnodePool->getNode(fd,offset,PAGE_SIZE*i,true,currentMemoryLocation);
vnode * newVnode = vmBlock -> vnodePool -> get ();
2002-10-03 03:42:59 +00:00
newVnode -> fd = fd ;
2002-11-19 04:05:16 +00:00
newVnode -> offset = offset ;
2002-10-03 03:42:59 +00:00
newPage -> setup ( base + PAGE_SIZE * i , newVnode , NULL , protect , inState );
}
else
newPage -> setup ( base + PAGE_SIZE * i , NULL , NULL , protect , inState );
vpages . add ( newPage );
}
2002-11-19 04:05:16 +00:00
else // cloned
// Need to lock other area, here, just in case...
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-10-03 03:42:59 +00:00
vpage * page = ( vpage * ) cur ;
newPage = new ( vmBlock -> vpagePool -> get ()) vpage ;
newPage -> setup ( base , page -> getBacking (), page -> getPhysPage (), protect , inState ); // Cloned area has the same physical page and backing store...
vpages . add ( newPage );
base += PAGE_SIZE ;
}
2002-11-19 04:05:16 +00:00
dump ();
2002-09-14 17:03:16 +00:00
return B_OK ;
2002-10-03 03:42:59 +00:00
}
2002-11-19 04:05:16 +00:00
status_t area :: createAreaMappingFile ( char * inName , int pageCount , void ** address , addressSpec type , pageState inState , protectType protect , int fd , size_t offset ) {
2002-10-03 03:42:59 +00:00
return createAreaGuts ( inName , pageCount , address , type , inState , protect , true , fd , offset );
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
status_t area :: createArea ( char * inName , int pageCount , void ** address , addressSpec type , pageState inState , protectType protect ) {
2002-10-03 03:42:59 +00:00
return createAreaGuts ( inName , pageCount , address , type , inState , protect , false , 0 , 0 );
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
status_t area :: cloneArea ( area * origArea , char * inName , void ** address , addressSpec type , pageState inState , protectType protect ) {
if ( type == CLONE ) {
2002-10-03 03:42:59 +00:00
* address = ( void * )( origArea -> getStartAddress ());
type = EXACT ;
2002-08-26 03:12:35 +00:00
}
2002-11-19 04:05:16 +00:00
if ( origArea -> getAreaManager () != manager ) {
2002-10-03 03:42:59 +00:00
origArea -> getAreaManager () -> lock (); // This is just begging for a deadlock...
status_t retVal = createAreaGuts ( inName , origArea -> getPageCount (), address , type , inState , protect , false , 0 , 0 , origArea );
origArea -> getAreaManager () -> unlock ();
return retVal ;
}
else
return createAreaGuts ( inName , origArea -> getPageCount (), address , type , inState , protect , false , 0 , 0 , origArea );
2002-08-26 03:12:35 +00:00
}
2002-11-19 04:05:16 +00:00
void area :: freeArea ( void ) {
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: starting \n");
2002-07-31 02:20:33 +00:00
2002-08-07 03:21:02 +00:00
// vpages.dump();
2002-08-26 20:14:54 +00:00
node * cur ;
2002-11-19 04:05:16 +00:00
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: wasting a page: %x\n",cur);
2002-08-26 20:14:54 +00:00
vpage * page = reinterpret_cast < vpage *> ( cur );
2002-08-26 03:12:35 +00:00
if ( finalWrite )
page -> flush ();
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: flushed a page \n");
2002-08-26 20:14:54 +00:00
page -> cleanup ();
//page->next=NULL;
2002-09-05 03:26:02 +00:00
vmBlock -> vpagePool -> put ( page );
2002-07-19 03:55:07 +00:00
}
2002-09-16 03:14:44 +00:00
//error ("area::freeArea: unlocking \n");
//error ("area::freeArea: ending \n");
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
status_t area :: getInfo ( area_info * dest ) {
2002-09-14 17:03:16 +00:00
dest -> area = areaID ;
2002-07-19 03:55:07 +00:00
strcpy ( dest -> name , name );
dest -> size = end_address - start_address ;
dest -> lock = state ;
2002-09-14 17:03:16 +00:00
dest -> protection = protection ;
2002-07-19 03:55:07 +00:00
dest -> team = manager -> getTeam ();
dest -> ram_size = 0 ;
dest -> in_count = 0 ;
dest -> out_count = 0 ;
dest -> copy_count = 0 ;
2002-11-19 04:05:16 +00:00
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-07-19 03:55:07 +00:00
vpage * page = ( vpage * ) cur ;
if ( page -> isMapped ())
dest -> ram_size += PAGE_SIZE ;
dest -> in_count += PAGE_SIZE ;
dest -> out_count += PAGE_SIZE ;
dest -> copy_count += PAGE_SIZE ;
}
dest -> address = ( void * ) start_address ;
return B_OK ;
}
2002-11-19 04:05:16 +00:00
bool area :: contains ( void * address ) {
2002-07-19 03:55:07 +00:00
unsigned long base = ( unsigned long )( address );
2002-09-16 03:14:44 +00:00
// error ("area::contains: looking for %d in %d -- %d, value = %d\n",base,start_address,end_address, ((start_address<=base) && (end_address>=base)));
2002-07-25 01:27:00 +00:00
2002-09-14 17:03:16 +00:00
return (( start_address <= base ) && ( base <= end_address ));
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
status_t area :: resize ( size_t newSize ) {
2002-07-19 03:55:07 +00:00
size_t oldSize = end_address - start_address ;
if ( newSize == oldSize )
return B_OK ;
2002-11-19 04:05:16 +00:00
if ( newSize > oldSize ) {
2002-10-03 03:42:59 +00:00
int pageCount = ( newSize - oldSize + PAGE_SIZE - 1 ) / PAGE_SIZE ;
2002-07-19 03:55:07 +00:00
vpage * newPage ;
2002-11-19 04:05:16 +00:00
for ( int i = 0 ; i < pageCount ; i ++ ) {
2002-09-05 03:26:02 +00:00
newPage = new ( vmBlock -> vpagePool -> get ()) vpage ;
2002-08-26 20:14:54 +00:00
newPage -> setup ( end_address + PAGE_SIZE * i - 1 , NULL , NULL , protection , state );
2002-07-19 03:55:07 +00:00
vpages . add ( newPage );
}
end_address += start_address + newSize ;
}
2002-11-19 04:05:16 +00:00
else {
2002-10-03 03:42:59 +00:00
int pageCount = ( oldSize - newSize + PAGE_SIZE - 1 ) / PAGE_SIZE ;
2002-07-19 03:55:07 +00:00
vpage * oldPage ;
struct node * cur ;
2002-11-19 04:05:16 +00:00
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 ;
}
oldPage = reinterpret_cast < vpage *> ( max );
2002-09-14 17:03:16 +00:00
vpages . remove ( cur );
2002-10-03 03:42:59 +00:00
if ( finalWrite )
oldPage -> flush ();
2002-08-26 20:14:54 +00:00
oldPage -> cleanup ();
2002-09-05 03:26:02 +00:00
vmBlock -> vpagePool -> put ( oldPage );
2002-07-19 03:55:07 +00:00
}
}
2002-09-14 17:03:16 +00:00
return B_OK ;
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
status_t area :: setProtection ( protectType prot ) {
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-07-19 03:55:07 +00:00
vpage * page = ( vpage * ) cur ;
page -> setProtection ( prot );
}
protection = prot ;
2002-09-14 17:03:16 +00:00
return B_OK ;
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
vpage * area :: findVPage ( unsigned long address ) {
vpage findMe ( address );
return reinterpret_cast < vpage *> ( vpages . find ( & findMe ));
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
bool area :: fault ( void * fault_address , bool writeError ) { // true = OK, false = panic.
2002-07-19 03:55:07 +00:00
vpage * page = findVPage (( unsigned long ) fault_address );
if ( page )
return page -> fault ( fault_address , writeError );
else
return false ;
}
2002-11-19 04:05:16 +00:00
char area :: getByte ( unsigned long address ) { // This is for testing only
2002-07-19 03:55:07 +00:00
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
return page -> getByte ( address , manager );
2002-07-19 03:55:07 +00:00
else
return 0 ;
}
2002-11-19 04:05:16 +00:00
void area :: setByte ( unsigned long address , char value ) { // This is for testing only
2002-07-19 03:55:07 +00:00
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
page -> setByte ( address , value , manager );
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
int area :: getInt ( unsigned long address ) { // This is for testing only
2002-07-19 03:55:07 +00:00
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
return page -> getInt ( address , manager );
else
return 0 ;
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
void area :: setInt ( unsigned long address , int value ) { // This is for testing only
2002-07-19 03:55:07 +00:00
vpage * page = findVPage ( address );
if ( page )
2002-09-14 17:03:16 +00:00
page -> setInt ( address , value , manager );
2002-07-19 03:55:07 +00:00
}
2002-11-19 04:05:16 +00:00
void area :: pager ( int desperation ) {
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-07-19 03:55:07 +00:00
vpage * page = ( vpage * ) cur ;
page -> pager ( desperation );
}
}
2002-11-19 04:05:16 +00:00
void area :: saver ( void ) {
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-07-19 03:55:07 +00:00
vpage * page = ( vpage * ) cur ;
page -> saver ();
}
}
2002-11-19 04:05:16 +00:00
void area :: dump ( void ) {
2002-09-16 03:14:44 +00:00
error ( "area::dump: size = %ld, lock = %d, address = %lx \n " , end_address - start_address , state , start_address );
2002-11-19 04:05:16 +00:00
vpages . dump ();
for ( hashIterate hi ( vpages ); node * cur = hi . get ();) {
2002-08-26 03:12:35 +00:00
vpage * page = ( vpage * ) cur ;
page -> dump ();
cur = cur -> next ;
}
}