FairMQ  1.3.7
C++ Message Passing Framework
FairMQDevice.h
1 /********************************************************************************
2  * Copyright (C) 2012-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
3  * *
4  * This software is distributed under the terms of the *
5  * GNU Lesser General Public Licence (LGPL) version 3, *
6  * copied verbatim in the file "LICENSE" *
7  ********************************************************************************/
8 
9 #ifndef FAIRMQDEVICE_H_
10 #define FAIRMQDEVICE_H_
11 
12 #include <FairMQStateMachine.h>
13 #include <FairMQTransportFactory.h>
14 #include <fairmq/Transports.h>
15 
16 #include <FairMQSocket.h>
17 #include <FairMQChannel.h>
18 #include <FairMQMessage.h>
19 #include <FairMQParts.h>
20 #include <FairMQUnmanagedRegion.h>
21 #include <FairMQLogger.h>
22 #include <options/FairMQProgOptions.h>
23 
24 #include <vector>
25 #include <memory> // unique_ptr
26 #include <algorithm> // std::sort()
27 #include <string>
28 #include <chrono>
29 #include <iostream>
30 #include <unordered_map>
31 #include <functional>
32 #include <assert.h> // static_assert
33 #include <type_traits> // is_trivially_copyable
34 #include <stdexcept>
35 
36 #include <mutex>
37 #include <condition_variable>
38 
39 #include <fairmq/Tools.h>
40 
41 using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
42 
43 using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
44 using InputMultipartCallback = std::function<bool(FairMQParts&, int)>;
45 
47 {
48  friend class FairMQChannel;
49 
50  public:
52  FairMQDevice();
55 
58 
61 
62  private:
64 
65  public:
67  FairMQDevice(const FairMQDevice&) = delete;
69  FairMQDevice operator=(const FairMQDevice&) = delete;
71  virtual ~FairMQDevice();
72 
74  void CatchSignals();
75 
77  virtual void LogSocketRates();
78 
82  void SortChannel(const std::string& name, const bool reindex = true);
83 
84  template<typename Serializer, typename DataType, typename... Args>
85  void Serialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
86  {
87  Serializer().Serialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
88  }
89 
90  template<typename Deserializer, typename DataType, typename... Args>
91  void Deserialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
92  {
93  Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
94  }
95 
102  int Send(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
103  {
104  return GetChannel(channel, index).Send(msg, sndTimeoutInMs);
105  }
106 
113  int Receive(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
114  {
115  return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
116  }
117 
118  int SendAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, \"channelA\", subchannelIndex, timeout);")))
119  {
120  return GetChannel(channel, index).Send(msg, 0);
121  }
122  int ReceiveAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, \"channelA\", subchannelIndex, timeout);")))
123  {
124  return GetChannel(channel, index).Receive(msg, 0);
125  }
126 
133  int64_t Send(FairMQParts& parts, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
134  {
135  return GetChannel(channel, index).Send(parts.fParts, sndTimeoutInMs);
136  }
137 
144  int64_t Receive(FairMQParts& parts, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
145  {
146  return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
147  }
148 
149  int64_t SendAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, \"channelA\", subchannelIndex, timeout);")))
150  {
151  return GetChannel(channel, index).Send(parts.fParts, 0);
152  }
153  int64_t ReceiveAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, \"channelA\", subchannelIndex, timeout);")))
154  {
155  return GetChannel(channel, index).Receive(parts.fParts, 0);
156  }
157 
160  {
161  return fTransportFactory.get();
162  }
163 
164  template<typename... Args>
165  FairMQMessagePtr NewMessage(Args&&... args)
166  {
167  return Transport()->CreateMessage(std::forward<Args>(args)...);
168  }
169 
170  template<typename... Args>
171  FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
172  {
173  return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
174  }
175 
176  template<typename T>
177  FairMQMessagePtr NewStaticMessage(const T& data)
178  {
179  return Transport()->NewStaticMessage(data);
180  }
181 
182  template<typename T>
183  FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
184  {
185  return GetChannel(channel, index).NewStaticMessage(data);
186  }
187 
188  template<typename T>
189  FairMQMessagePtr NewSimpleMessage(const T& data)
190  {
191  return Transport()->NewSimpleMessage(data);
192  }
193 
194  template<typename T>
195  FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
196  {
197  return GetChannel(channel, index).NewSimpleMessage(data);
198  }
199 
200  FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size)
201  {
202  return Transport()->CreateUnmanagedRegion(size);
203  }
204 
205  FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, const size_t size, FairMQRegionCallback callback = nullptr)
206  {
207  return GetChannel(channel, index).Transport()->CreateUnmanagedRegion(size, callback);
208  }
209 
210  template<typename ...Ts>
211  FairMQPollerPtr NewPoller(const Ts&... inputs)
212  {
213  std::vector<std::string> chans{inputs...};
214 
215  // if more than one channel provided, check compatibility
216  if (chans.size() > 1)
217  {
218  fair::mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
219 
220  for (unsigned int i = 1; i < chans.size(); ++i)
221  {
222  if (type != GetChannel(chans.at(i), 0).Transport()->GetType())
223  {
224  LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
225  throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
226  }
227  }
228  }
229 
230  return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
231  }
232 
233  FairMQPollerPtr NewPoller(const std::vector<FairMQChannel*>& channels)
234  {
235  // if more than one channel provided, check compatibility
236  if (channels.size() > 1)
237  {
238  fair::mq::Transport type = channels.at(0)->Transport()->GetType();
239 
240  for (unsigned int i = 1; i < channels.size(); ++i)
241  {
242  if (type != channels.at(i)->Transport()->GetType())
243  {
244  LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
245  throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
246  }
247  }
248  }
249 
250  return channels.at(0)->Transport()->CreatePoller(channels);
251  }
252 
254  void WaitForInitialValidation() __attribute__((deprecated("This method will have no effect in future versions and will be removed. Instead subscribe for state changes and inspect configuration values."))) {}
255 
258  std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
259 
261  void SetConfig(FairMQProgOptions& config);
264  {
265  return fConfig;
266  }
267 
271  static bool SortSocketsByAddress(const FairMQChannel &lhs, const FairMQChannel &rhs);
272 
273  // overload to easily bind member functions
274  template<typename T>
275  void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQMessagePtr& msg, int index))
276  {
277  fDataCallbacks = true;
278  fMsgInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQMessagePtr& msg, int index)
279  {
280  return (static_cast<T*>(this)->*memberFunction)(msg, index);
281  }));
282 
283  if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
284  {
285  fInputChannelKeys.push_back(channelName);
286  }
287  }
288 
289  void OnData(const std::string& channelName, InputMsgCallback callback)
290  {
291  fDataCallbacks = true;
292  fMsgInputs.insert(make_pair(channelName, callback));
293 
294  if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
295  {
296  fInputChannelKeys.push_back(channelName);
297  }
298  }
299 
300  // overload to easily bind member functions
301  template<typename T>
302  void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQParts& parts, int index))
303  {
304  fDataCallbacks = true;
305  fMultipartInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQParts& parts, int index)
306  {
307  return (static_cast<T*>(this)->*memberFunction)(parts, index);
308  }));
309 
310  if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
311  {
312  fInputChannelKeys.push_back(channelName);
313  }
314  }
315 
316  void OnData(const std::string& channelName, InputMultipartCallback callback)
317  {
318  fDataCallbacks = true;
319  fMultipartInputs.insert(make_pair(channelName, callback));
320 
321  if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
322  {
323  fInputChannelKeys.push_back(channelName);
324  }
325  }
326 
327  FairMQChannel& GetChannel(const std::string& channelName, const int index = 0)
328  try {
329  return fChannels.at(channelName).at(index);
330  } catch (const std::out_of_range& oor) {
331  LOG(error) << "out of range: " << oor.what();
332  LOG(error) << "requested channel has not been configured? check channel names/configuration.";
333  fRateLogging = false;
334  throw;
335  }
336 
337  virtual void RegisterChannelEndpoints() {}
338 
339  bool RegisterChannelEndpoint(const std::string& channelName, uint16_t minNumSubChannels = 1, uint16_t maxNumSubChannels = 1)
340  {
341  bool ok = fChannelRegistry.insert(std::make_pair(channelName, std::make_pair(minNumSubChannels, maxNumSubChannels))).second;
342  if (!ok)
343  {
344  LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
345  }
346  return ok;
347  }
348 
349  void PrintRegisteredChannels()
350  {
351  if (fChannelRegistry.size() < 1)
352  {
353  std::cout << "no channels registered." << std::endl;
354  }
355  else
356  {
357  for (const auto& c : fChannelRegistry)
358  {
359  std::cout << c.first << ":" << c.second.first << ":" << c.second.second << std::endl;
360  }
361  }
362  }
363 
364  void SetId(const std::string& id) { fId = id; }
365  std::string GetId() { return fId; }
366 
367  const fair::mq::tools::Version GetVersion() const { return fVersion; }
368 
369  void SetNumIoThreads(int numIoThreads) { fConfig->SetValue<int>("io-threads", numIoThreads);}
370  int GetNumIoThreads() const { return fConfig->GetValue<int>("io-threads"); }
371 
372  void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetValue<std::string>("network-interface", networkInterface); }
373  std::string GetNetworkInterface() const { return fConfig->GetValue<std::string>("network-interface"); }
374 
375  void SetDefaultTransport(const std::string& name) { fConfig->SetValue<std::string>("transport", name); }
376  std::string GetDefaultTransport() const { return fConfig->GetValue<std::string>("transport"); }
377 
378  void SetInitializationTimeoutInS(int initializationTimeoutInS) { fConfig->SetValue<int>("initialization-timeout", initializationTimeoutInS); }
379  int GetInitializationTimeoutInS() const { return fConfig->GetValue<int>("initialization-timeout"); }
380 
383  void SetTransport(const std::string& transport) { fConfig->SetValue<std::string>("transport", transport); }
385  std::string GetTransportName() const { return fConfig->GetValue<std::string>("transport"); }
386 
387  void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
388  std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
389 
390  void RunStateMachine()
391  {
392  CallStateChangeCallbacks(FairMQStateMachine::IDLE);
393  ProcessWork();
394  };
395 
399  template<class Rep, class Period>
400  bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
401  {
402  std::unique_lock<std::mutex> lock(fInterruptedMtx);
403  return !fInterruptedCV.wait_for(lock, duration, [&] { return fInterrupted.load(); }); // return true if no interruption happened
404  }
405 
406  protected:
407  std::shared_ptr<FairMQTransportFactory> fTransportFactory;
408  std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports;
409 
410  public:
411  std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels;
412  std::unique_ptr<FairMQProgOptions> fInternalConfig;
414 
415  void AddChannel(const std::string& channelName, const FairMQChannel& channel)
416  {
417  fConfig->AddChannel(channelName, channel);
418  }
419 
420  protected:
421  std::string fId;
422 
424  virtual void Init();
425 
427  virtual void InitTask();
428 
430  virtual void Run();
431 
433  virtual void PreRun();
434 
436  virtual bool ConditionalRun();
437 
439  virtual void PostRun();
440 
442  virtual void Pause();
443 
445  virtual void ResetTask();
446 
448  virtual void Reset();
449 
450  private:
451  fair::mq::Transport fDefaultTransportType;
452 
454  void InitWrapper();
456  void InitTaskWrapper();
458  void RunWrapper();
460  void PauseWrapper();
462  void ResetTaskWrapper();
464  void ResetWrapper();
465 
467  void Unblock();
468 
470  void Exit();
471 
473  void AttachChannels(std::vector<FairMQChannel*>& chans);
474  bool AttachChannel(FairMQChannel& ch);
475 
476  void HandleSingleChannelInput();
477  void HandleMultipleChannelInput();
478  void HandleMultipleTransportInput();
479  void PollForTransport(const FairMQTransportFactory* factory, const std::vector<std::string>& channelKeys);
480 
481  bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
482  bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i);
483 
484  void CreateOwnConfig();
485 
486  bool fDataCallbacks;
487  std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
488  std::unordered_map<std::string, InputMultipartCallback> fMultipartInputs;
489  std::unordered_map<fair::mq::Transport, std::vector<std::string>> fMultitransportInputs;
490  std::unordered_map<std::string, std::pair<uint16_t, uint16_t>> fChannelRegistry;
491  std::vector<std::string> fInputChannelKeys;
492  std::mutex fMultitransportMutex;
493  std::atomic<bool> fMultitransportProceed;
494 
495  const fair::mq::tools::Version fVersion;
496  float fRate;
497  std::vector<std::string> fRawCmdLineArgs;
498 
499  std::atomic<bool> fInterrupted;
500  std::condition_variable fInterruptedCV;
501  std::mutex fInterruptedMtx;
502  mutable std::atomic<bool> fRateLogging;
503 };
504 
505 #endif /* FAIRMQDEVICE_H_ */
virtual void Pause()
Handles the PAUSE state.
Definition: FairMQDevice.cxx:627
std::string GetTransportName() const
Gets the default transport name.
Definition: FairMQDevice.h:385
std::unordered_map< fair::mq::Transport, std::shared_ptr< FairMQTransportFactory > > fTransports
Container for transports.
Definition: FairMQDevice.h:408
virtual void Run()
Runs the device (to be overloaded in child classes)
Definition: FairMQDevice.cxx:603
int Send(FairMQMessagePtr &msg, int sndTimeoutInMs=-1)
Definition: FairMQChannel.h:234
virtual bool ConditionalRun()
Called during RUNNING state repeatedly until it returns false or device state changes.
Definition: FairMQDevice.cxx:611
int Receive(FairMQMessagePtr &msg, int rcvTimeoutInMs=-1)
Definition: FairMQChannel.h:244
FairMQProgOptions * fConfig
Pointer to config (internal or external)
Definition: FairMQDevice.h:413
Definition: FairMQTransportFactory.h:28
void SetTransport(const std::string &transport)
Definition: FairMQDevice.h:383
int Send(FairMQMessagePtr &msg, const std::string &channel, const int index=0, int sndTimeoutInMs=-1)
Definition: FairMQDevice.h:102
bool WaitFor(std::chrono::duration< Rep, Period > const &duration)
Definition: FairMQDevice.h:400
std::unique_ptr< FairMQProgOptions > fInternalConfig
Internal program options configuration.
Definition: FairMQDevice.h:412
Definition: FairMQChannel.h:27
int64_t Send(FairMQParts &parts, const std::string &channel, const int index=0, int sndTimeoutInMs=-1)
Definition: FairMQDevice.h:133
Definition: FairMQProgOptions.h:37
virtual void PreRun()
Called in the RUNNING state once before executing the Run()/ConditionalRun() method.
Definition: FairMQDevice.cxx:607
virtual void ResetTask()
Resets the user task (to be overloaded in child classes)
Definition: FairMQDevice.cxx:795
std::string fId
Device ID.
Definition: FairMQDevice.h:421
void CatchSignals()
Catches interrupt signals (SIGINT, SIGTERM)
std::shared_ptr< FairMQTransportFactory > AddTransport(const fair::mq::Transport transport)
Definition: FairMQDevice.cxx:637
virtual ~FairMQDevice()
Default destructor.
Definition: FairMQDevice.cxx:832
int Receive(FairMQMessagePtr &msg, const std::string &channel, const int index=0, int rcvTimeoutInMs=-1)
Definition: FairMQDevice.h:113
void SortChannel(const std::string &name, const bool reindex=true)
Definition: FairMQDevice.cxx:314
void WaitForInitialValidation() __attribute__((deprecated("This method will have no effect in future versions and will be removed. Instead subscribe for state changes and inspect configuration values.")))
Waits for the first initialization run to finish.
Definition: FairMQDevice.h:254
virtual void PostRun()
Called in the RUNNING state once after executing the Run()/ConditionalRun() method.
Definition: FairMQDevice.cxx:616
std::unordered_map< std::string, std::vector< FairMQChannel > > fChannels
Device channels.
Definition: FairMQDevice.h:411
Definition: FairMQStateMachine.h:27
int64_t Receive(FairMQParts &parts, const std::string &channel, const int index=0, int rcvTimeoutInMs=-1)
Definition: FairMQDevice.h:144
FairMQProgOptions * GetConfig() const
Get pointer to the config.
Definition: FairMQDevice.h:263
FairMQParts is a lightweight convenience wrapper around a vector of unique pointers to FairMQMessage...
Definition: FairMQParts.h:20
std::shared_ptr< FairMQTransportFactory > fTransportFactory
Default transport factory.
Definition: FairMQDevice.h:407
void SetConfig(FairMQProgOptions &config)
Assigns config to the device.
Definition: FairMQDevice.cxx:659
virtual void Reset()
Resets the device (can be overloaded in child classes)
Definition: FairMQDevice.cxx:824
static bool SortSocketsByAddress(const FairMQChannel &lhs, const FairMQChannel &rhs)
Definition: FairMQDevice.cxx:309
Definition: FairMQDevice.h:46
virtual void Init()
Additional user initialization (can be overloaded in child classes). Prefer to use InitTask()...
Definition: FairMQDevice.cxx:198
Definition: FairMQMessage.h:20
virtual void InitTask()
Task initialization (can be overloaded in child classes)
Definition: FairMQDevice.cxx:305
FairMQDevice operator=(const FairMQDevice &)=delete
Assignment operator (disabled)
auto Transport() const -> FairMQTransportFactory *
Getter for default transport factory.
Definition: FairMQDevice.h:159
virtual void LogSocketRates()
Outputs the socket transfer rates.
Definition: FairMQDevice.cxx:665
FairMQDevice()
Default constructor.
Definition: FairMQDevice.cxx:30
Definition: Version.h:22

privacy