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
00189 if (block->size >= nunits) {
00190
00191
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
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
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
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