First version of the shared memory transport.

Use via `--transport shmem` cmd option. No pub/sub.
This commit is contained in:
Alexey Rybalchenko
2016-06-03 11:24:12 +02:00
parent 6c3b01f09c
commit a332d9fc83
39 changed files with 2121 additions and 309 deletions

View File

@@ -0,0 +1,81 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <zmq.h>
#include <boost/interprocess/managed_shared_memory.hpp>
#include "FairMQLogger.h"
#include "FairMQContextSHM.h"
#include "FairMQShmManager.h"
using namespace FairMQ::shmem;
FairMQContextSHM::FairMQContextSHM(int numIoThreads)
: fContext()
{
fContext = zmq_ctx_new();
if (fContext == NULL)
{
LOG(ERROR) << "failed creating context, reason: " << zmq_strerror(errno);
exit(EXIT_FAILURE);
}
if (zmq_ctx_set(fContext, ZMQ_IO_THREADS, numIoThreads) != 0)
{
LOG(ERROR) << "failed configuring context, reason: " << zmq_strerror(errno);
}
// Set the maximum number of allowed sockets on the context.
if (zmq_ctx_set(fContext, ZMQ_MAX_SOCKETS, 10000) != 0)
{
LOG(ERROR) << "failed configuring context, reason: " << zmq_strerror(errno);
}
Manager::Instance().InitializeSegment("open_or_create", "FairMQSharedMemory", 2000000000);
LOG(INFO) << "Created/Opened shared memory segment of 2,000,000,000 bytes. Available are " << Manager::Instance().Segment()->get_free_memory() << " bytes.";
}
FairMQContextSHM::~FairMQContextSHM()
{
Close();
if (boost::interprocess::shared_memory_object::remove("FairMQSharedMemory"))
{
LOG(INFO) << "Successfully removed shared memory after the device has stopped.";
}
else
{
LOG(INFO) << "Did not remove shared memory after the device stopped. Still in use?";
}
}
void* FairMQContextSHM::GetContext()
{
return fContext;
}
void FairMQContextSHM::Close()
{
if (fContext == NULL)
{
return;
}
if (zmq_ctx_destroy(fContext) != 0)
{
if (errno == EINTR)
{
LOG(ERROR) << " failed closing context, reason: " << zmq_strerror(errno);
}
else
{
fContext = NULL;
return;
}
}
}

View File

@@ -0,0 +1,27 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIRMQCONTEXTSHM_H_
#define FAIRMQCONTEXTSHM_H_
class FairMQContextSHM
{
public:
/// Constructor
FairMQContextSHM(int numIoThreads);
FairMQContextSHM(const FairMQContextSHM&) = delete;
FairMQContextSHM operator=(const FairMQContextSHM&) = delete;
virtual ~FairMQContextSHM();
void* GetContext();
void Close();
private:
void* fContext;
};
#endif /* FAIRMQCONTEXTSHM_H_ */

View File

