refactor: Prepare deprecation of non-namespaced types and headers

This commit is contained in:
Dennis Klein 2021-06-09 16:11:57 +02:00
parent d0e152ee4c
commit f7d16b04c7
28 changed files with 1920 additions and 1770 deletions

View File

@ -158,6 +158,7 @@ if(BUILD_FAIRMQ)
MemoryResourceTools.h MemoryResourceTools.h
MemoryResources.h MemoryResources.h
Message.h Message.h
Parts.h
Plugin.h Plugin.h
PluginManager.h PluginManager.h
PluginServices.h PluginServices.h
@ -216,24 +217,20 @@ if(BUILD_FAIRMQ)
# libFairMQ source files # # libFairMQ source files #
########################## ##########################
set(FAIRMQ_SOURCE_FILES set(FAIRMQ_SOURCE_FILES
Channel.cxx
Device.cxx
DeviceRunner.cxx DeviceRunner.cxx
FairMQChannel.cxx JSONParser.cxx
FairMQDevice.cxx MemoryResources.cxx
FairMQLogger.cxx
FairMQMessage.cxx
FairMQPoller.cxx
FairMQSocket.cxx
FairMQTransportFactory.cxx
Plugin.cxx Plugin.cxx
PluginManager.cxx PluginManager.cxx
PluginServices.cxx PluginServices.cxx
ProgOptions.cxx ProgOptions.cxx
JSONParser.cxx
Properties.cxx Properties.cxx
SuboptParser.cxx SuboptParser.cxx
TransportFactory.cxx
plugins/config/Config.cxx plugins/config/Config.cxx
plugins/control/Control.cxx plugins/control/Control.cxx
MemoryResources.cxx
shmem/Manager.cxx shmem/Manager.cxx
shmem/Monitor.cxx shmem/Monitor.cxx
) )

View File

@ -1,30 +1,27 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
#include "FairMQChannel.h" #include <boost/algorithm/string.hpp> // join/split
#include <cstddef> // size_t
#include <fairmq/tools/Strings.h>
#include <fairmq/Properties.h>
#include <fairlogger/Logger.h> #include <fairlogger/Logger.h>
#include <fairmq/Channel.h>
#include <boost/algorithm/string.hpp> // join/split #include <fairmq/Properties.h>
#include <fairmq/Tools.h>
#include <cstddef> // size_t #include <random>
#include <regex> #include <regex>
#include <set> #include <set>
#include <random>
namespace fair::mq {
using namespace std; using namespace std;
using namespace fair::mq;
template<typename T> template<typename T>
T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T& ifNotFound) T GetPropertyOrDefault(const Properties& m, const string& k, const T& ifNotFound)
{ {
if (m.count(k)) { if (m.count(k)) {
return boost::any_cast<T>(m.at(k)); return boost::any_cast<T>(m.at(k));
@ -32,39 +29,39 @@ T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T&
return ifNotFound; return ifNotFound;
} }
constexpr fair::mq::Transport FairMQChannel::DefaultTransportType; constexpr Transport Channel::DefaultTransportType;
constexpr const char* FairMQChannel::DefaultTransportName; constexpr const char* Channel::DefaultTransportName;
constexpr const char* FairMQChannel::DefaultName; constexpr const char* Channel::DefaultName;
constexpr const char* FairMQChannel::DefaultType; constexpr const char* Channel::DefaultType;
constexpr const char* FairMQChannel::DefaultMethod; constexpr const char* Channel::DefaultMethod;
constexpr const char* FairMQChannel::DefaultAddress; constexpr const char* Channel::DefaultAddress;
constexpr int FairMQChannel::DefaultSndBufSize; constexpr int Channel::DefaultSndBufSize;
constexpr int FairMQChannel::DefaultRcvBufSize; constexpr int Channel::DefaultRcvBufSize;
constexpr int FairMQChannel::DefaultSndKernelSize; constexpr int Channel::DefaultSndKernelSize;
constexpr int FairMQChannel::DefaultRcvKernelSize; constexpr int Channel::DefaultRcvKernelSize;
constexpr int FairMQChannel::DefaultLinger; constexpr int Channel::DefaultLinger;
constexpr int FairMQChannel::DefaultRateLogging; constexpr int Channel::DefaultRateLogging;
constexpr int FairMQChannel::DefaultPortRangeMin; constexpr int Channel::DefaultPortRangeMin;
constexpr int FairMQChannel::DefaultPortRangeMax; constexpr int Channel::DefaultPortRangeMax;
constexpr bool FairMQChannel::DefaultAutoBind; constexpr bool Channel::DefaultAutoBind;
FairMQChannel::FairMQChannel() Channel::Channel()
: FairMQChannel(DefaultName, DefaultType, DefaultMethod, DefaultAddress, nullptr) : Channel(DefaultName, DefaultType, DefaultMethod, DefaultAddress, nullptr)
{} {}
FairMQChannel::FairMQChannel(const string& name) Channel::Channel(const string& name)
: FairMQChannel(name, DefaultType, DefaultMethod, DefaultAddress, nullptr) : Channel(name, DefaultType, DefaultMethod, DefaultAddress, nullptr)
{} {}
FairMQChannel::FairMQChannel(const string& type, const string& method, const string& address) Channel::Channel(const string& type, const string& method, const string& address)
: FairMQChannel(DefaultName, type, method, address, nullptr) : Channel(DefaultName, type, method, address, nullptr)
{} {}
FairMQChannel::FairMQChannel(const string& name, const string& type, shared_ptr<FairMQTransportFactory> factory) Channel::Channel(const string& name, const string& type, shared_ptr<TransportFactory> factory)
: FairMQChannel(name, type, DefaultMethod, DefaultAddress, factory) : Channel(name, type, DefaultMethod, DefaultAddress, factory)
{} {}
FairMQChannel::FairMQChannel(string name, string type, string method, string address, shared_ptr<FairMQTransportFactory> factory) Channel::Channel(string name, string type, string method, string address, shared_ptr<TransportFactory> factory)
: fTransportFactory(factory) : fTransportFactory(factory)
, fTransportType(factory ? factory->GetType() : DefaultTransportType) , fTransportType(factory ? factory->GetType() : DefaultTransportType)
, fSocket(factory ? factory->CreateSocket(type, name) : nullptr) , fSocket(factory ? factory->CreateSocket(type, name) : nullptr)
@ -87,8 +84,8 @@ FairMQChannel::FairMQChannel(string name, string type, string method, string add
// LOG(warn) << "Constructing channel '" << fName << "'"; // LOG(warn) << "Constructing channel '" << fName << "'";
} }
FairMQChannel::FairMQChannel(const string& name, int index, const fair::mq::Properties& properties) Channel::Channel(const string& name, int index, const Properties& properties)
: FairMQChannel(tools::ToString(name, "[", index, "]"), "unspecified", "unspecified", "unspecified", nullptr) : Channel(tools::ToString(name, "[", index, "]"), "unspecified", "unspecified", "unspecified", nullptr)
{ {
string prefix(tools::ToString("chans.", name, ".", index, ".")); string prefix(tools::ToString("chans.", name, ".", index, "."));
@ -107,11 +104,11 @@ FairMQChannel::FairMQChannel(const string& name, int index, const fair::mq::Prop
fAutoBind = GetPropertyOrDefault(properties, string(prefix + "autoBind"), DefaultAutoBind); fAutoBind = GetPropertyOrDefault(properties, string(prefix + "autoBind"), DefaultAutoBind);
} }
FairMQChannel::FairMQChannel(const FairMQChannel& chan) Channel::Channel(const Channel& chan)
: FairMQChannel(chan, chan.fName) : Channel(chan, chan.fName)
{} {}
FairMQChannel::FairMQChannel(const FairMQChannel& chan, string newName) Channel::Channel(const Channel& chan, string newName)
: fTransportFactory(nullptr) : fTransportFactory(nullptr)
, fTransportType(chan.fTransportType) , fTransportType(chan.fTransportType)
, fSocket(nullptr) , fSocket(nullptr)
@ -132,7 +129,7 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan, string newName)
, fMultipart(chan.fMultipart) , fMultipart(chan.fMultipart)
{} {}
FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan) Channel& Channel::operator=(const Channel& chan)
{ {
if (this == &chan) { if (this == &chan) {
return *this; return *this;
@ -160,7 +157,7 @@ FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
return *this; return *this;
} }
bool FairMQChannel::Validate() bool Channel::Validate()
try { try {
stringstream ss; stringstream ss;
ss << "Validating channel '" << fName << "'... "; ss << "Validating channel '" << fName << "'... ";
@ -305,11 +302,11 @@ try {
LOG(debug) << ss.str(); LOG(debug) << ss.str();
return true; return true;
} catch (exception& e) { } catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::ValidateChannel: " << e.what(); LOG(error) << "Exception caught in Channel::ValidateChannel: " << e.what();
throw ChannelConfigurationError(tools::ToString(e.what())); throw ChannelConfigurationError(tools::ToString(e.what()));
} }
void FairMQChannel::Init() void Channel::Init()
{ {
fSocket = fTransportFactory->CreateSocket(fType, fName); fSocket = fTransportFactory->CreateSocket(fType, fName);
@ -329,12 +326,12 @@ void FairMQChannel::Init()
} }
} }
bool FairMQChannel::ConnectEndpoint(const string& endpoint) bool Channel::ConnectEndpoint(const string& endpoint)
{ {
return fSocket->Connect(endpoint); return fSocket->Connect(endpoint);
} }
bool FairMQChannel::BindEndpoint(string& endpoint) bool Channel::BindEndpoint(string& endpoint)
{ {
// try to bind to the configured port. If it fails, try random one (if AutoBind is on). // try to bind to the configured port. If it fails, try random one (if AutoBind is on).
if (fSocket->Bind(endpoint)) { if (fSocket->Bind(endpoint)) {
@ -374,5 +371,6 @@ bool FairMQChannel::BindEndpoint(string& endpoint)
return false; return false;
} }
} }
} }
} // namespace fair::mq

View File

