shared.C
上传用户:shtangtang
上传日期:2007-01-04
资源大小:167k
文件大小:8k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. #include "shared.h"
  2. #include <string>
  3. extern "C" {
  4. #   include <sys/types.h>
  5. #   include <sys/stat.h>
  6. #   include <fcntl.h>
  7. #   include <errno.h>
  8. #   include "cloning.h"
  9. };
  10. shared_mem::shared_mem()
  11. {
  12.   _perm             = IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
  13.   _key_root         = new char[80];
  14.   _blocks           = 0;
  15.   _work_area._file  = 0;
  16.   change_proj( "/tmp/project" );
  17. }
  18. shared_mem::shared_mem(const char *p_root)
  19. {
  20.   _perm             = IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;
  21.   _key_root         = new char[80];
  22.   _blocks           = 0;
  23.   _work_area._file  = 0;
  24.   change_proj( p_root );
  25. }
  26. shared_mem::~shared_mem()
  27. {
  28.   cleanup();
  29.   delete _key_root;
  30. }
  31. void shared_mem::change_proj(const char *p_root)
  32. {
  33.   strncpy( _key_root,p_root,79 );
  34. }
  35. void shared_mem::change_perm(int p_perm)
  36. {
  37.   _perm = p_perm&0777;
  38. }
  39. int shared_mem::create_proj(const char *p_id)
  40. {
  41.   int fd;
  42.   string s = _key_root;
  43.   sto_iterator i;
  44.   _key_lock.lock();
  45. #ifdef DEBUG
  46.   cout << "create_proj(" << p_id << ")n";
  47. #endif
  48.   if ( p_id && strlen(p_id) > 0 ) {
  49.     s += "_";
  50.     s += p_id;
  51.   }
  52.   fd = open( s.c_str(),O_CREAT,_perm );
  53.   if ( fd != -1 ) {
  54.     close( fd );
  55.     for( i=_shared.begin();(i != _shared.end());i++ )
  56.       if ( (*i)._file != 0 && strcmp((*i)._file,s.c_str()) == 0 ) {
  57. _key_lock.unlock();
  58. return (*i)._id;
  59.       }
  60.     _work_area._id   = ++_blocks;
  61.     _work_area._key  = -1;
  62.     _work_area._file = strdup( s.c_str() );
  63.     _work_area._proj = 0;
  64.     _work_area._ptr  = 0;
  65.     _work_area._page = 0;
  66.     _work_area._mid  = 0;
  67. #ifdef DEBUG
  68.     cout << "new project " << _blocks << endl;
  69. #endif
  70.     _shared.push_back( _work_area );
  71.   } else
  72.     return -1;
  73.   _key_lock.unlock();
  74.   return _blocks;
  75. }
  76. key_t shared_mem::get_key(const char *p_id,int p_proj)
  77. {
  78.   string s = _key_root;
  79.   key_t key = -1;
  80.   sto_iterator i;
  81.   _key_lock.lock();
  82.   if ( p_id && strlen(p_id) > 0 ) {
  83.     s += "_";
  84.     s += p_id;
  85.   }
  86.   for( i=_shared.begin();(i != _shared.end());i++ )
  87.     if ( strcmp((*i)._file,s.c_str()) == 0 && (*i)._proj == p_proj ) {
  88.       key = (*i)._key;
  89.       break;
  90.     }
  91.   _key_lock.unlock();
  92.   return key;
  93. }
  94. key_t shared_mem::make_key(int p_proj)
  95. {
  96.   sto_iterator k = _shared.end();
  97.   sto_iterator i = _shared.begin();
  98.   _key_lock.lock();
  99. #ifdef DEBUG
  100.   cout << "make_key(" << p_proj << ")n";
  101. #endif
  102.   _work_area._key = -1;
  103.   for( ;(i != _shared.end());i++ )
  104.     if ( (*i)._id == p_proj )
  105.       if ( k == _shared.end() || (*i)._key == -1 || (*k)._proj < (*i)._proj )
  106. k = i;
  107.   if ( k != _shared.end() ) {
  108.     if ( (*k)._key != -1 ) {
  109.       _work_area = (*k);
  110.       if ( ++_work_area._proj != 0 ) {
  111. _work_area._key  = ftok( _work_area._file,_work_area._proj );
  112. #ifdef DEBUG
  113. cout << "new key " << _work_area._key << endl;
  114. #endif
  115. _shared.push_back( _work_area );
  116.       }
  117.     } else {
  118.       _work_area._key = (*k)._key = ftok( (*k)._file,(*k)._proj );
  119. #ifdef DEBUG
  120.       cout << "added a key " << (*k)._key << endl;
  121. #endif
  122.     }
  123.   }
  124.   _key_lock.unlock();
  125.   return _work_area._key;
  126. }
  127. list<shared_mem::mem_entry>::iterator
  128. shared_mem::getmem(sto_iterator i,size_t p_size)
  129. {
  130.   size_t total_size = ((p_size/PAGE_SIZE)+1)*PAGE_SIZE;
  131.   _mem_entry._size = 0;
  132.   (*i)._mid = shmget( (*i)._key,p_size,IPC_CREAT|_perm );
  133.   if ( (*i)._mid == -1 )
  134.     return _free_list.end();
  135.   (*i)._ptr  = shmat( (*i)._mid,0,0 );
  136.   (*i)._page = total_size;
  137. #ifdef DEBUG
  138.   cout.form("Got a segment %p, sized %dn",(*i)._ptr,(*i)._page);
  139. #endif
  140.   _mem_entry._size = total_size;
  141.   _mem_entry._data = (*i)._ptr;
  142.   return _free_list.insert( _free_list.end(),_mem_entry );
  143. }
  144. void shared_mem::fragment(mem_iterator i,size_t p_size)
  145. {
  146. #ifdef DEBUG
  147.   cout.form("Fragmenting %p",(*i)._data);
  148.   cout << " cutting out " << p_size;
  149. #endif
  150.   _mem_entry._size = p_size;
  151.   _mem_entry._data = (*i)._data;
  152.   (*i)._size      -= p_size;
  153.   (*i)._data       = (void *)((long)(*i)._data + p_size);
  154. #ifdef DEBUG
  155.   cout << " redusing it to " << (*i)._size << endl;
  156. #endif
  157. }
  158. void *shared_mem::keyalloc(key_t p_key,size_t p_size)
  159. {
  160.   void *ptr = 0;
  161.   sto_iterator i;
  162.   // Notice the order of the locks, doing it the other way around
  163.   // may cause a deadlock... see: alloc-fillup
  164.   _mem_lock.lock();
  165.   _key_lock.lock();
  166.   for( i=_shared.begin();(i != _shared.end());i++ )
  167.     if ( (*i)._key == p_key && (*i)._page <= p_size ) {
  168.       ptr = (*i)._ptr;
  169.       break;
  170.     }
  171.   if ( ptr == 0 && i != _shared.end() )
  172.     fragment( getmem(i,p_size),p_size );
  173.   _key_lock.unlock();
  174.   _mem_lock.unlock();
  175.   return ptr;
  176. }
  177. void *shared_mem::alloc(size_t p_size,int p_proj)
  178. {
  179.   mem_iterator i,j;
  180.   _mem_lock.lock();
  181. #ifdef DEBUG
  182.   cout << "alloc(" << p_size << "," << p_proj << ")n";
  183. #endif
  184.   j = _free_list.end();
  185.   for ( i=_free_list.begin();(i != _free_list.end());i++ )
  186.     if ( (*i)._size >= p_size )
  187.       if ( j == _free_list.end() || (*i)._size < (*j)._size )
  188. j = i;
  189.   if ( j == _free_list.end() ) {
  190.     j = fillup(p_size,p_proj);
  191.     if ( j == _free_list.end() ) {
  192.       _mem_lock.unlock();
  193.       return 0;   // if we throw an error, we need to cleanup first.
  194.     }
  195.   }
  196.   fragment( j,p_size );
  197.   if ( (*j)._size == 0 )
  198.     _free_list.erase( j );
  199.   _used_list.push_back(_mem_entry);
  200.   _mem_lock.unlock();
  201.   return _mem_entry._data;
  202. }
  203. list<shared_mem::mem_entry>::iterator
  204. shared_mem::fillup(size_t p_size, int p_proj)
  205. {
  206.   key_t key = -1;
  207.   sto_iterator i;
  208. #ifdef DEBUG
  209.   cout << "fillup(" << p_size << "," << p_proj << ")n";
  210. #endif
  211.   if ( p_proj == 0 )
  212.     p_proj = create_proj( 0 );
  213.   for( i=_shared.begin();(i != _shared.end());i++ )
  214.     if ( (*i)._proj == p_proj )
  215.       if ( (*i)._ptr == 0  && (*i)._key != -1 ) {
  216. key = (*i)._key;
  217. break;
  218.       }
  219.   if ( key == -1 )
  220.     key = make_key( p_proj );
  221.   if ( key != -1 ) {
  222.     for( i=_shared.begin();(i != _shared.end());i++ )
  223.       if ( (*i)._key == key )
  224. break;
  225.     return getmem( i,p_size );
  226.   }
  227.   return _free_list.end();
  228. }
  229. void shared_mem::dealloc(void *p_ptr)
  230. {
  231.   struct shmid_ds sm;
  232.   mem_iterator i;
  233.   sto_iterator k;
  234.   _mem_lock.lock();
  235.   for( i=_used_list.begin();(i != _used_list.end());i++ )
  236.     if ( p_ptr == (*i)._data )
  237.       break;
  238.   if ( i == _used_list.end() )
  239.     return;   // memory doesn't belong to us, or fragmented.
  240.   _mem_entry = (*i);
  241.   _used_list.erase( i );
  242. #ifdef DEBUG
  243.   cout.form("Returning %p(%d) ",_mem_entry._data,_mem_entry._size);
  244. #endif
  245.   // Now collect all consequtive freed memory
  246.   for ( i=_free_list.begin();(i != _free_list.end());i++ ) {
  247. #ifdef DEBUG
  248.     cout.form(" ?%p(%d)",(*i)._data,(*i)._size);
  249. #endif
  250.     if ( (*i)._data == (void *)((long)_mem_entry._data - (*i)._size) ) {
  251.       _mem_entry._size += (*i)._size;
  252.       _mem_entry._data  = (*i)._data;
  253. #ifdef DEBUG
  254.       cout << " concatenated";
  255. #endif
  256.       i = _free_list.erase( i );
  257.     }
  258.     if ( _mem_entry._data == (void *)((long)(*i)._data - _mem_entry._size) ) {
  259.       _mem_entry._size += (*i)._size;
  260. #ifdef DEBUG
  261.       cout << " attached";
  262. #endif
  263.       i = _free_list.erase( i );
  264.     }
  265. #ifdef DEBUG
  266.     cout << endl;
  267. #endif
  268.   }
  269.   // Now we have a pointer to free memory, now let's see if we
  270.   // should return this memory to the system.
  271.   _key_lock.lock();
  272.   for( k=_shared.begin();(k != _shared.end());k++ ) 
  273.     if ( (*k)._ptr == _mem_entry._data && (*k)._page == _mem_entry._size ) {
  274.       // Ah ha... we've freed the whole page.
  275. #ifdef DEBUG
  276.       cout.form("Freeing dereferenced page %p(%d)n",(*k)._ptr,(*k)._page);
  277. #endif
  278.       shmctl( (*k)._mid,IPC_RMID,&sm );
  279.       shmdt( (*k)._ptr );
  280.       (*k)._ptr  = 0;
  281.       (*k)._mid  = 0;
  282.       (*k)._page = 0;
  283.       break;
  284.     }
  285.   if ( k == _shared.end() )
  286.     _free_list.push_back(_mem_entry);
  287.   _key_lock.unlock();
  288.   _mem_lock.unlock();
  289. }
  290. //
  291. // cleanup
  292. //
  293. // Cleanup all memory allocated pages, by removing them
  294. // and marking them for destruction.
  295. //
  296. // dilemma:
  297. //  Suppose there are some dirty pages around, a user hasn't
  298. //  freed all memory, that he isn't using... what should I do?
  299. //  should I destroy the page, or leave it?  At this poiint,
  300. //  I am destroying all references to shared memory.
  301. void shared_mem::cleanup()
  302. {
  303.   struct shmid_ds sm;
  304.   sto_iterator i;
  305.   _key_lock.lock();
  306.   _mem_lock.lock();
  307.   for( i=_shared.begin();(i != _shared.end());i++ ) {
  308.     if ( (*i)._ptr != 0 ) {
  309. #ifdef DEBUG
  310.       cout.form("Mark page %p for removaln",(*i)._ptr);
  311. #endif
  312.       // The page will be removed, when unattached... the
  313.       // unattachement will occurr normally on exit.
  314.       shmctl( (*i)._mid,IPC_RMID,&sm );
  315.     }
  316.   }
  317.   // We have destroyed the pages, no re-entry is allowed.
  318. }