@@ -0,0 +1,292 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <string>
#include <cstdlib>
#include "FairMQMessageSHM.h"
#include "FairMQLogger.h"
using namespace std;
using namespace FairMQ::shmem;
uint64_t FairMQMessageSHM::fMessageID = 0;
string FairMQMessageSHM::fDeviceID = string();
atomic<bool> FairMQMessageSHM::fInterrupted(false);
FairMQMessageSHM::FairMQMessageSHM()
: fMessage()
, fOwner(nullptr)
, fReceiving(false)
, fQueued(false)
{
if (zmq_msg_init(&fMessage) != 0)
{
LOG(ERROR) << "failed initializing message, reason: " << zmq_strerror(errno);
}
}
void FairMQMessageSHM::StringDeleter(void* /*data*/, void* str)
{
delete static_cast<string*>(str);
}
FairMQMessageSHM::FairMQMessageSHM(const size_t size)
: fMessage()
, fOwner(nullptr)
, fReceiving(false)
, fQueued(false)
{
InitializeChunk(size);
}
FairMQMessageSHM::FairMQMessageSHM(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
: fMessage()
, fOwner(nullptr)
, fReceiving(false)
, fQueued(false)
{
InitializeChunk(size);
memcpy(fOwner->fPtr->GetData(), data, size);
if (ffn)
{
ffn(data, hint);
}
else
{
free(data);
}
}
void FairMQMessageSHM::InitializeChunk(const size_t size)
{
string chunkID = fDeviceID + "c" + to_string(fMessageID);
string* ownerID = new string(fDeviceID + "o" + to_string(fMessageID));
bool success = false;
while (!success)
{
try
{
fOwner = Manager::Instance().Segment()->construct<ShPtrOwner>(ownerID->c_str())(
make_managed_shared_ptr(Manager::Instance().Segment()->construct<Chunk>(chunkID.c_str())(size),
*(Manager::Instance().Segment())));
success = true;
}
catch (bipc::bad_alloc& ba)
{
LOG(WARN) << "Shared memory full...";
this_thread::sleep_for(chrono::milliseconds(50));
if (fInterrupted)
{
break;
}
else
{
continue;
}
}
}
if (zmq_msg_init_data(&fMessage, const_cast<char*>(ownerID->c_str()), ownerID->length(), StringDeleter, ownerID) != 0)
{
LOG(ERROR) << "failed initializing meta message, reason: " << zmq_strerror(errno);
}
++fMessageID;
}
void FairMQMessageSHM::Rebuild()
{
CloseMessage();
fReceiving = false;
fQueued = false;
if (zmq_msg_init(&fMessage) != 0)
{
LOG(ERROR) << "failed initializing message, reason: " << zmq_strerror(errno);
}
}
void FairMQMessageSHM::Rebuild(const size_t size)
{
CloseMessage();
fReceiving = false;
fQueued = false;
InitializeChunk(size);
}
void FairMQMessageSHM::Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
{
CloseMessage();
fReceiving = false;
fQueued = false;
InitializeChunk(size);
memcpy(fOwner->fPtr->GetData(), data, size);
if (ffn)
{
ffn(data, hint);
}
else
{
free(data);
}
}
void* FairMQMessageSHM::GetMessage()
{
return &fMessage;
}
void* FairMQMessageSHM::GetData()
{
if (fOwner)
{
return fOwner->fPtr->GetData();
}
else
{
LOG(ERROR) << "Trying to get data of an empty shared memory message";
exit(EXIT_FAILURE);
}
}
size_t FairMQMessageSHM::GetSize()
{
if (fOwner)
{
return fOwner->fPtr->GetSize();
}
else
{
return 0;
}
}
void FairMQMessageSHM::SetMessage(void*, const size_t)
{
// dummy method to comply with the interface. functionality not allowed in zeromq.
}
void FairMQMessageSHM::SetDeviceId(const string& deviceId)
{
fDeviceID = deviceId;
}
void FairMQMessageSHM::Copy(const unique_ptr<FairMQMessage>& msg)
{
if (!fOwner)
{
FairMQ::shmem::ShPtrOwner* otherOwner = static_cast<FairMQMessageSHM*>(msg.get())->fOwner;
if (otherOwner)
{
InitializeChunk(otherOwner->fPtr->GetSize());
memcpy(fOwner->fPtr->GetData(), otherOwner->fPtr->GetData(), otherOwner->fPtr->GetSize());
}
else
{
LOG(ERROR) << "FairMQMessageSHM::Copy() fail: source message not initialized!";
}
}
else
{
LOG(ERROR) << "FairMQMessageSHM::Copy() fail: target message already initialized!";
}
// version with sharing the sent data
// if (!fOwner)
// {
// if (static_cast<FairMQMessageSHM*>(msg.get())->fOwner)
// {
// string* ownerID = new string(fDeviceID + "o" + to_string(fMessageID));
// bool success = false;
// do
// {
// try
// {
// fOwner = Manager::Instance().Segment()->construct<ShPtrOwner>(ownerID->c_str())(*(static_cast<FairMQMessageSHM*>(msg.get())->fOwner));
// success = true;
// }
// catch (bipc::bad_alloc& ba)
// {
// LOG(WARN) << "Shared memory full...";
// this_thread::sleep_for(chrono::milliseconds(10));
// if (fInterrupted)
// {
// break;
// }
// else
// {
// continue;
// }
// }
// }
// while (!success);
// if (zmq_msg_init_data(&fMessage, const_cast<char*>(ownerID->c_str()), ownerID->length(), StringDeleter, ownerID) != 0)
// {
// LOG(ERROR) << "failed initializing meta message, reason: " << zmq_strerror(errno);
// }
// ++fMessageID;
// }
// else
// {
// LOG(ERROR) << "FairMQMessageSHM::Copy() fail: source message not initialized!";
// }
// }
// else
// {
// LOG(ERROR) << "FairMQMessageSHM::Copy() fail: target message already initialized!";
// }
}
void FairMQMessageSHM::CloseMessage()
{
if (fReceiving)
{
if (fOwner)
{
Manager::Instance().Segment()->destroy_ptr(fOwner);
fOwner = nullptr;
}
else
{
LOG(ERROR) << "No shared pointer owner when closing a received message";
}
}
else
{
if (fOwner && !fQueued)
{
LOG(WARN) << "Destroying unsent message";
Manager::Instance().Segment()->destroy_ptr(fOwner);
fOwner = nullptr;
}
}
if (zmq_msg_close(&fMessage) != 0)
{
LOG(ERROR) << "failed closing message, reason: " << zmq_strerror(errno);
}
}
FairMQMessageSHM::~FairMQMessageSHM()
{
CloseMessage();
}

View File

@@ -0,0 +1,63 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIRMQMESSAGESHM_H_
#define FAIRMQMESSAGESHM_H_
#include <cstddef>
#include <string>
#include <atomic>
#include <zmq.h>
#include "FairMQMessage.h"
#include "FairMQShmManager.h"
class FairMQMessageSHM : public FairMQMessage
{
friend class FairMQSocketSHM;
public:
FairMQMessageSHM();
FairMQMessageSHM(const size_t size);
FairMQMessageSHM(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr);
FairMQMessageSHM(const FairMQMessageSHM&) = delete;
FairMQMessageSHM operator=(const FairMQMessageSHM&) = delete;
void InitializeChunk(const size_t size);
virtual void Rebuild();
virtual void Rebuild(const size_t size);
virtual void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr);
virtual void* GetMessage();
virtual void* GetData();
virtual size_t GetSize();
virtual void SetMessage(void* data, const size_t size);
virtual void SetDeviceId(const std::string& deviceId);
virtual void Copy(const std::unique_ptr<FairMQMessage>& msg);
void CloseMessage();
virtual ~FairMQMessageSHM();
static void StringDeleter(void* data, void* str);
private:
zmq_msg_t fMessage;
FairMQ::shmem::ShPtrOwner* fOwner;
static uint64_t fMessageID;
static std::string fDeviceID;
bool fReceiving;
bool fQueued;
static std::atomic<bool> fInterrupted;
};
#endif /* FAIRMQMESSAGESHM_H_ */

View File

