shm_allocator.h

Go to the documentation of this file.
00001 
00004 #ifndef SHM_ALLOCATOR_H
00005 #define SHM_ALLOCATOR_H 1
00006 
00007 
00008 #include "shm_ptr.h"
00009 #include "scoped_lock.h"
00010 
00044 class shm_allocator
00045 {
00046  private:
00053   struct shm_allocator_block
00054   {
00055     shm_ptr<shm_allocator_block> prev;
00056     shm_ptr<shm_allocator_block> next;
00057     size_t size;
00058   };
00059   #define get_block(c) ((shm_allocator_block *)(c.get(seg)))
00060   #define next_block(c) ((shm_allocator_block *)((c->next).get(seg)))
00061   #define prev_block(c) ((shm_allocator_block *)((c->prev).get(seg)))
00062   #define set_next_block(b,n) ((b->next).reset(n,seg))
00063   #define set_prev_block(b,n) ((b->prev).reset(n,seg))
00064   #define block_size(c) (c->size)
00065 
00073   struct shm_allocator_header
00074   {
00075     key_t  key;
00076     pthread_mutex_t lock;
00077     shm_ptr<shm_allocator_block> freelist;
00078   };
00079                                                                                 
00080   #define overhead()  sizeof(shm_allocator_header)+sizeof(shm_allocator_block)
00081   #define get_freelist()  ((shm_allocator_block *)(header->freelist.get(seg)))
00082   #define set_freelist(b) (header->freelist.reset(b,seg))
00083 
00092   void init() {
00093     shm_allocator_header *seg_head;
00094     seg_head = static_cast<shm_allocator_header*>(seg.get_base());
00095     if ( seg_head->key != seg.get_key() ) {
00096       init_allocator_header();
00097      } else {
00098       header = seg_head;
00099     }
00100   }
00101 
00108   void init_allocator_header() {
00109       header = new ( seg.get_base() ) shm_allocator_header ;
00110       shm_allocator_block * first;
00111       first = (shm_allocator_block *)( ( char * ) header + sizeof( shm_allocator_header ) );
00112       first->size = seg.get_size() - ( overhead() );
00113       first->prev.reset( first, seg ) ;
00114       first->next.reset( first, seg ) ;
00115       header->freelist.reset( first, seg ) ;
00116       header->key = seg.get_key();
00117       init_allocator_header_lock( header );
00118   }
00119 
00125   void init_allocator_header_lock( shm_allocator_header *head ) {
00126     pthread_mutexattr_t mattr; 
00127     pthread_condattr_t cattr; 
00128     int rc; 
00129     rc = pthread_mutexattr_init(&mattr); 
00130     rc = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
00131     rc = pthread_mutex_init( &(head->lock), &mattr );
00132   }
00133                                                                                 
00134   shm_segment& seg ;
00135   shm_allocator_header* header ;
00136 
00137  public:
00148   shm_allocator( shm_segment& s ) : seg( s ) {
00149     init();
00150     return ; 
00151   } ;
00152 
00153   shm_allocator_block * split_block( shm_allocator_block * b, size_t s );
00154   shm_allocator_block * insert_block( shm_allocator_block * b );
00155   shm_allocator_block * remove_block( shm_allocator_block * b );
00156   void* alloc( size_t nbytes );
00157   void free( void * addr );
00158   const shm_segment& get_segment() const { return seg ; } ;
00159   size_t get_overhead() 
00160   { 
00161     return (size_t) 
00162       sizeof(shm_allocator_header) + 
00163       sizeof(shm_allocator_block) ;
00164   } ;
00165 };
00166 
00176 void* shm_allocator::alloc(size_t bytes)
00177 {
00178   scoped_lock guard(&header->lock);
00179   size_t nbytes = ( ( bytes % sizeof( long ) ) ? bytes : 
00180             bytes + ( sizeof( long ) - ( bytes % sizeof( long ) ) ) );
00181   size_t nunits = (nbytes + sizeof(shm_allocator_block) - 1) /
00182     sizeof(shm_allocator_block) + 1;
00183  
00184   shm_allocator_block* prev = get_freelist();
00185   shm_allocator_block* block = next_block( prev );
00186   do
00187     {
00188       // current block is large enough
00189       if (block->size >= nunits) {
00190     // if current block is exact size, 
00191     // remove block from freelist
00192     if (block->size == nunits) {
00193       shm_ptr<shm_allocator_block> next;
00194       prev->next = next = block->next;
00195       (next.get(seg))->prev = block->prev;
00196     } else {
00197       // split block
00198       shm_allocator_block* remainder = split_block( block, nbytes );
00199       insert_block( remainder );
00200       remove_block( block );
00201     }
00202     return (void*)( block + 1 );
00203       }
00204       prev = block;
00205       block = next_block( block );
00206     } while( block != get_freelist() );
00207   return NULL;
00208 }
00209 
00210 void shm_allocator::free(void* addr)
00211 {
00212   scoped_lock guard(&header->lock);
00213   shm_allocator_block* block = static_cast<shm_allocator_block*>(addr) - 1;
00214   insert_block( block ) ;
00215   return;
00216 }
00217 
00228 shm_allocator::shm_allocator_block * shm_allocator::remove_block( shm_allocator::shm_allocator_block * b ) 
00229 {
00230   shm_allocator_block *first;
00231   first = (shm_allocator_block *) get_freelist();
00232   if ( b == first ) {
00233     if( b == next_block( first ) ) {
00234       //      int i = 1 / 0;
00235       set_freelist((shm_allocator_block *)seg.get_base() + sizeof( shm_allocator_header ) );
00236     }
00237     set_freelist(next_block(b));
00238   }
00239   set_prev_block( next_block(b), prev_block(b) );
00240   set_next_block( prev_block(b), next_block(b) );
00241   return b;
00242 }
00243 
00250 shm_allocator::shm_allocator_block * shm_allocator::insert_block( shm_allocator::shm_allocator_block * b ) 
00251 {
00252   shm_allocator_block *first, *last, *current;
00253   first = current = get_freelist();
00254   last = prev_block( current );
00255   if ( block_size(b) < block_size(first) ) {
00256     set_freelist(b);
00257   }
00258   // block is smaller than first
00259   while ( block_size(b) > block_size(current) && 
00260                     current != last ) {
00261     current = next_block(current);
00262   }
00263   if ( first == last ) {
00264     set_prev_block(b, first);
00265     set_next_block(b, first);
00266     set_prev_block(first,b);
00267     set_next_block(first,b);
00268     return current;
00269   }
00270   set_prev_block(b, prev_block(current));
00271   set_next_block(prev_block(current),b);
00272   set_prev_block(current,b);
00273   set_next_block(b,current);
00274   return current;
00275 }
00276 
00289 shm_allocator::shm_allocator_block * shm_allocator::split_block( shm_allocator::shm_allocator_block * b, size_t s ) 
00290 {  
00291   shm_allocator_block * remainder;
00292   long displacement = (long) sizeof(shm_allocator_block) + s;
00293   remainder = (shm_allocator_block *)( ( char * ) b + displacement );
00294   remainder->size = b->size - displacement;
00295   remainder->prev.set(0);
00296   remainder->next.set(0);
00297   b->size = s;
00298   return remainder;
00299 }
00300 
00301   
00302 #endif
00303  

Project shmq hosted by   SourceForge.net
Documentation generated on Sat Sep 2 10:07:40 2006 for shmq by   doxygen.org 1.4.6