📄 shared.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 + -