@@ -0,0 +1,240 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* FairMQPollerSHM.cxx
*
* @since 2014-01-23
* @author A. Rybalchenko
*/
#include <zmq.h>
#include "FairMQPollerSHM.h"
#include "FairMQLogger.h"
using namespace std;
FairMQPollerSHM::FairMQPollerSHM(const vector<FairMQChannel>& channels)
: items()
, fNumItems(0)
, fOffsetMap()
{
fNumItems = channels.size();
items = new zmq_pollitem_t[fNumItems];
for (int i = 0; i < fNumItems; ++i)
{
items[i].socket = channels.at(i).fSocket->GetSocket();
items[i].fd = 0;
items[i].revents = 0;
int type = 0;
size_t size = sizeof(type);
zmq_getsockopt (channels.at(i).fSocket->GetSocket(), ZMQ_TYPE, &type, &size);
if (type == ZMQ_REQ || type == ZMQ_REP || type == ZMQ_PAIR || type == ZMQ_DEALER || type == ZMQ_ROUTER)
{
items[i].events = ZMQ_POLLIN|ZMQ_POLLOUT;
}
else if (type == ZMQ_PUSH || type == ZMQ_PUB || type == ZMQ_XPUB)
{
items[i].events = ZMQ_POLLOUT;
}
else if (type == ZMQ_PULL || type == ZMQ_SUB || type == ZMQ_XSUB)
{
items[i].events = ZMQ_POLLIN;
}
else
{
LOG(ERROR) << "invalid poller configuration, exiting.";
exit(EXIT_FAILURE);
}
}
}
FairMQPollerSHM::FairMQPollerSHM(const unordered_map<string, vector<FairMQChannel>>& channelsMap, const vector<string>& channelList)
: items()
, fNumItems(0)
, fOffsetMap()
{
int offset = 0;
try
{
// calculate offsets and the total size of the poll item set
for (string channel : channelList)
{
fOffsetMap[channel] = offset;
offset += channelsMap.at(channel).size();
fNumItems += channelsMap.at(channel).size();
}
items = new zmq_pollitem_t[fNumItems];
int index = 0;
for (string channel : channelList)
{
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i)
{
index = fOffsetMap[channel] + i;
items[index].socket = channelsMap.at(channel).at(i).fSocket->GetSocket();
items[index].fd = 0;
items[index].revents = 0;
int type = 0;
size_t size = sizeof(type);
zmq_getsockopt (channelsMap.at(channel).at(i).fSocket->GetSocket(), ZMQ_TYPE, &type, &size);
if (type == ZMQ_REQ || type == ZMQ_REP || type == ZMQ_PAIR || type == ZMQ_DEALER || type == ZMQ_ROUTER)
{
items[index].events = ZMQ_POLLIN|ZMQ_POLLOUT;
}
else if (type == ZMQ_PUSH || type == ZMQ_PUB || type == ZMQ_XPUB)
{
items[index].events = ZMQ_POLLOUT;
}
else if (type == ZMQ_PULL || type == ZMQ_SUB || type == ZMQ_XSUB)
{
items[index].events = ZMQ_POLLIN;
}
else
{
LOG(ERROR) << "invalid poller configuration, exiting.";
exit(EXIT_FAILURE);
}
}
}
}
catch (const std::out_of_range& oor)
{
LOG(ERROR) << "At least one of the provided channel keys for poller initialization is invalid";
LOG(ERROR) << "Out of Range error: " << oor.what() << '\n';
exit(EXIT_FAILURE);
}
}
FairMQPollerSHM::FairMQPollerSHM(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket)
: items()
, fNumItems(2)
, fOffsetMap()
{
items = new zmq_pollitem_t[fNumItems];
items[0].socket = cmdSocket.GetSocket();
items[0].fd = 0;
items[0].events = ZMQ_POLLIN;
items[0].revents = 0;
items[1].socket = dataSocket.GetSocket();
items[1].fd = 0;
items[1].revents = 0;
int type = 0;
size_t size = sizeof(type);
zmq_getsockopt(dataSocket.GetSocket(), ZMQ_TYPE, &type, &size);
if (type == ZMQ_REQ || type == ZMQ_REP || type == ZMQ_PAIR || type == ZMQ_DEALER || type == ZMQ_ROUTER)
{
items[1].events = ZMQ_POLLIN|ZMQ_POLLOUT;
}
else if (type == ZMQ_PUSH || type == ZMQ_PUB || type == ZMQ_XPUB)
{
items[1].events = ZMQ_POLLOUT;
}
else if (type == ZMQ_PULL || type == ZMQ_SUB || type == ZMQ_XSUB)
{
items[1].events = ZMQ_POLLIN;
}
else
{
LOG(ERROR) << "invalid poller configuration, exiting.";
exit(EXIT_FAILURE);
}
}
void FairMQPollerSHM::Poll(const int timeout)
{
if (zmq_poll(items, fNumItems, timeout) < 0)
{
if (errno == ETERM)
{
LOG(DEBUG) << "polling exited, reason: " << zmq_strerror(errno);
}
else
{
LOG(ERROR) << "polling failed, reason: " << zmq_strerror(errno);
}
}
}
bool FairMQPollerSHM::CheckInput(const int index)
{
if (items[index].revents & ZMQ_POLLIN)
{
return true;
}
return false;
}
bool FairMQPollerSHM::CheckOutput(const int index)
{
if (items[index].revents & ZMQ_POLLOUT)
{
return true;
}
return false;
}
bool FairMQPollerSHM::CheckInput(const string channelKey, const int index)
{
try
{
if (items[fOffsetMap.at(channelKey) + index].revents & ZMQ_POLLIN)
{
return true;
}
return false;
}
catch (const std::out_of_range& oor)
{
LOG(ERROR) << "Invalid channel key: \"" << channelKey << "\"";
LOG(ERROR) << "Out of Range error: " << oor.what() << '\n';
exit(EXIT_FAILURE);
}
}
bool FairMQPollerSHM::CheckOutput(const string channelKey, const int index)
{
try
{
if (items[fOffsetMap.at(channelKey) + index].revents & ZMQ_POLLOUT)
{
return true;
}
return false;
}
catch (const std::out_of_range& oor)
{
LOG(ERROR) << "Invalid channel key: \"" << channelKey << "\"";
LOG(ERROR) << "Out of Range error: " << oor.what() << '\n';
exit(EXIT_FAILURE);
}
}
FairMQPollerSHM::~FairMQPollerSHM()
{
if (items != NULL)
{
delete[] items;
}
}

