⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 shared.c

📁 C++ SOCKET 类
💻 C
字号:
/*************************************************************************** *                                                                         * *   This program is free software; you can redistribute it and/or modify  * *   it under the terms of the GNU General Public License as published by  * *   the Free Software Foundation; either version 2 of the License, or     * *   (at your option) any later version.                                   * *                                                                         * ***************************************************************************///// This file is part of Linux Multi-Threaded Environment.//// Copyright (C) 2000-2001 The Linux MTE team.//// This file performs the function of maintaining shared memory,// in a similar fashion to malloc.  It allocates pages of memory// at a time, and can distribute memory allocated in parts of// a page.//#include "shared.h"#include <string>#include <cerrno>extern "C" {#   include <sys/types.h>#   include <sys/stat.h>#   include <fcntl.h>#   include "cloning.h"};namespace cpp_threads {  SharedMemory::SharedMemory()  {    _perm             = IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;    _key_root         = "";    _blocks           = 0;    _work_area.s_file = 0;    changeProj( "/tmp/project" );  }  SharedMemory::SharedMemory(const std::string& root_p)  {    _perm             = IPC_CREAT|S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH;    _key_root         = root_p;    _blocks           = 0;    _work_area.s_file = 0;    changeProj( root_p );  }  SharedMemory::~SharedMemory()  {    cleanup();  }  void SharedMemory::changeProj(const std::string& root_p)  {    _key_root = root_p;  }  void SharedMemory::changePerm(int p_perm)  {    _perm = p_perm&0777;  }  int SharedMemory::createProj(const std::string& id_p)  {    int fd;    std::string s = _key_root;    sto_iterator i;    Pthread::debug("SharedMemory::createProj('%s')",id_p.c_str());    _key_lock.lock();    if ( id_p.length() > 0 ) {      s += "_";      s += id_p;    }    Pthread::debug(" - open('%s',%d,%d)",s.c_str(),O_CREAT,_perm);    fd = open( s.c_str(),O_CREAT,_perm );    if ( fd != -1 ) {      close( fd );      for( i=_shared.begin();(i != _shared.end());i++ )	if ( (*i).s_file != 0 && s == (*i).s_file ) {	  _key_lock.unLock();	  return (*i).s_id;	}      _work_area.s_id   = ++_blocks;      _work_area.s_key  = -1;      _work_area.s_file = strdup( s.c_str() );      _work_area.s_proj = 0;      _work_area.s_ptr  = 0;      _work_area.s_page = 0;      _work_area.s_mid  = 0;      Pthread::debug("new project %d",_blocks);      _shared.push_back( _work_area );    } else      return -1;    _key_lock.unLock();    return _blocks;  }  key_t SharedMemory::getKey(const std::string& id_p,int proj_p)  {    std::string s = _key_root;    key_t key = -1;    sto_iterator i;    _key_lock.lock();    if ( id_p.length() > 0 ) {      s += "_";      s += id_p;    }    for( i=_shared.begin();(i != _shared.end());i++ )      if ( s == (*i).s_file && (*i).s_proj == proj_p ) {	key = (*i).s_key;	break;      }    _key_lock.unLock();    return key;  }  key_t SharedMemory::makeKey(int proj_p)  {    sto_iterator k = _shared.end();    sto_iterator i = _shared.begin();        _key_lock.lock();    Pthread::debug("SharedMemory::make_key(%d)",proj_p);    _work_area.s_key = -1;    for( ;(i != _shared.end());i++ )      if ( (*i).s_id == proj_p )	if ( k == _shared.end()||(*i).s_key == -1||(*k).s_proj < (*i).s_proj )	  k = i;    if ( k != _shared.end() ) {      if ( (*k).s_key != -1 ) {	_work_area = (*k);	if ( ++_work_area.s_proj != 0 ) {	  _work_area.s_key  = ftok( _work_area.s_file,_work_area.s_proj );	  Pthread::debug("new key %d",_work_area.s_key);	  _shared.push_back( _work_area );	}      } else {	_work_area.s_key = (*k).s_key = ftok( (*k).s_file,(*k).s_proj );	Pthread::debug("added a key %d",(*k).s_key);      }    }    _key_lock.unLock();    return _work_area.s_key;  }  list<SharedMemory::mem_entry>::iterator  SharedMemory::getmem(sto_iterator i_p,size_t size_p)  {    size_t total_size = ((size_p/STACK_PAGE_SIZE)+1)*STACK_PAGE_SIZE;    _mem_entry.s_size = 0;    (*i_p).s_mid = shmget( (*i_p).s_key,size_p,IPC_CREAT|_perm );    if ( (*i_p).s_mid == -1 )      return _free_list.end();    (*i_p).s_ptr  = shmat( (*i_p).s_mid,0,0 );    (*i_p).s_page = total_size;    Pthread::debug("Got a segment %p, sized %d",(*i_p).s_ptr,(*i_p).s_page);    _mem_entry.s_size = total_size;    _mem_entry.s_data = (*i_p).s_ptr;    return _free_list.insert( _free_list.end(),_mem_entry );  }  void SharedMemory::fragment(mem_iterator i_p,size_t size_p)  {    Pthread::debug("Fragmenting %p, cutting out %d",(*i_p).s_data,size_p);    _mem_entry.s_size = size_p;    _mem_entry.s_data = (*i_p).s_data;    (*i_p).s_size    -= size_p;    (*i_p).s_data     = (void *)((long)(*i_p).s_data + size_p);    Pthread::debug(" - redused it to %d",(*i_p).s_size);  }  void *SharedMemory::keyAlloc(key_t key_p,size_t size_p)  {    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).s_key == key_p && (*i).s_page <= size_p ) {	ptr = (*i).s_ptr;	break;      }    if ( ptr == 0 && i != _shared.end() )      fragment( getmem(i,size_p),size_p );    _key_lock.unLock();    _mem_lock.unLock();    return ptr;  }  void *SharedMemory::alloc(size_t size_p,int proj_p)  {    mem_iterator i,j;    _mem_lock.lock();    Pthread::debug("SharedMemory::alloc(%d,%d)",size_p,proj_p);    j = _free_list.end();    for ( i=_free_list.begin();(i != _free_list.end());i++ )      if ( (*i).s_size >= size_p )	if ( j == _free_list.end() || (*i).s_size < (*j).s_size )	  j = i;    if ( j == _free_list.end() ) {      j = fillup(size_p,proj_p);      if ( j == _free_list.end() ) {	_mem_lock.unLock();	return 0;   // if we throw an error, we need to cleanup first.      }    }    fragment( j,size_p );    if ( (*j).s_size == 0 )      _free_list.erase( j );    _used_list.push_back(_mem_entry);    _mem_lock.unLock();    return _mem_entry.s_data;  }    list<SharedMemory::mem_entry>::iterator  SharedMemory::fillup(size_t size_p, int proj_p)  {    key_t key = -1;    sto_iterator i;    Pthread::debug("SharedMemory::fillup(%d,%d)",size_p,proj_p);    if ( proj_p == 0 )      proj_p = createProj( 0 );    for( i=_shared.begin();(i != _shared.end());i++ )      if ( (*i).s_proj == proj_p )	if ( (*i).s_ptr == 0  && (*i).s_key != -1 ) {	  key = (*i).s_key;	  break;	}    if ( key == -1 )      key = makeKey( proj_p );    if ( key != -1 ) {      for( i=_shared.begin();(i != _shared.end());i++ )	if ( (*i).s_key == key )	  break;      return getmem( i,size_p );    }    return _free_list.end();  }  void SharedMemory::deAlloc(void *ptr_p)  {    struct shmid_ds sm;    mem_iterator i;    sto_iterator k;    _mem_lock.lock();    for( i=_used_list.begin();(i != _used_list.end());i++ )      if ( ptr_p == (*i).s_data )	break;    if ( i == _used_list.end() )      return;   // memory doesn't belong to us, or fragmented.    _mem_entry = (*i);    _used_list.erase( i );    Pthread::debug("Returning %p(%d)",_mem_entry.s_data,_mem_entry.s_size);    // Now collect all consequtive freed memory    for ( i=_free_list.begin();(i != _free_list.end());i++ ) {      Pthread::debug(" ?%p(%d)",(*i).s_data,(*i).s_size);      if ( (*i).s_data == (void *)((long)_mem_entry.s_data - (*i).s_size) ) {	_mem_entry.s_size += (*i).s_size;	_mem_entry.s_data  = (*i).s_data;	Pthread::debug(" concatenated.");	i = _free_list.erase( i );      }      if ( _mem_entry.s_data == (void *)((long)(*i).s_data - _mem_entry.s_size) ) {	_mem_entry.s_size += (*i).s_size;	Pthread::debug(" attached");	i = _free_list.erase( i );      }    }    // 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).s_ptr == _mem_entry.s_data && (*k).s_page == _mem_entry.s_size ) {	// Ah ha... we've freed the whole page.	Pthread::debug("Free dereferenced page %p(%d)",(*k).s_ptr,(*k).s_page);	shmctl( (*k).s_mid,IPC_RMID,&sm );	shmdt( (*k).s_ptr );	(*k).s_ptr  = 0;	(*k).s_mid  = 0;	(*k).s_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 SharedMemory::cleanup()  {    struct shmid_ds sm;    sto_iterator i;        _key_lock.lock();    _mem_lock.lock();    for( i=_shared.begin();(i != _shared.end());i++ ) {      if ( (*i).s_ptr != 0 ) {	Pthread::debug("Mark page %p for removal",(*i).s_ptr);	// The page will be removed, when unattached... the	// unattachement will occurr normally on exit.	shmctl( (*i).s_mid,IPC_RMID,&sm );      }    }    // We have destroyed the pages, no re-entry is allowed.  }}; // Namespace

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -