artdaq  v3_12_02
CommandableFragmentGenerator.hh
1 #ifndef artdaq_Application_CommandableFragmentGenerator_hh
2 #define artdaq_Application_CommandableFragmentGenerator_hh
3 
4 #include "fhiclcpp/types/Sequence.h" // Must pre-empt fhiclcpp/types/Atom.h
5 
6 #include "TRACE/tracemf.h" // Pre-empt TRACE/trace.h from Fragment.hh.
7 #include "artdaq-core/Data/Fragment.hh"
8 
9 #include "artdaq-core/Plugins/FragmentGenerator.hh"
10 #include "artdaq/DAQrate/FragmentBuffer.hh"
11 #include "artdaq/DAQrate/RequestBuffer.hh"
12 
13 #include "fhiclcpp/types/Atom.h"
14 #include "fhiclcpp/types/Comment.h"
15 #include "fhiclcpp/types/ConfigurationTable.h"
16 #include "fhiclcpp/types/Name.h"
17 namespace fhicl {
18 class ParameterSet;
19 }
20 
21 #include <boost/thread.hpp>
22 
23 #include <array>
24 #include <atomic>
25 #include <chrono>
26 #include <condition_variable>
27 #include <list>
28 #include <memory>
29 #include <mutex>
30 #include <queue>
31 
32 // Socket Includes
33 #include <arpa/inet.h>
34 #include <netinet/in.h>
35 #include <sys/socket.h>
36 #include <sys/types.h>
37 #include <unistd.h>
38 
39 namespace artdaq {
40 
83 class CommandableFragmentGenerator : public FragmentGenerator
84 {
85 public:
89  struct Config
90  {
92  fhicl::Atom<std::string> generator_type{fhicl::Name{"generator"}, fhicl::Comment{"Name of the CommandableFragmentGenerator plugin to load"}};
94  fhicl::Atom<Fragment::type_t> expected_fragment_type{fhicl::Name{"expected_fragment_type"}, fhicl::Comment{"The type of Fragments this CFG will be generating. \"Empty\" will auto-detect type based on Fragments generated."}, Fragment::type_t(Fragment::EmptyFragmentType)};
96  fhicl::Atom<size_t> sleep_on_no_data_us{fhicl::Name{"sleep_on_no_data_us"}, fhicl::Comment{"How long to sleep after calling getNext_ if no data is returned"}, 0};
98  fhicl::Atom<bool> separate_monitoring_thread{fhicl::Name{"separate_monitoring_thread"}, fhicl::Comment{"Whether a thread that calls the checkHWStatus_ method should be created"}, false};
100  fhicl::Atom<int64_t> hardware_poll_interval_us{fhicl::Name{"hardware_poll_interval_us"}, fhicl::Comment{"If a separate monitoring thread is used, how often should it call checkHWStatus_"}, 0};
102  fhicl::Atom<int> board_id{fhicl::Name{"board_id"}, fhicl::Comment{"The identification number for this CommandableFragmentGenerator"}};
105  fhicl::Sequence<Fragment::fragment_id_t> fragment_ids{fhicl::Name("fragment_ids"), fhicl::Comment("A list of Fragment IDs created by this CommandableFragmentGenerator")};
108  fhicl::Atom<int> fragment_id{fhicl::Name{"fragment_id"}, fhicl::Comment{"The Fragment ID created by this CommandableFragmentGenerator"}, -99};
110  fhicl::Atom<int> sleep_on_stop_us{fhicl::Name{"sleep_on_stop_us"}, fhicl::Comment{"How long to sleep before returning when stop transition is called"}, 0};
111  };
113  using Parameters = fhicl::WrappedTable<Config>;
114 
119  explicit CommandableFragmentGenerator(const fhicl::ParameterSet& ps);
120 
127 
134  void joinThreads();
135 
141  bool getNext(FragmentPtrs& output) override final;
142 
146  void startMonitoringThread();
147 
151  void getMonitoringDataLoop();
152 
157  std::vector<Fragment::fragment_id_t> fragmentIDs() override
158  {
159  std::vector<Fragment::fragment_id_t> output;
160 
161  for (auto& id : expectedTypes_)
162  {
163  output.push_back(id.first);
164  }
165 
166  return output;
167  }
168 
173  size_t ev_counter() const { return ev_counter_.load(); }
174 
175  //
176  // State-machine related interface below.
177  //
178 
193  void StartCmd(int run, uint64_t timeout, uint64_t timestamp);
194 
204  void StopCmd(uint64_t timeout, uint64_t timestamp);
205 
215  void PauseCmd(uint64_t timeout, uint64_t timestamp);
216 
225  void ResumeCmd(uint64_t timeout, uint64_t timestamp);
226 
237  std::string ReportCmd(std::string const& which = "");
238 
243  virtual std::string metricsReportingInstanceName() const
244  {
245  return instance_name_for_metrics_;
246  }
247 
248  // The following functions are not yet implemented, and their
249  // signatures may be subject to change.
250 
251  // John F., 12/6/13 -- do we want Reset and Shutdown commands?
252  // Kurt B., 15-Feb-2014. For the moment, I suspect that we don't
253  // want a Shutdown command. FragmentGenerator instances are
254  // Constructed at Initialization time, and they are destructed
255  // at Shutdown time. So, any shutdown operations that need to be
256  // done should be put in the FragmentGenerator child class
257  // destructors. If we find that want shutdown (or initialization)
258  // operations that are different from destruction (construction),
259  // then we'll have to add InitCmd and ShutdownCmd methods.
260 
261  // virtual void ResetCmd() final {}
262  // virtual void ShutdownCmd() final {}
263 
268  bool exception() const { return exception_.load(); }
269 
276  virtual bool metaCommand(std::string const& command, std::string const& arg);
277 
282  void SetRequestBuffer(std::shared_ptr<RequestBuffer> buffer) { requestBuffer_ = buffer; }
283 
284  void SetFragmentBuffer(std::shared_ptr<FragmentBuffer> buffer) { fragmentBuffer_ = buffer; }
285 
286 protected:
287  // John F., 12/6/13 -- need to figure out which of these getter
288  // functions should be promoted to "public"
289 
290  // John F., 1/21/15 -- after more than a year, there hasn't been a
291  // single complaint that a CommandableFragmentGenerator-derived
292  // class hasn't allowed its users to access these quantities, so
293  // they're probably fine as is
294 
299  int run_number() const { return run_number_; }
304  int subrun_number() const { return subrun_number_; }
309  uint64_t timeout() const { return timeout_; }
314  uint64_t timestamp() const { return timestamp_; }
315 
321  artdaq::Fragment::fragment_id_t fragment_id() const
322  {
323  if (expectedTypes_.size() > 1) throw cet::exception("FragmentID") << "fragment_id() was called, indicating that Fragment Generator was expecting one and only one Fragment ID, but " << expectedTypes_.size() << " were declared!"; // NOLINT(cert-err60-cpp)
324  return (*expectedTypes_.begin()).first;
325  }
326 
331  bool should_stop() const { return should_stop_.load(); }
332 
337  bool check_stop();
338 
343  int board_id() const { return board_id_; }
344 
350  size_t ev_counter_inc(size_t step = 1); // returns the prev value
351 
356  void set_exception(bool exception) { exception_.store(exception); }
357 
362  void metricsReportingInstanceName(std::string const& name)
363  {
364  instance_name_for_metrics_ = name;
365  }
366 
367  // John F., 12/10/13
368  // Is there a better way to handle mutex_ than leaving it a protected variable?
369 
370  // John F., 1/21/15
371  // Translation above is "should mutex_ be a private variable,
372  // accessible via a getter function". Probably, but at this point
373  // it's not worth breaking code by implementing this.
374 
375  std::mutex mutex_;
376 
381  std::shared_ptr<RequestBuffer> GetRequestBuffer() { return requestBuffer_; }
382 
383  std::shared_ptr<FragmentBuffer> GetFragmentBuffer() { return fragmentBuffer_; }
384 
385 private:
390 
391  // FHiCL-configurable variables. Note that the C++ variable names
392  // are the FHiCL variable names with a "_" appended
393 
394  // Socket parameters
395 
396  std::map<Fragment::fragment_id_t, Fragment::type_t> expectedTypes_;
397 
398  bool useMonitoringThread_;
399  boost::thread monitoringThread_;
400  int64_t monitoringInterval_; // Microseconds
401  std::chrono::steady_clock::time_point lastMonitoringCall_;
402  std::atomic<bool> isHardwareOK_;
403 
404  // In order to support the state-machine related behavior, all
405  // CommandableFragmentGenerators must be able to remember a run number and a
406  // subrun number.
407  int run_number_, subrun_number_;
408 
409  // JCF, 8/28/14
410 
411  // Provide a user-adjustable timeout for the start transition
412  uint64_t timeout_;
413 
414  // JCF, 8/21/14
415 
416  // In response to a need to synchronize various components using
417  // different fragment generators in an experiment, keep a record
418  // of a timestamp (see Redmine Issue #6783 for more)
419 
420  uint64_t timestamp_;
421 
422  std::atomic<bool> should_stop_, exception_;
423  std::string latest_exception_report_;
424  std::atomic<size_t> ev_counter_;
425 
426  int board_id_;
427  std::string instance_name_for_metrics_;
428 
429  // Depending on what sleep_on_stop_us_ is set to, this gives the
430  // stopping thread the chance to gather the required lock
431 
432  int sleep_on_stop_us_;
433 
434  // So that derived classes can access information about requests
435  std::shared_ptr<RequestBuffer> requestBuffer_;
436  std::shared_ptr<FragmentBuffer> fragmentBuffer_;
437 
438 protected:
446  virtual bool getNext_(FragmentPtrs& output) = 0;
447 
454  virtual bool checkHWStatus_();
455 
456  //
457  // State-machine related implementor interface below.
458  //
459 
470  virtual void start() = 0;
471 
478  virtual void stopNoMutex() = 0;
479 
488  virtual void stop() = 0;
489 
494  virtual void pauseNoMutex();
495 
501  virtual void pause();
502 
506  virtual void resume();
507 
519  virtual std::string report();
520 
526  virtual std::string reportSpecific(std::string const& what);
527 };
528 } // namespace artdaq
529 
530 #endif /* artdaq_Application_CommandableFragmentGenerator_hh */
fhicl::Atom< Fragment::type_t > expected_fragment_type
&quot;expected_fragment_type&quot; (Default: 231, EmptyFragmentType) : The type of Fragments this CFG will be g...
fhicl::Atom< int > board_id
&quot;board_id&quot; (REQUIRED) : The identification number for this CommandableFragmentGenerator ...
CommandableFragmentGenerator(const fhicl::ParameterSet &ps)
CommandableFragmentGenerator Constructor.
int subrun_number() const
Get the current Subrun number.
virtual void start()=0
If a CommandableFragmentGenerator subclass is reading from a file, and start() is called...
fhicl::Atom< int64_t > hardware_poll_interval_us
&quot;hardware_poll_interval_us&quot; (Default: 0) : If a separate monitoring thread is used, how often should it call checkHWStatus_
virtual bool checkHWStatus_()
Check any relavent hardware status registers. Return false if an error condition exists that should h...
virtual ~CommandableFragmentGenerator()
CommandableFragmentGenerator Destructor.
bool exception() const
Get the current value of the exception flag.
void metricsReportingInstanceName(std::string const &name)
Sets the name for metrics reporting.
std::mutex mutex_
Mutex used to ensure that multiple transition commands do not run at the same time.
void getMonitoringDataLoop()
This function regularly calls checkHWStatus_(), and sets the isHardwareOK flag accordingly.
artdaq::Fragment::fragment_id_t fragment_id() const
Get the Fragment ID of this Fragment generator.
std::string ReportCmd(std::string const &which="")
Get a report about a user-specified run-time quantity.
virtual bool metaCommand(std::string const &command, std::string const &arg)
The meta-command is used for implementing user-specific commands in a CommandableFragmentGenerator.
void StopCmd(uint64_t timeout, uint64_t timestamp)
Stop the CommandableFragmentGenerator.
uint64_t timeout() const
Timeout of last command.
void StartCmd(int run, uint64_t timeout, uint64_t timestamp)
Start the CommandableFragmentGenerator.
virtual void pauseNoMutex()
On call to PauseCmd, pauseNoMutex() is called prior to PauseCmd acquiring the mutex ...
bool check_stop()
Routine used by applyRequests to make sure that all outstanding requests have been fulfilled before r...
void ResumeCmd(uint64_t timeout, uint64_t timestamp)
Resume the CommandableFragmentGenerator.
bool getNext(FragmentPtrs &output) overridefinal
getNext calls either applyRequests or getNext_ to get any data that is ready to be sent to the EventB...
std::vector< Fragment::fragment_id_t > fragmentIDs() override
Get the list of Fragment IDs handled by this CommandableFragmentGenerator.
fhicl::Atom< int > sleep_on_stop_us
&quot;sleep_on_stop_us&quot; (Default: 0) : How long to sleep before returning when stop transition is called ...
void PauseCmd(uint64_t timeout, uint64_t timestamp)
Pause the CommandableFragmentGenerator.
fhicl::Sequence< Fragment::fragment_id_t > fragment_ids
virtual std::string metricsReportingInstanceName() const
Get the name used when reporting metrics.
bool should_stop() const
Get the current value of the should_stop flag.
CommandableFragmentGenerator is a FragmentGenerator-derived abstract class that defines the interface...
fhicl::WrappedTable< Config > Parameters
Used for ParameterSet validation (if desired)
virtual bool getNext_(FragmentPtrs &output)=0
Obtain the next group of Fragments, if any are available. Return false if readout cannot continue...
void startMonitoringThread()
Function that launches the monitoring thread (getMonitoringDataLoop())
virtual void pause()
If a CommandableFragmentGenerator subclass is reading from hardware, the implementation of pause() sh...
virtual void resume()
The subrun number will be incremented before a call to resume.
size_t ev_counter() const
Get the current value of the event counter.
fhicl::Atom< size_t > sleep_on_no_data_us
&quot;sleep_on_no_data_us&quot; (Default: 0 (no sleep)) : How long to sleep after calling getNext_ if no data i...
virtual std::string report()
Let&#39;s say that the contract with the report() functions is that they return a non-empty string if the...
virtual void stopNoMutex()=0
On call to StopCmd, stopNoMutex() is called prior to StopCmd acquiring the mutex
int board_id() const
Gets the current board_id.
std::shared_ptr< RequestBuffer > GetRequestBuffer()
Get the shared_ptr to the RequestBuffer.
void SetRequestBuffer(std::shared_ptr< RequestBuffer > buffer)
Set the shared_ptr to the RequestBuffer.
void set_exception(bool exception)
Control the exception flag.
uint64_t timestamp() const
Timestamp of last command.
Configuration of the CommandableFragmentGenerator. May be used for parameter validation ...
fhicl::Atom< std::string > generator_type
&quot;generator&quot; (REQUIRED) Name of the CommandableFragmentGenerator plugin to load
size_t ev_counter_inc(size_t step=1)
Increment the event counter.
virtual void stop()=0
If a CommandableFragmentGenerator subclass is reading from a file, calling stop() should arrange that...
virtual std::string reportSpecific(std::string const &what)
Report the status of a specific quantity
int run_number() const
Get the current Run number.
fhicl::Atom< bool > separate_monitoring_thread
&quot;separate_monitoring_thread&quot; (Default: false) : Whether a thread that calls the checkHWStatus_ method...
void joinThreads()
Join any data-taking threads. Should be called when destructing CommandableFragmentGenerator.