View File

@@ -0,0 +1,51 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIRMQPOLLERSHM_H_
#define FAIRMQPOLLERSHM_H_
#include <vector>
#include <unordered_map>
#include <initializer_list>
#include <zmq.h>
#include "FairMQPoller.h"
#include "FairMQChannel.h"
#include "FairMQTransportFactorySHM.h"
class FairMQChannel;
class FairMQPollerSHM : public FairMQPoller
{
friend class FairMQChannel;
friend class FairMQTransportFactorySHM;
public:
FairMQPollerSHM(const std::vector<FairMQChannel>& channels);
FairMQPollerSHM(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList);
FairMQPollerSHM(const FairMQPollerSHM&) = delete;
FairMQPollerSHM operator=(const FairMQPollerSHM&) = delete;
virtual void Poll(const int timeout);
virtual bool CheckInput(const int index);
virtual bool CheckOutput(const int index);
virtual bool CheckInput(const std::string channelKey, const int index);
virtual bool CheckOutput(const std::string channelKey, const int index);
virtual ~FairMQPollerSHM();
private:
FairMQPollerSHM(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket);
zmq_pollitem_t* items;
int fNumItems;
std::unordered_map<std::string, int> fOffsetMap;
};
#endif /* FAIRMQPOLLERSHM_H_ */

View File

@@ -0,0 +1,185 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* FairMQShmManager.h
*
* @since 2016-04-08
* @author A. Rybalchenko
*/
#ifndef FAIRMQSHMMANAGER_H_
#define FAIRMQSHMMANAGER_H_
#include <thread>
#include <chrono>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
#include "FairMQLogger.h"
namespace bipc = boost::interprocess;
namespace FairMQ
{
namespace shmem
{
class Manager
{
public:
static Manager& Instance()
{
static Manager man;
return man;
}
void InitializeSegment(const std::string& op, const std::string& name, const size_t size = 0)
{
if (!fSegment)
{
try
{
if (op == "open_or_create")
{
fSegment = new bipc::managed_shared_memory(bipc::open_or_create, name.c_str(), size);
}
else if (op == "create_only")
{
fSegment = new bipc::managed_shared_memory(bipc::create_only, name.c_str(), size);
}
else if (op == "open_only")
{
int numTries = 0;
bool success = false;
do
{
try
{
fSegment = new bipc::managed_shared_memory(bipc::open_only, name.c_str());
success = true;
}
catch (bipc::interprocess_exception& ie)
{
if (++numTries == 5)
{
LOG(ERROR) << "Could not open shared memory after " << numTries << " attempts, exiting!";
exit(EXIT_FAILURE);
}
else
{
LOG(DEBUG) << "Could not open shared memory segment on try " << numTries << ". Retrying in 1 second...";
LOG(DEBUG) << ie.what();
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
}
}
}
while (!success);
}
else
{
LOG(ERROR) << "Unknown operation when initializing shared memory segment: " << op;
}
}
catch (std::exception& e)
{
LOG(ERROR) << "Exception during shared memory segment initialization: " << e.what() << ", application will now exit";
exit(EXIT_FAILURE);
}
}
else
{
LOG(INFO) << "Segment already initialized";
}
}
bipc::managed_shared_memory* Segment() const
{
if (fSegment)
{
return fSegment;
}
else
{
LOG(ERROR) << "Segment not initialized";
exit(EXIT_FAILURE);
}
}
private:
Manager()
: fSegment(nullptr)
{}
bipc::managed_shared_memory* fSegment;
};
class Chunk
{
public:
Chunk()
: fHandle()
, fSize(0)
{
}
Chunk(const size_t size)
: fHandle()
, fSize(size)
{
void* ptr = Manager::Instance().Segment()->allocate(size);
fHandle = Manager::Instance().Segment()->get_handle_from_address(ptr);
}
~Chunk()
{
Manager::Instance().Segment()->deallocate(Manager::Instance().Segment()->get_address_from_handle(fHandle));
}
// bipc::managed_shared_memory::handle_t GetHandle() const
// {
// return fHandle;
// }
void* GetData() const
{
return Manager::Instance().Segment()->get_address_from_handle(fHandle);
}
size_t GetSize() const
{
return fSize;
}
private:
bipc::managed_shared_memory::handle_t fHandle;
size_t fSize;
};
typedef bipc::managed_shared_ptr<Chunk, bipc::managed_shared_memory>::type ShPtrType;
struct ShPtrOwner
{
ShPtrOwner(const ShPtrType& other)
: fPtr(other)
{}
ShPtrOwner(const ShPtrOwner& other)
: fPtr(other.fPtr)
{}
ShPtrType fPtr;
};
} // namespace shmem
} // namespace FairMQ
#endif /* FAIRMQSHMMANAGER_H_ */

