Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

PsnThreadMemoryManager Class Reference

defines a memory manager that allocates memory for a thread. More...

#include <PsnThreadMemoryManager.h>

Inheritance diagram for PsnThreadMemoryManager:

Inheritance graph
[legend]
Collaboration diagram for PsnThreadMemoryManager:

Collaboration graph
[legend]
List of all members.

Public Methods

virtual ~PsnThreadMemoryManager ()
 Desctructor.

 PsnThreadMemoryManager (void *startDsm, size_t sizeDsm, PsnMemoryManager &rawMemoryProvider, PsnMemoryManager &descriptorMemoryProvider)
 Constructor.

virtual void * allocateSizeRemembered (size_t size)
 alloc a memory zone that can be correctly freed by calling freeSizeRemembered with the resulting pointer

virtual void freeSizeRemembered (void *ptr)
 free a memory zone allocated with allocateSizeRemembered

virtual void mfreeSizeRememberedOtherThread (void *ptr)
 free a memory zone allocated with allocateSizeRemembered, but freed by a different thread (should be called when in mutual exclusion with allocateSizeRemembered, freeSizeRemembered and inAdressSpace

virtual bool inAdressSpace (void *ptr) const
 find out if a given adress is managed by the current memory manager


Static Public Methods

void freeLeakedMemoryBlocks ()
 should only be called in mutual exclusion of all thread memory managers


Protected Methods

virtual void * getFromFree (size_t size)
virtual void addInFree (void *ptr, size_t size)

Static Protected Methods

list< void * > & getListOfDetachedMemoryBlocks ()
 the list of detached memory blocks is the list of memory blocks that didn't belong to the memory manager to which they where handed.

list< pair< void *, PsnThreadMemoryManager * > > & getListOfLeakedMemoryBlocks ()
 the list of leaked memory blocks is the list of memory blocks that couldn't be freed at the time they where handled to their memory manager because they were handled to the memory manager by a thread different of the thread that had allocated them

PsnMutexLockgetFreedMemoryBlocksMutex ()
PsnMutexLockgetLeakedMemoryBlocksMutex ()

Protected Attributes

size_t _memoryManaged
 the size of the memory managed

PsnMemoryManager_rawMemoryProvider
 if more memory is needed, get it from this memory manager

PsnMemoryManager_descriptorMemoryProvider
 allocate the memory element descriptors from this memory manager

PsnMemoryElementDescriptor_freeMemoryZones
 head of the free memory elements

PsnMemoryElementDescriptor_managedMemoryZones
 head of the list of managed memory zones

pthread_t _user
 for debugging purposes : ths id of the thread that should be doing allocations with this memory manager


Detailed Description

defines a memory manager that allocates memory for a thread.

Author:
David Margery
Version:
1.0

Definition at line 29 of file PsnThreadMemoryManager.h.


Constructor & Destructor Documentation

PsnThreadMemoryManager::~PsnThreadMemoryManager   [virtual]
 

Desctructor.

Definition at line 59 of file PsnThreadMemoryManager.cxx.

00060 {
00061 }

PsnThreadMemoryManager::PsnThreadMemoryManager void *    startDsm,
size_t    sizeDsm,
PsnMemoryManager   rawMemoryProvider,
PsnMemoryManager   descriptorMemoryProvider
 

Constructor.

Parameters:
startDsm the adress of the memory zone to manage
sizeDsm the size of the memory zone to manage
rawMemoryProvider: if more memory is needed, get it from this memory manager
descriptorMemoryProvider: get the memory needed for the memory bmock descriptors from this memory manager

Definition at line 64 of file PsnThreadMemoryManager.cxx.

References _freeMemoryZones, _managedMemoryZones, PsnMemoryElementDescriptor::base, PsnMemoryElementDescriptor::next, and PsnMemoryElementDescriptor::size.

00067                                                                                                :
00068    PsnMemoryManager(),
00069    _memoryManaged ( sizeDsm ),
00070    _rawMemoryProvider ( rawMemoryProvider ),
00071    _descriptorMemoryProvider ( descriptorMemoryProvider ),
00072    _freeMemoryZones ( new(&descriptorMemoryProvider) PsnMemoryElementDescriptor ( ) ),
00073    _managedMemoryZones ( new(&descriptorMemoryProvider) PsnMemoryElementDescriptor ( ) ),
00074    _user ( pthread_self() )
00075 {
00076    // the getFromFree member function relies on that
00077    assert ( startDsm != 0 ) ;
00078 
00079    _managedMemoryZones->base = (unsigned int) startDsm ;
00080    _managedMemoryZones->size = sizeDsm ;
00081    _managedMemoryZones->next = 0 ;
00082 
00083    _freeMemoryZones->base = (unsigned int) startDsm ;
00084    _freeMemoryZones->size = sizeDsm ;
00085    _freeMemoryZones->next = 0 ;
00086 }


Member Function Documentation

void PsnThreadMemoryManager::addInFree void *    ptr,
size_t    size
[protected, virtual]
 

Definition at line 280 of file PsnThreadMemoryManager.cxx.

References _descriptorMemoryProvider, _freeMemoryZones, _user, PsnMemoryElementDescriptor::base, inAdressSpace(), PsnMemoryElementDescriptor::next, and PsnMemoryElementDescriptor::size.

Referenced by allocateSizeRemembered(), freeSizeRemembered(), and mfreeSizeRememberedOtherThread().

00281 {
00282 #ifdef _DEBUGMEMORYMANAGEMENT
00283    assert ( _user == pthread_self() ) ;
00284    //integrity check
00285    PsnMemoryElementDescriptor * test = _freeMemoryZones ;
00286    while (test != 0)
00287       {
00288          assert (inAdressSpace ( ( PsnMemoryElementDescriptor *)test->base ) ) ;
00289          assert ( test != ( PsnMemoryElementDescriptor *)test->next ) ;
00290          if ( test->next != 0)
00291             {
00292                assert ( ((PsnMemoryElementDescriptor *)test->next)->base > test->base + test->size ) ;
00293             }
00294          test = ( PsnMemoryElementDescriptor *)test->next ;
00295       }
00296 #endif
00297 #ifdef _DEBUGMEMORYMANAGEMENT
00298    cerr<<"PsnThreadMemoryManager:"<<this<<":addInFree: ("<<ptr<<","<<size<<")"<<endl;
00299 #endif
00300    PsnMemoryElementDescriptor *l, *iNew, *tmp ;
00301 
00302    iNew = new(& _descriptorMemoryProvider) PsnMemoryElementDescriptor();
00303    iNew->base = (unsigned int)ptr ;
00304    iNew->size = size;
00305    
00306    if ( _freeMemoryZones  == NULL) 
00307       { /* No free memory in the memory manager */
00308          iNew->next = (unsigned int) NULL ;
00309          _freeMemoryZones = iNew ;
00310       }    
00311    else 
00312       {
00313          l = _freeMemoryZones ;
00314          if ( l->base > iNew->base ) 
00315             {
00316                /* iNew is the lowest interval */
00317                iNew->next = (unsigned int) _freeMemoryZones ;
00318                _freeMemoryZones = iNew ;
00319                //reorder so that l->next == iNew for merge test
00320                l = iNew ;
00321                iNew = (PsnMemoryElementDescriptor *) l->next ;
00322             }    
00323          else 
00324             { 
00325                /* Search the immediate lower interval */
00326                tmp = (PsnMemoryElementDescriptor * ) l -> next ;
00327                bool onBoucle = ( tmp != NULL ) ;
00328                if (onBoucle )
00329                   {
00330                      onBoucle = ( iNew->base > tmp->base ) ;
00331                   } 
00332                while ( onBoucle ) 
00333                   {
00334                      l = tmp ;
00335                      tmp = (PsnMemoryElementDescriptor * ) l->next ;
00336                      if (tmp != NULL) 
00337                         {
00338                            onBoucle = iNew->base > tmp->base ;
00339                         }       
00340                      else 
00341                         {
00342                            onBoucle = false ;
00343                         }
00344                   }
00345                
00346                iNew->next = (unsigned int) tmp ;
00347                l->next = (unsigned int) iNew ;
00348                if ( tmp != NULL ) 
00349                   {
00350                      //try to merge the the new free zone with the following free zonee
00351                      if (iNew->base + iNew->size == tmp -> base) 
00352                         {
00353 #ifdef _DEBUGMEMORYMANAGEMENT
00354                            cerr<<"Merging new free zone ("<<ptr<<") with following"<<endl;
00355 #endif
00356                            iNew->size += tmp->size ;
00357                            iNew->next = tmp->next ;
00358                            delete tmp ;
00359                         }
00360                   }
00361             }
00362          if ( l->base + l->size == iNew->base ) 
00363             {
00364                //try and merger the preceeding free memory block with the freed one
00365 #ifdef _DEBUGMEMORYMANAGEMENT
00366                cerr<<"Merging new free zone ("<<ptr<<") with preceeding"<<endl;
00367 #endif
00368                l->size += iNew->size ;
00369                l->next = iNew->next ;
00370                if (_freeMemoryZones == iNew) 
00371                   {
00372                      _freeMemoryZones = l;
00373                   }
00374                delete iNew ;
00375             }     
00376       }
00377 #ifdef _DEBUGMEMORYMANAGEMENT
00378    //integrity check
00379    test = _freeMemoryZones ;
00380    while (test != 0)
00381       {
00382          assert (inAdressSpace ( ( PsnMemoryElementDescriptor *)test->base ) ) ;
00383          assert ( test != ( PsnMemoryElementDescriptor *)test->next ) ;
00384          if ( test->next != 0)
00385             {
00386                assert ( ((PsnMemoryElementDescriptor *)test->next)->base > test->base + test->size ) ;
00387             }
00388          test = ( PsnMemoryElementDescriptor *)test->next ;
00389       }
00390 #endif
00391 }

void * PsnThreadMemoryManager::allocateSizeRemembered size_t    size [virtual]
 

alloc a memory zone that can be correctly freed by calling freeSizeRemembered with the resulting pointer

Implements PsnMemoryManager.

Definition at line 90 of file PsnThreadMemoryManager.cxx.

References _descriptorMemoryProvider, _managedMemoryZones, _memoryManaged, _rawMemoryProvider, _user, addInFree(), PsnMemoryManager::allocateSizeRemembered(), PsnMemoryElementDescriptor::base, getFromFree(), PsnMemoryElementDescriptor::next, and PsnMemoryElementDescriptor::size.

00091 {
00092 #ifdef _DEBUGMEMORYMANAGEMENT
00093    assert ( _user == pthread_self() ) ;
00094 #endif
00095    size_t sizeNeeded =  sizeof(size_t) + size ;
00096    void * result = getFromFree ( sizeNeeded  ) ;
00097    //cerr<<"PsnThreadMemoryManager::allocateSizeRemembered "<<result<<endl;
00098    if ( result == NULL )
00099       {
00100          PsnMemoryElementDescriptor * iNew ;
00101          
00102          //allocate more memory
00103          result = _rawMemoryProvider.allocateSizeRemembered ( _memoryManaged ) ;
00104          if ( result != NULL)
00105             {
00106                iNew = new (& _descriptorMemoryProvider) PsnMemoryElementDescriptor();
00107                iNew->base = (unsigned int)result ;
00108                iNew->size = _memoryManaged ;
00109                iNew->next = 0 ;
00110                _managedMemoryZones->next = (unsigned int) iNew ;
00111 
00112                addInFree (result, _memoryManaged ) ;
00113                _memoryManaged += _memoryManaged ;
00114 
00115                //retry
00116                result = allocateSizeRemembered ( sizeNeeded ) ;
00117             }
00118          else
00119             {//allocation has failed, try minimum allocation
00120                result = _rawMemoryProvider.allocateSizeRemembered ( sizeNeeded ) ;
00121                if ( result != NULL)
00122                   {
00123                      iNew = new (& _descriptorMemoryProvider) PsnMemoryElementDescriptor();
00124                      iNew->base = (unsigned int)result ;
00125                      iNew->size = sizeNeeded;
00126                      iNew->next = 0 ;
00127                      _managedMemoryZones->next = (unsigned int) iNew ;
00128 
00129                      addInFree (result, sizeNeeded ) ;
00130                      _memoryManaged += sizeNeeded ;
00131                      
00132                      //retry
00133                      result = allocateSizeRemembered ( sizeNeeded ) ;
00134                   }
00135             }
00136       }
00137    if (result != NULL) 
00138       {
00139          *((size_t *)result) = size;
00140          
00141          result = (void *) ((unsigned int)result + sizeof (size_t ) ) ;
00142       }
00143    return result ;
00144 }

void PsnThreadMemoryManager::freeLeakedMemoryBlocks   [static]
 

should only be called in mutual exclusion of all thread memory managers

Definition at line 34 of file PsnThreadMemoryManager.cxx.

References list< T, Alloc >::begin(), list< T, Alloc >::end(), list< T, Alloc >::erase(), PsnMemoryManager::freeSizeRemembered(), getFreedMemoryBlocksMutex(), getLeakedMemoryBlocksMutex(), getListOfDetachedMemoryBlocks(), getListOfLeakedMemoryBlocks(), PsnMutexLock::protect(), PsnMutexLock::unprotect(), and PsnMemoryManager::whichMemoryManager().

Referenced by PsnMultiThreadedScheduler::runStep(), and PsnMultiThreadedBenchmarkingScheduler::runStep().

00035 {
00036    getFreedMemoryBlocksMutex().protect() ;
00037    list <void *> & mylist ( getListOfDetachedMemoryBlocks () ) ;
00038    for ( list <void *>::iterator i = mylist.begin() ;
00039          i != mylist.end() ;
00040          i = mylist.erase (i) )
00041       {
00042          PsnMemoryManager * correctMemoryManager = PsnMemoryManager::whichMemoryManager ( *i ) ;
00043          correctMemoryManager->freeSizeRemembered ( *i ) ;
00044       }
00045    getFreedMemoryBlocksMutex().unprotect() ;
00046    getLeakedMemoryBlocksMutex().protect() ;
00047    list <pair <void *, PsnThreadMemoryManager *> > & alist ( getListOfLeakedMemoryBlocks () ) ;
00048    for ( list <pair <void *, PsnThreadMemoryManager *> >::iterator i = alist.begin() ;
00049          i != alist.end() ;
00050          i = alist.erase (i) )
00051       {
00052          (*i).second->mfreeSizeRememberedOtherThread ( (*i).first ) ;
00053       }
00054    getLeakedMemoryBlocksMutex().unprotect() ;
00055 } 

void PsnThreadMemoryManager::freeSizeRemembered void *    ptr [virtual]
 

free a memory zone allocated with allocateSizeRemembered

Implements PsnMemoryManager.

Definition at line 159 of file PsnThreadMemoryManager.cxx.

References _descriptorMemoryProvider, _user, addInFree(), PsnMemoryManager::freeSizeRemembered(), getFreedMemoryBlocksMutex(), getLeakedMemoryBlocksMutex(), getListOfDetachedMemoryBlocks(), getListOfLeakedMemoryBlocks(), PsnMemoryManager::inAdressSpace(), inAdressSpace(), make_pair(), PsnMutexLock::protect(), and PsnMutexLock::unprotect().

00160 {
00161    //cerr<<"PsnThreadMemoryManager::freeSizeRemembered "<<pthread_self()<<endl;
00162    if ( _user == pthread_self() ) 
00163       {
00164          if (inAdressSpace ( ptr) )
00165             {
00166                size_t * addressOfSize = (size_t *) ((unsigned int)ptr - sizeof ( size_t ) ) ;
00167                addInFree ( (void *)addressOfSize, *addressOfSize + sizeof ( size_t ) ) ;
00168             }
00169          else
00170             {
00171                if ( _descriptorMemoryProvider.inAdressSpace ( ptr ) )
00172                   {
00173                      _descriptorMemoryProvider.freeSizeRemembered( ptr ) ;
00174                   }
00175                else
00176                   {
00177                      getFreedMemoryBlocksMutex().protect() ;
00178                      getListOfDetachedMemoryBlocks().push_back ( ptr ) ;
00179                      getFreedMemoryBlocksMutex().unprotect() ;
00180                   }
00181             }
00182       }
00183    else
00184    {
00185       getLeakedMemoryBlocksMutex().protect() ;
00186       getListOfLeakedMemoryBlocks().push_back ( make_pair ( ptr, this) ) ;
00187       getLeakedMemoryBlocksMutex().unprotect() ;
00188    }
00189 }

PsnMutexLock & PsnThreadMemoryManager::getFreedMemoryBlocksMutex   [static, protected]
 

Definition at line 23 of file PsnThreadMemoryManager.cxx.

Referenced by freeLeakedMemoryBlocks(), and freeSizeRemembered().

00024 {
00025    static PsnMutexLock toto ;
00026    return toto ;
00027 }

void * PsnThreadMemoryManager::getFromFree size_t    size [protected, virtual]
 

Definition at line 191 of file PsnThreadMemoryManager.cxx.

References _freeMemoryZones, _user, PsnMemoryElementDescriptor::base, inAdressSpace(), PsnMemoryElementDescriptor::next, and PsnMemoryElementDescriptor::size.

Referenced by allocateSizeRemembered().

00192 {
00193 #ifdef _DEBUGMEMORYMANAGEMENT
00194    assert ( _user == pthread_self() ) ;
00195    //integrity check
00196    PsnMemoryElementDescriptor * test = _freeMemoryZones ;
00197    while (test != 0)
00198       {
00199          assert (inAdressSpace ( ( PsnMemoryElementDescriptor *)test->base ) ) ;
00200          assert ( test != ( PsnMemoryElementDescriptor *)test->next ) ;
00201          if ( test->next != 0)
00202             {
00203                assert ( ((PsnMemoryElementDescriptor *)test->next)->base > test->base + test->size ) ;
00204             }
00205          test = ( PsnMemoryElementDescriptor *)test->next ;
00206       }
00207 #endif
00208    PsnMemoryElementDescriptor *i , *pred ;
00209    
00210    unsigned int addr ;
00211    
00212    
00213    i = _freeMemoryZones ;
00214 
00215    pred = NULL ;
00216    
00217    addr = 0 ;
00218    
00219    while ( i != NULL )
00220     {
00221        if ( i->size >= size )   /* First fit strategy */
00222           {
00223              addr = i->base ;
00224              if ( i->size == size )
00225                 {
00226                    if ( pred == NULL ) 
00227                       {
00228                          PsnMemoryElementDescriptor * newStartFreeList = (PsnMemoryElementDescriptor *) i -> next ;
00229                          delete _freeMemoryZones ;
00230                          _freeMemoryZones = newStartFreeList ; 
00231                       }
00232                    else 
00233                       {
00234                          pred->next = i->next ;
00235                          delete ( i ) ;
00236                       }     
00237                 }
00238              else
00239                 {
00240                    i->base = i->base + size ;
00241                    i->size = i->size - size ;
00242                 }
00243              i = NULL ;
00244           }
00245        else
00246           {
00247              pred = i ;
00248              i = (PsnMemoryElementDescriptor *) i->next ;
00249           }
00250     }
00251 #ifdef _DEBUGMEMORYMANAGEMENT
00252    //integrity check
00253    test = _freeMemoryZones ;
00254    while (test != 0)
00255       {
00256          assert (inAdressSpace ( ( PsnMemoryElementDescriptor *)test->base ) ) ;
00257          assert ( test != ( PsnMemoryElementDescriptor *)test->next ) ;
00258          if ( test->next != 0)
00259             {
00260                assert ( ((PsnMemoryElementDescriptor *)test->next)->base > test->base + test->size ) ;
00261             }
00262          test = ( PsnMemoryElementDescriptor *)test->next ;
00263       }
00264 #endif
00265   if (addr == 0 ) //no correct memory zone was found
00266      {
00267         return NULL ;
00268      }
00269   else 
00270      {
00271         return (void *)addr ;
00272      }
00273 #ifdef _DEBUGMEMORYMANAGEMENT
00274    cerr<<"PsnThreadMemoryManager:"<<this<<":addInFree: ("<<(void *)addr<<","<<size<<")"<<endl;
00275 #endif
00276 }

PsnMutexLock & PsnThreadMemoryManager::getLeakedMemoryBlocksMutex   [static, protected]
 

Definition at line 28 of file PsnThreadMemoryManager.cxx.

Referenced by freeLeakedMemoryBlocks(), and freeSizeRemembered().

00029 {
00030    static PsnMutexLock toto ;
00031    return toto ;
00032 }

list< void * > & PsnThreadMemoryManager::getListOfDetachedMemoryBlocks   [static, protected]
 

the list of detached memory blocks is the list of memory blocks that didn't belong to the memory manager to which they where handed.

They therefore need to be handed to the memory manager that allocated them

Definition at line 11 of file PsnThreadMemoryManager.cxx.

Referenced by freeLeakedMemoryBlocks(), and freeSizeRemembered().

00012 {
00013    static list <void  *> designPattern ; 
00014    return  designPattern ;
00015 }

list< pair< void *, PsnThreadMemoryManager * > > & PsnThreadMemoryManager::getListOfLeakedMemoryBlocks   [static, protected]
 

the list of leaked memory blocks is the list of memory blocks that couldn't be freed at the time they where handled to their memory manager because they were handled to the memory manager by a thread different of the thread that had allocated them

Definition at line 17 of file PsnThreadMemoryManager.cxx.

Referenced by freeLeakedMemoryBlocks(), and freeSizeRemembered().

00018 {
00019    static list <pair <void *, PsnThreadMemoryManager *> > designPattern ; 
00020    return  designPattern ;
00021 }

bool PsnThreadMemoryManager::inAdressSpace void *    ptr const [virtual]
 

find out if a given adress is managed by the current memory manager

Implements PsnMemoryManager.

Definition at line 394 of file PsnThreadMemoryManager.cxx.

References _managedMemoryZones, PsnMemoryElementDescriptor::inAdressSpace(), and PsnMemoryElementDescriptor::next.

Referenced by addInFree(), freeSizeRemembered(), getFromFree(), and mfreeSizeRememberedOtherThread().

00395 {
00396    bool result = false ;
00397    unsigned int adress = (unsigned int ) ptr ;
00398    PsnMemoryElementDescriptor * current = _managedMemoryZones ;
00399    while ( (! result) && ( current != NULL ) )
00400    {
00401       result = current->inAdressSpace ( adress ) ;
00402       current = (PsnMemoryElementDescriptor *) current->next ;
00403    }
00404    return result ;
00405 }

void PsnThreadMemoryManager::mfreeSizeRememberedOtherThread void *    ptr [virtual]
 

free a memory zone allocated with allocateSizeRemembered, but freed by a different thread (should be called when in mutual exclusion with allocateSizeRemembered, freeSizeRemembered and inAdressSpace

Definition at line 148 of file PsnThreadMemoryManager.cxx.

References addInFree(), and inAdressSpace().

00149 {
00150 #ifdef _DEBUGMEMORYALLOCATION
00151    inAdressSpace ( ptr) ;
00152 #endif
00153    size_t * addressOfSize = (size_t *) ((unsigned int)ptr - sizeof ( size_t ) ) ;
00154    addInFree ( (void *)addressOfSize, *addressOfSize + sizeof ( size_t ) ) ;
00155 }


Member Data Documentation

PsnMemoryManager& PsnThreadMemoryManager::_descriptorMemoryProvider [protected]
 

allocate the memory element descriptors from this memory manager

Definition at line 85 of file PsnThreadMemoryManager.h.

Referenced by addInFree(), allocateSizeRemembered(), and freeSizeRemembered().

PsnMemoryElementDescriptor* PsnThreadMemoryManager::_freeMemoryZones [protected]
 

head of the free memory elements

Definition at line 88 of file PsnThreadMemoryManager.h.

Referenced by addInFree(), getFromFree(), and PsnThreadMemoryManager().

PsnMemoryElementDescriptor* PsnThreadMemoryManager::_managedMemoryZones [protected]
 

head of the list of managed memory zones

Definition at line 91 of file PsnThreadMemoryManager.h.

Referenced by allocateSizeRemembered(), inAdressSpace(), and PsnThreadMemoryManager().

size_t PsnThreadMemoryManager::_memoryManaged [protected]
 

the size of the memory managed

Definition at line 79 of file PsnThreadMemoryManager.h.

Referenced by allocateSizeRemembered().

PsnMemoryManager& PsnThreadMemoryManager::_rawMemoryProvider [protected]
 

if more memory is needed, get it from this memory manager

Definition at line 82 of file PsnThreadMemoryManager.h.

Referenced by allocateSizeRemembered().

pthread_t PsnThreadMemoryManager::_user [protected]
 

for debugging purposes : ths id of the thread that should be doing allocations with this memory manager

Definition at line 94 of file PsnThreadMemoryManager.h.

Referenced by addInFree(), allocateSizeRemembered(), freeSizeRemembered(), and getFromFree().


The documentation for this class was generated from the following files:
logo OpenMask

Documentation generated on Mon Nov 25 15:26:31 2002

Generated with doxygen 1.2.12 by Dimitri van Heesch ,   1997-2001