@ -9,12 +9,449 @@
#ifndef FAIR_MQ_CHANNEL_H #ifndef FAIR_MQ_CHANNEL_H
#define FAIR_MQ_CHANNEL_H #define FAIR_MQ_CHANNEL_H
#include <FairMQChannel.h> #include <cstdint> // int64_t
#include <fairmq/Message.h>
#include <fairmq/Parts.h>
#include <fairmq/Properties.h>
#include <fairmq/Socket.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/UnmanagedRegion.h>
#include <memory> // unique_ptr, shared_ptr
#include <mutex>
#include <stdexcept>
#include <string>
#include <utility> // std::move
#include <vector>
namespace fair::mq { namespace fair::mq {
using Channel = FairMQChannel; /**
* @class Channel Channel.h <fairmq/Channel.h>
* @brief Wrapper class for Socket and related methods
*
* The class is not thread-safe.
*/
class Channel
{
friend class Device;
} // namespace fair::mq public:
/// Default constructor
Channel();
/// Constructor
/// @param name Channel name
Channel(const std::string& name);
/// Constructor
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param method Socket method (bind/connect)
/// @param address Network address to bind/connect to (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
Channel(const std::string& type, const std::string& method, const std::string& address);
/// Constructor
/// @param name Channel name
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param factory TransportFactory
Channel(const std::string& name, const std::string& type, std::shared_ptr<TransportFactory> factory);
/// Constructor
/// @param name Channel name
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param method Socket method (bind/connect)
/// @param address Network address to bind/connect to (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
/// @param factory TransportFactory
Channel(std::string name, std::string type, std::string method, std::string address, std::shared_ptr<TransportFactory> factory);
Channel(const std::string& name, int index, const Properties& properties);
/// Copy Constructor
Channel(const Channel&);
/// Copy Constructor (with new name)
Channel(const Channel&, std::string name);
/// Move constructor
// Channel(Channel&&) = delete;
/// Assignment operator
Channel& operator=(const Channel&);
/// Move assignment operator
// Channel& operator=(Channel&&) = delete;
/// Destructor
virtual ~Channel() = default;
// { LOG(warn) << "Destroying channel '" << fName << "'"; }
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
Socket& GetSocket() const { assert(fSocket); return *fSocket; }
bool Bind(const std::string& address)
{
fMethod = "bind";
fAddress = address;
return fSocket->Bind(address);
}
bool Connect(const std::string& address)
{
fMethod = "connect";
fAddress = address;
return fSocket->Connect(address);
}
/// Get channel name
/// @return Returns full channel name (e.g. "data[0]")
std::string GetName() const { return fName; }
/// Get channel prefix
/// @return Returns channel prefix (e.g. "data" in "data[0]")
std::string GetPrefix() const
{
std::string prefix = fName;
prefix = prefix.erase(fName.rfind('['));
return prefix;
}
/// Get channel index
/// @return Returns channel index (e.g. 0 in "data[0]")
std::string GetIndex() const
{
std::string indexStr = fName;
indexStr.erase(indexStr.rfind(']'));
indexStr.erase(0, indexStr.rfind('[') + 1);
return indexStr;
}
/// Get socket type
/// @return Returns socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
std::string GetType() const { return fType; }
/// Get socket method
/// @return Returns socket method (bind/connect)
std::string GetMethod() const { return fMethod; }
/// Get socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
/// @return Returns socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
std::string GetAddress() const { return fAddress; }
/// Get channel transport name ("default", "zeromq" or "shmem")
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
std::string GetTransportName() const { return TransportName(fTransportType); }
/// Get channel transport type
/// @return Returns channel transport type
mq::Transport GetTransportType() const { return fTransportType; }
/// Get socket send buffer size (in number of messages)
/// @return Returns socket send buffer size (in number of messages)
int GetSndBufSize() const { return fSndBufSize; }
/// Get socket receive buffer size (in number of messages)
/// @return Returns socket receive buffer size (in number of messages)
int GetRcvBufSize() const { return fRcvBufSize; }
/// Get socket kernel transmit send buffer size (in bytes)
/// @return Returns socket kernel transmit send buffer size (in bytes)
int GetSndKernelSize() const { return fSndKernelSize; }
/// Get socket kernel transmit receive buffer size (in bytes)
/// @return Returns socket kernel transmit receive buffer size (in bytes)
int GetRcvKernelSize() const { return fRcvKernelSize; }
/// Get linger duration (in milliseconds)
/// @return Returns linger duration (in milliseconds)
int GetLinger() const { return fLinger; }
/// Get socket rate logging interval (in seconds)
/// @return Returns socket rate logging interval (in seconds)
int GetRateLogging() const { return fRateLogging; }
/// Get start of the port range for automatic binding
/// @return start of the port range
int GetPortRangeMin() const { return fPortRangeMin; }
/// Get end of the port range for automatic binding
/// @return end of the port range
int GetPortRangeMax() const { return fPortRangeMax; }
/// Set automatic binding (pick random port if bind fails)
/// @return true/false, true if automatic binding is enabled
bool GetAutoBind() const { return fAutoBind; }
/// Set channel name
/// @param name Arbitrary channel name
void UpdateName(const std::string& name) { fName = name; Invalidate(); }
/// Set socket type
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
void UpdateType(const std::string& type) { fType = type; Invalidate(); }
/// Set socket method
/// @param method Socket method (bind/connect)
void UpdateMethod(const std::string& method) { fMethod = method; Invalidate(); }
/// Set socket address
/// @param Socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
void UpdateAddress(const std::string& address) { fAddress = address; Invalidate(); }
/// Set channel transport
/// @param transport transport string ("default", "zeromq" or "shmem")
void UpdateTransport(const std::string& transport) { fTransportType = TransportType(transport); Invalidate(); }
/// Set socket send buffer size
/// @param sndBufSize Socket send buffer size (in number of messages)
void UpdateSndBufSize(const int sndBufSize) { fSndBufSize = sndBufSize; Invalidate(); }
/// Set socket receive buffer size
/// @param rcvBufSize Socket receive buffer size (in number of messages)
void UpdateRcvBufSize(const int rcvBufSize) { fRcvBufSize = rcvBufSize; Invalidate(); }
/// Set socket kernel transmit send buffer size (in bytes)
/// @param sndKernelSize Socket send buffer size (in bytes)
void UpdateSndKernelSize(const int sndKernelSize) { fSndKernelSize = sndKernelSize; Invalidate(); }
/// Set socket kernel transmit receive buffer size (in bytes)
/// @param rcvKernelSize Socket receive buffer size (in bytes)
void UpdateRcvKernelSize(const int rcvKernelSize) { fRcvKernelSize = rcvKernelSize; Invalidate(); }
/// Set linger duration (in milliseconds)
/// @param duration linger duration (in milliseconds)
void UpdateLinger(const int duration) { fLinger = duration; Invalidate(); }
/// Set socket rate logging interval (in seconds)
/// @param rateLogging Socket rate logging interval (in seconds)
void UpdateRateLogging(const int rateLogging) { fRateLogging = rateLogging; Invalidate(); }
/// Set start of the port range for automatic binding
/// @param minPort start of the port range
void UpdatePortRangeMin(const int minPort) { fPortRangeMin = minPort; Invalidate(); }
/// Set end of the port range for automatic binding
/// @param maxPort end of the port range
void UpdatePortRangeMax(const int maxPort) { fPortRangeMax = maxPort; Invalidate(); }
/// Set automatic binding (pick random port if bind fails)
/// @param autobind true/false, true to enable automatic binding
void UpdateAutoBind(const bool autobind) { fAutoBind = autobind; Invalidate(); }
/// Checks if the configured channel settings are valid (checks the validity parameter, without running full validation (as oposed to ValidateChannel()))
/// @return true if channel settings are valid, false otherwise.
bool IsValid() const { return fValid; }
/// Validates channel configuration
/// @return true if channel settings are valid, false otherwise.
bool Validate();
void Init();
bool ConnectEndpoint(const std::string& endpoint);
bool BindEndpoint(std::string& endpoint);
/// invalidates the channel (requires validation to be used again).
void Invalidate() { fValid = false; }
/// Sends a message to the socket queue.
/// @param msg Constant reference of unique_ptr to a Message
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(MessagePtr& msg, int sndTimeoutInMs = -1)
{
CheckSendCompatibility(msg);
return fSocket->Send(msg, sndTimeoutInMs);
}
/// Receives a message from the socket queue.
/// @param msg Constant reference of unique_ptr to a Message
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(MessagePtr& msg, int rcvTimeoutInMs = -1)
{
CheckReceiveCompatibility(msg);
return fSocket->Receive(msg, rcvTimeoutInMs);
}
/// Send a vector of messages
/// @param msgVec message vector reference
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(std::vector<MessagePtr>& msgVec, int sndTimeoutInMs = -1)
{
CheckSendCompatibility(msgVec);
return fSocket->Send(msgVec, sndTimeoutInMs);
}
/// Receive a vector of messages
/// @param msgVec message vector reference
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(std::vector<MessagePtr>& msgVec, int rcvTimeoutInMs = -1)
{
CheckReceiveCompatibility(msgVec);
return fSocket->Receive(msgVec, rcvTimeoutInMs);
}
/// Send Parts
/// @param parts Parts reference
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(Parts& parts, int sndTimeoutInMs = -1)
{
return Send(parts.fParts, sndTimeoutInMs);
}
/// Receive Parts
/// @param parts Parts reference
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(Parts& parts, int rcvTimeoutInMs = -1)
{
return Receive(parts.fParts, rcvTimeoutInMs);
}
unsigned long GetBytesTx() const { return fSocket->GetBytesTx(); }
unsigned long GetBytesRx() const { return fSocket->GetBytesRx(); }
unsigned long GetMessagesTx() const { return fSocket->GetMessagesTx(); }
unsigned long GetMessagesRx() const { return fSocket->GetMessagesRx(); }
auto Transport() -> TransportFactory* { return fTransportFactory.get(); };
template<typename... Args>
MessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
template<typename T>
MessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
template<typename T>
MessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
template<typename... Args>
UnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
static constexpr mq::Transport DefaultTransportType = mq::Transport::DEFAULT;
static constexpr const char* DefaultTransportName = "default";
static constexpr const char* DefaultName = "";
static constexpr const char* DefaultType = "unspecified";
static constexpr const char* DefaultMethod = "unspecified";
static constexpr const char* DefaultAddress = "unspecified";
static constexpr int DefaultSndBufSize = 1000;
static constexpr int DefaultRcvBufSize = 1000;
static constexpr int DefaultSndKernelSize = 0;
static constexpr int DefaultRcvKernelSize = 0;
static constexpr int DefaultLinger = 500;
static constexpr int DefaultRateLogging = 1;
static constexpr int DefaultPortRangeMin = 22000;
static constexpr int DefaultPortRangeMax = 23000;
static constexpr bool DefaultAutoBind = true;
private:
std::shared_ptr<TransportFactory> fTransportFactory;
mq::Transport fTransportType;
std::unique_ptr<Socket> fSocket;
std::string fName;
std::string fType;
std::string fMethod;
std::string fAddress;
int fSndBufSize;
int fRcvBufSize;
int fSndKernelSize;
int fRcvKernelSize;
int fLinger;
int fRateLogging;
int fPortRangeMin;
int fPortRangeMax;
bool fAutoBind;
bool fValid;
bool fMultipart;
void CheckSendCompatibility(MessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
MessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<Message*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void CheckSendCompatibility(std::vector<MessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
MessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<Message*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
}
void CheckReceiveCompatibility(MessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
void CheckReceiveCompatibility(std::vector<MessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void InitTransport(std::shared_ptr<TransportFactory> factory)
{
fTransportFactory = factory;
fTransportType = factory->GetType();
}
};
} // namespace fair::mq
// using FairMQChannel [[deprecated("Use fair::mq::Channel")]] = fair::mq::Channel;
using FairMQChannel = fair::mq::Channel;
#endif // FAIR_MQ_CHANNEL_H #endif // FAIR_MQ_CHANNEL_H

View File

@ -1,51 +1,48 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2012-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
#include <FairMQDevice.h> #include <algorithm> // std::max
#include <boost/algorithm/string.hpp> // join/split
#include <fairmq/tools/RateLimit.h>
#include <fairmq/tools/Network.h>
#include <boost/algorithm/string.hpp> // join/split
#include <list>
#include <chrono> #include <chrono>
#include <fairmq/Device.h>
#include <fairmq/Tools.h>
#include <future>
#include <iomanip>
#include <list>
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <iomanip>
#include <future> namespace fair::mq {
#include <algorithm> // std::max
using namespace std; using namespace std;
using namespace fair::mq;
constexpr const char* FairMQDevice::DefaultId; constexpr const char* Device::DefaultId;
constexpr int FairMQDevice::DefaultIOThreads; constexpr int Device::DefaultIOThreads;
constexpr const char* FairMQDevice::DefaultTransportName; constexpr const char* Device::DefaultTransportName;
constexpr fair::mq::Transport FairMQDevice::DefaultTransportType; constexpr mq::Transport Device::DefaultTransportType;
constexpr const char* FairMQDevice::DefaultNetworkInterface; constexpr const char* Device::DefaultNetworkInterface;
constexpr int FairMQDevice::DefaultInitTimeout; constexpr int Device::DefaultInitTimeout;
constexpr uint64_t FairMQDevice::DefaultMaxRunTime; constexpr uint64_t Device::DefaultMaxRunTime;
constexpr float FairMQDevice::DefaultRate; constexpr float Device::DefaultRate;
constexpr const char* FairMQDevice::DefaultSession; constexpr const char* Device::DefaultSession;
struct StateSubscription struct StateSubscription
{ {
fair::mq::StateMachine& fStateMachine; StateMachine& fStateMachine;
fair::mq::StateQueue& fStateQueue; StateQueue& fStateQueue;
string fId; string fId;
explicit StateSubscription(string id, fair::mq::StateMachine& stateMachine, fair::mq::StateQueue& stateQueue) explicit StateSubscription(string id, StateMachine& stateMachine, StateQueue& stateQueue)
: fStateMachine(stateMachine) : fStateMachine(stateMachine)
, fStateQueue(stateQueue) , fStateQueue(stateQueue)
, fId(std::move(id)) , fId(std::move(id))
{ {
fStateMachine.SubscribeToStateChange(fId, [&](fair::mq::State state) { fStateMachine.SubscribeToStateChange(fId, [&](State state) {
fStateQueue.Push(state); fStateQueue.Push(state);
}); });
} }
@ -55,23 +52,23 @@ struct StateSubscription
} }
}; };
FairMQDevice::FairMQDevice() Device::Device()
: FairMQDevice(nullptr, {0, 0, 0}) : Device(nullptr, {0, 0, 0})
{} {}
FairMQDevice::FairMQDevice(ProgOptions& config) Device::Device(ProgOptions& config)
: FairMQDevice(&config, {0, 0, 0}) : Device(&config, {0, 0, 0})
{} {}
FairMQDevice::FairMQDevice(const tools::Version version) Device::Device(const tools::Version version)
: FairMQDevice(nullptr, version) : Device(nullptr, version)
{} {}
FairMQDevice::FairMQDevice(ProgOptions& config, const tools::Version version) Device::Device(ProgOptions& config, const tools::Version version)
: FairMQDevice(&config, version) : Device(&config, version)
{} {}
FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version) Device::Device(ProgOptions* config, const tools::Version version)
: fTransportFactory(nullptr) : fTransportFactory(nullptr)
, fInternalConfig(config ? nullptr : make_unique<ProgOptions>()) , fInternalConfig(config ? nullptr : make_unique<ProgOptions>())
, fConfig(config ? config : fInternalConfig.get()) , fConfig(config ? config : fInternalConfig.get())
@ -97,34 +94,34 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
} }
}); });
fStateMachine.HandleStates([&](fair::mq::State state) { fStateMachine.HandleStates([&](State state) {
LOG(trace) << "device notified on new state: " << state; LOG(trace) << "device notified on new state: " << state;
fStateQueue.Push(state); fStateQueue.Push(state);
switch (state) { switch (state) {
case fair::mq::State::InitializingDevice: case State::InitializingDevice:
InitWrapper(); InitWrapper();
break; break;
case fair::mq::State::Binding: case State::Binding:
BindWrapper(); BindWrapper();
break; break;
case fair::mq::State::Connecting: case State::Connecting:
ConnectWrapper(); ConnectWrapper();
break; break;
case fair::mq::State::InitializingTask: case State::InitializingTask:
InitTaskWrapper(); InitTaskWrapper();
break; break;
case fair::mq::State::Running: case State::Running:
RunWrapper(); RunWrapper();
break; break;
case fair::mq::State::ResettingTask: case State::ResettingTask:
ResetTaskWrapper(); ResetTaskWrapper();
break; break;
case fair::mq::State::ResettingDevice: case State::ResettingDevice:
ResetWrapper(); ResetWrapper();
break; break;
case fair::mq::State::Exiting: case State::Exiting:
Exit(); Exit();
break; break;
default: default:
@ -136,7 +133,7 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
fStateMachine.Start(); fStateMachine.Start();
} }
void FairMQDevice::TransitionTo(const fair::mq::State s) void Device::TransitionTo(const State s)
{ {
{ {
lock_guard<mutex> lock(fTransitionMtx); lock_guard<mutex> lock(fTransitionMtx);
@ -147,7 +144,7 @@ void FairMQDevice::TransitionTo(const fair::mq::State s)
fTransitioning = true; fTransitioning = true;
} }
using fair::mq::State; using mq::State;
StateQueue sq; StateQueue sq;
StateSubscription ss(tools::ToString(fId, ".TransitionTo"), fStateMachine, sq); StateSubscription ss(tools::ToString(fId, ".TransitionTo"), fStateMachine, sq);
@ -203,7 +200,7 @@ void FairMQDevice::TransitionTo(const fair::mq::State s)
} }
} }
void FairMQDevice::InitWrapper() void Device::InitWrapper()
{ {
// run initialization once CompleteInit transition is requested // run initialization once CompleteInit transition is requested
fStateMachine.WaitForPendingState(); fStateMachine.WaitForPendingState();
@ -217,7 +214,7 @@ void FairMQDevice::InitWrapper()
fInitializationTimeoutInS = fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout); fInitializationTimeoutInS = fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout);
try { try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetProperty<string>("transport", DefaultTransportName)); fDefaultTransportType = TransportTypes.at(fConfig->GetProperty<string>("transport", DefaultTransportName));
} catch (const exception& e) { } catch (const exception& e) {
LOG(error) << "exception: " << e.what(); LOG(error) << "exception: " << e.what();
LOG(error) << "invalid transport type provided: " << fConfig->GetProperty<string>("transport", "not provided"); LOG(error) << "invalid transport type provided: " << fConfig->GetProperty<string>("transport", "not provided");
@ -231,7 +228,7 @@ void FairMQDevice::InitWrapper()
} }
} }
LOG(debug) << "Setting '" << fair::mq::TransportNames.at(fDefaultTransportType) << "' as default transport for the device"; LOG(debug) << "Setting '" << TransportNames.at(fDefaultTransportType) << "' as default transport for the device";
fTransportFactory = AddTransport(fDefaultTransportType); fTransportFactory = AddTransport(fDefaultTransportType);
string networkInterface = fConfig->GetProperty<string>("network-interface", DefaultNetworkInterface); string networkInterface = fConfig->GetProperty<string>("network-interface", DefaultNetworkInterface);
@ -241,7 +238,7 @@ void FairMQDevice::InitWrapper()
int subChannelIndex = 0; int subChannelIndex = 0;
for (auto& subChannel : channel.second) { for (auto& subChannel : channel.second) {
// set channel transport // set channel transport
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << fair::mq::TransportNames.at(subChannel.fTransportType); LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << TransportNames.at(subChannel.fTransportType);
subChannel.InitTransport(AddTransport(subChannel.fTransportType)); subChannel.InitTransport(AddTransport(subChannel.fTransportType));
if (subChannel.fMethod == "bind") { if (subChannel.fMethod == "bind") {
@ -278,7 +275,7 @@ void FairMQDevice::InitWrapper()
// ChangeState(Transition::Auto); // ChangeState(Transition::Auto);
} }
void FairMQDevice::BindWrapper() void Device::BindWrapper()
{ {
// Bind channels. Here one run is enough, because bind settings should be available locally // Bind channels. Here one run is enough, because bind settings should be available locally
// If necessary this could be handled in the same way as the connecting channels // If necessary this could be handled in the same way as the connecting channels
@ -294,7 +291,7 @@ void FairMQDevice::BindWrapper()
ChangeState(Transition::Auto); ChangeState(Transition::Auto);
} }
void FairMQDevice::ConnectWrapper() void Device::ConnectWrapper()
{ {
// go over the list of channels until all are initialized (and removed from the uninitialized list) // go over the list of channels until all are initialized (and removed from the uninitialized list)
int numAttempts = 1; int numAttempts = 1;
@ -331,7 +328,7 @@ void FairMQDevice::ConnectWrapper()
ChangeState(Transition::Auto); ChangeState(Transition::Auto);
} }
void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans) void Device::AttachChannels(vector<Channel*>& chans)
{ {
auto itr = chans.begin(); auto itr = chans.begin();
@ -351,7 +348,7 @@ void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
} }
} }
bool FairMQDevice::AttachChannel(FairMQChannel& chan) bool Device::AttachChannel(Channel& chan)
{ {
vector<string> endpoints; vector<string> endpoints;
string chanAddress = chan.GetAddress(); string chanAddress = chan.GetAddress();
@ -424,19 +421,19 @@ bool FairMQDevice::AttachChannel(FairMQChannel& chan)
return true; return true;
} }
void FairMQDevice::InitTaskWrapper() void Device::InitTaskWrapper()
{ {
InitTask(); InitTask();
ChangeState(Transition::Auto); ChangeState(Transition::Auto);
} }
void FairMQDevice::RunWrapper() void Device::RunWrapper()
{ {
LOG(info) << "DEVICE: Running..."; LOG(info) << "DEVICE: Running...";
// start the rate logger thread // start the rate logger thread
future<void> rateLogger = async(launch::async, &FairMQDevice::LogSocketRates, this); future<void> rateLogger = async(launch::async, &Device::LogSocketRates, this);
// notify transports to resume transfers // notify transports to resume transfers
for (auto& t : fTransports) { for (auto& t : fTransports) {
@ -486,7 +483,7 @@ void FairMQDevice::RunWrapper()
rateLogger.get(); rateLogger.get();
} }
void FairMQDevice::HandleSingleChannelInput() void Device::HandleSingleChannelInput()
{ {
bool proceed = true; bool proceed = true;
@ -501,14 +498,14 @@ void FairMQDevice::HandleSingleChannelInput()
} }
} }
void FairMQDevice::HandleMultipleChannelInput() void Device::HandleMultipleChannelInput()
{ {
// check if more than one transport is used // check if more than one transport is used
fMultitransportInputs.clear(); fMultitransportInputs.clear();
for (const auto& k : fInputChannelKeys) { for (const auto& k : fInputChannelKeys) {
fair::mq::Transport t = fChannels.at(k).at(0).fTransportType; mq::Transport t = fChannels.at(k).at(0).fTransportType;
if (fMultitransportInputs.find(t) == fMultitransportInputs.end()) { if (fMultitransportInputs.find(t) == fMultitransportInputs.end()) {
fMultitransportInputs.insert(pair<fair::mq::Transport, vector<string>>(t, vector<string>())); fMultitransportInputs.insert(pair<mq::Transport, vector<string>>(t, vector<string>()));
fMultitransportInputs.at(t).push_back(k); fMultitransportInputs.at(t).push_back(k);
} else { } else {
fMultitransportInputs.at(t).push_back(k); fMultitransportInputs.at(t).push_back(k);
@ -533,7 +530,7 @@ void FairMQDevice::HandleMultipleChannelInput()
} else { // otherwise poll directly } else { // otherwise poll directly
bool proceed = true; bool proceed = true;
FairMQPollerPtr poller(fChannels.at(fInputChannelKeys.at(0)).at(0).fTransportFactory->CreatePoller(fChannels, fInputChannelKeys)); PollerPtr poller(fChannels.at(fInputChannelKeys.at(0)).at(0).fTransportFactory->CreatePoller(fChannels, fInputChannelKeys));
while (!NewStatePending() && proceed) { while (!NewStatePending() && proceed) {
poller->Poll(200); poller->Poll(200);
@ -561,14 +558,14 @@ void FairMQDevice::HandleMultipleChannelInput()
} }
} }
void FairMQDevice::HandleMultipleTransportInput() void Device::HandleMultipleTransportInput()
{ {
vector<thread> threads; vector<thread> threads;
fMultitransportProceed = true; fMultitransportProceed = true;
for (const auto& i : fMultitransportInputs) { for (const auto& i : fMultitransportInputs) {
threads.emplace_back(thread(&FairMQDevice::PollForTransport, this, fTransports.at(i.first).get(), i.second)); threads.emplace_back(thread(&Device::PollForTransport, this, fTransports.at(i.first).get(), i.second));
} }
for (thread& t : threads) { for (thread& t : threads) {
@ -576,10 +573,10 @@ void FairMQDevice::HandleMultipleTransportInput()
} }
} }
void FairMQDevice::PollForTransport(const FairMQTransportFactory* factory, const vector<string>& channelKeys) void Device::PollForTransport(const TransportFactory* factory, const vector<string>& channelKeys)
{ {
try { try {
FairMQPollerPtr poller(factory->CreatePoller(fChannels, channelKeys)); PollerPtr poller(factory->CreatePoller(fChannels, channelKeys));
while (!NewStatePending() && fMultitransportProceed) { while (!NewStatePending() && fMultitransportProceed) {
poller->Poll(500); poller->Poll(500);
@ -610,14 +607,14 @@ void FairMQDevice::PollForTransport(const FairMQTransportFactory* factory, const
} }
} }
} catch (exception& e) { } catch (exception& e) {
LOG(error) << "FairMQDevice::PollForTransport() failed: " << e.what() << ", going to ERROR state."; LOG(error) << "fair::mq::Device::PollForTransport() failed: " << e.what() << ", going to ERROR state.";
throw runtime_error(tools::ToString("FairMQDevice::PollForTransport() failed: ", e.what(), ", going to ERROR state.")); throw runtime_error(tools::ToString("fair::mq::Device::PollForTransport() failed: ", e.what(), ", going to ERROR state."));
} }
} }
bool FairMQDevice::HandleMsgInput(const string& chName, const InputMsgCallback& callback, int i) bool Device::HandleMsgInput(const string& chName, const InputMsgCallback& callback, int i)
{ {
unique_ptr<FairMQMessage> input(fChannels.at(chName).at(i).fTransportFactory->CreateMessage()); unique_ptr<Message> input(fChannels.at(chName).at(i).fTransportFactory->CreateMessage());
if (Receive(input, chName, i) >= 0) { if (Receive(input, chName, i) >= 0) {
return callback(input, i); return callback(input, i);
@ -626,9 +623,9 @@ bool FairMQDevice::HandleMsgInput(const string& chName, const InputMsgCallback&
} }
} }
bool FairMQDevice::HandleMultipartInput(const string& chName, const InputMultipartCallback& callback, int i) bool Device::HandleMultipartInput(const string& chName, const InputMultipartCallback& callback, int i)
{ {
FairMQParts input; Parts input;
if (Receive(input, chName, i) >= 0) { if (Receive(input, chName, i) >= 0) {
return callback(input, i); return callback(input, i);
@ -637,34 +634,34 @@ bool FairMQDevice::HandleMultipartInput(const string& chName, const InputMultipa
} }
} }
shared_ptr<FairMQTransportFactory> FairMQDevice::AddTransport(fair::mq::Transport transport) shared_ptr<TransportFactory> Device::AddTransport(mq::Transport transport)
{ {
if (transport == fair::mq::Transport::DEFAULT) { if (transport == mq::Transport::DEFAULT) {
transport = fDefaultTransportType; transport = fDefaultTransportType;
} }
auto i = fTransports.find(transport); auto i = fTransports.find(transport);
if (i == fTransports.end()) { if (i == fTransports.end()) {
LOG(debug) << "Adding '" << fair::mq::TransportNames.at(transport) << "' transport"; LOG(debug) << "Adding '" << TransportNames.at(transport) << "' transport";
auto tr = FairMQTransportFactory::CreateTransportFactory(fair::mq::TransportNames.at(transport), fId, fConfig); auto tr = TransportFactory::CreateTransportFactory(TransportNames.at(transport), fId, fConfig);
fTransports.insert({transport, tr}); fTransports.insert({transport, tr});
return tr; return tr;
} else { } else {
LOG(debug) << "Reusing existing '" << fair::mq::TransportNames.at(transport) << "' transport"; LOG(debug) << "Reusing existing '" << TransportNames.at(transport) << "' transport";
return i->second; return i->second;
} }
} }
void FairMQDevice::SetConfig(ProgOptions& config) void Device::SetConfig(ProgOptions& config)
{ {
fInternalConfig.reset(); fInternalConfig.reset();
fConfig = &config; fConfig = &config;
} }
void FairMQDevice::LogSocketRates() void Device::LogSocketRates()
{ {
vector<FairMQChannel*> filteredChannels; vector<Channel*> filteredChannels;
vector<string> filteredChannelNames; vector<string> filteredChannelNames;
vector<int> logIntervals; vector<int> logIntervals;
vector<int> intervalCounters; vector<int> intervalCounters;
@ -760,21 +757,21 @@ void FairMQDevice::LogSocketRates()
} }
} }
void FairMQDevice::UnblockTransports() void Device::UnblockTransports()
{ {
for (auto& transport : fTransports) { for (auto& transport : fTransports) {
transport.second->Interrupt(); transport.second->Interrupt();
} }
} }
void FairMQDevice::ResetTaskWrapper() void Device::ResetTaskWrapper()
{ {
ResetTask(); ResetTask();
ChangeState(Transition::Auto); ChangeState(Transition::Auto);
} }
void FairMQDevice::ResetWrapper() void Device::ResetWrapper()
{ {
for (auto& transport : fTransports) { for (auto& transport : fTransports) {
transport.second->Reset(); transport.second->Reset();
@ -788,9 +785,11 @@ void FairMQDevice::ResetWrapper()
ChangeState(Transition::Auto); ChangeState(Transition::Auto);
} }
FairMQDevice::~FairMQDevice() Device::~Device()
{ {
UnsubscribeFromNewTransition("device"); UnsubscribeFromNewTransition("device");
fStateMachine.StopHandlingStates(); fStateMachine.StopHandlingStates();
LOG(debug) << "Shutting down device " << fId; LOG(debug) << "Shutting down device " << fId;
} }
} // namespace fair::mq

View File

@ -9,13 +9,627 @@
#ifndef FAIR_MQ_DEVICE_H #ifndef FAIR_MQ_DEVICE_H
#define FAIR_MQ_DEVICE_H #define FAIR_MQ_DEVICE_H
#include <FairMQDevice.h> #include <algorithm> // find
#include <atomic>
#include <chrono>
#include <cstddef>
#include <fairlogger/Logger.h>
#include <fairmq/Channel.h>
#include <fairmq/Message.h>
#include <fairmq/Parts.h>
#include <fairmq/ProgOptions.h>
#include <fairmq/StateMachine.h>
#include <fairmq/StateQueue.h>
#include <fairmq/Tools.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/UnmanagedRegion.h>
#include <functional>
#include <memory> // unique_ptr
#include <mutex>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility> // pair
#include <vector>
namespace fair::mq namespace fair::mq {
using ChannelMap = std::unordered_map<std::string, std::vector<Channel>>;
struct OngoingTransition : std::runtime_error
{ {
using std::runtime_error::runtime_error;
};
using Device = ::FairMQDevice; using InputMsgCallback = std::function<bool(MessagePtr&, int)>;
} // namespace fair::mq using InputMultipartCallback = std::function<bool(Parts&, int)>;
class Device
{
friend class Channel;
public:
Device();
Device(ProgOptions& config);
Device(const tools::Version version);
Device(ProgOptions& config, const tools::Version version);
private:
Device(ProgOptions* config, const tools::Version version);
public:
Device(const Device&) = delete;
Device operator=(const Device&) = delete;
virtual ~Device();
/// Outputs the socket transfer rates
virtual void LogSocketRates();
template<typename Serializer, typename DataType, typename... Args>
[[deprecated]] void Serialize(Message& msg, DataType&& data, Args&&... args) const
{
Serializer().Serialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
template<typename Deserializer, typename DataType, typename... Args>
[[deprecated]] void Deserialize(Message& msg, DataType&& data, Args&&... args) const
{
Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
/// Shorthand method to send `msg` on `chan` at index `i`
/// @param msg message reference
/// @param chan channel name
/// @param i channel index
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via
/// state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out,
/// TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by
/// requested state change)
int64_t Send(MessagePtr& msg,
const std::string& channel,
const int index = 0,
int sndTimeoutInMs = -1)
{
return GetChannel(channel, index).Send(msg, sndTimeoutInMs);
}
/// Shorthand method to receive `msg` on `chan` at index `i`
/// @param msg message reference
/// @param chan channel name
/// @param i channel index
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g.
/// via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out,
/// TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by
/// requested state change)
int64_t Receive(MessagePtr& msg,
const std::string& channel,
const int index = 0,
int rcvTimeoutInMs = -1)
{
return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
}
/// Shorthand method to send Parts on `chan` at index `i`
/// @param parts parts reference
/// @param chan channel name
/// @param i channel index
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via
/// state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out,
/// TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by
/// requested state change)
int64_t Send(Parts& parts,
const std::string& channel,
const int index = 0,
int sndTimeoutInMs = -1)
{
return GetChannel(channel, index).Send(parts.fParts, sndTimeoutInMs);
}
/// Shorthand method to receive Parts on `chan` at index `i`
/// @param parts parts reference
/// @param chan channel name
/// @param i channel index
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g.
/// via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out,
/// TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by
/// requested state change)
int64_t Receive(Parts& parts,
const std::string& channel,
const int index = 0,
int rcvTimeoutInMs = -1)
{
return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
}
/// @brief Getter for default transport factory
auto Transport() const -> TransportFactory* { return fTransportFactory.get(); }
// creates message with the default device transport
template<typename... Args>
MessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
// creates message with the transport of the specified channel
template<typename... Args>
MessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
}
// creates a message that will not be cleaned up after transfer, with the default device
// transport
template<typename T>
MessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
// creates a message that will not be cleaned up after transfer, with the transport of the
// specified channel
template<typename T>
MessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewStaticMessage(data);
}
// creates a message with a copy of the provided data, with the default device transport
template<typename T>
MessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
// creates a message with a copy of the provided data, with the transport of the specified
// channel
template<typename T>
MessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewSimpleMessage(data);
}
// creates unamanaged region with the default device transport
template<typename... Args>
UnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
// creates unmanaged region with the transport of the specified channel
template<typename... Args>
UnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewUnmanagedRegion(std::forward<Args>(args)...);
}
template<typename... Ts>
PollerPtr NewPoller(const Ts&... inputs)
{
std::vector<std::string> chans{inputs...};
// if more than one channel provided, check compatibility
if (chans.size() > 1) {
mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
for (unsigned int i = 1; i < chans.size(); ++i) {
if (type != GetChannel(chans.at(i), 0).Transport()->GetType()) {
LOG(error) << "poller failed: different transports within same poller are not "
"yet supported. Going to ERROR state.";
throw std::runtime_error("poller failed: different transports within same "
"poller are not yet supported.");
}
}
}
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
}
PollerPtr NewPoller(const std::vector<Channel*>& channels)
{
// if more than one channel provided, check compatibility
if (channels.size() > 1) {
mq::Transport type = channels.at(0)->Transport()->GetType();
for (unsigned int i = 1; i < channels.size(); ++i) {
if (type != channels.at(i)->Transport()->GetType()) {
LOG(error) << "poller failed: different transports within same poller are not "
"yet supported. Going to ERROR state.";
throw std::runtime_error("poller failed: different transports within same "
"poller are not yet supported.");
}
}
}
return channels.at(0)->Transport()->CreatePoller(channels);
}
/// Adds a transport to the device if it doesn't exist
/// @param transport Transport string ("zeromq"/"shmem")
std::shared_ptr<TransportFactory> AddTransport(const mq::Transport transport);
/// Assigns config to the device
void SetConfig(ProgOptions& config);
/// Get pointer to the config
ProgOptions* GetConfig() const { return fConfig; }
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName,
bool (T::*memberFunction)(MessagePtr& msg, int index))
{
fDataCallbacks = true;
fMsgInputs.insert(
std::make_pair(channelName, [this, memberFunction](MessagePtr& msg, int index) {
return (static_cast<T*>(this)->*memberFunction)(msg, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMsgCallback callback)
{
fDataCallbacks = true;
fMsgInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName, bool (T::*memberFunction)(Parts& parts, int index))
{
fDataCallbacks = true;
fMultipartInputs.insert(
std::make_pair(channelName, [this, memberFunction](Parts& parts, int index) {
return (static_cast<T*>(this)->*memberFunction)(parts, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMultipartCallback callback)
{
fDataCallbacks = true;
fMultipartInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
Channel& GetChannel(const std::string& channelName, const int index = 0)
try {
return fChannels.at(channelName).at(index);
} catch (const std::out_of_range& oor) {
LOG(error)
<< "requested channel has not been configured? check channel names/configuration.";
LOG(error) << "channel: " << channelName << ", index: " << index;
LOG(error) << "out of range: " << oor.what();
throw;
}
virtual void RegisterChannelEndpoints() {}
bool RegisterChannelEndpoint(const std::string& channelName,
uint16_t minNumSubChannels = 1,
uint16_t maxNumSubChannels = 1)
{
bool ok = fChannelRegistry
.insert(std::make_pair(channelName,
std::make_pair(minNumSubChannels, maxNumSubChannels)))
.second;
if (!ok) {
LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
}
return ok;
}
void PrintRegisteredChannels()
{
if (fChannelRegistry.empty()) {
LOGV(info, verylow) << "no channels registered.";
} else {
for (const auto& c : fChannelRegistry) {
LOGV(info, verylow) << c.first << ":" << c.second.first << ":" << c.second.second;
}
}
}
void SetId(const std::string& id) { fId = id; }
std::string GetId() { return fId; }
const tools::Version GetVersion() const { return fVersion; }
void SetNumIoThreads(int numIoThreads) { fConfig->SetProperty("io-threads", numIoThreads); }
int GetNumIoThreads() const
{
return fConfig->GetProperty<int>("io-threads", DefaultIOThreads);
}
void SetNetworkInterface(const std::string& networkInterface)
{
fConfig->SetProperty("network-interface", networkInterface);
}
std::string GetNetworkInterface() const
{
return fConfig->GetProperty<std::string>("network-interface", DefaultNetworkInterface);
}
void SetDefaultTransport(const std::string& name) { fConfig->SetProperty("transport", name); }
std::string GetDefaultTransport() const
{
return fConfig->GetProperty<std::string>("transport", DefaultTransportName);
}
void SetInitTimeoutInS(int initTimeoutInS)
{
fConfig->SetProperty("init-timeout", initTimeoutInS);
}
int GetInitTimeoutInS() const
{
return fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout);
}
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"shmem")
void SetTransport(const std::string& transport)
{
fConfig->SetProperty("transport", transport);
}
/// Gets the default transport name
std::string GetTransportName() const
{
return fConfig->GetProperty<std::string>("transport", DefaultTransportName);
}
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine() { fStateMachine.ProcessWork(); };
/// Wait for the supplied amount of time or for interruption.
/// If interrupted, returns false, otherwise true.
/// @param duration wait duration
template<typename Rep, typename Period>
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
{
return !fStateMachine.WaitForPendingStateFor(
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
}
protected:
std::shared_ptr<TransportFactory> fTransportFactory; ///< Default transport factory
std::unordered_map<mq::Transport, std::shared_ptr<TransportFactory>>
fTransports; ///< Container for transports
public:
std::unordered_map<std::string, std::vector<Channel>> fChannels; ///< Device channels
std::unique_ptr<ProgOptions> fInternalConfig; ///< Internal program options configuration
ProgOptions* fConfig; ///< Pointer to config (internal or external)
void AddChannel(const std::string& name, Channel&& channel)
{
fConfig->AddChannel(name, channel);
}
protected:
std::string fId; ///< Device ID
/// Additional user initialization (can be overloaded in child classes). Prefer to use
/// InitTask().
virtual void Init() {}
virtual void Bind() {}
virtual void Connect() {}
/// Task initialization (can be overloaded in child classes)
virtual void InitTask() {}
/// Runs the device (to be overloaded in child classes)
virtual void Run() {}
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
virtual void PreRun() {}
/// Called during RUNNING state repeatedly until it returns false or device state changes
virtual bool ConditionalRun() { return false; }
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
virtual void PostRun() {}
/// Resets the user task (to be overloaded in child classes)
virtual void ResetTask() {}
/// Resets the device (can be overloaded in child classes)
virtual void Reset() {}
public:
/// @brief Request a device state transition
/// @param transition state transition
///
/// The state transition may not happen immediately, but when the current state evaluates the
/// pending transition event and terminates. In other words, the device states are scheduled
/// cooperatively.
bool ChangeState(const Transition transition) { return fStateMachine.ChangeState(transition); }
/// @brief Request a device state transition
/// @param transition state transition
///
/// The state transition may not happen immediately, but when the current state evaluates the
/// pending transition event and terminates. In other words, the device states are scheduled
/// cooperatively.
bool ChangeState(const std::string& transition)
{
return fStateMachine.ChangeState(GetTransition(transition));
}
/// @brief waits for the next state (any) to occur
State WaitForNextState() { return fStateQueue.WaitForNext(); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(State state) { fStateQueue.WaitForState(state); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(const std::string& state) { WaitForState(GetState(state)); }
void TransitionTo(const State state);
/// @brief Subscribe with a callback to state changes
/// @param key id to identify your subscription
/// @param callback callback (called with the new state as the parameter)
///
/// The callback is called at the beginning of a new state.
/// The callback is called from the thread the state is running in.
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback)
{
fStateMachine.SubscribeToStateChange(key, callback);
}
/// @brief Unsubscribe from state changes
/// @param key id (that was used when subscribing)
void UnsubscribeFromStateChange(const std::string& key)
{
fStateMachine.UnsubscribeFromStateChange(key);
}
/// @brief Subscribe with a callback to incoming state transitions
/// @param key id to identify your subscription
/// @param callback callback (called with the incoming transition as the parameter)
/// The callback is called when new transition is initiated.
/// The callback is called from the thread that initiates the transition (via ChangeState).
void SubscribeToNewTransition(const std::string& key,
std::function<void(const Transition)> callback)
{
fStateMachine.SubscribeToNewTransition(key, callback);
}
/// @brief Unsubscribe from state transitions
/// @param key id (that was used when subscribing)
void UnsubscribeFromNewTransition(const std::string& key)
{
fStateMachine.UnsubscribeFromNewTransition(key);
}
/// @brief Returns true if a new state has been requested, signaling the current handler to
/// stop.
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
/// @brief Returns the current state
State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
/// @brief Returns the name of the current state as a string
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
/// @brief Returns name of the given state as a string
/// @param state state
static std::string GetStateName(const State state) { return GetStateName(state); }
/// @brief Returns name of the given transition as a string
/// @param transition transition
static std::string GetTransitionName(const Transition transition)
{
return GetTransitionName(transition);
}
static constexpr const char* DefaultId = "";
static constexpr int DefaultIOThreads = 1;
static constexpr const char* DefaultTransportName = "zeromq";
static constexpr mq::Transport DefaultTransportType = mq::Transport::ZMQ;
static constexpr const char* DefaultNetworkInterface = "default";
static constexpr int DefaultInitTimeout = 120;
static constexpr uint64_t DefaultMaxRunTime = 0;
static constexpr float DefaultRate = 0.;
static constexpr const char* DefaultSession = "default";
private:
mq::Transport fDefaultTransportType; ///< Default transport for the device
StateMachine fStateMachine;
/// Handles the initialization
void InitWrapper();
/// Initializes binding channels
void BindWrapper();
/// Initializes connecting channels
void ConnectWrapper();
/// Handles the InitTask() method
void InitTaskWrapper();
/// Handles the Run() method
void RunWrapper();
/// Handles the ResetTask() method
void ResetTaskWrapper();
/// Handles the Reset() method
void ResetWrapper();
/// Notifies transports to cease any blocking activity
void UnblockTransports();
/// Shuts down the transports and the device
void Exit() {}
/// Attach (bind/connect) channels in the list
void AttachChannels(std::vector<Channel*>& chans);
bool AttachChannel(Channel& ch);
void HandleSingleChannelInput();
void HandleMultipleChannelInput();
void HandleMultipleTransportInput();
void PollForTransport(const TransportFactory* factory,
const std::vector<std::string>& channelKeys);
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
bool HandleMultipartInput(const std::string& chName,
const InputMultipartCallback& callback,
int i);
std::vector<Channel*> fUninitializedBindingChannels;
std::vector<Channel*> fUninitializedConnectingChannels;
bool fDataCallbacks;
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
std::unordered_map<std::string, InputMultipartCallback> fMultipartInputs;
std::unordered_map<mq::Transport, std::vector<std::string>> fMultitransportInputs;
std::unordered_map<std::string, std::pair<uint16_t, uint16_t>> fChannelRegistry;
std::vector<std::string> fInputChannelKeys;
std::mutex fMultitransportMutex;
std::atomic<bool> fMultitransportProceed;
const tools::Version fVersion;
float fRate; ///< Rate limiting for ConditionalRun
uint64_t fMaxRunRuntimeInS; ///< Maximum runtime for the Running state handler, after which
///< state will change to Ready (in seconds, 0 for no limit).
int fInitializationTimeoutInS;
std::vector<std::string> fRawCmdLineArgs;
StateQueue fStateQueue;
std::mutex fTransitionMtx;
bool fTransitioning;
};
} // namespace fair::mq
// using FairMQChannelMap [[deprecated("Use fair::mq::ChannelMap")]] = fair::mq::ChannelMap;
// using InputMsgCallback [[deprecated("Use fair::mq::InputMsgCallback")]] =
// fair::mq::InputMsgCallback;
// using InputMultipartCallback [[deprecated("Use fair::mq::InputMultipartCallback")]] =
// fair::mq::InputMultipartCallback;
// using FairMQDevice [[deprecated("Use fair::mq::Device")]] = fair::mq::Device;
using FairMQChannelMap = fair::mq::ChannelMap;
using InputMsgCallback = fair::mq::InputMsgCallback;
using InputMultipartCallback = fair::mq::InputMultipartCallback;
using FairMQDevice = fair::mq::Device;
#endif /* FAIR_MQ_DEVICE_H */ #endif /* FAIR_MQ_DEVICE_H */

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,442 +9,12 @@
#ifndef FAIRMQCHANNEL_H_ #ifndef FAIRMQCHANNEL_H_
#define FAIRMQCHANNEL_H_ #define FAIRMQCHANNEL_H_
#include <FairMQTransportFactory.h> #if 0
#include <FairMQUnmanagedRegion.h> #ifndef FAIR_MQ_CHANNEL_H
#include <FairMQSocket.h> #pragma GCC warning "Deprecated header: Use <fairmq/Channel.h> instead"
#include <fairmq/Transports.h> #endif
#include <FairMQParts.h> #endif
#include <fairmq/Properties.h>
#include <FairMQMessage.h>
#include <string> #include <fairmq/Channel.h>
#include <memory> // unique_ptr, shared_ptr
#include <vector>
#include <mutex>
#include <stdexcept>
#include <utility> // std::move
#include <cstdint> // int64_t
/**
* @class FairMQChannel FairMQChannel.h <FairMQChannel.h>
* @brief Wrapper class for FairMQSocket and related methods
*
* The class is not thread-safe.
*/
class FairMQChannel
{
friend class FairMQDevice;
public:
/// Default constructor
FairMQChannel();
/// Constructor
/// @param name Channel name
FairMQChannel(const std::string& name);
/// Constructor
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param method Socket method (bind/connect)
/// @param address Network address to bind/connect to (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
FairMQChannel(const std::string& type, const std::string& method, const std::string& address);
/// Constructor
/// @param name Channel name
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param factory TransportFactory
FairMQChannel(const std::string& name, const std::string& type, std::shared_ptr<FairMQTransportFactory> factory);
/// Constructor
/// @param name Channel name
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param method Socket method (bind/connect)
/// @param address Network address to bind/connect to (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
/// @param factory TransportFactory
FairMQChannel(std::string name, std::string type, std::string method, std::string address, std::shared_ptr<FairMQTransportFactory> factory);
FairMQChannel(const std::string& name, int index, const fair::mq::Properties& properties);
/// Copy Constructor
FairMQChannel(const FairMQChannel&);
/// Copy Constructor (with new name)
FairMQChannel(const FairMQChannel&, std::string name);
/// Move constructor
// FairMQChannel(FairMQChannel&&) = delete;
/// Assignment operator
FairMQChannel& operator=(const FairMQChannel&);
/// Move assignment operator
// FairMQChannel& operator=(FairMQChannel&&) = delete;
/// Destructor
virtual ~FairMQChannel() = default;
// { LOG(warn) << "Destroying channel '" << fName << "'"; }
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
FairMQSocket& GetSocket() const { assert(fSocket); return *fSocket; }
bool Bind(const std::string& address)
{
fMethod = "bind";
fAddress = address;
return fSocket->Bind(address);
}
bool Connect(const std::string& address)
{
fMethod = "connect";
fAddress = address;
return fSocket->Connect(address);
}
/// Get channel name
/// @return Returns full channel name (e.g. "data[0]")
std::string GetName() const { return fName; }
/// Get channel prefix
/// @return Returns channel prefix (e.g. "data" in "data[0]")
std::string GetPrefix() const
{
std::string prefix = fName;
prefix = prefix.erase(fName.rfind('['));
return prefix;
}
/// Get channel index
/// @return Returns channel index (e.g. 0 in "data[0]")
std::string GetIndex() const
{
std::string indexStr = fName;
indexStr.erase(indexStr.rfind(']'));
indexStr.erase(0, indexStr.rfind('[') + 1);
return indexStr;
}
/// Get socket type
/// @return Returns socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
std::string GetType() const { return fType; }
/// Get socket method
/// @return Returns socket method (bind/connect)
std::string GetMethod() const { return fMethod; }
/// Get socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
/// @return Returns socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
std::string GetAddress() const { return fAddress; }
/// Get channel transport name ("default", "zeromq" or "shmem")
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
std::string GetTransportName() const { return fair::mq::TransportName(fTransportType); }
/// Get channel transport type
/// @return Returns channel transport type
fair::mq::Transport GetTransportType() const { return fTransportType; }
/// Get socket send buffer size (in number of messages)
/// @return Returns socket send buffer size (in number of messages)
int GetSndBufSize() const { return fSndBufSize; }
/// Get socket receive buffer size (in number of messages)
/// @return Returns socket receive buffer size (in number of messages)
int GetRcvBufSize() const { return fRcvBufSize; }
/// Get socket kernel transmit send buffer size (in bytes)
/// @return Returns socket kernel transmit send buffer size (in bytes)
int GetSndKernelSize() const { return fSndKernelSize; }
/// Get socket kernel transmit receive buffer size (in bytes)
/// @return Returns socket kernel transmit receive buffer size (in bytes)
int GetRcvKernelSize() const { return fRcvKernelSize; }
/// Get linger duration (in milliseconds)
/// @return Returns linger duration (in milliseconds)
int GetLinger() const { return fLinger; }
/// Get socket rate logging interval (in seconds)
/// @return Returns socket rate logging interval (in seconds)
int GetRateLogging() const { return fRateLogging; }
/// Get start of the port range for automatic binding
/// @return start of the port range
int GetPortRangeMin() const { return fPortRangeMin; }
/// Get end of the port range for automatic binding
/// @return end of the port range
int GetPortRangeMax() const { return fPortRangeMax; }
/// Set automatic binding (pick random port if bind fails)
/// @return true/false, true if automatic binding is enabled
bool GetAutoBind() const { return fAutoBind; }
/// Set channel name
/// @param name Arbitrary channel name
void UpdateName(const std::string& name) { fName = name; Invalidate(); }
/// Set socket type
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
void UpdateType(const std::string& type) { fType = type; Invalidate(); }
/// Set socket method
/// @param method Socket method (bind/connect)
void UpdateMethod(const std::string& method) { fMethod = method; Invalidate(); }
/// Set socket address
/// @param Socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
void UpdateAddress(const std::string& address) { fAddress = address; Invalidate(); }
/// Set channel transport
/// @param transport transport string ("default", "zeromq" or "shmem")
void UpdateTransport(const std::string& transport) { fTransportType = fair::mq::TransportType(transport); Invalidate(); }
/// Set socket send buffer size
/// @param sndBufSize Socket send buffer size (in number of messages)
void UpdateSndBufSize(const int sndBufSize) { fSndBufSize = sndBufSize; Invalidate(); }
/// Set socket receive buffer size
/// @param rcvBufSize Socket receive buffer size (in number of messages)
void UpdateRcvBufSize(const int rcvBufSize) { fRcvBufSize = rcvBufSize; Invalidate(); }
/// Set socket kernel transmit send buffer size (in bytes)
/// @param sndKernelSize Socket send buffer size (in bytes)
void UpdateSndKernelSize(const int sndKernelSize) { fSndKernelSize = sndKernelSize; Invalidate(); }
/// Set socket kernel transmit receive buffer size (in bytes)
/// @param rcvKernelSize Socket receive buffer size (in bytes)
void UpdateRcvKernelSize(const int rcvKernelSize) { fRcvKernelSize = rcvKernelSize; Invalidate(); }
/// Set linger duration (in milliseconds)
/// @param duration linger duration (in milliseconds)
void UpdateLinger(const int duration) { fLinger = duration; Invalidate(); }
/// Set socket rate logging interval (in seconds)
/// @param rateLogging Socket rate logging interval (in seconds)
void UpdateRateLogging(const int rateLogging) { fRateLogging = rateLogging; Invalidate(); }
/// Set start of the port range for automatic binding
/// @param minPort start of the port range
void UpdatePortRangeMin(const int minPort) { fPortRangeMin = minPort; Invalidate(); }
/// Set end of the port range for automatic binding
/// @param maxPort end of the port range
void UpdatePortRangeMax(const int maxPort) { fPortRangeMax = maxPort; Invalidate(); }
/// Set automatic binding (pick random port if bind fails)
/// @param autobind true/false, true to enable automatic binding
void UpdateAutoBind(const bool autobind) { fAutoBind = autobind; Invalidate(); }
/// Checks if the configured channel settings are valid (checks the validity parameter, without running full validation (as oposed to ValidateChannel()))
/// @return true if channel settings are valid, false otherwise.
bool IsValid() const { return fValid; }
/// Validates channel configuration
/// @return true if channel settings are valid, false otherwise.
bool Validate();
void Init();
bool ConnectEndpoint(const std::string& endpoint);
bool BindEndpoint(std::string& endpoint);
/// invalidates the channel (requires validation to be used again).
void Invalidate() { fValid = false; }
/// Sends a message to the socket queue.
/// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQMessagePtr& msg, int sndTimeoutInMs = -1)
{
CheckSendCompatibility(msg);
return fSocket->Send(msg, sndTimeoutInMs);
}
/// Receives a message from the socket queue.
/// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs = -1)
{
CheckReceiveCompatibility(msg);
return fSocket->Receive(msg, rcvTimeoutInMs);
}
/// Send a vector of messages
/// @param msgVec message vector reference
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs = -1)
{
CheckSendCompatibility(msgVec);
return fSocket->Send(msgVec, sndTimeoutInMs);
}
/// Receive a vector of messages
/// @param msgVec message vector reference
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs = -1)
{
CheckReceiveCompatibility(msgVec);
return fSocket->Receive(msgVec, rcvTimeoutInMs);
}
/// Send FairMQParts
/// @param parts FairMQParts reference
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQParts& parts, int sndTimeoutInMs = -1)
{
return Send(parts.fParts, sndTimeoutInMs);
}
/// Receive FairMQParts
/// @param parts FairMQParts reference
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQParts& parts, int rcvTimeoutInMs = -1)
{
return Receive(parts.fParts, rcvTimeoutInMs);
}
unsigned long GetBytesTx() const { return fSocket->GetBytesTx(); }
unsigned long GetBytesRx() const { return fSocket->GetBytesRx(); }
unsigned long GetMessagesTx() const { return fSocket->GetMessagesTx(); }
unsigned long GetMessagesRx() const { return fSocket->GetMessagesRx(); }
auto Transport() -> FairMQTransportFactory* { return fTransportFactory.get(); };
template<typename... Args>
FairMQMessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
template<typename... Args>
FairMQUnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::DEFAULT;
static constexpr const char* DefaultTransportName = "default";
static constexpr const char* DefaultName = "";
static constexpr const char* DefaultType = "unspecified";
static constexpr const char* DefaultMethod = "unspecified";
static constexpr const char* DefaultAddress = "unspecified";
static constexpr int DefaultSndBufSize = 1000;
static constexpr int DefaultRcvBufSize = 1000;
static constexpr int DefaultSndKernelSize = 0;
static constexpr int DefaultRcvKernelSize = 0;
static constexpr int DefaultLinger = 500;
static constexpr int DefaultRateLogging = 1;
static constexpr int DefaultPortRangeMin = 22000;
static constexpr int DefaultPortRangeMax = 23000;
static constexpr bool DefaultAutoBind = true;
private:
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
fair::mq::Transport fTransportType;
std::unique_ptr<FairMQSocket> fSocket;
std::string fName;
std::string fType;
std::string fMethod;
std::string fAddress;
int fSndBufSize;
int fRcvBufSize;
int fSndKernelSize;
int fRcvKernelSize;
int fLinger;
int fRateLogging;
int fPortRangeMin;
int fPortRangeMax;
bool fAutoBind;
bool fValid;
bool fMultipart;
void CheckSendCompatibility(FairMQMessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
FairMQMessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
FairMQMessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
}
void CheckReceiveCompatibility(FairMQMessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory)
{
fTransportFactory = factory;
fTransportType = factory->GetType();
}
};
#endif /* FAIRMQCHANNEL_H_ */ #endif /* FAIRMQCHANNEL_H_ */

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2012-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,545 +9,12 @@
#ifndef FAIRMQDEVICE_H_ #ifndef FAIRMQDEVICE_H_
#define FAIRMQDEVICE_H_ #define FAIRMQDEVICE_H_
#include <FairMQChannel.h> #if 0
#include <FairMQLogger.h> #ifndef FAIR_MQ_DEVICE_H
#include <FairMQMessage.h> #pragma GCC warning "Deprecated header: Use <fairmq/Device.h> instead"
#include <FairMQParts.h> #endif
#include <FairMQTransportFactory.h> #endif
#include <FairMQUnmanagedRegion.h>
#include <fairmq/ProgOptions.h>
#include <fairmq/StateMachine.h>
#include <fairmq/StateQueue.h>
#include <fairmq/Transports.h>
#include <fairmq/tools/Version.h>
#include <vector> #include <fairmq/Device.h>
#include <memory> // unique_ptr
#include <algorithm> // find
#include <string>
#include <chrono>
#include <unordered_map>
#include <functional>
#include <stdexcept>
#include <mutex>
#include <atomic>
#include <cstddef>
#include <utility> // pair
using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
using InputMultipartCallback = std::function<bool(FairMQParts&, int)>;
namespace fair::mq
{
struct OngoingTransition : std::runtime_error { using std::runtime_error::runtime_error; };
}
class FairMQDevice
{
friend class FairMQChannel;
public:
/// Default constructor
FairMQDevice();
/// Constructor with external fair::mq::ProgOptions
FairMQDevice(fair::mq::ProgOptions& config);
/// Constructor that sets the version
FairMQDevice(const fair::mq::tools::Version version);
/// Constructor that sets the version and external fair::mq::ProgOptions
FairMQDevice(fair::mq::ProgOptions& config, const fair::mq::tools::Version version);
private:
FairMQDevice(fair::mq::ProgOptions* config, const fair::mq::tools::Version version);
public:
/// Copy constructor (disabled)
FairMQDevice(const FairMQDevice&) = delete;
/// Assignment operator (disabled)
FairMQDevice operator=(const FairMQDevice&) = delete;
/// Default destructor
virtual ~FairMQDevice();
/// Outputs the socket transfer rates
virtual void LogSocketRates();
template<typename Serializer, typename DataType, typename... Args>
void Serialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
{
Serializer().Serialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
template<typename Deserializer, typename DataType, typename... Args>
void Deserialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
{
Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
/// Shorthand method to send `msg` on `chan` at index `i`
/// @param msg message reference
/// @param chan channel name
/// @param i channel index
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
{
return GetChannel(channel, index).Send(msg, sndTimeoutInMs);
}
/// Shorthand method to receive `msg` on `chan` at index `i`
/// @param msg message reference
/// @param chan channel name
/// @param i channel index
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
{
return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
}
/// Shorthand method to send FairMQParts on `chan` at index `i`
/// @param parts parts reference
/// @param chan channel name
/// @param i channel index
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
/// @return Number of bytes that have been queued, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQParts& parts, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
{
return GetChannel(channel, index).Send(parts.fParts, sndTimeoutInMs);
}
/// Shorthand method to receive FairMQParts on `chan` at index `i`
/// @param parts parts reference
/// @param chan channel name
/// @param i channel index
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
/// @return Number of bytes that have been received, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQParts& parts, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
{
return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
}
/// @brief Getter for default transport factory
auto Transport() const -> FairMQTransportFactory*
{
return fTransportFactory.get();
}
// creates message with the default device transport
template<typename... Args>
FairMQMessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
// creates message with the transport of the specified channel
template<typename... Args>
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
}
// creates a message that will not be cleaned up after transfer, with the default device transport
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
// creates a message that will not be cleaned up after transfer, with the transport of the specified channel
template<typename T>
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewStaticMessage(data);
}
// creates a message with a copy of the provided data, with the default device transport
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
// creates a message with a copy of the provided data, with the transport of the specified channel
template<typename T>
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewSimpleMessage(data);
}
// creates unamanaged region with the default device transport
template<typename... Args>
FairMQUnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
// creates unmanaged region with the transport of the specified channel
template<typename... Args>
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewUnmanagedRegion(std::forward<Args>(args)...);
}
template<typename ...Ts>
FairMQPollerPtr NewPoller(const Ts&... inputs)
{
std::vector<std::string> chans{inputs...};
// if more than one channel provided, check compatibility
if (chans.size() > 1)
{
fair::mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
for (unsigned int i = 1; i < chans.size(); ++i)
{
if (type != GetChannel(chans.at(i), 0).Transport()->GetType())
{
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
}
}
}
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
}
FairMQPollerPtr NewPoller(const std::vector<FairMQChannel*>& channels)
{
// if more than one channel provided, check compatibility
if (channels.size() > 1)
{
fair::mq::Transport type = channels.at(0)->Transport()->GetType();
for (unsigned int i = 1; i < channels.size(); ++i)
{
if (type != channels.at(i)->Transport()->GetType())
{
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
}
}
}
return channels.at(0)->Transport()->CreatePoller(channels);
}
/// Adds a transport to the device if it doesn't exist
/// @param transport Transport string ("zeromq"/"shmem")
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
/// Assigns config to the device
void SetConfig(fair::mq::ProgOptions& config);
/// Get pointer to the config
fair::mq::ProgOptions* GetConfig() const
{
return fConfig;
}
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQMessagePtr& msg, int index))
{
fDataCallbacks = true;
fMsgInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQMessagePtr& msg, int index)
{
return (static_cast<T*>(this)->*memberFunction)(msg, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMsgCallback callback)
{
fDataCallbacks = true;
fMsgInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQParts& parts, int index))
{
fDataCallbacks = true;
fMultipartInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQParts& parts, int index)
{
return (static_cast<T*>(this)->*memberFunction)(parts, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMultipartCallback callback)
{
fDataCallbacks = true;
fMultipartInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
FairMQChannel& GetChannel(const std::string& channelName, const int index = 0)
try {
return fChannels.at(channelName).at(index);
} catch (const std::out_of_range& oor) {
LOG(error) << "requested channel has not been configured? check channel names/configuration.";
LOG(error) << "channel: " << channelName << ", index: " << index;
LOG(error) << "out of range: " << oor.what();
throw;
}
virtual void RegisterChannelEndpoints() {}
bool RegisterChannelEndpoint(const std::string& channelName, uint16_t minNumSubChannels = 1, uint16_t maxNumSubChannels = 1)
{
bool ok = fChannelRegistry.insert(std::make_pair(channelName, std::make_pair(minNumSubChannels, maxNumSubChannels))).second;
if (!ok) {
LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
}
return ok;
}
void PrintRegisteredChannels()
{
if (fChannelRegistry.empty()) {
LOGV(info, verylow) << "no channels registered.";
} else {
for (const auto& c : fChannelRegistry) {
LOGV(info, verylow) << c.first << ":" << c.second.first << ":" << c.second.second;
}
}
}
void SetId(const std::string& id) { fId = id; }
std::string GetId() { return fId; }
const fair::mq::tools::Version GetVersion() const { return fVersion; }
void SetNumIoThreads(int numIoThreads) { fConfig->SetProperty("io-threads", numIoThreads);}
int GetNumIoThreads() const { return fConfig->GetProperty<int>("io-threads", DefaultIOThreads); }
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetProperty("network-interface", networkInterface); }
std::string GetNetworkInterface() const { return fConfig->GetProperty<std::string>("network-interface", DefaultNetworkInterface); }
void SetDefaultTransport(const std::string& name) { fConfig->SetProperty("transport", name); }
std::string GetDefaultTransport() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
void SetInitTimeoutInS(int initTimeoutInS) { fConfig->SetProperty("init-timeout", initTimeoutInS); }
int GetInitTimeoutInS() const { return fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout); }
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"shmem")
void SetTransport(const std::string& transport) { fConfig->SetProperty("transport", transport); }
/// Gets the default transport name
std::string GetTransportName() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine()
{
fStateMachine.ProcessWork();
};
/// Wait for the supplied amount of time or for interruption.
/// If interrupted, returns false, otherwise true.
/// @param duration wait duration
template<typename Rep, typename Period>
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
{
return !fStateMachine.WaitForPendingStateFor(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
}
protected:
std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory
std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports
public:
std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels
std::unique_ptr<fair::mq::ProgOptions> fInternalConfig; ///< Internal program options configuration
fair::mq::ProgOptions* fConfig; ///< Pointer to config (internal or external)
void AddChannel(const std::string& name, FairMQChannel&& channel)
{
fConfig->AddChannel(name, channel);
}
protected:
std::string fId; ///< Device ID
/// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask().
virtual void Init() {}
virtual void Bind() {}
virtual void Connect() {}
/// Task initialization (can be overloaded in child classes)
virtual void InitTask() {}
/// Runs the device (to be overloaded in child classes)
virtual void Run() {}
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
virtual void PreRun() {}
/// Called during RUNNING state repeatedly until it returns false or device state changes
virtual bool ConditionalRun() { return false; }
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
virtual void PostRun() {}
/// Resets the user task (to be overloaded in child classes)
virtual void ResetTask() {}
/// Resets the device (can be overloaded in child classes)
virtual void Reset() {}
public:
/// @brief Request a device state transition
/// @param transition state transition
///
/// The state transition may not happen immediately, but when the current state evaluates the
/// pending transition event and terminates. In other words, the device states are scheduled cooperatively.
bool ChangeState(const fair::mq::Transition transition) { return fStateMachine.ChangeState(transition); }
/// @brief Request a device state transition
/// @param transition state transition
///
/// The state transition may not happen immediately, but when the current state evaluates the
/// pending transition event and terminates. In other words, the device states are scheduled cooperatively.
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::GetTransition(transition)); }
/// @brief waits for the next state (any) to occur
fair::mq::State WaitForNextState() { return fStateQueue.WaitForNext(); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(fair::mq::State state) { fStateQueue.WaitForState(state); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(const std::string& state) { WaitForState(fair::mq::GetState(state)); }
void TransitionTo(const fair::mq::State state);
/// @brief Subscribe with a callback to state changes
/// @param key id to identify your subscription
/// @param callback callback (called with the new state as the parameter)
///
/// The callback is called at the beginning of a new state.
/// The callback is called from the thread the state is running in.
void SubscribeToStateChange(const std::string& key, std::function<void(const fair::mq::State)> callback) { fStateMachine.SubscribeToStateChange(key, callback); }
/// @brief Unsubscribe from state changes
/// @param key id (that was used when subscribing)
void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); }
/// @brief Subscribe with a callback to incoming state transitions
/// @param key id to identify your subscription
/// @param callback callback (called with the incoming transition as the parameter)
/// The callback is called when new transition is initiated.
/// The callback is called from the thread that initiates the transition (via ChangeState).
void SubscribeToNewTransition(const std::string& key, std::function<void(const fair::mq::Transition)> callback) { fStateMachine.SubscribeToNewTransition(key, callback); }
/// @brief Unsubscribe from state transitions
/// @param key id (that was used when subscribing)
void UnsubscribeFromNewTransition(const std::string& key) { fStateMachine.UnsubscribeFromNewTransition(key); }
/// @brief Returns true if a new state has been requested, signaling the current handler to stop.
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
/// @brief Returns the current state
fair::mq::State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
/// @brief Returns the name of the current state as a string
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
/// @brief Returns name of the given state as a string
/// @param state state
static std::string GetStateName(const fair::mq::State state) { return fair::mq::GetStateName(state); }
/// @brief Returns name of the given transition as a string
/// @param transition transition
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::GetTransitionName(transition); }
static constexpr const char* DefaultId = "";
static constexpr int DefaultIOThreads = 1;
static constexpr const char* DefaultTransportName = "zeromq";
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::ZMQ;
static constexpr const char* DefaultNetworkInterface = "default";
static constexpr int DefaultInitTimeout = 120;
static constexpr uint64_t DefaultMaxRunTime = 0;
static constexpr float DefaultRate = 0.;
static constexpr const char* DefaultSession = "default";
private:
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
fair::mq::StateMachine fStateMachine;
/// Handles the initialization
void InitWrapper();
/// Initializes binding channels
void BindWrapper();
/// Initializes connecting channels
void ConnectWrapper();
/// Handles the InitTask() method
void InitTaskWrapper();
/// Handles the Run() method
void RunWrapper();
/// Handles the ResetTask() method
void ResetTaskWrapper();
/// Handles the Reset() method
void ResetWrapper();
/// Notifies transports to cease any blocking activity
void UnblockTransports();
/// Shuts down the transports and the device
void Exit() {}
/// Attach (bind/connect) channels in the list
void AttachChannels(std::vector<FairMQChannel*>& chans);
bool AttachChannel(FairMQChannel& ch);
void HandleSingleChannelInput();
void HandleMultipleChannelInput();
void HandleMultipleTransportInput();
void PollForTransport(const FairMQTransportFactory* factory, const std::vector<std::string>& channelKeys);
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i);
std::vector<FairMQChannel*> fUninitializedBindingChannels;
std::vector<FairMQChannel*> fUninitializedConnectingChannels;
bool fDataCallbacks;
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
std::unordered_map<std::string, InputMultipartCallback> fMultipartInputs;
std::unordered_map<fair::mq::Transport, std::vector<std::string>> fMultitransportInputs;
std::unordered_map<std::string, std::pair<uint16_t, uint16_t>> fChannelRegistry;
std::vector<std::string> fInputChannelKeys;
std::mutex fMultitransportMutex;
std::atomic<bool> fMultitransportProceed;
const fair::mq::tools::Version fVersion;
float fRate; ///< Rate limiting for ConditionalRun
uint64_t fMaxRunRuntimeInS; ///< Maximum runtime for the Running state handler, after which state will change to Ready (in seconds, 0 for no limit).
int fInitializationTimeoutInS;
std::vector<std::string> fRawCmdLineArgs;
fair::mq::StateQueue fStateQueue;
std::mutex fTransitionMtx;
bool fTransitioning;
};
#endif /* FAIRMQDEVICE_H_ */ #endif /* FAIRMQDEVICE_H_ */

View File

@ -1,15 +0,0 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* FairMQLogger.cxx
*
* @since 2012-12-04
* @author D. Klein, A. Rybalchenko
*/
#include "FairMQLogger.h"

View File

@ -1,13 +0,0 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* FairMQMessage.cxx
*
* @since 2012-12-05
* @author D. Klein, A. Rybalchenko
*/

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,65 +9,12 @@
#ifndef FAIRMQMESSAGE_H_ #ifndef FAIRMQMESSAGE_H_
#define FAIRMQMESSAGE_H_ #define FAIRMQMESSAGE_H_
#include <cstddef> // for size_t #if 0
#include <memory> // unique_ptr #ifndef FAIR_MQ_MESSAGE_H
#include <stdexcept> #pragma GCC warning "Deprecated header: Use <fairmq/Message.h> instead"
#endif
#endif
#include <fairmq/Transports.h> #include <fairmq/Message.h>
using fairmq_free_fn = void(void* data, void* hint);
class FairMQTransportFactory;
namespace fair::mq
{
struct Alignment
{
size_t alignment;
explicit operator size_t() const { return alignment; }
};
} // namespace fair::mq
class FairMQMessage
{
public:
FairMQMessage() = default;
FairMQMessage(FairMQTransportFactory* factory) : fTransport(factory) {}
virtual void Rebuild() = 0;
virtual void Rebuild(fair::mq::Alignment alignment) = 0;
virtual void Rebuild(const size_t size) = 0;
virtual void Rebuild(const size_t size, fair::mq::Alignment alignment) = 0;
virtual void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
virtual bool SetUsedSize(const size_t size) = 0;
virtual fair::mq::Transport GetType() const = 0;
FairMQTransportFactory* GetTransport() { return fTransport; }
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
virtual void Copy(const FairMQMessage& msg) = 0;
virtual ~FairMQMessage() = default;
private:
FairMQTransportFactory* fTransport{nullptr};
};
using FairMQMessagePtr = std::unique_ptr<FairMQMessage>;
namespace fair::mq
{
using Message = FairMQMessage;
using MessagePtr = FairMQMessagePtr;
struct MessageError : std::runtime_error { using std::runtime_error::runtime_error; };
struct MessageBadAlloc : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#endif /* FAIRMQMESSAGE_H_ */ #endif /* FAIRMQMESSAGE_H_ */

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,90 +9,12 @@
#ifndef FAIRMQPARTS_H_ #ifndef FAIRMQPARTS_H_
#define FAIRMQPARTS_H_ #define FAIRMQPARTS_H_
#include "FairMQTransportFactory.h" #if 0
#include "FairMQMessage.h" #ifndef FAIR_MQ_PARTS_H
#pragma GCC warning "Deprecated header: Use <fairmq/Parts.h> instead"
#endif
#endif
#include <vector> #include <fairmq/Parts.h>
#include <memory> // unique_ptr
/// FairMQParts is a lightweight convenience wrapper around a vector of unique pointers to FairMQMessage, used for sending multi-part messages
class FairMQParts
{
private:
using container = std::vector<std::unique_ptr<FairMQMessage>>;
public:
/// Default constructor
FairMQParts() = default;
/// Copy Constructor
FairMQParts(const FairMQParts&) = delete;
/// Move constructor
FairMQParts(FairMQParts&& p) = default;
/// Assignment operator
FairMQParts& operator=(const FairMQParts&) = delete;
/// Constructor from argument pack of std::unique_ptr<FairMQMessage> rvalues
template <typename... Ts>
FairMQParts(Ts&&... messages) { AddPart(std::forward<Ts>(messages)...); }
/// Default destructor
~FairMQParts() = default;
/// Adds part (FairMQMessage) to the container
/// @param msg message pointer (for example created with NewMessage() method of FairMQDevice)
void AddPart(FairMQMessage* msg)
{
fParts.push_back(std::unique_ptr<FairMQMessage>(msg));
}
/// Adds part (std::unique_ptr<FairMQMessage>&) to the container (move)
/// @param msg unique pointer to FairMQMessage
/// rvalue ref (move required when passing argument)
void AddPart(std::unique_ptr<FairMQMessage>&& msg)
{
fParts.push_back(std::move(msg));
}
/// Add variable list of parts to the container (move)
template <typename... Ts>
void AddPart(std::unique_ptr<FairMQMessage>&& first, Ts&&... remaining)
{
AddPart(std::move(first));
AddPart(std::forward<Ts>(remaining)...);
}
/// Add content of another object by move
void AddPart(FairMQParts&& other)
{
container parts = std::move(other.fParts);
for (auto& part : parts) {
fParts.push_back(std::move(part));
}
}
/// Get reference to part in the container at index (without bounds check)
/// @param index container index
FairMQMessage& operator[](const int index) { return *(fParts[index]); }
/// Get reference to unique pointer to part in the container at index (with bounds check)
/// @param index container index
std::unique_ptr<FairMQMessage>& At(const int index) { return fParts.at(index); }
// ref version
FairMQMessage& AtRef(const int index) { return *(fParts.at(index)); }
/// Get number of parts in the container
/// @return number of parts in the container
int Size() const { return fParts.size(); }
container fParts;
// forward container iterators
using iterator = container::iterator;
using const_iterator = container::const_iterator;
auto begin() -> decltype(fParts.begin()) { return fParts.begin(); }
auto end() -> decltype(fParts.end()) { return fParts.end(); }
auto cbegin() -> decltype(fParts.cbegin()) { return fParts.cbegin(); }
auto cend() -> decltype(fParts.cend()) { return fParts.cend(); }
};
#endif /* FAIRMQPARTS_H_ */ #endif /* FAIRMQPARTS_H_ */

View File

@ -1,13 +0,0 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/**
* FairMQPoller.cxx
*
* @since 2014-01-23
* @author A. Rybalchenko
*/

View File

@ -9,31 +9,12 @@
#ifndef FAIRMQPOLLER_H_ #ifndef FAIRMQPOLLER_H_
#define FAIRMQPOLLER_H_ #define FAIRMQPOLLER_H_
#include <memory> #if 0
#include <stdexcept> #ifndef FAIR_MQ_POLLER_H
#include <string> #pragma GCC warning "Deprecated header: Use <fairmq/Poller.h> instead"
#endif
#endif
class FairMQPoller #include <fairmq/Poller.h>
{
public:
virtual void Poll(const int timeout) = 0;
virtual bool CheckInput(const int index) = 0;
virtual bool CheckOutput(const int index) = 0;
virtual bool CheckInput(const std::string& channelKey, const int index) = 0;
virtual bool CheckOutput(const std::string& channelKey, const int index) = 0;
virtual ~FairMQPoller() = default;
};
using FairMQPollerPtr = std::unique_ptr<FairMQPoller>;
namespace fair::mq
{
using Poller = FairMQPoller;
using PollerPtr = FairMQPollerPtr;
struct PollerError : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#endif /* FAIRMQPOLLER_H_ */ #endif /* FAIRMQPOLLER_H_ */

View File

@ -1,9 +0,0 @@
/********************************************************************************
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <FairMQSocket.h>

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,88 +9,12 @@
#ifndef FAIRMQSOCKET_H_ #ifndef FAIRMQSOCKET_H_
#define FAIRMQSOCKET_H_ #define FAIRMQSOCKET_H_
#include "FairMQMessage.h" #if 0
#ifndef FAIR_MQ_SOCKET_H
#pragma GCC warning "Deprecated header: Use <fairmq/Socket.h> instead"
#endif
#endif
#include <memory> #include <fairmq/Socket.h>
#include <ostream>
#include <stdexcept>
#include <string>
#include <vector>
class FairMQTransportFactory;
namespace fair::mq
{
enum class TransferCode : int
{
success = 0,
error = -1,
timeout = -2,
interrupted = -3
};
} // namespace fair::mq
class FairMQSocket
{
public:
FairMQSocket() = default;
FairMQSocket(FairMQTransportFactory* fac) : fTransport(fac) {}
virtual std::string GetId() const = 0;
virtual bool Bind(const std::string& address) = 0;
virtual bool Connect(const std::string& address) = 0;
virtual int64_t Send(FairMQMessagePtr& msg, int timeout = -1) = 0;
virtual int64_t Receive(FairMQMessagePtr& msg, int timeout = -1) = 0;
virtual int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = -1) = 0;
virtual int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = -1) = 0;
virtual void Close() = 0;
virtual void SetOption(const std::string& option, const void* value, size_t valueSize) = 0;
virtual void GetOption(const std::string& option, void* value, size_t* valueSize) = 0;
/// If the backend supports it, fills the unsigned integer @a events with the ZMQ_EVENTS value
/// DISCLAIMER: this API is experimental and unsupported and might be dropped / refactored in
/// the future.
virtual int Events(uint32_t* events) = 0;
virtual void SetLinger(const int value) = 0;
virtual int GetLinger() const = 0;
virtual void SetSndBufSize(const int value) = 0;
virtual int GetSndBufSize() const = 0;
virtual void SetRcvBufSize(const int value) = 0;
virtual int GetRcvBufSize() const = 0;
virtual void SetSndKernelSize(const int value) = 0;
virtual int GetSndKernelSize() const = 0;
virtual void SetRcvKernelSize(const int value) = 0;
virtual int GetRcvKernelSize() const = 0;
virtual unsigned long GetBytesTx() const = 0;
virtual unsigned long GetBytesRx() const = 0;
virtual unsigned long GetMessagesTx() const = 0;
virtual unsigned long GetMessagesRx() const = 0;
FairMQTransportFactory* GetTransport() { return fTransport; }
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
virtual ~FairMQSocket() = default;
private:
FairMQTransportFactory* fTransport{nullptr};
};
using FairMQSocketPtr = std::unique_ptr<FairMQSocket>;
namespace fair::mq
{
using Socket = FairMQSocket;
using SocketPtr = FairMQSocketPtr;
struct SocketError : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#endif /* FAIRMQSOCKET_H_ */ #endif /* FAIRMQSOCKET_H_ */

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,174 +9,12 @@
#ifndef FAIRMQTRANSPORTFACTORY_H_ #ifndef FAIRMQTRANSPORTFACTORY_H_
#define FAIRMQTRANSPORTFACTORY_H_ #define FAIRMQTRANSPORTFACTORY_H_
#include <FairMQMessage.h> #if 0
#include <FairMQPoller.h> #ifndef FAIR_MQ_TRANSPORTFACTORY_H
#include <FairMQSocket.h> #pragma GCC warning "Deprecated header: Use <fairmq/TransportFactory.h> instead"
#include <FairMQUnmanagedRegion.h> #endif
#include <fairmq/MemoryResources.h> #endif
#include <fairmq/Transports.h>
#include <string> #include <fairmq/TransportFactory.h>
#include <memory> // shared_ptr
#include <vector>
#include <unordered_map>
#include <stdexcept>
#include <cstddef> // size_t
class FairMQChannel;
namespace fair::mq { class ProgOptions; }
class FairMQTransportFactory
{
private:
/// Topology wide unique id
const std::string fkId;
/// The polymorphic memory resource associated with the transport
fair::mq::ChannelResource fMemoryResource{this};
public:
/// ctor
/// @param id Topology wide unique id, usually the device id.
FairMQTransportFactory(std::string id);
auto GetId() const -> const std::string { return fkId; };
/// Get a pointer to the associated polymorphic memory resource
fair::mq::ChannelResource* GetMemoryResource() { return &fMemoryResource; }
operator fair::mq::ChannelResource*() { return &fMemoryResource; }
/// @brief Create empty FairMQMessage (for receiving)
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage() = 0;
/// @brief Create empty FairMQMessage (for receiving), align received buffer to specified alignment
/// @param alignment alignment to align received buffer to
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(fair::mq::Alignment alignment) = 0;
/// @brief Create new FairMQMessage of specified size
/// @param size message size
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(const size_t size) = 0;
/// @brief Create new FairMQMessage of specified size and alignment
/// @param size message size
/// @param alignment message alignment
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(const size_t size, fair::mq::Alignment alignment) = 0;
/// @brief Create new FairMQMessage with user provided buffer and size
/// @param data pointer to user provided buffer
/// @param size size of the user provided buffer
/// @param ffn callback, called when the message is transfered (and can be deleted)
/// @param obj optional helper pointer that can be used in the callback
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
/// @brief create a message with the buffer located within the corresponding unmanaged region
/// @param unmanagedRegion the unmanaged region that this message buffer belongs to
/// @param data message buffer (must be within the region - checked at runtime by the transport)
/// @param size size of the message
/// @param hint optional parameter, returned to the user in the FairMQRegionCallback
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) = 0;
/// @brief Create a socket
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
/// @brief Create a poller for a single channel (all subchannels)
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
/// @brief Create a poller for specific channels
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
/// @brief Create a poller for specific channels (all subchannels)
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const = 0;
/// @brief Create new UnmanagedRegion
/// @param size size of the region
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
/// @param path optional parameter to pass to the underlying transport
/// @param flags optional parameter to pass to the underlying transport
/// @return pointer to UnmanagedRegion
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
/// @brief Create new UnmanagedRegion
/// @param size size of the region
/// @param userFlags flags to be stored with the region, have no effect on the transport, but can be retrieved from the region by the user
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
/// @param path optional parameter to pass to the underlying transport
/// @param flags optional parameter to pass to the underlying transport
/// @return pointer to UnmanagedRegion
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
/// @brief Subscribe to region events (creation, destruction, ...)
/// @param callback the callback that is called when a region event occurs
virtual void SubscribeToRegionEvents(FairMQRegionEventCallback callback) = 0;
/// @brief Check if there is an active subscription to region events
/// @return true/false
virtual bool SubscribedToRegionEvents() = 0;
/// @brief Unsubscribe from region events
virtual void UnsubscribeFromRegionEvents() = 0;
virtual std::vector<FairMQRegionInfo> GetRegionInfo() = 0;
/// Get transport type
virtual fair::mq::Transport GetType() const = 0;
virtual void Interrupt() = 0;
virtual void Resume() = 0;
virtual void Reset() = 0;
virtual ~FairMQTransportFactory() = default;
static auto CreateTransportFactory(const std::string& type, const std::string& id = "", const fair::mq::ProgOptions* config = nullptr) -> std::shared_ptr<FairMQTransportFactory>;
static void FairMQNoCleanup(void* /*data*/, void* /*obj*/)
{
}
template<typename T>
static void FairMQSimpleMsgCleanup(void* /*data*/, void* obj)
{
delete static_cast<T*>(obj);
}
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data)
{
// todo: is_trivially_copyable not available on gcc < 5, workaround?
// static_assert(std::is_trivially_copyable<T>::value, "The argument type for NewSimpleMessage has to be trivially copyable!");
T* dataCopy = new T(data);
return CreateMessage(dataCopy, sizeof(T), FairMQSimpleMsgCleanup<T>, dataCopy);
}
template<std::size_t N>
FairMQMessagePtr NewSimpleMessage(const char(&data)[N])
{
std::string* msgStr = new std::string(data);
return CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
}
FairMQMessagePtr NewSimpleMessage(const std::string& str)
{
std::string* msgStr = new std::string(str);
return CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
}
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return CreateMessage(data, sizeof(T), FairMQNoCleanup, nullptr);
}
FairMQMessagePtr NewStaticMessage(const std::string& str)
{
return CreateMessage(const_cast<char*>(str.c_str()), str.length(), FairMQNoCleanup, nullptr);
}
};
namespace fair::mq
{
using TransportFactory = FairMQTransportFactory;
struct TransportFactoryError : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#endif /* FAIRMQTRANSPORTFACTORY_H_ */ #endif /* FAIRMQTRANSPORTFACTORY_H_ */

View File

@ -9,120 +9,12 @@
#ifndef FAIRMQUNMANAGEDREGION_H_ #ifndef FAIRMQUNMANAGEDREGION_H_
#define FAIRMQUNMANAGEDREGION_H_ #define FAIRMQUNMANAGEDREGION_H_
#include <cstddef> // size_t #if 0
#include <cstdint> // uint32_t #ifndef FAIR_MQ_UNMANAGEDREGION_H
#include <fairmq/Transports.h> #pragma GCC warning "Deprecated header: Use <fairmq/UnmanagedRegion.h> instead"
#include <functional> // std::function #endif
#include <memory> // std::unique_ptr #endif
#include <ostream> // std::ostream
#include <vector>
class FairMQTransportFactory; #include <fairmq/UnmanagedRegion.h>
enum class FairMQRegionEvent : int
{
created,
destroyed,
local_only
};
struct FairMQRegionInfo
{
FairMQRegionInfo() = default;
FairMQRegionInfo(bool _managed, uint64_t _id, void* _ptr, size_t _size, int64_t _flags, FairMQRegionEvent _event)
: managed(_managed)
, id(_id)
, ptr(_ptr)
, size(_size)
, flags(_flags)
, event(_event)
{}
bool managed = true; // managed/unmanaged
uint64_t id = 0; // id of the region
void* ptr = nullptr; // pointer to the start of the region
size_t size = 0; // region size
int64_t flags = 0; // custom flags set by the creator
FairMQRegionEvent event = FairMQRegionEvent::created;
};
struct FairMQRegionBlock {
void* ptr;
size_t size;
void* hint;
FairMQRegionBlock(void* p, size_t s, void* h)
: ptr(p), size(s), hint(h)
{}
};
using FairMQRegionCallback = std::function<void(void*, size_t, void*)>;
using FairMQRegionBulkCallback = std::function<void(const std::vector<FairMQRegionBlock>&)>;
using FairMQRegionEventCallback = std::function<void(FairMQRegionInfo)>;
class FairMQUnmanagedRegion
{
public:
FairMQUnmanagedRegion() = default;
FairMQUnmanagedRegion(FairMQTransportFactory* factory) : fTransport(factory) {}
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
virtual uint16_t GetId() const = 0;
virtual void SetLinger(uint32_t linger) = 0;
virtual uint32_t GetLinger() const = 0;
virtual fair::mq::Transport GetType() const = 0;
FairMQTransportFactory* GetTransport() { return fTransport; }
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
virtual ~FairMQUnmanagedRegion() = default;
private:
FairMQTransportFactory* fTransport{nullptr};
};
using FairMQUnmanagedRegionPtr = std::unique_ptr<FairMQUnmanagedRegion>;
inline std::ostream& operator<<(std::ostream& os, const FairMQRegionEvent& event)
{
switch (event) {
case FairMQRegionEvent::created:
return os << "created";
case FairMQRegionEvent::destroyed:
return os << "destroyed";
case FairMQRegionEvent::local_only:
return os << "local_only";
default:
return os << "unrecognized event";
}
}
namespace fair::mq
{
struct RegionConfig
{
RegionConfig() = default;
RegionConfig(bool l, bool z)
: lock(l), zero(z)
{}
bool lock = false;
bool zero = false;
};
using RegionCallback = FairMQRegionCallback;
using RegionBulkCallback = FairMQRegionBulkCallback;
using RegionEventCallback = FairMQRegionEventCallback;
using RegionEvent = FairMQRegionEvent;
using RegionInfo = FairMQRegionInfo;
using RegionBlock = FairMQRegionBlock;
using UnmanagedRegion = FairMQUnmanagedRegion;
using UnmanagedRegionPtr = FairMQUnmanagedRegionPtr;
} // namespace fair::mq
#endif /* FAIRMQUNMANAGEDREGION_H_ */ #endif /* FAIRMQUNMANAGEDREGION_H_ */

View File

@ -1,10 +1,10 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 * * Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
/// @brief Memory allocators and interfaces related to managing memory via the /// @brief Memory allocators and interfaces related to managing memory via the
@ -15,27 +15,24 @@
#ifndef FAIR_MQ_MEMORY_RESOURCES_H #ifndef FAIR_MQ_MEMORY_RESOURCES_H
#define FAIR_MQ_MEMORY_RESOURCES_H #define FAIR_MQ_MEMORY_RESOURCES_H
#include <FairMQMessage.h>
class FairMQTransportFactory;
#include <boost/container/container_fwd.hpp> #include <boost/container/container_fwd.hpp>
#include <boost/container/flat_map.hpp> #include <boost/container/flat_map.hpp>
#include <boost/container/pmr/memory_resource.hpp> #include <boost/container/pmr/memory_resource.hpp>
#include <cstring> #include <cstring>
#include <fairmq/Message.h>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
namespace fair::mq namespace fair::mq {
{
class TransportFactory;
using byte = unsigned char; using byte = unsigned char;
namespace pmr = boost::container::pmr; namespace pmr = boost::container::pmr;
/// All FairMQ related memory resources need to inherit from this interface /// All FairMQ related memory resources need to inherit from this interface
/// class for the /// class for the
/// getMessage() api. /// getMessage() api.
class FairMQMemoryResource : public pmr::memory_resource class MemoryResource : public pmr::memory_resource
{ {
public: public:
/// return the message containing data associated with the pointer (to start /// return the message containing data associated with the pointer (to start
@ -43,9 +40,9 @@ class FairMQMemoryResource : public pmr::memory_resource
/// buffer), e.g. pointer returned by std::vector::data() return nullptr if /// buffer), e.g. pointer returned by std::vector::data() return nullptr if
/// returning /// returning
/// a message does not make sense! /// a message does not make sense!
virtual FairMQMessagePtr getMessage(void *p) = 0; virtual MessagePtr getMessage(void* p) = 0;
virtual void *setMessage(FairMQMessagePtr) = 0; virtual void* setMessage(MessagePtr) = 0;
virtual FairMQTransportFactory *getTransportFactory() noexcept = 0; virtual TransportFactory* getTransportFactory() noexcept = 0;
virtual size_t getNumberOfMessages() const noexcept = 0; virtual size_t getNumberOfMessages() const noexcept = 0;
}; };
@ -54,41 +51,42 @@ class FairMQMemoryResource : public pmr::memory_resource
/// delegated to FairMQ so standard (e.g. STL) containers can construct their /// delegated to FairMQ so standard (e.g. STL) containers can construct their
/// stuff in /// stuff in
/// memory regions appropriate for the data channel configuration. /// memory regions appropriate for the data channel configuration.
class ChannelResource : public FairMQMemoryResource class ChannelResource : public MemoryResource
{ {
protected: protected:
FairMQTransportFactory* factory{nullptr}; TransportFactory* factory{nullptr};
// TODO: for now a map to keep track of allocations, something else would // TODO: for now a map to keep track of allocations, something else would
// probably be // probably be
// faster, but for now this does not need to be fast. // faster, but for now this does not need to be fast.
boost::container::flat_map<void*, FairMQMessagePtr> messageMap; boost::container::flat_map<void*, MessagePtr> messageMap;
public: public:
ChannelResource() = delete; ChannelResource() = delete;
ChannelResource(FairMQTransportFactory* _factory) ChannelResource(TransportFactory* _factory)
: factory(_factory) : factory(_factory)
{ {
if (!_factory) { if (!_factory) {
throw std::runtime_error("Tried to construct from a nullptr FairMQTransportFactory"); throw std::runtime_error(
"Tried to construct from a nullptr fair::mq::TransportFactory");
} }
}; };
FairMQMessagePtr getMessage(void* p) override MessagePtr getMessage(void* p) override
{ {
auto mes = std::move(messageMap[p]); auto mes = std::move(messageMap[p]);
messageMap.erase(p); messageMap.erase(p);
return mes; return mes;
} }
void* setMessage(FairMQMessagePtr message) override void* setMessage(MessagePtr message) override
{ {
void* addr = message->GetData(); void* addr = message->GetData();
messageMap[addr] = std::move(message); messageMap[addr] = std::move(message);
return addr; return addr;
} }
FairMQTransportFactory* getTransportFactory() noexcept override { return factory; } TransportFactory* getTransportFactory() noexcept override { return factory; }
size_t getNumberOfMessages() const noexcept override { return messageMap.size(); } size_t getNumberOfMessages() const noexcept override { return messageMap.size(); }
@ -99,12 +97,16 @@ class ChannelResource : public FairMQMemoryResource
messageMap.erase(p); messageMap.erase(p);
}; };
bool do_is_equal(const pmr::memory_resource &other) const noexcept override bool do_is_equal(const pmr::memory_resource& other) const noexcept override
{ {
return this == &other; return this == &other;
}; };
}; };
} // namespace fair::mq } // namespace fair::mq
// using FairMQMemoryResource [[deprecated("Use fair::mq::MemoryResource")]] =
// fair::mq::MemoryResource;
using FairMQMemoryResource = fair::mq::MemoryResource;
#endif /* FAIR_MQ_MEMORY_RESOURCES_H */ #endif /* FAIR_MQ_MEMORY_RESOURCES_H */