View File

@@ -0,0 +1,591 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <sstream>
#include <zmq.h>
#include "FairMQSocketSHM.h"
#include "FairMQMessageSHM.h"
#include "FairMQLogger.h"
using namespace std;
using namespace FairMQ::shmem;
// Context to hold the ZeroMQ sockets
unique_ptr<FairMQContextSHM> FairMQSocketSHM::fContext = unique_ptr<FairMQContextSHM>(new FairMQContextSHM(1));
// bool FairMQSocketSHM::fContextInitialized = false;
FairMQSocketSHM::FairMQSocketSHM(const string& type, const string& name, const int numIoThreads, const string& id /*= ""*/)
: FairMQSocket(ZMQ_SNDMORE, ZMQ_RCVMORE, ZMQ_DONTWAIT)
, fSocket(NULL)
, fId()
, fBytesTx(0)
, fBytesRx(0)
, fMessagesTx(0)
, fMessagesRx(0)
{
fId = id + "." + name + "." + type;
// if (!fContextInitialized)
// {
// fContext = unique_ptr<FairMQContextSHM>(new FairMQContextSHM(1));
// fContextInitialized = true;
// }
if (zmq_ctx_set(fContext->GetContext(), ZMQ_IO_THREADS, numIoThreads) != 0)
{
LOG(ERROR) << "Failed configuring context, reason: " << zmq_strerror(errno);
}
fSocket = zmq_socket(fContext->GetContext(), GetConstant(type));
if (fSocket == NULL)
{
LOG(ERROR) << "Failed creating socket " << fId << ", reason: " << zmq_strerror(errno);
exit(EXIT_FAILURE);
}
if (zmq_setsockopt(fSocket, ZMQ_IDENTITY, fId.c_str(), fId.length()) != 0)
{
LOG(ERROR) << "Failed setting ZMQ_IDENTITY socket option, reason: " << zmq_strerror(errno);
}
// Tell socket to try and send/receive outstanding messages for <linger> milliseconds before terminating.
// Default value for ZeroMQ is -1, which is to wait forever.
int linger = 500;
if (zmq_setsockopt(fSocket, ZMQ_LINGER, &linger, sizeof(linger)) != 0)
{
LOG(ERROR) << "Failed setting ZMQ_LINGER socket option, reason: " << zmq_strerror(errno);
}
int kernelSndSize = 10000;
if (zmq_setsockopt(fSocket, ZMQ_SNDBUF, &kernelSndSize, sizeof(kernelSndSize)) != 0)
{
LOG(ERROR) << "Failed setting ZMQ_SNDBUF socket option, reason: " << zmq_strerror(errno);
}
int kernelRcvSize = 10000;
if (zmq_setsockopt(fSocket, ZMQ_RCVBUF, &kernelRcvSize, sizeof(kernelRcvSize)) != 0)
{
LOG(ERROR) << "Failed setting ZMQ_RCVBUF socket option, reason: " << zmq_strerror(errno);
}
if (type == "sub")
{
if (zmq_setsockopt(fSocket, ZMQ_SUBSCRIBE, NULL, 0) != 0)
{
LOG(ERROR) << "Failed setting ZMQ_SUBSCRIBE socket option, reason: " << zmq_strerror(errno);
}
}
// LOG(INFO) << "created socket " << fId;
}
string FairMQSocketSHM::GetId()
{
return fId;
}
bool FairMQSocketSHM::Bind(const string& address)
{
// LOG(INFO) << "bind socket " << fId << " on " << address;
if (zmq_bind(fSocket, address.c_str()) != 0)
{
if (errno == EADDRINUSE) {
// do not print error in this case, this is handled by FairMQDevice in case no connection could be established after trying a number of random ports from a range.
return false;
}
LOG(ERROR) << "Failed binding socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
return true;
}
void FairMQSocketSHM::Connect(const string& address)
{
// LOG(INFO) << "connect socket " << fId << " on " << address;
if (zmq_connect(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed connecting socket " << fId << ", reason: " << zmq_strerror(errno);
// error here means incorrect configuration. exit if it happens.
exit(EXIT_FAILURE);
}
}
int FairMQSocketSHM::Send(FairMQMessage* msg, const string& flag)
{
return Send(msg, GetConstant(flag));
}
int FairMQSocketSHM::Send(FairMQMessage* msg, const int flags)
{
int nbytes = zmq_msg_send(static_cast<zmq_msg_t*>(msg->GetMessage()), fSocket, flags);
if (nbytes >= 0)
{
static_cast<FairMQMessageSHM*>(msg)->fReceiving = false;
static_cast<FairMQMessageSHM*>(msg)->fQueued = true;
size_t size = msg->GetSize();
fBytesTx += size;
++fMessagesTx;
return size;
}
if (zmq_errno() == EAGAIN)
{
return -2;
}
if (zmq_errno() == ETERM)
{
LOG(INFO) << "terminating socket " << fId;
return -1;
}
LOG(ERROR) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes;
}
int64_t FairMQSocketSHM::Send(const vector<FairMQMessagePtr>& msgVec, const int flags)
{
// Sending vector typicaly handles more then one part
if (msgVec.size() > 1)
{
int64_t totalSize = 0;
for (unsigned int i = 0; i < msgVec.size() - 1; ++i)
{
int nbytes = zmq_msg_send(static_cast<zmq_msg_t*>(msgVec[i]->GetMessage()), fSocket, ZMQ_SNDMORE|flags);
if (nbytes >= 0)
{
static_cast<FairMQMessageSHM*>(msgVec[i].get())->fReceiving = false;
static_cast<FairMQMessageSHM*>(msgVec[i].get())->fQueued = true;
size_t size = msgVec[i]->GetSize();
totalSize += size;
fBytesTx += size;
}
else
{
if (zmq_errno() == EAGAIN)
{
return -2;
}
if (zmq_errno() == ETERM)
{
LOG(INFO) << "terminating socket " << fId;
return -1;
}
LOG(ERROR) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes;
}
}
int nbytes = zmq_msg_send(static_cast<zmq_msg_t*>(msgVec.back()->GetMessage()), fSocket, flags);
if (nbytes >= 0)
{
static_cast<FairMQMessageSHM*>(msgVec.back().get())->fReceiving = false;
static_cast<FairMQMessageSHM*>(msgVec.back().get())->fQueued = true;
size_t size = msgVec.back()->GetSize();
totalSize += size;
fBytesTx += size;
}
else
{
if (zmq_errno() == EAGAIN)
{
return -2;
}
if (zmq_errno() == ETERM)
{
LOG(INFO) << "terminating socket " << fId;
return -1;
}
LOG(ERROR) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes;
}
// store statistics on how many messages have been sent (handle all parts as a single message)
++fMessagesTx;
return totalSize;
} // If there's only one part, send it as a regular message
else if (msgVec.size() == 1)
{
return Send(msgVec.back().get(), flags);
}
else // if the vector is empty, something might be wrong
{
LOG(WARN) << "Will not send empty vector";
return -1;
}
}
int FairMQSocketSHM::Receive(FairMQMessage* msg, const string& flag)
{
return Receive(msg, GetConstant(flag));
}
int FairMQSocketSHM::Receive(FairMQMessage* msg, const int flags)
{
zmq_msg_t* msgPtr = static_cast<zmq_msg_t*>(msg->GetMessage());
int nbytes = zmq_msg_recv(msgPtr, fSocket, flags);
if (nbytes == 0)
{
++fMessagesRx;
return nbytes;
}
else if (nbytes > 0)
{
string ownerID(static_cast<char*>(zmq_msg_data(msgPtr)), zmq_msg_size(msgPtr));
ShPtrOwner* owner = Manager::Instance().Segment()->find<ShPtrOwner>(ownerID.c_str()).first;
size_t size = 0;
if (owner)
{
static_cast<FairMQMessageSHM*>(msg)->fOwner = owner;
static_cast<FairMQMessageSHM*>(msg)->fReceiving = true;
size = msg->GetSize();
fBytesRx += size;
++fMessagesRx;
return size;
}
else
{
LOG(ERROR) << "Received meta data, but could not find corresponding chunk";
return -1;
}
}
if (zmq_errno() == EAGAIN)
{
return -2;
}
if (zmq_errno() == ETERM)
{
LOG(INFO) << "terminating socket " << fId;
return -1;
}
LOG(ERROR) << "Failed receiving on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes;
}
int64_t FairMQSocketSHM::Receive(vector<FairMQMessagePtr>& msgVec, const int flags)
{
// Warn if the vector is filled before Receive() and empty it.
if (msgVec.size() > 0)
{
LOG(WARN) << "Message vector contains elements before Receive(), they will be deleted!";
msgVec.clear();
}
int64_t totalSize = 0;
int64_t more = 0;
do
{
FairMQMessagePtr part(new FairMQMessageSHM());
zmq_msg_t* msgPtr = static_cast<zmq_msg_t*>(part->GetMessage());
int nbytes = zmq_msg_recv(msgPtr, fSocket, flags);
if (nbytes == 0)
{
msgVec.push_back(move(part));
}
else if (nbytes > 0)
{
string ownerID(static_cast<char*>(zmq_msg_data(msgPtr)), zmq_msg_size(msgPtr));
ShPtrOwner* owner = Manager::Instance().Segment()->find<ShPtrOwner>(ownerID.c_str()).first;
size_t size = 0;
if (owner)
{
static_cast<FairMQMessageSHM*>(part.get())->fOwner = owner;
static_cast<FairMQMessageSHM*>(part.get())->fReceiving = true;
size = part->GetSize();
msgVec.push_back(move(part));
fBytesRx += size;
totalSize += size;
}
else
{
LOG(ERROR) << "Received meta data, but could not find corresponding chunk";
return -1;
}
}
else
{
return nbytes;
}
size_t more_size = sizeof(more);
zmq_getsockopt(fSocket, ZMQ_RCVMORE, &more, &more_size);
}
while (more);
// store statistics on how many messages have been received (handle all parts as a single message)
++fMessagesRx;
return totalSize;
}
void FairMQSocketSHM::Close()
{
// LOG(DEBUG) << "Closing socket " << fId;
if (fSocket == NULL)
{
return;
}
if (zmq_close(fSocket) != 0)
{
LOG(ERROR) << "Failed closing socket " << fId << ", reason: " << zmq_strerror(errno);
}
fSocket = NULL;
}
void FairMQSocketSHM::Terminate()
{
if (zmq_ctx_destroy(fContext->GetContext()) != 0)
{
LOG(ERROR) << "Failed terminating context, reason: " << zmq_strerror(errno);
}
}
void FairMQSocketSHM::Interrupt()
{
FairMQMessageSHM::fInterrupted = true;
}
void FairMQSocketSHM::Resume()
{
FairMQMessageSHM::fInterrupted = false;
}
void* FairMQSocketSHM::GetSocket() const
{
return fSocket;
}
int FairMQSocketSHM::GetSocket(int) const
{
// dummy method to comply with the interface. functionality not possible in zeromq.
return -1;
}
void FairMQSocketSHM::SetOption(const string& option, const void* value, size_t valueSize)
{
if (zmq_setsockopt(fSocket, GetConstant(option), value, valueSize) < 0)
{
LOG(ERROR) << "Failed setting socket option, reason: " << zmq_strerror(errno);
}
}
void FairMQSocketSHM::GetOption(const string& option, void* value, size_t* valueSize)
{
if (zmq_getsockopt(fSocket, GetConstant(option), value, valueSize) < 0)
{
LOG(ERROR) << "Failed getting socket option, reason: " << zmq_strerror(errno);
}
}
unsigned long FairMQSocketSHM::GetBytesTx() const
{
return fBytesTx;
}
unsigned long FairMQSocketSHM::GetBytesRx() const
{
return fBytesRx;
}
unsigned long FairMQSocketSHM::GetMessagesTx() const
{
return fMessagesTx;
}
unsigned long FairMQSocketSHM::GetMessagesRx() const
{
return fMessagesRx;
}
bool FairMQSocketSHM::SetSendTimeout(const int timeout, const string& address, const string& method)
{
if (method == "bind")
{
if (zmq_unbind(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed unbinding socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_setsockopt(fSocket, ZMQ_SNDTIMEO, &timeout, sizeof(int)) != 0)
{
LOG(ERROR) << "Failed setting option on socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_bind(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed binding socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
}
else if (method == "connect")
{
if (zmq_disconnect(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed disconnecting socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_setsockopt(fSocket, ZMQ_SNDTIMEO, &timeout, sizeof(int)) != 0)
{
LOG(ERROR) << "Failed setting option on socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_connect(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed connecting socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
}
else
{
LOG(ERROR) << "SetSendTimeout() failed - unknown method provided!";
return false;
}
return true;
}
int FairMQSocketSHM::GetSendTimeout() const
{
int timeout = -1;
size_t size = sizeof(timeout);
if (zmq_getsockopt(fSocket, ZMQ_SNDTIMEO, &timeout, &size) != 0)
{
LOG(ERROR) << "Failed getting option 'receive timeout' on socket " << fId << ", reason: " << zmq_strerror(errno);
}
return timeout;
}
bool FairMQSocketSHM::SetReceiveTimeout(const int timeout, const string& address, const string& method)
{
if (method == "bind")
{
if (zmq_unbind(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed unbinding socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_setsockopt(fSocket, ZMQ_RCVTIMEO, &timeout, sizeof(int)) != 0)
{
LOG(ERROR) << "Failed setting option on socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_bind(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed binding socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
}
else if (method == "connect")
{
if (zmq_disconnect(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed disconnecting socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_setsockopt(fSocket, ZMQ_RCVTIMEO, &timeout, sizeof(int)) != 0)
{
LOG(ERROR) << "Failed setting option on socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
if (zmq_connect(fSocket, address.c_str()) != 0)
{
LOG(ERROR) << "Failed connecting socket " << fId << ", reason: " << zmq_strerror(errno);
return false;
}
}
else
{
LOG(ERROR) << "SetReceiveTimeout() failed - unknown method provided!";
return false;
}
return true;
}
int FairMQSocketSHM::GetReceiveTimeout() const
{
int timeout = -1;
size_t size = sizeof(timeout);
if (zmq_getsockopt(fSocket, ZMQ_RCVTIMEO, &timeout, &size) != 0)
{
LOG(ERROR) << "Failed getting option 'receive timeout' on socket " << fId << ", reason: " << zmq_strerror(errno);
}
return timeout;
}
int FairMQSocketSHM::GetConstant(const string& constant)
{
if (constant == "")
return 0;
if (constant == "sub")
return ZMQ_SUB;
if (constant == "pub")
return ZMQ_PUB;
if (constant == "xsub")
return ZMQ_XSUB;
if (constant == "xpub")
return ZMQ_XPUB;
if (constant == "push")
return ZMQ_PUSH;
if (constant == "pull")
return ZMQ_PULL;
if (constant == "req")
return ZMQ_REQ;
if (constant == "rep")
return ZMQ_REP;
if (constant == "dealer")
return ZMQ_DEALER;
if (constant == "router")
return ZMQ_ROUTER;
if (constant == "pair")
return ZMQ_PAIR;
if (constant == "snd-hwm")
return ZMQ_SNDHWM;
if (constant == "rcv-hwm")
return ZMQ_RCVHWM;
if (constant == "snd-size")
return ZMQ_SNDBUF;
if (constant == "rcv-size")
return ZMQ_RCVBUF;
if (constant == "snd-more")
return ZMQ_SNDMORE;
if (constant == "rcv-more")
return ZMQ_RCVMORE;
if (constant == "linger")
return ZMQ_LINGER;
if (constant == "no-block")
return ZMQ_DONTWAIT;
if (constant == "snd-more no-block")
return ZMQ_DONTWAIT|ZMQ_SNDMORE;
return -1;
}
FairMQSocketSHM::~FairMQSocketSHM()
{
}

View File

@@ -0,0 +1,76 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIRMQSOCKETSHM_H_
#define FAIRMQSOCKETSHM_H_
#include <atomic>
#include <memory> // unique_ptr
#include "FairMQSocket.h"
#include "FairMQContextSHM.h"
#include "FairMQShmManager.h"
class FairMQSocketSHM : public FairMQSocket
{
public:
FairMQSocketSHM(const std::string& type, const std::string& name, const int numIoThreads, const std::string& id = "");
FairMQSocketSHM(const FairMQSocketSHM&) = delete;
FairMQSocketSHM operator=(const FairMQSocketSHM&) = delete;
virtual std::string GetId();
virtual bool Bind(const std::string& address);
virtual void Connect(const std::string& address);
virtual int Send(FairMQMessage* msg, const std::string& flag = "");
virtual int Send(FairMQMessage* msg, const int flags = 0);
virtual int64_t Send(const std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int flags = 0);
virtual int Receive(FairMQMessage* msg, const std::string& flag = "");
virtual int Receive(FairMQMessage* msg, const int flags = 0);
virtual int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int flags = 0);
virtual void* GetSocket() const;
virtual int GetSocket(int nothing) const;
virtual void Close();
virtual void Terminate();
virtual void Interrupt();
virtual void Resume();
virtual void SetOption(const std::string& option, const void* value, size_t valueSize);
virtual void GetOption(const std::string& option, void* value, size_t* valueSize);
virtual unsigned long GetBytesTx() const;
virtual unsigned long GetBytesRx() const;
virtual unsigned long GetMessagesTx() const;
virtual unsigned long GetMessagesRx() const;
virtual bool SetSendTimeout(const int timeout, const std::string& address, const std::string& method);
virtual int GetSendTimeout() const;
virtual bool SetReceiveTimeout(const int timeout, const std::string& address, const std::string& method);
virtual int GetReceiveTimeout() const;
static int GetConstant(const std::string& constant);
virtual ~FairMQSocketSHM();
private:
void* fSocket;
std::string fId;
std::atomic<unsigned long> fBytesTx;
std::atomic<unsigned long> fBytesRx;
std::atomic<unsigned long> fMessagesTx;
std::atomic<unsigned long> fMessagesRx;
static std::unique_ptr<FairMQContextSHM> fContext;
// static bool fContextInitialized;
};
#endif /* FAIRMQSOCKETSHM_H_ */

View File

@@ -0,0 +1,56 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "zmq.h"
#include <boost/version.hpp>
#include "FairMQTransportFactorySHM.h"
using namespace std;
FairMQTransportFactorySHM::FairMQTransportFactorySHM()
{
int major, minor, patch;
zmq_version(&major, &minor, &patch);
LOG(DEBUG) << "Using ZeroMQ (" << major << "." << minor << "." << patch << ") & "
<< "boost::interprocess (" << (BOOST_VERSION / 100000) << "." << (BOOST_VERSION / 100 % 1000) << "." << (BOOST_VERSION % 100) << ")";
}
FairMQMessagePtr FairMQTransportFactorySHM::CreateMessage() const
{
return unique_ptr<FairMQMessage>(new FairMQMessageSHM());
}
FairMQMessagePtr FairMQTransportFactorySHM::CreateMessage(const size_t size) const
{
return unique_ptr<FairMQMessage>(new FairMQMessageSHM(size));
}
FairMQMessagePtr FairMQTransportFactorySHM::CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint) const
{
return unique_ptr<FairMQMessage>(new FairMQMessageSHM(data, size, ffn, hint));
}
FairMQSocketPtr FairMQTransportFactorySHM::CreateSocket(const string& type, const string& name, const int numIoThreads, const string& id /*= ""*/) const
{
return unique_ptr<FairMQSocket>(new FairMQSocketSHM(type, name, numIoThreads, id));
}
FairMQPollerPtr FairMQTransportFactorySHM::CreatePoller(const vector<FairMQChannel>& channels) const
{
return unique_ptr<FairMQPoller>(new FairMQPollerSHM(channels));
}
FairMQPollerPtr FairMQTransportFactorySHM::CreatePoller(const unordered_map<string, vector<FairMQChannel>>& channelsMap, const vector<string>& channelList) const
{
return unique_ptr<FairMQPoller>(new FairMQPollerSHM(channelsMap, channelList));
}
FairMQPollerPtr FairMQTransportFactorySHM::CreatePoller(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket) const
{
return unique_ptr<FairMQPoller>(new FairMQPollerSHM(cmdSocket, dataSocket));
}

View File

@@ -0,0 +1,37 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence version 3 (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIRMQTRANSPORTFACTORYSHM_H_
#define FAIRMQTRANSPORTFACTORYSHM_H_
#include <vector>
#include "FairMQTransportFactory.h"
#include "FairMQContextSHM.h"
#include "FairMQMessageSHM.h"
#include "FairMQSocketSHM.h"
#include "FairMQPollerSHM.h"
class FairMQTransportFactorySHM : public FairMQTransportFactory
{
public:
FairMQTransportFactorySHM();
virtual FairMQMessagePtr CreateMessage() const;
virtual FairMQMessagePtr CreateMessage(const size_t size) const;
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = NULL) const;
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name, const int numIoThreads, const std::string& id = "") const;
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const;
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const;
virtual FairMQPollerPtr CreatePoller(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket) const;
virtual ~FairMQTransportFactorySHM() {};
};
#endif /* FAIRMQTRANSPORTFACTORYSHM_H_ */

10
fairmq/shmem/README.md Normal file
View File

@@ -0,0 +1,10 @@
# Shared Memory transport
First version of the shared memory transport. To try with existing devices, run the devices with `--transport shmem` option.
The transport manages shared memory via boost::interprocess library. The transfer of the meta data, required to locate the content in the share memory, is done via ZeroMQ. The transport supports all communication patterns where a single message is received by a single receiver. For multiple receivers for the same message, the message has to be copied.
Under development:
- Cleanup of the shared memory segment in case all devices crash. Currently at least one device has to stop properly for a cleanup.
- Implement more than one transport per device.
- Configuration of the shared memory size (currently hard-coded).