artdaq  v3_09_06a
BoardReaderApp.cc
1 #include "artdaq/Application/BoardReaderApp.hh"
2 #include "artdaq-core/Utilities/ExceptionHandler.hh"
3 
4 #include "artdaq/DAQdata/Globals.hh"
5 #define TRACE_NAME (app_name + "_BoardReaderApp").c_str() // NOLINT
6 
7 #include <memory>
8 #include <string>
9 
11  : fragment_receiver_ptr_(nullptr)
12 {
13 }
14 
15 // *******************************************************************
16 // *** The following methods implement the state machine operations.
17 // *******************************************************************
18 
19 bool artdaq::BoardReaderApp::do_initialize(fhicl::ParameterSet const& pset, uint64_t timeout, uint64_t timestamp)
20 {
21  report_string_ = "";
22  external_request_status_ = true;
23 
24  // in the following block, we first destroy the existing BoardReader
25  // instance, then create a new one. Doing it in one step does not
26  // produce the desired result since that creates a new instance and
27  // then deletes the old one, and we need the opposite order.
28  TLOG(TLVL_DEBUG) << "Initializing first deleting old instance " << static_cast<void*>(fragment_receiver_ptr_.get());
29  fragment_receiver_ptr_.reset(nullptr);
30  fragment_receiver_ptr_ = std::make_unique<BoardReaderCore>(*this);
31  TLOG(TLVL_DEBUG) << "Initializing new BoardReaderCore at " << static_cast<void*>(fragment_receiver_ptr_.get()) << " with pset " << pset.to_string();
32  external_request_status_ = fragment_receiver_ptr_->initialize(pset, timeout, timestamp);
33  if (!external_request_status_)
34  {
35  report_string_ = "Error initializing ";
36  report_string_.append(app_name + " ");
37  report_string_.append("with ParameterSet = \"" + pset.to_string() + "\".");
38  }
39 
40  TLOG(TLVL_DEBUG) << "do_initialize(fhicl::ParameterSet, uint64_t, uint64_t): "
41  << "Done initializing.";
42  return external_request_status_;
43 }
44 
45 bool artdaq::BoardReaderApp::do_start(art::RunID id, uint64_t timeout, uint64_t timestamp)
46 {
47  report_string_ = "";
48  if (timeout == 0)
49  {
50  timeout = 3600; // seconds
51  }
52  fragment_receiver_ptr_->SetStartTransitionTimeout(timeout);
53  external_request_status_ = true;
54 
55  boost::thread::attributes attrs;
56  attrs.set_stack_size(4096 * 2000); // 8 MB
57  try
58  {
59  fragment_output_thread_ = boost::thread(attrs, boost::bind(&BoardReaderCore::send_fragments, fragment_receiver_ptr_.get()));
60  char tname[16]; // Size 16 - see man page pthread_setname_np(3) and/or prctl(2)
61  snprintf(tname, sizeof(tname) - 1, "%d-FragOutput", my_rank); // NOLINT
62  tname[sizeof(tname) - 1] = '\0'; // assure term. snprintf is not too evil :)
63  auto handle = fragment_output_thread_.native_handle();
64  pthread_setname_np(handle, tname);
65  fragment_input_thread_ = boost::thread(attrs, boost::bind(&BoardReaderCore::receive_fragments, fragment_receiver_ptr_.get()));
66  snprintf(tname, sizeof(tname) - 1, "%d-FragInput", my_rank); // NOLINT
67  tname[sizeof(tname) - 1] = '\0'; // assure term. snprintf is not too evil :)
68  handle = fragment_input_thread_.native_handle();
69  pthread_setname_np(handle, tname);
70  }
71  catch (const boost::exception& e)
72  {
73  std::stringstream exception_string;
74  exception_string << "Caught boost::exception starting Fragment Processing threads: " << boost::diagnostic_information(e) << ", errno=" << errno;
75 
76  ExceptionHandler(ExceptionHandlerRethrow::yes, exception_string.str());
77  }
78 
79  auto start_wait = std::chrono::steady_clock::now();
80  while (!fragment_receiver_ptr_->GetSenderThreadActive() || !fragment_receiver_ptr_->GetReceiverThreadActive())
81  {
82  if (TimeUtils::GetElapsedTime(start_wait) > timeout)
83  {
84  TLOG(TLVL_ERROR) << "Timeout occurred waiting for BoardReaderCore threads to start. Timeout = " << timeout << " s, Time waited = " << TimeUtils::GetElapsedTime(start_wait) << " s,"
85  << " Receiver ready: " << std::boolalpha << fragment_receiver_ptr_->GetReceiverThreadActive() << ", Sender ready: " << fragment_receiver_ptr_->GetSenderThreadActive();
86  external_request_status_ = false;
87  break;
88  }
89  usleep(10000);
90  }
91 
92  // Only if starting threads successful
93  if (external_request_status_)
94  {
95  external_request_status_ = fragment_receiver_ptr_->start(id, timeout, timestamp);
96  }
97 
98  if (!external_request_status_)
99  {
100  report_string_ = "Error starting ";
101  report_string_.append(app_name + " ");
102  report_string_.append("for run number ");
103  report_string_.append(boost::lexical_cast<std::string>(id.run()));
104  report_string_.append(", timeout ");
105  report_string_.append(boost::lexical_cast<std::string>(timeout));
106  report_string_.append(", timestamp ");
107  report_string_.append(boost::lexical_cast<std::string>(timestamp));
108  report_string_.append(".");
109  }
110 
111  return external_request_status_;
112 }
113 
114 bool artdaq::BoardReaderApp::do_stop(uint64_t timeout, uint64_t timestamp)
115 {
116  report_string_ = "";
117  external_request_status_ = fragment_receiver_ptr_->stop(timeout, timestamp);
118  if (!external_request_status_)
119  {
120  report_string_ = "Error stopping ";
121  report_string_.append(app_name + ".");
122  return false;
123  }
124  if (fragment_input_thread_.joinable())
125  {
126  TLOG(TLVL_DEBUG) << "Joining fragment input (Generator) thread";
127  fragment_input_thread_.join();
128  }
129  if (fragment_output_thread_.joinable())
130  {
131  TLOG(TLVL_DEBUG) << "Joining fragment output (Sender) thread";
132  fragment_output_thread_.join();
133  }
134 
135  TLOG(TLVL_DEBUG) << "BoardReader Stopped. Getting run statistics";
136  int number_of_fragments_sent = -1;
137  if (fragment_receiver_ptr_)
138  {
139  number_of_fragments_sent = fragment_receiver_ptr_->GetFragmentsProcessed();
140  }
141  TLOG(TLVL_DEBUG) << "do_stop(uint64_t, uint64_t): "
142  << "Number of fragments sent = " << number_of_fragments_sent
143  << ".";
144 
145  return external_request_status_;
146 }
147 
148 bool artdaq::BoardReaderApp::do_pause(uint64_t timeout, uint64_t timestamp)
149 {
150  report_string_ = "";
151  external_request_status_ = fragment_receiver_ptr_->pause(timeout, timestamp);
152  if (!external_request_status_)
153  {
154  report_string_ = "Error pausing ";
155  report_string_.append(app_name + ".");
156  }
157 
158  if (fragment_input_thread_.joinable()) fragment_input_thread_.join();
159  if (fragment_output_thread_.joinable()) fragment_output_thread_.join();
160  int number_of_fragments_sent = fragment_receiver_ptr_->GetFragmentsProcessed();
161  TLOG(TLVL_DEBUG) << "do_pause(uint64_t, uint64_t): "
162  << "Number of fragments sent = " << number_of_fragments_sent
163  << ".";
164 
165  return external_request_status_;
166 }
167 
168 bool artdaq::BoardReaderApp::do_resume(uint64_t timeout, uint64_t timestamp)
169 {
170  report_string_ = "";
171  if (timeout == 0)
172  {
173  timeout = 3600; // seconds
174  }
175  external_request_status_ = true;
176 
177  boost::thread::attributes attrs;
178  attrs.set_stack_size(4096 * 2000); // 8 MB
179  try
180  {
181  fragment_output_thread_ = boost::thread(attrs, boost::bind(&BoardReaderCore::send_fragments, fragment_receiver_ptr_.get()));
182  char tname[16]; // Size 16 - see man page pthread_setname_np(3) and/or prctl(2)
183  snprintf(tname, sizeof(tname) - 1, "%d-FragOutput", my_rank); // NOLINT
184  tname[sizeof(tname) - 1] = '\0'; // assure term. snprintf is not too evil :)
185  auto handle = fragment_output_thread_.native_handle();
186  pthread_setname_np(handle, tname);
187  fragment_input_thread_ = boost::thread(attrs, boost::bind(&BoardReaderCore::receive_fragments, fragment_receiver_ptr_.get()));
188 
189  snprintf(tname, sizeof(tname) - 1, "%d-FragInput", my_rank); // NOLINT
190  tname[sizeof(tname) - 1] = '\0'; // assure term. snprintf is not too evil :)
191  handle = fragment_input_thread_.native_handle();
192  pthread_setname_np(handle, tname);
193  }
194  catch (const boost::exception& e)
195  {
196  std::stringstream exception_string;
197  exception_string << "Caught boost::exception starting Fragment Processing threads: " << boost::diagnostic_information(e) << ", errno=" << errno;
198 
199  ExceptionHandler(ExceptionHandlerRethrow::yes, exception_string.str());
200  }
201 
202  auto start_wait = std::chrono::steady_clock::now();
203  while (!fragment_receiver_ptr_->GetSenderThreadActive() || !fragment_receiver_ptr_->GetReceiverThreadActive())
204  {
205  if (TimeUtils::GetElapsedTimeMicroseconds(start_wait) > timeout * 1000000)
206  {
207  TLOG(TLVL_ERROR) << "Timeout occurred waiting for BoardReaderCore threads to start. Timeout = " << timeout << " s, Time waited = " << TimeUtils::GetElapsedTime(start_wait) << " s,"
208  << " Receiver ready: " << std::boolalpha << fragment_receiver_ptr_->GetReceiverThreadActive() << ", Sender ready: " << fragment_receiver_ptr_->GetSenderThreadActive();
209  external_request_status_ = false;
210  break;
211  }
212  usleep(10000);
213  }
214 
215  // Only if starting threads successful
216  if (external_request_status_)
217  {
218  external_request_status_ = fragment_receiver_ptr_->resume(timeout, timestamp);
219  }
220  if (!external_request_status_)
221  {
222  report_string_ = "Error resuming ";
223  report_string_.append(app_name + ".");
224  }
225  return external_request_status_;
226 }
227 
229 {
230  report_string_ = "";
231  external_request_status_ = fragment_receiver_ptr_->shutdown(timeout);
232  // 02-Jun-2018, ELF & KAB: it's very, very unlikely that the following call is needed,
233  // but just in case...
234  if (fragment_input_thread_.joinable()) fragment_input_thread_.join();
235  if (fragment_output_thread_.joinable()) fragment_output_thread_.join();
236  if (!external_request_status_)
237  {
238  report_string_ = "Error shutting down ";
239  report_string_.append(app_name + ".");
240  }
241  return external_request_status_;
242 }
243 
244 bool artdaq::BoardReaderApp::do_soft_initialize(fhicl::ParameterSet const& pset, uint64_t timeout, uint64_t timestamp)
245 {
246  report_string_ = "";
247  external_request_status_ = fragment_receiver_ptr_->soft_initialize(pset, timeout, timestamp);
248  if (!external_request_status_)
249  {
250  report_string_ = "Error soft-initializing ";
251  report_string_.append(app_name + " ");
252  report_string_.append("with ParameterSet = \"" + pset.to_string() + "\".");
253  }
254  return external_request_status_;
255 }
256 
257 bool artdaq::BoardReaderApp::do_reinitialize(fhicl::ParameterSet const& pset, uint64_t timeout, uint64_t timestamp)
258 {
259  external_request_status_ = fragment_receiver_ptr_->reinitialize(pset, timeout, timestamp);
260  if (!external_request_status_)
261  {
262  report_string_ = "Error reinitializing ";
263  report_string_.append(app_name + " ");
264  report_string_.append("with ParameterSet = \"" + pset.to_string() + "\".");
265  }
266  return external_request_status_;
267 }
268 
270 {
271  TLOG(TLVL_DEBUG) << "Booted state entry action called.";
272 
273  // the destruction of any existing BoardReaderCore has to happen in the
274  // Booted Entry action rather than the Initialized Exit action because the
275  // Initialized Exit action is only called after the "init" transition guard
276  // condition is executed.
277  fragment_receiver_ptr_.reset(nullptr);
278 }
279 
280 bool artdaq::BoardReaderApp::do_meta_command(std::string const& command, std::string const& arg)
281 {
282  external_request_status_ = fragment_receiver_ptr_->metaCommand(command, arg);
283  if (!external_request_status_)
284  {
285  report_string_ = "Error running meta-command on ";
286  report_string_.append(app_name + " ");
287  report_string_.append("with command = \"" + command + "\", arg = \"" + arg + "\".");
288  }
289  return external_request_status_;
290 }
291 
292 std::string artdaq::BoardReaderApp::report(std::string const& which) const
293 {
294  std::string resultString;
295 
296  // if all that is requested is the latest state change result, return it
297  if (which == "transition_status")
298  {
299  if (report_string_.length() > 0) { return report_string_; }
300 
301  return "Success";
302  }
303 
306  //if (report_string_.length() > 0) {
307  // resultString.append("*** Overall status message:\r\n");
308  // resultString.append(report_string_ + "\r\n");
309  // resultString.append("*** Requested report response:\r\n");
310  //}
311 
312  // pass the request to the BoardReaderCore instance, if it's available
313  if (fragment_receiver_ptr_ != nullptr)
314  {
315  resultString.append(fragment_receiver_ptr_->report(which));
316  }
317  else
318  {
319  resultString.append("This BoardReader has not yet been initialized and ");
320  resultString.append("therefore can not provide reporting.");
321  }
322 
323  return resultString;
324 }
bool do_soft_initialize(fhicl::ParameterSet const &pset, uint64_t timeout, uint64_t timestamp) override
Soft-Initialize the BoardReaderCore.
bool do_resume(uint64_t timeout, uint64_t timestamp) override
Resume the BoardReaderCore.
bool do_stop(uint64_t timeout, uint64_t timestamp) override
Stop the BoardReaderCore.
bool do_meta_command(std::string const &command, std::string const &arg) override
Perform a user-defined command (passed to CommandableFragmentGenerator)
bool do_shutdown(uint64_t timeout) override
Shutdown the BoardReaderCore.
bool do_reinitialize(fhicl::ParameterSet const &pset, uint64_t timeout, uint64_t timestamp) override
Reinitialize the BoardReaderCore.
std::string report(std::string const &which) const override
If which is &quot;transition_status&quot;, report the status of the last transition. Otherwise pass through to ...
void send_fragments()
Main working loop of the BoardReaderCore, pt. 2.
BoardReaderApp()
BoardReaderApp Constructor.
void BootedEnter() override
Action taken upon entering the &quot;Booted&quot; state.
void receive_fragments()
Main working loop of the BoardReaderCore.
bool do_start(art::RunID id, uint64_t timeout, uint64_t timestamp) override
Start the BoardReaderCore.
bool do_initialize(fhicl::ParameterSet const &pset, uint64_t timeout, uint64_t timestamp) override
Initialize the BoardReaderCore.
bool do_pause(uint64_t timeout, uint64_t timestamp) override
Pause the BoardReaderCore.