View File

@ -9,6 +9,71 @@
#ifndef FAIR_MQ_MESSAGE_H #ifndef FAIR_MQ_MESSAGE_H
#define FAIR_MQ_MESSAGE_H #define FAIR_MQ_MESSAGE_H
#include <FairMQMessage.h> #include <cstddef> // for size_t
#include <fairmq/Transports.h>
#include <memory> // unique_ptr
#include <stdexcept>
namespace fair::mq {
using FreeFn = void(void* data, void* hint);
class TransportFactory;
struct Alignment
{
size_t alignment;
explicit operator size_t() const { return alignment; }
};
struct Message
{
Message() = default;
Message(TransportFactory* factory)
: fTransport(factory)
{}
virtual void Rebuild() = 0;
virtual void Rebuild(Alignment alignment) = 0;
virtual void Rebuild(const size_t size) = 0;
virtual void Rebuild(const size_t size, Alignment alignment) = 0;
virtual void Rebuild(void* data, const size_t size, FreeFn* ffn, void* hint = nullptr) = 0;
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
virtual bool SetUsedSize(const size_t size) = 0;
virtual Transport GetType() const = 0;
TransportFactory* GetTransport() { return fTransport; }
void SetTransport(TransportFactory* transport) { fTransport = transport; }
virtual void Copy(const Message& msg) = 0;
virtual ~Message() = default;
private:
TransportFactory* fTransport{nullptr};
};
using MessagePtr = std::unique_ptr<Message>;
struct MessageError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
struct MessageBadAlloc : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
// using FairMQMessage [[deprecated("Use fair::mq::Message")]] = fair::mq::Message;
// using FairMQMessagePtr [[deprecated("Use fair::mq::MessagePtr")]] = fair::mq::MessagePtr;
using fairmq_free_fn = fair::mq::FreeFn;
using FairMQMessage = fair::mq::Message;
using FairMQMessagePtr = fair::mq::MessagePtr;
#endif // FAIR_MQ_MESSAGE_H #endif // FAIR_MQ_MESSAGE_H

94
fairmq/Parts.h Normal file
View File

@ -0,0 +1,94 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_PARTS_H
#define FAIR_MQ_PARTS_H
#include <fairmq/Message.h>
#include <memory> // unique_ptr
#include <vector>
namespace fair::mq {
/// fair::mq::Parts is a lightweight convenience wrapper around a vector of unique pointers to
/// Message, used for sending multi-part messages
class Parts
{
private:
using container = std::vector<MessagePtr>;
public:
Parts() = default;
Parts(const Parts&) = delete;
Parts(Parts&& p) = default;
Parts& operator=(const Parts&) = delete;
template<typename... Ts>
Parts(Ts&&... messages)
{
AddPart(std::forward<Ts>(messages)...);
}
~Parts() = default;
/// Adds part (Message) to the container
/// @param msg message pointer (for example created with NewMessage() method of Device)
void AddPart(Message* msg) { fParts.push_back(MessagePtr(msg)); }
/// Adds part to the container (move)
/// @param msg unique pointer to Message
/// rvalue ref (move required when passing argument)
void AddPart(MessagePtr&& msg) { fParts.push_back(std::move(msg)); }
/// Add variable list of parts to the container (move)
template<typename... Ts>
void AddPart(MessagePtr&& first, Ts&&... remaining)
{
AddPart(std::move(first));
AddPart(std::forward<Ts>(remaining)...);
}
/// Add content of another object by move
void AddPart(Parts&& other)
{
container parts = std::move(other.fParts);
for (auto& part : parts) {
fParts.push_back(std::move(part));
}
}
/// Get reference to part in the container at index (without bounds check)
/// @param index container index
Message& operator[](const int index) { return *(fParts[index]); }
/// Get reference to unique pointer to part in the container at index (with bounds check)
/// @param index container index
MessagePtr& At(const int index) { return fParts.at(index); }
// ref version
Message& AtRef(const int index) { return *(fParts.at(index)); }
/// Get number of parts in the container
/// @return number of parts in the container
int Size() const { return fParts.size(); }
container fParts;
// forward container iterators
using iterator = container::iterator;
using const_iterator = container::const_iterator;
auto begin() -> decltype(fParts.begin()) { return fParts.begin(); }
auto end() -> decltype(fParts.end()) { return fParts.end(); }
auto cbegin() -> decltype(fParts.cbegin()) { return fParts.cbegin(); }
auto cend() -> decltype(fParts.cend()) { return fParts.cend(); }
};
} // namespace fair::mq
// using FairMQParts [[deprecated("Use fair::mq::Parts")]] = fair::mq::Parts;
using FairMQParts = fair::mq::Parts;
#endif /* FAIR_MQ_PARTS_H */

View File

@ -9,6 +9,35 @@
#ifndef FAIR_MQ_POLLER_H #ifndef FAIR_MQ_POLLER_H
#define FAIR_MQ_POLLER_H #define FAIR_MQ_POLLER_H
#include <FairMQPoller.h> #include <memory>
#include <stdexcept>
#include <string>
namespace fair::mq {
struct Poller
{
virtual void Poll(const int timeout) = 0;
virtual bool CheckInput(const int index) = 0;
virtual bool CheckOutput(const int index) = 0;
virtual bool CheckInput(const std::string& channelKey, const int index) = 0;
virtual bool CheckOutput(const std::string& channelKey, const int index) = 0;
virtual ~Poller() = default;
};
using PollerPtr = std::unique_ptr<Poller>;
struct PollerError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using FairMQPoller [[deprecated("Use fair::mq::Poller")]] = fair::mq::Poller;
// using FairMQPollerPtr [[deprecated("Use fair::mq::PollerPtr")]] = fair::mq::PollerPtr;
using FairMQPoller = fair::mq::Poller;
using FairMQPollerPtr = fair::mq::PollerPtr;
#endif // FAIR_MQ_POLLER_H #endif // FAIR_MQ_POLLER_H

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,11 @@
#ifndef FAIR_MQ_PROGOPTIONSFWD_H #ifndef FAIR_MQ_PROGOPTIONSFWD_H
#define FAIR_MQ_PROGOPTIONSFWD_H #define FAIR_MQ_PROGOPTIONSFWD_H
namespace fair::mq namespace fair::mq {
{
class ProgOptions; class ProgOptions;
} }
// using FairMQProgOptions [[deprecated("Use fair::mq::ProgOptions")]] = fair::mq::ProgOptions;
using FairMQProgOptions = fair::mq::ProgOptions; using FairMQProgOptions = fair::mq::ProgOptions;
#endif /* FAIR_MQ_PROGOPTIONSFWD_H */ #endif /* FAIR_MQ_PROGOPTIONSFWD_H */

View File

@ -9,6 +9,87 @@
#ifndef FAIR_MQ_SOCKET_H #ifndef FAIR_MQ_SOCKET_H
#define FAIR_MQ_SOCKET_H #define FAIR_MQ_SOCKET_H
#include <FairMQSocket.h> #include <fairmq/Message.h>
#include <memory>
#include <stdexcept>
#include <string>
#include <vector>
namespace fair::mq {
class TransportFactory;
enum class TransferCode : int
{
success = 0,
error = -1,
timeout = -2,
interrupted = -3
};
struct Socket
{
Socket() = default;
Socket(TransportFactory* fac)
: fTransport(fac)
{}
virtual std::string GetId() const = 0;
virtual bool Bind(const std::string& address) = 0;
virtual bool Connect(const std::string& address) = 0;
virtual int64_t Send(MessagePtr& msg, int timeout = -1) = 0;
virtual int64_t Receive(MessagePtr& msg, int timeout = -1) = 0;
virtual int64_t Send(std::vector<std::unique_ptr<Message>>& msgVec, int timeout = -1) = 0;
virtual int64_t Receive(std::vector<std::unique_ptr<Message>>& msgVec, int timeout = -1) = 0;
virtual void Close() = 0;
virtual void SetOption(const std::string& option, const void* value, size_t valueSize) = 0;
virtual void GetOption(const std::string& option, void* value, size_t* valueSize) = 0;
/// If the backend supports it, fills the unsigned integer @a events with the ZMQ_EVENTS value
/// DISCLAIMER: this API is experimental and unsupported and might be dropped / refactored in
/// the future.
virtual int Events(uint32_t* events) = 0;
virtual void SetLinger(const int value) = 0;
virtual int GetLinger() const = 0;
virtual void SetSndBufSize(const int value) = 0;
virtual int GetSndBufSize() const = 0;
virtual void SetRcvBufSize(const int value) = 0;
virtual int GetRcvBufSize() const = 0;
virtual void SetSndKernelSize(const int value) = 0;
virtual int GetSndKernelSize() const = 0;
virtual void SetRcvKernelSize(const int value) = 0;
virtual int GetRcvKernelSize() const = 0;
virtual unsigned long GetBytesTx() const = 0;
virtual unsigned long GetBytesRx() const = 0;
virtual unsigned long GetMessagesTx() const = 0;
virtual unsigned long GetMessagesRx() const = 0;
TransportFactory* GetTransport() { return fTransport; }
void SetTransport(TransportFactory* transport) { fTransport = transport; }
virtual ~Socket() = default;
private:
TransportFactory* fTransport{nullptr};
};
using SocketPtr = std::unique_ptr<Socket>;
struct SocketError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using FairMQSocket [[deprecated("Use fair::mq::Socket")]] = fair::mq::Socket;
// using FairMQSocketPtr [[deprecated("Use fair::mq::SocketPtr")]] = fair::mq::SocketPtr;
using FairMQSocket = fair::mq::Socket;
using FairMQSocketPtr = fair::mq::SocketPtr;
#endif // FAIR_MQ_SOCKET_H #endif // FAIR_MQ_SOCKET_H

View File

@ -1,53 +1,47 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
#include <FairMQTransportFactory.h> #include <fairmq/TransportFactory.h>
#include <fairmq/shmem/TransportFactory.h> #include <fairmq/shmem/TransportFactory.h>
#include <fairmq/zeromq/TransportFactory.h> #include <fairmq/zeromq/TransportFactory.h>
#ifdef BUILD_OFI_TRANSPORT #ifdef BUILD_OFI_TRANSPORT
#include <fairmq/ofi/TransportFactory.h> #include <fairmq/ofi/TransportFactory.h>
#endif #endif
#include <FairMQLogger.h>
#include <fairmq/tools/Unique.h>
#include <fairmq/tools/Strings.h>
#include <fairlogger/Logger.h> #include <fairlogger/Logger.h>
#include <fairmq/Tools.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> // move #include <utility> // move
using namespace std; using namespace std;
FairMQTransportFactory::FairMQTransportFactory(string id) namespace fair::mq {
: fkId(std::move(id))
{}
auto FairMQTransportFactory::CreateTransportFactory(const string& type, auto TransportFactory::CreateTransportFactory(const string& type,
const string& id, const string& id,
const fair::mq::ProgOptions* config) const ProgOptions* config)
-> shared_ptr<FairMQTransportFactory> -> shared_ptr<TransportFactory>
{ {
auto finalId = id; auto finalId = id;
// Generate uuid if empty // Generate uuid if empty
if (finalId.empty()) { if (finalId.empty()) {
finalId = fair::mq::tools::Uuid(); finalId = tools::Uuid();
} }
if (type == "zeromq") { if (type == "zeromq") {
return make_shared<fair::mq::zmq::TransportFactory>(finalId, config); return make_shared<zmq::TransportFactory>(finalId, config);
} else if (type == "shmem") { } else if (type == "shmem") {
return make_shared<fair::mq::shmem::TransportFactory>(finalId, config); return make_shared<shmem::TransportFactory>(finalId, config);
} }
#ifdef BUILD_OFI_TRANSPORT #ifdef BUILD_OFI_TRANSPORT
else if (type == "ofi") { else if (type == "ofi") {
return make_shared<fair::mq::ofi::TransportFactory>(finalId, config); return make_shared<ofi::TransportFactory>(finalId, config);
} }
#endif /* BUILD_OFI_TRANSPORT */ #endif /* BUILD_OFI_TRANSPORT */
else { else {
@ -60,6 +54,8 @@ auto FairMQTransportFactory::CreateTransportFactory(const string& type,
<< ", and \"ofi\"" << ", and \"ofi\""
#endif /* BUILD_OFI_TRANSPORT */ #endif /* BUILD_OFI_TRANSPORT */
<< ". Exiting."; << ". Exiting.";
throw fair::mq::TransportFactoryError(fair::mq::tools::ToString("Unavailable transport requested: ", type)); throw TransportFactoryError(tools::ToString("Unavailable transport requested: ", type));
} }
} }
} // namespace fair::mq

View File

@ -9,6 +9,220 @@
#ifndef FAIR_MQ_TRANSPORTFACTORY_H #ifndef FAIR_MQ_TRANSPORTFACTORY_H
#define FAIR_MQ_TRANSPORTFACTORY_H #define FAIR_MQ_TRANSPORTFACTORY_H
#include <FairMQTransportFactory.h> #include <cstddef> // size_t
#include <fairmq/MemoryResources.h>
#include <fairmq/Message.h>
#include <fairmq/Poller.h>
#include <fairmq/Socket.h>
#include <fairmq/Transports.h>
#include <fairmq/UnmanagedRegion.h>
#include <memory> // shared_ptr
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
namespace fair::mq {
class Channel;
class ProgOptions;
class TransportFactory
{
private:
/// Topology wide unique id
const std::string fkId;
/// The polymorphic memory resource associated with the transport
ChannelResource fMemoryResource{this};
public:
/// ctor
/// @param id Topology wide unique id, usually the device id.
TransportFactory(std::string id)
: fkId(std::move(id))
{}
auto GetId() const -> const std::string { return fkId; };
/// Get a pointer to the associated polymorphic memory resource
ChannelResource* GetMemoryResource() { return &fMemoryResource; }
operator ChannelResource*() { return &fMemoryResource; }
/// @brief Create empty Message (for receiving)
/// @return pointer to Message
virtual MessagePtr CreateMessage() = 0;
/// @brief Create empty Message (for receiving), align received buffer to specified alignment
/// @param alignment alignment to align received buffer to
/// @return pointer to Message
virtual MessagePtr CreateMessage(Alignment alignment) = 0;
/// @brief Create new Message of specified size
/// @param size message size
/// @return pointer to Message
virtual MessagePtr CreateMessage(const size_t size) = 0;
/// @brief Create new Message of specified size and alignment
/// @param size message size
/// @param alignment message alignment
/// @return pointer to Message
virtual MessagePtr CreateMessage(const size_t size, Alignment alignment) = 0;
/// @brief Create new Message with user provided buffer and size
/// @param data pointer to user provided buffer
/// @param size size of the user provided buffer
/// @param ffn callback, called when the message is transfered (and can be deleted)
/// @param obj optional helper pointer that can be used in the callback
/// @return pointer to Message
virtual MessagePtr CreateMessage(void* data,
const size_t size,
fairmq_free_fn* ffn,
void* hint = nullptr) = 0;
/// @brief create a message with the buffer located within the corresponding unmanaged region
/// @param unmanagedRegion the unmanaged region that this message buffer belongs to
/// @param data message buffer (must be within the region - checked at runtime by the transport)
/// @param size size of the message
/// @param hint optional parameter, returned to the user in the RegionCallback
virtual MessagePtr CreateMessage(UnmanagedRegionPtr& unmanagedRegion,
void* data,
const size_t size,
void* hint = 0) = 0;
/// @brief Create a socket
virtual SocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
/// @brief Create a poller for a single channel (all subchannels)
virtual PollerPtr CreatePoller(const std::vector<Channel>& channels) const = 0;
/// @brief Create a poller for specific channels
virtual PollerPtr CreatePoller(const std::vector<Channel*>& channels) const = 0;
/// @brief Create a poller for specific channels (all subchannels)
virtual PollerPtr CreatePoller(
const std::unordered_map<std::string, std::vector<Channel>>& channelsMap,
const std::vector<std::string>& channelList) const = 0;
/// @brief Create new UnmanagedRegion
/// @param size size of the region
/// @param callback callback to be called when a message belonging to this region is no longer
/// needed by the transport
/// @param path optional parameter to pass to the underlying transport
/// @param flags optional parameter to pass to the underlying transport
/// @return pointer to UnmanagedRegion
virtual UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size,
RegionCallback callback = nullptr,
const std::string& path = "",
int flags = 0,
RegionConfig cfg = RegionConfig()) = 0;
virtual UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size,
RegionBulkCallback callback = nullptr,
const std::string& path = "",
int flags = 0,
RegionConfig cfg = RegionConfig()) = 0;
/// @brief Create new UnmanagedRegion
/// @param size size of the region
/// @param userFlags flags to be stored with the region, have no effect on the transport, but
/// can be retrieved from the region by the user
/// @param callback callback to be called when a message belonging to this region is no longer
/// needed by the transport
/// @param path optional parameter to pass to the underlying transport
/// @param flags optional parameter to pass to the underlying transport
/// @return pointer to UnmanagedRegion
virtual UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size,
const int64_t userFlags,
RegionCallback callback = nullptr,
const std::string& path = "",
int flags = 0,
RegionConfig cfg = RegionConfig()) = 0;
virtual UnmanagedRegionPtr CreateUnmanagedRegion(const size_t size,
const int64_t userFlags,
RegionBulkCallback callback = nullptr,
const std::string& path = "",
int flags = 0,
RegionConfig cfg = RegionConfig()) = 0;
/// @brief Subscribe to region events (creation, destruction, ...)
/// @param callback the callback that is called when a region event occurs
virtual void SubscribeToRegionEvents(RegionEventCallback callback) = 0;
/// @brief Check if there is an active subscription to region events
/// @return true/false
virtual bool SubscribedToRegionEvents() = 0;
/// @brief Unsubscribe from region events
virtual void UnsubscribeFromRegionEvents() = 0;
virtual std::vector<RegionInfo> GetRegionInfo() = 0;
/// Get transport type
virtual Transport GetType() const = 0;
virtual void Interrupt() = 0;
virtual void Resume() = 0;
virtual void Reset() = 0;
virtual ~TransportFactory() = default;
static auto CreateTransportFactory(const std::string& type,
const std::string& id = "",
const ProgOptions* config = nullptr)
-> std::shared_ptr<TransportFactory>;
static void NoCleanup(void* /*data*/, void* /*obj*/) {}
template<typename T>
static void SimpleMsgCleanup(void* /*data*/, void* obj)
{
delete static_cast<T*>(obj);
}
template<typename T>
MessagePtr NewSimpleMessage(const T& data)
{
// todo: is_trivially_copyable not available on gcc < 5, workaround?
// static_assert(std::is_trivially_copyable<T>::value, "The argument type for
// NewSimpleMessage has to be trivially copyable!");
T* dataCopy = new T(data);
return CreateMessage(dataCopy, sizeof(T), SimpleMsgCleanup<T>, dataCopy);
}
template<std::size_t N>
MessagePtr NewSimpleMessage(const char (&data)[N])
{
std::string* msgStr = new std::string(data);
return CreateMessage(const_cast<char*>(msgStr->c_str()),
msgStr->length(),
SimpleMsgCleanup<std::string>,
msgStr);
}
MessagePtr NewSimpleMessage(const std::string& str)
{
std::string* msgStr = new std::string(str);
return CreateMessage(const_cast<char*>(msgStr->c_str()),
msgStr->length(),
SimpleMsgCleanup<std::string>,
msgStr);
}
template<typename T>
MessagePtr NewStaticMessage(const T& data)
{
return CreateMessage(data, sizeof(T), NoCleanup, nullptr);
}
MessagePtr NewStaticMessage(const std::string& str)
{
return CreateMessage(const_cast<char*>(str.c_str()), str.length(), NoCleanup, nullptr);
}
};
struct TransportFactoryError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using FairMQTransportFactory [[deprecated("Use fair::mq::TransportFactory")]] =
// fair::mq::TransportFactory;
// using FairMQTransportFactoryError [[deprecated("Use fair::mq::TransportFactoryError")]] =
// fair::mq::TransportFactoryError;
using FairMQTransportFactory = fair::mq::TransportFactory;
using FairMQTransportFactoryError = fair::mq::TransportFactoryError;
#endif // FAIR_MQ_TRANSPORTFACTORY_H #endif // FAIR_MQ_TRANSPORTFACTORY_H

View File

@ -9,6 +9,139 @@
#ifndef FAIR_MQ_UNMANAGEDREGION_H #ifndef FAIR_MQ_UNMANAGEDREGION_H
#define FAIR_MQ_UNMANAGEDREGION_H #define FAIR_MQ_UNMANAGEDREGION_H
#include <FairMQUnmanagedRegion.h> #include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <fairmq/Transports.h>
#include <functional> // std::function
#include <memory> // std::unique_ptr
#include <ostream> // std::ostream
#include <vector>
namespace fair::mq {
class TransportFactory;
enum class RegionEvent : int
{
created,
destroyed,
local_only
};
struct RegionInfo
{
RegionInfo() = default;
RegionInfo(bool _managed,
uint64_t _id,
void* _ptr,
size_t _size,
int64_t _flags,
RegionEvent _event)
: managed(_managed)
, id(_id)
, ptr(_ptr)
, size(_size)
, flags(_flags)
, event(_event)
{}
bool managed = true; // managed/unmanaged
uint64_t id = 0; // id of the region
void* ptr = nullptr; // pointer to the start of the region
size_t size = 0; // region size
int64_t flags = 0; // custom flags set by the creator
RegionEvent event = RegionEvent::created;
};
struct RegionBlock
{
void* ptr;
size_t size;
void* hint;
RegionBlock(void* p, size_t s, void* h)
: ptr(p)
, size(s)
, hint(h)
{}
};
using RegionCallback = std::function<void(void*, size_t, void*)>;
using RegionBulkCallback = std::function<void(const std::vector<RegionBlock>&)>;
using RegionEventCallback = std::function<void(RegionInfo)>;
struct UnmanagedRegion
{
UnmanagedRegion() = default;
UnmanagedRegion(TransportFactory* factory)
: fTransport(factory)
{}
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
virtual uint16_t GetId() const = 0;
virtual void SetLinger(uint32_t linger) = 0;
virtual uint32_t GetLinger() const = 0;
virtual Transport GetType() const = 0;
TransportFactory* GetTransport() { return fTransport; }
void SetTransport(TransportFactory* transport) { fTransport = transport; }
virtual ~UnmanagedRegion() = default;
private:
TransportFactory* fTransport{nullptr};
};
using UnmanagedRegionPtr = std::unique_ptr<UnmanagedRegion>;
inline std::ostream& operator<<(std::ostream& os, const RegionEvent& event)
{
switch (event) {
case RegionEvent::created:
return os << "created";
case RegionEvent::destroyed:
return os << "destroyed";
case RegionEvent::local_only:
return os << "local_only";
default:
return os << "unrecognized event";
}
}
struct RegionConfig
{
RegionConfig() = default;
RegionConfig(bool l, bool z)
: lock(l)
, zero(z)
{}
bool lock = false;
bool zero = false;
};
} // namespace fair::mq
// using FairMQRegionEvent [[deprecated("Use fair::mq::RegionBlock")]] = fair::mq::RegionEvent;
// using FairMQRegionInfo [[deprecated("Use fair::mq::RegionInfo")]] = fair::mq::RegionInfo;
// using FairMQRegionBlock [[deprecated("Use fair::mq::RegionBlock")]] = fair::mq::RegionBlock;
// using FairMQRegionCallback [[deprecated("Use fair::mq::RegionCallback")]] = fair::mq::RegionCallback;
// using FairMQRegionBulkCallback [[deprecated("Use fair::mq::RegionBulkCallback")]] = fair::mq::RegionBulkCallback;
// using FairMQRegionEventCallback [[deprecated("Use fair::mq::RegionEventCallback")]] = fair::mq::RegionEventCallback;
// using FairMQUnmanagedRegion [[deprecated("Use fair::mq::UnmanagedRegion")]] = fair::mq::UnmanagedRegion;
// using FairMQUnmanagedRegionPtr [[deprecated("Use fair::mq::UnmanagedRegionPtr")]] = fair::mq::UnmanagedRegionPtr;
// using FairMQRegionConfig [[deprecated("Use fair::mq::RegionConfig")]] = fair::mq::RegionConfig;
using FairMQRegionEvent = fair::mq::RegionEvent;
using FairMQRegionInfo = fair::mq::RegionInfo;
using FairMQRegionBlock = fair::mq::RegionBlock;
using FairMQRegionCallback = fair::mq::RegionCallback;
using FairMQRegionBulkCallback = fair::mq::RegionBulkCallback;
using FairMQRegionEventCallback = fair::mq::RegionEventCallback;
using FairMQUnmanagedRegion = fair::mq::UnmanagedRegion;
using FairMQUnmanagedRegionPtr = fair::mq::UnmanagedRegionPtr;
using FairMQRegionConfig = fair::mq::RegionConfig;
#endif // FAIR_MQ_UNMANAGEDREGION_H #endif // FAIR_MQ_UNMANAGEDREGION_H

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -19,8 +19,6 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
class FairMQChannel;
namespace fair::mq::shmem namespace fair::mq::shmem
{ {

View File

@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@ -22,7 +22,9 @@
#include <atomic> #include <atomic>
#include <memory> // make_unique #include <memory> // make_unique
class FairMQTransportFactory; namespace fair::mq {
class TransportFactory;
}
namespace fair::mq::shmem namespace fair::mq::shmem
{ {