osrm-backend/include/storage/shared_memory.hpp

361 lines
10 KiB
C++
Raw Normal View History

#ifndef SHARED_MEMORY_HPP
#define SHARED_MEMORY_HPP
2013-09-17 08:23:06 -04:00
2016-01-28 08:27:05 -05:00
#include "util/exception.hpp"
2016-01-02 11:13:44 -05:00
#include "util/simple_logger.hpp"
2013-09-17 08:23:06 -04:00
#include <boost/filesystem.hpp>
2013-09-26 05:28:51 -04:00
#include <boost/filesystem/fstream.hpp>
2013-09-17 08:23:06 -04:00
#include <boost/interprocess/mapped_region.hpp>
#ifndef WIN32
2013-09-17 08:23:06 -04:00
#include <boost/interprocess/xsi_shared_memory.hpp>
#else
#include <boost/interprocess/shared_memory_object.hpp>
#endif
2013-09-17 08:23:06 -04:00
2013-11-14 12:33:09 -05:00
#ifdef __linux__
#include <sys/ipc.h>
#include <sys/shm.h>
#endif
2014-05-07 12:39:16 -04:00
// #include <cstring>
2014-05-07 08:46:46 -04:00
#include <cstdint>
2013-09-17 08:23:06 -04:00
#include <algorithm>
#include <exception>
2016-01-05 10:51:13 -05:00
namespace osrm
{
namespace storage
2016-01-05 10:51:13 -05:00
{
2014-05-07 12:39:16 -04:00
struct OSRMLockFile
{
boost::filesystem::path operator()()
{
boost::filesystem::path temp_dir = boost::filesystem::temp_directory_path();
boost::filesystem::path lock_file = temp_dir / "osrm.lock";
return lock_file;
}
2013-09-17 08:23:06 -04:00
};
#ifndef WIN32
2014-05-07 12:39:16 -04:00
class SharedMemory
{
// Remove shared memory on destruction
class shm_remove
{
private:
int m_shmid;
bool m_initialized;
public:
void SetID(int shmid)
{
m_shmid = shmid;
m_initialized = true;
}
shm_remove() : m_shmid(INT_MIN), m_initialized(false) {}
2014-05-07 12:39:16 -04:00
shm_remove(const shm_remove &) = delete;
shm_remove &operator=(const shm_remove &) = delete;
2014-05-07 12:39:16 -04:00
~shm_remove()
{
if (m_initialized)
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
2014-05-07 12:39:16 -04:00
if (!boost::interprocess::xsi_shared_memory::remove(m_shmid))
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
2014-05-07 12:39:16 -04:00
}
}
}
};
public:
void *Ptr() const { return region.get_address(); }
SharedMemory(const SharedMemory &) = delete;
SharedMemory &operator=(const SharedMemory &) = delete;
2014-05-07 12:39:16 -04:00
template <typename IdentifierT>
SharedMemory(const boost::filesystem::path &lock_file,
const IdentifierT id,
const uint64_t size = 0,
bool read_write = false,
bool remove_prev = true)
: key(lock_file.string().c_str(), id)
{
if (0 == size)
{ // read_only
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_only, key);
region = boost::interprocess::mapped_region(
shm,
(read_write ? boost::interprocess::read_write : boost::interprocess::read_only));
}
else
{ // writeable pointer
// remove previously allocated mem
if (remove_prev)
{
Remove(key);
}
2015-01-27 11:44:46 -05:00
shm = boost::interprocess::xsi_shared_memory(boost::interprocess::open_or_create, key,
size);
2013-11-14 12:33:09 -05:00
#ifdef __linux__
if (-1 == shmctl(shm.get_shmid(), SHM_LOCK, nullptr))
2014-05-07 12:39:16 -04:00
{
if (ENOMEM == errno)
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logWARNING) << "could not lock shared memory to RAM";
2014-05-07 12:39:16 -04:00
}
}
2013-11-14 12:33:09 -05:00
#endif
2014-05-07 12:39:16 -04:00
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
remover.SetID(shm.get_shmid());
2016-01-07 19:31:57 -05:00
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
<< " bytes";
2014-05-07 12:39:16 -04:00
}
}
template <typename IdentifierT> static bool RegionExists(const IdentifierT id)
{
bool result = true;
try
{
OSRMLockFile lock_file;
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
result = RegionExists(key);
}
2015-01-27 11:44:46 -05:00
catch (...)
{
result = false;
}
2014-05-07 12:39:16 -04:00
return result;
}
template <typename IdentifierT> static bool Remove(const IdentifierT id)
{
OSRMLockFile lock_file;
boost::interprocess::xsi_key key(lock_file().string().c_str(), id);
return Remove(key);
}
private:
static bool RegionExists(const boost::interprocess::xsi_key &key)
{
bool result = true;
2015-01-27 11:44:46 -05:00
try
{
boost::interprocess::xsi_shared_memory shm(boost::interprocess::open_only, key);
}
catch (...)
{
result = false;
}
2014-05-07 12:39:16 -04:00
return result;
}
static bool Remove(const boost::interprocess::xsi_key &key)
{
bool ret = false;
try
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
2014-05-07 12:39:16 -04:00
boost::interprocess::xsi_shared_memory xsi(boost::interprocess::open_only, key);
ret = boost::interprocess::xsi_shared_memory::remove(xsi.get_shmid());
}
catch (const boost::interprocess::interprocess_exception &e)
{
if (e.get_error_code() != boost::interprocess::not_found_error)
{
throw;
}
}
return ret;
}
boost::interprocess::xsi_key key;
boost::interprocess::xsi_shared_memory shm;
boost::interprocess::mapped_region region;
shm_remove remover;
2013-09-17 08:23:06 -04:00
};
#else
// Windows - specific code
class SharedMemory
{
2015-01-27 11:44:46 -05:00
SharedMemory(const SharedMemory &) = delete;
SharedMemory &operator=(const SharedMemory &) = delete;
// Remove shared memory on destruction
class shm_remove
{
private:
char *m_shmid;
bool m_initialized;
public:
void SetID(char *shmid)
{
m_shmid = shmid;
m_initialized = true;
}
shm_remove() : m_shmid("undefined"), m_initialized(false) {}
shm_remove(const shm_remove &) = delete;
shm_remove &operator=(const shm_remove &) = delete;
~shm_remove()
{
if (m_initialized)
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logDEBUG) << "automatic memory deallocation";
if (!boost::interprocess::shared_memory_object::remove(m_shmid))
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logDEBUG) << "could not deallocate id " << m_shmid;
}
}
}
};
public:
void *Ptr() const { return region.get_address(); }
SharedMemory(const boost::filesystem::path &lock_file,
const int id,
const uint64_t size = 0,
bool read_write = false,
bool remove_prev = true)
{
sprintf(key, "%s.%d", "osrm.lock", id);
if (0 == size)
{ // read_only
shm = boost::interprocess::shared_memory_object(
2015-01-27 11:44:46 -05:00
boost::interprocess::open_only, key,
read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
region = boost::interprocess::mapped_region(
shm, read_write ? boost::interprocess::read_write : boost::interprocess::read_only);
}
else
{ // writeable pointer
// remove previously allocated mem
if (remove_prev)
{
Remove(key);
}
2015-01-27 11:44:46 -05:00
shm = boost::interprocess::shared_memory_object(boost::interprocess::open_or_create,
key, boost::interprocess::read_write);
shm.truncate(size);
region = boost::interprocess::mapped_region(shm, boost::interprocess::read_write);
remover.SetID(key);
2016-01-07 19:31:57 -05:00
util::SimpleLogger().Write(logDEBUG) << "writeable memory allocated " << size
<< " bytes";
}
}
static bool RegionExists(const int id)
{
bool result = true;
try
{
char k[500];
build_key(id, k);
result = RegionExists(k);
}
2015-01-27 11:44:46 -05:00
catch (...)
{
result = false;
}
return result;
}
static bool Remove(const int id)
{
char k[500];
build_key(id, k);
return Remove(k);
}
private:
2015-01-27 11:44:46 -05:00
static void build_key(int id, char *key) { sprintf(key, "%s.%d", "osrm.lock", id); }
2014-06-17 09:48:47 -04:00
static bool RegionExists(const char *key)
{
bool result = true;
try
{
2015-01-27 11:44:46 -05:00
boost::interprocess::shared_memory_object shm(boost::interprocess::open_only, key,
boost::interprocess::read_write);
}
catch (...)
{
result = false;
}
return result;
}
static bool Remove(char *key)
{
bool ret = false;
try
{
2016-01-05 10:51:13 -05:00
util::SimpleLogger().Write(logDEBUG) << "deallocating prev memory";
ret = boost::interprocess::shared_memory_object::remove(key);
}
catch (const boost::interprocess::interprocess_exception &e)
{
if (e.get_error_code() != boost::interprocess::not_found_error)
{
throw;
}
}
return ret;
}
char key[500];
boost::interprocess::shared_memory_object shm;
boost::interprocess::mapped_region region;
shm_remove remover;
};
#endif
2013-09-17 08:23:06 -04:00
template <typename IdentifierT, typename LockFileT = OSRMLockFile>
SharedMemory *makeSharedMemory(const IdentifierT &id,
const uint64_t size = 0,
bool read_write = false,
bool remove_prev = true)
2014-05-07 12:39:16 -04:00
{
try
2014-05-07 12:39:16 -04:00
{
LockFileT lock_file;
if (!boost::filesystem::exists(lock_file()))
{
if (0 == size)
{
throw util::exception("lock file does not exist, exiting");
}
else
{
boost::filesystem::ofstream ofs(lock_file());
}
}
return new SharedMemory(lock_file(), id, size, read_write, remove_prev);
}
catch (const boost::interprocess::interprocess_exception &e)
{
util::SimpleLogger().Write(logWARNING) << "caught exception: " << e.what() << ", code "
<< e.get_error_code();
throw util::exception(e.what());
2014-05-07 12:39:16 -04:00
}
}
2016-01-05 10:51:13 -05:00
}
}
#endif // SHARED_MEMORY_HPP