?? shared_memory.cc
字號:
// file: shared_memory.cc// author: Marc Bumble// June 1, 2000// Page memory source for shared memory // Copyright (C) 2000 by Marc D. Bumble// 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 program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.#include <shared_memory.h>namespace mem_space { //////////////////////////////////////////////////////////////////// ////// Memory Locks //////////////////////////////////////////////////////////////////// ////// ////// Locks are mutual exclusion locks used to protect process ////// from writing simultaneously to shared memory. Each ////// allocator will get one semaphore set, and then with that ////// semaphore set, each chunk will lock individual elements ////// with semaphores from that set. So each chunk is has ////// access to the semid and the semnum. A semid is common for ////// all chunks within a given allocator, and then each of the ////// allocator's chunks will have its own individual semnum ////// which indicates which semaphore in the semid array. ////// //////////////////////////////////////////////////////////////////// // constructor locks::locks(const mem_space::allocator_key_t& alloc_key, const int& proj_id) { std::string key_file(alloc_key); // create a file for System V ftok from alloc_key key_file = std::string("/tmp") + key_file; // create the empty shm key file, used by ftok() std::ofstream to(key_file.data()); if (!to) perror("Cannot open key file"); to.close(); // set the semaphore key key_t mykey = ftok(key_file.c_str(),proj_id); if (mykey == -1) { std::clog << "Error:" << __FILE__ << ':' << __LINE__ << ':' << " ftok unable to create sem key: " << strerror(errno) << ": " << key_file << std::endl; // create an error message to throw with the exception std::stringstream s; s << __FILE__ << ':' << __LINE__ << ':' << " project id out of range (1 <= proj_id < 128)."; throw (Alloc_Exception::ftok_exception(s.str())); } semid = semget(mykey, num_in_array, IPC_CREAT | IPC_EXCL | 0666);// std::clog << "Status:" << __FILE__ << ':' << __LINE__ << ':'// << " semid: " << semid << " " << strerror(errno)// << std::endl; if (semid >= 0) { // first to create the semaphores // need to initialize the semaphore set union semun arg; struct semid_ds seminfo; arg.buf = &seminfo; // set all semaphores to 1 unit avail // binary locks, ie one process can sieze the lock at a time for each page. short unsigned sem_vals[num_in_array]; for (int i = 0; i < num_in_array; i++) { sem_vals[i] = 1;// std::clog << "i = " << i << std::endl; } arg.array = sem_vals; if (semctl(semid, 0, SETALL, arg) == -1) { std::cerr << "File: " << __FILE__ << ':' << __LINE__ << ':'<< "locks::make_lock()"; std::cerr << ": semaphore creation error: " << strerror(errno) << std::endl; std::stringstream s; s << __FILE__ << ':' << __LINE__ << ':' << " semaphore creation error."; throw (Alloc_Exception::lock_creation_exception(s.str())); } } else { // The semaphore set already exists // Do not initialize, just attach and wait until the semaphores are initialized union semun arg; struct semid_ds seminfo; arg.buf = &seminfo; // wait at most for 10 tries to see if the semaphore get // initialized by the process which created it. If within 10 // tests, the process does not get initialized, then fail. const int& tries = 10; bool initialized = false; for (int i = 0; ((i < tries) && (!initialized)); i++) { // retrieve information on the semaphores semctl(semid,0,IPC_STAT,arg); if (arg.buf->sem_otime != 0) { initialized = true; } sleep(1); } if (!initialized) { std::cerr << "File: " << __FILE__ << ':' << __LINE__ << ':'<< "locks::locks()"; std::cerr << ": semaphore initialization error: " << strerror(errno) << std::endl; std::stringstream s; s << __FILE__ << ':' << __LINE__ << ':' << " semaphore initialization error."; throw (Alloc_Exception::lock_creation_exception(s.str())); } } }; // constructor // destructor locks::~locks() { // union semun semctl_arg; // for (int i=0; i<num_in_array; i++) { // int semctlresult = semctl(semid, i, IPC_RMID, semctl_arg);#ifdef DEBUG std::cerr << __FILE__ << ":" << __LINE__ << " ~locks()" << std::endl;#endif int semctlresult = semctl(semid, 0, IPC_RMID); if ((semctlresult!=0)&&(errno!=EINVAL)) { std::cerr << __FILE__ << ':' << __LINE__ << " locks::~locks(): "; std::cerr << " semid: " << semid << "semctlresult: "; std::cerr << semctlresult << " " << strerror(errno) << std::endl; }#ifdef SHARED_MEMORY_MESG std::cerr << "semid: " << semid << " shmctlresult: "; std::cerr << semctlresult << " " << strerror(errno) << std::endl;#endif // } }; // destructor // copy consqtructor locks::locks(const locks& t) { semid=t.semid; }; // copy constructor // assignment operator locks& locks::operator=(const locks& t) { if (this != &t) { // avoid self assignment: t=t semid=t.semid; } // if (this != &t) return *this; }; // assignment operator // equality operator bool locks::operator==(const locks& t) { bool flag=false; if (semid==t.semid) { flag=true; } return flag; }; // equality operator // lock print void locks::print() const { // print the current semaphore lock values struct semid_ds seminfo; union semun arg; arg.buf = &seminfo; semctl(semid, 0, IPC_STAT, arg); // int nsems = arg.buf->sem_nsems; unsigned short sem_vals[num_in_array]; arg.array = sem_vals; semctl(semid, 0, GETALL, arg); std::cerr << std::endl; std::cerr << "locks::print()" << std::endl; std::cerr << "semid = " << semid << std::endl; std::cerr << "semval[] = "; for (int i = 0; i < num_in_array; i++) { if (!(i%25)) { std::cerr << std::endl; std::cerr << " "; } std::cerr << ":" << sem_vals[i]; } std::cerr << std::endl; }; // void locks::lock(int page_num) { // only set one lock at a time struct sembuf sem_buf_array[num_in_array]; sem_buf_array[0].sem_num = page_num % num_in_array; sem_buf_array[0].sem_op = -1; // take the lock, subtract it away. sem_buf_array[0].sem_flg = SEM_UNDO;// std::cerr << __FILE__ << ':' << __LINE__ << ':'<< " locks::lock()";// std::cerr << "semid: " << semid << std::endl; int result = semop(semid, sem_buf_array, 1); // operate on 1 lock at a time if (result!=0) { std::stringstream s; std::cerr << __FILE__ << ':' << __LINE__ << ':'<< " locks::lock()"; std::cerr << ": semaphore lock: " << strerror(errno) << " result: " << result << std::endl; s << ": semaphore lock errno: " << strerror(errno) << " result: " << result; s << " lock attempt error." << " semid: " << semid << " page_num: " << page_num; std::cerr << s .str()<< std::endl; throw (Alloc_Exception::locking_exception(s.str())); } }; // void lock(int page_num) // void locks::unlock(int page_num) { // only clear one lock at a time struct sembuf sem_buf_array[1]; sem_buf_array[0].sem_num = page_num % num_in_array; sem_buf_array[0].sem_op = 1; // release the lock, add it back sem_buf_array[0].sem_flg = SEM_UNDO; int result = semop(semid, sem_buf_array, 1); // operate on 1 lock at a time if (result!=0) { std::stringstream s; std::cerr << __FILE__ << ':' << __LINE__ << ':'<< " locks::unlock()"; std::cerr << ": semaphore unlock: " << strerror(errno) << " result: " << result << std::endl; s << ": semaphore unlock errno: " << strerror(errno) << " result: " << result; s << " unlock attempt error." << " semid: " << semid << " page_num: " << page_num; std::cerr << s .str()<< std::endl; throw (Alloc_Exception::locking_exception(s.str())); } }; // void unlock(int page_num) //////////////////////////////////////////////////////////////////// ////// class shared_memory_header //////////////////////////////////////////////////////////////////// ////// ////// This class is embedded as the first element in all shared ////// memory segments. It contains information describing the ////// state of the allocated memory segment. This class uses no ////// memory pointers as the shared memory segment is mapped to ////// different addresses for different processes. So all ////// address values must be relative offsets from the beginning ////// of the allocated segment. ////// //////////////////////////////////////////////////////////////////// int shared_memory_header_t::get_page_offset(int page_num) { // returns the offset from the beginning of the segment to the // page indicated by page_num. Just calculates size offset in // terms of the number of bytes. If shm (shared memory header) // points to the beginning of the allocated shared memory segment, // then the actual page address can be interepreted using the // following calls: // // int start_page_offset = smh->get_page_offset(start_page4); // unsigned char* addr = reinterpret_cast<unsigned char*>(smh) + // start_page_offset; // // addr will then contain the correct memory address. This // approach is required because the shared memory segment is // memory mapped to each process differently, so an offset from // the beginning of the segment address is required. return sizeof(shared_memory_header_t) + bit_vec_size + page_num*page_size; }; // get_page_offset() } // namespace mem_space
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -