/* Copyright (C) 2014 InfiniDB, Inc. 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; version 2 of the License. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /***************************************************************************** * $Id$ * ****************************************************************************/ #include #include //#define NDEBUG #include #include using namespace std; #include #include #include namespace bi = boost::interprocess; #include "shmkeys.h" #include "brmshmimpl.h" #include "brmtypes.h" #include "installdir.h" namespace BRM { BRMShmImpl::BRMShmImpl(unsigned key, off_t size, bool readOnly) : fKey(key), fSize(size), fReadOnly(readOnly) { string keyName = ShmKeys::keyToName(fKey); if (fSize == 0) { unsigned tries = 0; again: try { bi::shared_memory_object shm(bi::open_only, keyName.c_str(), bi::read_write); off_t curSize = 0; #ifdef _MSC_VER bi::offset_t tmp = 0; shm.get_size(tmp); curSize = static_cast(tmp); #else shm.get_size(curSize); #endif if (curSize == 0) throw bi::interprocess_exception("shm size is zero"); } catch (bi::interprocess_exception&) { if (++tries > 10) { log("BRMShmImpl::BRMShmImpl(): retrying on size==0"); throw; } cerr << "BRMShmImpl::BRMShmImpl(): retrying on size==0" << endl; usleep(500 * 1000); goto again; } } try { bi::permissions perms; perms.set_unrestricted(); bi::shared_memory_object shm(bi::create_only, keyName.c_str(), bi::read_write, perms); idbassert(fSize > 0); shm.truncate(fSize); fShmobj.swap(shm); } catch (bi::interprocess_exception &b) { if (b.get_error_code() != bi::already_exists_error) { ostringstream o; o << "BRM caught an exception creating a shared memory segment: " << b.what(); log(o.str()); throw; } bi::shared_memory_object *shm = NULL; try { shm = new bi::shared_memory_object(bi::open_only, keyName.c_str(), bi::read_write); } catch (exception &e) { ostringstream o; o << "BRM caught an exception attaching to a shared memory segment (" << keyName << "): " << b.what(); log(o.str()); throw; } off_t curSize = 0; #ifdef _MSC_VER bi::offset_t tmp = 0; shm->get_size(tmp); curSize = static_cast(tmp); #else shm->get_size(curSize); #endif idbassert(curSize > 0); idbassert(curSize >= fSize); fShmobj.swap(*shm); delete shm; fSize = curSize; } if (fReadOnly) { bi::mapped_region ro_region(fShmobj, bi::read_only); fMapreg.swap(ro_region); } else { bi::mapped_region region(fShmobj, bi::read_write); fMapreg.swap(region); } } int BRMShmImpl::grow(unsigned newKey, off_t newSize) { idbassert(newKey != fKey); idbassert(newSize >= fSize); string oldName = fShmobj.get_name(); string keyName = ShmKeys::keyToName(newKey); bi::permissions perms; perms.set_unrestricted(); bi::shared_memory_object shm(bi::create_only, keyName.c_str(), bi::read_write, perms); shm.truncate(newSize); bi::mapped_region region(shm, bi::read_write); //Copy old data into new region memcpy(region.get_address(), fMapreg.get_address(), fSize); //clear new region //make some versions of gcc happier... memset(reinterpret_cast(reinterpret_cast(region.get_address()) + fSize), 0, newSize - fSize); fShmobj.swap(shm); fMapreg.swap(region); if (!oldName.empty()) bi::shared_memory_object::remove(oldName.c_str()); fKey = newKey; fSize = newSize; if (fReadOnly) { bi::mapped_region ro_region(fShmobj, bi::read_only); fMapreg.swap(ro_region); } return 0; } int BRMShmImpl::clear(unsigned newKey, off_t newSize) { idbassert(newKey != fKey); string oldName = fShmobj.get_name(); string keyName = ShmKeys::keyToName(newKey); bi::permissions perms; perms.set_unrestricted(); bi::shared_memory_object shm(bi::create_only, keyName.c_str(), bi::read_write, perms); shm.truncate(newSize); bi::mapped_region region(shm, bi::read_write); //clear new region memset(region.get_address(), 0, newSize); fShmobj.swap(shm); fMapreg.swap(region); if (!oldName.empty()) bi::shared_memory_object::remove(oldName.c_str()); fKey = newKey; fSize = newSize; if (fReadOnly) { bi::mapped_region ro_region(fShmobj, bi::read_only); fMapreg.swap(ro_region); } return 0; } void BRMShmImpl::setReadOnly() { if (fReadOnly) return; bi::mapped_region ro_region(fShmobj, bi::read_only); fMapreg.swap(ro_region); fReadOnly = true; } void BRMShmImpl::swap(BRMShmImpl& rhs) { fShmobj.swap(rhs.fShmobj); fMapreg.swap(rhs.fMapreg); std::swap(fKey, rhs.fKey); std::swap(fSize, rhs.fSize); std::swap(fReadOnly, rhs.fReadOnly); } void BRMShmImpl::destroy() { string oldName = fShmobj.get_name(); if (!oldName.empty()) bi::shared_memory_object::remove(oldName.c_str()); } } //namespace // vim:ts=4 sw=4: