www.pudn.com > allocator.rar > 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. #includenamespace 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 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 (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