artdaq  v3_03_00
RequestReceiver.hh
1 #ifndef ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
2 #define ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
3 
4 #include <boost/thread.hpp>
5 #include "artdaq-core/Data/Fragment.hh"
6 #include "fhiclcpp/ParameterSet.h"
7 #include "fhiclcpp/types/Atom.h"
8 #include "fhiclcpp/types/ConfigurationTable.h"
9 
10 #include <mutex>
11 #include <condition_variable>
12 
13 namespace artdaq
14 {
19  {
20  public:
21 
25  struct Config
26  {
28  fhicl::Atom<int> request_port{ fhicl::Name{"request_port"}, fhicl::Comment{"Port to listen for request messages on"}, 3001 };
30  fhicl::Atom<std::string> request_addr{ fhicl::Name{"request_address"}, fhicl::Comment{"Multicast address to listen for request messages on"}, "227.128.12.26" };
32  fhicl::Atom<std::string> output_address{ fhicl::Name{ "multicast_interface_ip" }, fhicl::Comment{ "Use this hostname for multicast (to assign to the proper NIC)" }, "0.0.0.0" };
34  fhicl::Atom<size_t> end_of_run_timeout_ms{ fhicl::Name{"end_of_run_quiet_timeout_ms"}, fhicl::Comment{"Amount of time (in ms) to wait for no new requests when a Stop transition is pending"}, 1000 };
36  fhicl::Atom<artdaq::Fragment::sequence_id_t> request_increment{ fhicl::Name{"request_increment"}, fhicl::Comment{"Expected increment of sequence ID between each request"}, 1 };
37  };
38  using Parameters = fhicl::WrappedTable<Config>;
39 
44 
49  RequestReceiver(const fhicl::ParameterSet& ps);
50  virtual ~RequestReceiver();
51 
55  void setupRequestListener();
56 
61  void stopRequestReceiverThread(bool force = false);
62 
67 
71  void receiveRequestsLoop();
72 
77  std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetRequests() const
78  {
79  std::unique_lock<std::mutex> lk(request_mutex_);
80  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
81  for (auto& in : requests_)
82  {
83  out[in.first] = in.second;
84  }
85  return out;
86  }
87 
92  void RemoveRequest(artdaq::Fragment::sequence_id_t reqID);
93 
98  bool isRunning() { return running_; }
99 
104  {
105  std::unique_lock<std::mutex> lk(request_mutex_);
106  requests_.clear();
107  }
108 
113  std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetAndClearRequests()
114  {
115  std::unique_lock<std::mutex> lk(request_mutex_);
116  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
117  for (auto& in : requests_)
118  {
119  out[in.first] = in.second;
120  }
121  requests_.clear();
122  return out;
123  }
124 
129  size_t size() {
130  std::unique_lock<std::mutex> tlk(request_mutex_);
131  return requests_.size();
132  }
133 
139  bool WaitForRequests(int timeout_ms)
140  {
141  std::unique_lock<std::mutex> lk(request_mutex_); // Lock needed by wait_for
142  // See if we have to wait at all
143  if (requests_.size() > 0) return true;
144  // If we do have to wait, check requests_.size to make sure we're not being notified spuriously
145  return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
146  }
147 
153  std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
154  {
155  std::unique_lock<std::mutex> lk(request_mutex_);
156  return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
157  }
158  private:
159  // FHiCL-configurable variables. Note that the C++ variable names
160  // are the FHiCL variable names with a "_" appended
161  int request_port_;
162  std::string request_addr_;
163  std::string multicast_out_addr_;
164  bool running_;
165 
166  //Socket parameters
167  int request_socket_;
168  std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> requests_;
169  std::map<artdaq::Fragment::sequence_id_t, std::chrono::steady_clock::time_point> request_timing_;
170  std::atomic<bool> request_stop_requested_;
171  std::chrono::steady_clock::time_point request_stop_timeout_;
172  std::atomic<bool> request_received_;
173  size_t end_of_run_timeout_ms_;
174  std::atomic<bool> should_stop_;
175  mutable std::mutex request_mutex_;
176  mutable std::mutex state_mutex_;
177  std::condition_variable request_cv_;
178  boost::thread requestThread_;
179 
180  std::atomic<artdaq::Fragment::sequence_id_t> highest_seen_request_;
181  std::set<artdaq::Fragment::sequence_id_t> out_of_order_requests_;
182  artdaq::Fragment::sequence_id_t request_increment_;
183  };
184 }
185 
186 
187 #endif //ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
fhicl::Atom< size_t > end_of_run_timeout_ms
&quot;end_of_run_quiet_timeout_ms&quot; (Default: 1000) : Time, in milliseconds, that the entire system must be...
std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
Get the time a given request was received
void startRequestReceiverThread()
Function that launches the data request receiver thread (receiveRequestsLoop())
size_t size()
Get the number of requests currently stored in the RequestReceiver
fhicl::Atom< std::string > request_addr
&quot;request_address&quot; (Default: &quot;227.128.12.26&quot;) : Address which CommandableFragmentGenerator will listen...
fhicl::Atom< std::string > output_address
&quot;multicast_interface_ip&quot; (Default: &quot;0.0.0.0&quot;) : Use this hostname for multicast(to assign to the prop...
RequestReceiver()
RequestReceiver Default Constructor.
bool isRunning()
Determine if the RequestReceiver is receiving requests
void stopRequestReceiverThread(bool force=false)
Stop the data request receiver thread (receiveRequestsLoop)
void setupRequestListener()
Opens the socket used to listen for data requests.
void receiveRequestsLoop()
This function receives data request packets, adding new requests to the request list.
Receive data requests and make them available to CommandableFragmentGenerator or other interested par...
std::map< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetAndClearRequests()
Get the current requests, then clear the map
void ClearRequests()
Clear all requests from the map
bool WaitForRequests(int timeout_ms)
Wait for a new request message, up to the timeout given
fhicl::Atom< int > request_port
&quot;request_port&quot; (Default: 3001) : Port on which data requests will be received
void RemoveRequest(artdaq::Fragment::sequence_id_t reqID)
Remove the request with the given sequence ID from the request map
fhicl::Atom< artdaq::Fragment::sequence_id_t > request_increment
&quot;request_increment&quot; (Default: 1) : Expected increment of sequence ID between each request ...
std::map< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetRequests() const
Get the current requests
Configuration of the RequestReceiver. May be used for parameter validation