00001 #ifndef ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
00002 #define ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH
00003
00004 #include <boost/thread.hpp>
00005 #include "artdaq-core/Data/Fragment.hh"
00006 #include "fhiclcpp/ParameterSet.h"
00007 #include "fhiclcpp/types/Atom.h"
00008 #include "fhiclcpp/types/ConfigurationTable.h"
00009
00010 #include <mutex>
00011 #include <condition_variable>
00012
00013 namespace artdaq
00014 {
00018 class RequestReceiver
00019 {
00020 public:
00021
00025 struct Config
00026 {
00028 fhicl::Atom<int> request_port{ fhicl::Name{"request_port"}, fhicl::Comment{"Port to listen for request messages on"}, 3001 };
00030 fhicl::Atom<std::string> request_addr{ fhicl::Name{"request_address"}, fhicl::Comment{"Multicast address to listen for request messages on"}, "227.128.12.26" };
00032 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" };
00034 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 };
00036 fhicl::Atom<artdaq::Fragment::sequence_id_t> request_increment{ fhicl::Name{"request_increment"}, fhicl::Comment{"Expected increment of sequence ID between each request"}, 1 };
00037 };
00038 using Parameters = fhicl::WrappedTable<Config>;
00039
00043 RequestReceiver();
00044
00049 RequestReceiver(const fhicl::ParameterSet& ps);
00050 virtual ~RequestReceiver();
00051
00055 void setupRequestListener();
00056
00061 void stopRequestReceiverThread(bool force = false);
00062
00066 void startRequestReceiverThread();
00067
00071 void receiveRequestsLoop();
00072
00077 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetRequests() const
00078 {
00079 std::unique_lock<std::mutex> lk(request_mutex_);
00080 std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
00081 for (auto& in : requests_)
00082 {
00083 out[in.first] = in.second;
00084 }
00085 return out;
00086 }
00087
00092 void RemoveRequest(artdaq::Fragment::sequence_id_t reqID);
00093
00098 bool isRunning() { return running_; }
00099
00103 void ClearRequests()
00104 {
00105 std::unique_lock<std::mutex> lk(request_mutex_);
00106 requests_.clear();
00107 }
00108
00113 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> GetAndClearRequests()
00114 {
00115 std::unique_lock<std::mutex> lk(request_mutex_);
00116 std::map<artdaq::Fragment::sequence_id_t, Fragment::timestamp_t> out;
00117 for (auto& in : requests_)
00118 {
00119 out[in.first] = in.second;
00120 }
00121 requests_.clear();
00122 return out;
00123 }
00124
00129 size_t size() {
00130 std::unique_lock<std::mutex> tlk(request_mutex_);
00131 return requests_.size();
00132 }
00133
00139 bool WaitForRequests(int timeout_ms)
00140 {
00141 std::unique_lock<std::mutex> lk(request_mutex_);
00142
00143 if (requests_.size() > 0) return true;
00144
00145 return request_cv_.wait_for(lk, std::chrono::milliseconds(timeout_ms), [this]() { return requests_.size() > 0; });
00146 }
00147
00153 std::chrono::steady_clock::time_point GetRequestTime(artdaq::Fragment::sequence_id_t reqID)
00154 {
00155 std::unique_lock<std::mutex> lk(request_mutex_);
00156 return request_timing_.count(reqID) ? request_timing_[reqID] : std::chrono::steady_clock::now();
00157 }
00158 private:
00159
00160
00161 int request_port_;
00162 std::string request_addr_;
00163 std::string multicast_out_addr_;
00164 bool running_;
00165
00166
00167 int request_socket_;
00168 std::map<artdaq::Fragment::sequence_id_t, artdaq::Fragment::timestamp_t> requests_;
00169 std::map<artdaq::Fragment::sequence_id_t, std::chrono::steady_clock::time_point> request_timing_;
00170 std::atomic<bool> request_stop_requested_;
00171 std::chrono::steady_clock::time_point request_stop_timeout_;
00172 std::atomic<bool> request_received_;
00173 size_t end_of_run_timeout_ms_;
00174 std::atomic<bool> should_stop_;
00175 mutable std::mutex request_mutex_;
00176 mutable std::mutex state_mutex_;
00177 std::condition_variable request_cv_;
00178 boost::thread requestThread_;
00179
00180 std::atomic<artdaq::Fragment::sequence_id_t> highest_seen_request_;
00181 std::set<artdaq::Fragment::sequence_id_t> out_of_order_requests_;
00182 artdaq::Fragment::sequence_id_t request_increment_;
00183 };
00184 }
00185
00186
00187 #endif //ARTDAQ_DAQRATE_REQUEST_RECEVIER_HH