📄 shared.c
字号:
#include "shared.h"#include <string>extern "C" {# include <sys/types.h># include <sys/stat.h># include <fcntl.h># include <errno.h># include "cloning.h"};shared_mem::shared_mem(){ _perm = IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; _key_root = new char[80]; _blocks = 0; _work_area._file = 0; change_proj( "/tmp/project" );}shared_mem::shared_mem(const char *p_root){ _perm = IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; _key_root = new char[80]; _blocks = 0; _work_area._file = 0; change_proj( p_root );}shared_mem::~shared_mem(){ cleanup(); delete _key_root;}void shared_mem::change_proj(const char *p_root){ strncpy( _key_root,p_root,79 );}void shared_mem::change_perm(int p_perm){ _perm = p_perm&0777;}int shared_mem::create_proj(const char *p_id){ int fd; string s = _key_root; sto_iterator i; _key_lock.lock();#ifdef DEBUG cout << "create_proj(" << p_id << ")\n";#endif if ( p_id && strlen(p_id) > 0 ) { s += "_"; s += p_id; } fd = open( s.c_str(),O_CREAT,_perm ); if ( fd != -1 ) { close( fd ); for( i=_shared.begin();(i != _shared.end());i++ ) if ( (*i)._file != 0 && strcmp((*i)._file,s.c_str()) == 0 ) { _key_lock.unlock(); return (*i)._id; } _work_area._id = ++_blocks; _work_area._key = -1; _work_area._file = strdup( s.c_str() ); _work_area._proj = 0; _work_area._ptr = 0; _work_area._page = 0; _work_area._mid = 0;#ifdef DEBUG cout << "new project " << _blocks << endl;#endif _shared.push_back( _work_area ); } else return -1; _key_lock.unlock(); return _blocks;}key_t shared_mem::get_key(const char *p_id,int p_proj){ string s = _key_root; key_t key = -1; sto_iterator i; _key_lock.lock(); if ( p_id && strlen(p_id) > 0 ) { s += "_"; s += p_id; } for( i=_shared.begin();(i != _shared.end());i++ ) if ( strcmp((*i)._file,s.c_str()) == 0 && (*i)._proj == p_proj ) { key = (*i)._key; break; } _key_lock.unlock(); return key;}key_t shared_mem::make_key(int p_proj){ sto_iterator k = _shared.end(); sto_iterator i = _shared.begin(); _key_lock.lock();#ifdef DEBUG cout << "make_key(" << p_proj << ")\n";#endif _work_area._key = -1; for( ;(i != _shared.end());i++ ) if ( (*i)._id == p_proj ) if ( k == _shared.end() || (*i)._key == -1 || (*k)._proj < (*i)._proj ) k = i; if ( k != _shared.end() ) { if ( (*k)._key != -1 ) { _work_area = (*k); if ( ++_work_area._proj != 0 ) { _work_area._key = ftok( _work_area._file,_work_area._proj );#ifdef DEBUG cout << "new key " << _work_area._key << endl;#endif _shared.push_back( _work_area ); } } else { _work_area._key = (*k)._key = ftok( (*k)._file,(*k)._proj );#ifdef DEBUG cout << "added a key " << (*k)._key << endl;#endif } } _key_lock.unlock(); return _work_area._key;}list<shared_mem::mem_entry>::iteratorshared_mem::getmem(sto_iterator i,size_t p_size){ size_t total_size = ((p_size/PAGE_SIZE)+1)*PAGE_SIZE; _mem_entry._size = 0; (*i)._mid = shmget( (*i)._key,p_size,IPC_CREAT|_perm ); if ( (*i)._mid == -1 ) return _free_list.end(); (*i)._ptr = shmat( (*i)._mid,0,0 ); (*i)._page = total_size;#ifdef DEBUG cout.form("Got a segment %p, sized %d\n",(*i)._ptr,(*i)._page);#endif _mem_entry._size = total_size; _mem_entry._data = (*i)._ptr; return _free_list.insert( _free_list.end(),_mem_entry );}void shared_mem::fragment(mem_iterator i,size_t p_size){#ifdef DEBUG cout.form("Fragmenting %p",(*i)._data); cout << " cutting out " << p_size;#endif _mem_entry._size = p_size; _mem_entry._data = (*i)._data; (*i)._size -= p_size; (*i)._data = (void *)((long)(*i)._data + p_size);#ifdef DEBUG cout << " redusing it to " << (*i)._size << endl;#endif}void *shared_mem::keyalloc(key_t p_key,size_t p_size){ void *ptr = 0; sto_iterator i; // Notice the order of the locks, doing it the other way around // may cause a deadlock... see: alloc-fillup _mem_lock.lock(); _key_lock.lock(); for( i=_shared.begin();(i != _shared.end());i++ ) if ( (*i)._key == p_key && (*i)._page <= p_size ) { ptr = (*i)._ptr; break; } if ( ptr == 0 && i != _shared.end() ) fragment( getmem(i,p_size),p_size ); _key_lock.unlock(); _mem_lock.unlock(); return ptr;}void *shared_mem::alloc(size_t p_size,int p_proj){ mem_iterator i,j; _mem_lock.lock();#ifdef DEBUG cout << "alloc(" << p_size << "," << p_proj << ")\n";#endif j = _free_list.end(); for ( i=_free_list.begin();(i != _free_list.end());i++ ) if ( (*i)._size >= p_size ) if ( j == _free_list.end() || (*i)._size < (*j)._size ) j = i; if ( j == _free_list.end() ) { j = fillup(p_size,p_proj); if ( j == _free_list.end() ) { _mem_lock.unlock(); return 0; // if we throw an error, we need to cleanup first. } } fragment( j,p_size ); if ( (*j)._size == 0 ) _free_list.erase( j ); _used_list.push_back(_mem_entry); _mem_lock.unlock(); return _mem_entry._data;}list<shared_mem::mem_entry>::iteratorshared_mem::fillup(size_t p_size, int p_proj){ key_t key = -1; sto_iterator i;#ifdef DEBUG cout << "fillup(" << p_size << "," << p_proj << ")\n";#endif if ( p_proj == 0 ) p_proj = create_proj( 0 ); for( i=_shared.begin();(i != _shared.end());i++ ) if ( (*i)._proj == p_proj ) if ( (*i)._ptr == 0 && (*i)._key != -1 ) { key = (*i)._key; break; } if ( key == -1 ) key = make_key( p_proj ); if ( key != -1 ) { for( i=_shared.begin();(i != _shared.end());i++ ) if ( (*i)._key == key ) break; return getmem( i,p_size ); } return _free_list.end();}void shared_mem::dealloc(void *p_ptr){ struct shmid_ds sm; mem_iterator i; sto_iterator k; _mem_lock.lock(); for( i=_used_list.begin();(i != _used_list.end());i++ ) if ( p_ptr == (*i)._data ) break; if ( i == _used_list.end() ) return; // memory doesn't belong to us, or fragmented. _mem_entry = (*i); _used_list.erase( i );#ifdef DEBUG cout.form("Returning %p(%d) ",_mem_entry._data,_mem_entry._size);#endif // Now collect all consequtive freed memory for ( i=_free_list.begin();(i != _free_list.end());i++ ) {#ifdef DEBUG cout.form(" ?%p(%d)",(*i)._data,(*i)._size);#endif if ( (*i)._data == (void *)((long)_mem_entry._data - (*i)._size) ) { _mem_entry._size += (*i)._size; _mem_entry._data = (*i)._data;#ifdef DEBUG cout << " concatenated";#endif i = _free_list.erase( i ); } if ( _mem_entry._data == (void *)((long)(*i)._data - _mem_entry._size) ) { _mem_entry._size += (*i)._size;#ifdef DEBUG cout << " attached";#endif i = _free_list.erase( i ); }#ifdef DEBUG cout << endl;#endif } // Now we have a pointer to free memory, now let's see if we // should return this memory to the system. _key_lock.lock(); for( k=_shared.begin();(k != _shared.end());k++ ) if ( (*k)._ptr == _mem_entry._data && (*k)._page == _mem_entry._size ) { // Ah ha... we've freed the whole page.#ifdef DEBUG cout.form("Freeing dereferenced page %p(%d)\n",(*k)._ptr,(*k)._page);#endif shmctl( (*k)._mid,IPC_RMID,&sm ); shmdt( (*k)._ptr ); (*k)._ptr = 0; (*k)._mid = 0; (*k)._page = 0; break; } if ( k == _shared.end() ) _free_list.push_back(_mem_entry); _key_lock.unlock(); _mem_lock.unlock();}//// cleanup//// Cleanup all memory allocated pages, by removing them// and marking them for destruction.//// dilemma:// Suppose there are some dirty pages around, a user hasn't// freed all memory, that he isn't using... what should I do?// should I destroy the page, or leave it? At this poiint,// I am destroying all references to shared memory.void shared_mem::cleanup(){ struct shmid_ds sm; sto_iterator i; _key_lock.lock(); _mem_lock.lock(); for( i=_shared.begin();(i != _shared.end());i++ ) { if ( (*i)._ptr != 0 ) {#ifdef DEBUG cout.form("Mark page %p for removal\n",(*i)._ptr);#endif // The page will be removed, when unattached... the // unattachement will occurr normally on exit. shmctl( (*i)._mid,IPC_RMID,&sm ); } } // We have destroyed the pages, no re-entry is allowed.}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -