artdaq  v3_07_01
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 <condition_variable>
11 #include <mutex>
12 
13 namespace artdaq {
18 {
19 public:
23  struct Config
24  {
26  fhicl::Atom<int> request_port{fhicl::Name{"request_port"}, fhicl::Comment{"Port to listen for request messages on"}, 3001};
28  fhicl::Atom<std::string> request_addr{fhicl::Name{"request_address"}, fhicl::Comment{"Multicast address to listen for request messages on"}, "227.128.12.26"};
30  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"};
32  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};
34  fhicl::Atom<artdaq::Fragment::sequence_id_t> request_increment{fhicl::Name{"request_increment"}, fhicl::Comment{"Expected increment of sequence ID between each request"}, 1};
35  };
37  using Parameters = fhicl::WrappedTable<Config>;
38 
43 
48  RequestReceiver(const fhicl::ParameterSet& ps);
49  virtual ~RequestReceiver();
50 
54  void setupRequestListener();
55 
60  void stopRequestReception(bool force = false);
61 
65  void startRequestReception();
66 
70  void receiveRequestsLoop();
71 
76  std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetRequests() const
77  {
78  std::unique_lock<std::mutex> lk(request_mutex_);
79  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
80  for (auto& in : requests_)
81  {
82  out[in.first] = in.second;
83  }
84  return out;
85  }
86 
93  std::pair<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetNextRequest();
94 
99  void RemoveRequest(artdaq::Fragment::sequence_id_t reqID);
100 
105  bool isRunning() { return running_; }
106 
111  {
112  std::unique_lock<std::mutex> lk(request_mutex_);
113  requests_.clear();
114  }
115 
120  std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetAndClearRequests()
121  {
122  std::unique_lock<std::mutex> lk(request_mutex_);
123  std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
124  for (auto& in : requests_)
125  {
126  out[in.first] = in.second;
127  }
128  if (requests_.size()) { highest_seen_request_ = requests_.rbegin()->first; }
129  out_of_order_requests_.clear();
130  requests_.clear();
131  request_timing_.clear();
132  return out;
133  }
134 
139  size_t size()
140  {
141  std::unique_lock<std::mutex> tlk(request_mutex_);
142  return requests_.size();
143  }
144 
150  bool WaitForRequests(int timeout_ms)
151  {
152  std::unique_lock<std::mutex> lk(request_mutex_); // Lock needed by wait_for
153  // See if we have to wait at all
154  if (requests_.size() > 0) return true;
155  // If we do have to wait, check requests_.size to make sure we're not being notified spuriously
156  return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
157  }
158 
164  std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
165  {
166  std::unique_lock<std::mutex> lk(request_mutex_);
167  return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
168  }
169 
174  void SetRunNumber(uint32_t run) { run_number_ = run; }
175 
176 private:
177  // FHiCL-configurable variables. Note that the C++ variable names
178  // are the FHiCL variable names with a "_" appended
179  int request_port_;
180  std::string request_addr_;
181  std::string multicast_in_addr_;
182  bool running_;
183  uint32_t run_number_;
184 
185  //Socket parameters
186  int request_socket_;
187  std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> requests_;
188  std::map<artdaq::Fragment::sequence_id_t, std::chrono::steady_clock::time_point> request_timing_;
189  std::atomic<bool> request_stop_requested_;
190  std::chrono::steady_clock::time_point request_stop_timeout_;
191  std::atomic<bool> request_received_;
192  size_t end_of_run_timeout_ms_;
193  std::atomic<bool> should_stop_;
194  mutable std::mutex request_mutex_;
195  mutable std::mutex state_mutex_;
196  std::condition_variable request_cv_;
197  boost::thread requestThread_;
198 
199  std::atomic<artdaq::Fragment::sequence_id_t> highest_seen_request_;
200  std::atomic<artdaq::Fragment::sequence_id_t> last_next_request_; // The last request returned by GetNextRequest
201  std::set<artdaq::Fragment::sequence_id_t> out_of_order_requests_;
202  artdaq::Fragment::sequence_id_t request_increment_;
203 };
204 } // namespace artdaq
205 
206 #endif //ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
void startRequestReception()
Enables (starts) the reception of data requests.
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
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...
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
RequestReceiver()
RequestReceiver Default Constructor.
bool isRunning()
Determine if the RequestReceiver is receiving requests
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::pair< artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t > GetNextRequest()
Get the &quot;next&quot; request, i.e. the first unsatisfied request that has not already been returned by GetN...
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
void SetRunNumber(uint32_t run)
Sets the current run number
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 stopRequestReception(bool force=false)
Disables (stops) the reception of data requests.
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