ifw-daq  3.0.0-pre2
IFW Data Acquisition modules
awaitState.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_common_libdaq
4  * @copyright 2022 ESO - European Southern Observatory
5  *
6  * @brief Contains definitions for the AwaitStateAsync operation
7  */
8 #include <daq/op/awaitState.hpp>
9 
10 #include <fmt/format.h>
11 #include <fmt/ostream.h>
12 #include <log4cplus/loggingmacros.h>
13 
14 #include <daq/error.hpp>
15 
16 namespace daq::op {
17 
18 AwaitStateAsync::AwaitStateAsync(boost::asio::io_context& io_ctx,
19  std::shared_ptr<ObservableStatus> status,
20  State state,
21  std::chrono::milliseconds timeout,
22  log4cplus::Logger const& logger)
23  : m_io_ctx(io_ctx)
24  , m_status(std::move(status))
25  , m_target(state)
26  , m_timeout(timeout)
27  , m_aborted(false)
28  , m_timer(m_io_ctx)
29  , m_logger(logger) {
30  assert(m_status);
31 }
32 
33 boost::future<AwaitStateAsync::ResultType> AwaitStateAsync::Initiate() {
34  LOG4CPLUS_DEBUG(m_logger,
35  fmt::format("AwaitStateAsync::Initate(): Awaiting state {} with timeout {}ms",
36  m_target,
37  m_timeout.count()));
38  if (IsConditionSatisfied()) {
39  // Condition already satisfied
40  return boost::make_ready_future<ResultType>(ResultType{false, m_status->GetStatus()});
41  }
42 
43  // Set up status observer and timer
44  m_connection = m_status->ConnectObserver([this](ObservableStatus const&) {
45  if (IsConditionSatisfied()) {
46  LOG4CPLUS_DEBUG(m_logger,
47  fmt::format("Await condition is satisfied by status change "
48  "-> setting promise: ",
49  *m_status));
50  try {
51  m_promise.set_value(ResultType{false, m_status->GetStatus()});
52  m_timer.cancel();
53  } catch (boost::promise_already_satisfied const&) {
54  // Do nothing.
55  LOG4CPLUS_DEBUG(m_logger, "Promise already satisfied");
56  }
57  }
58  });
59 
60  m_timer.expires_after(m_timeout);
61  m_timer.async_wait([this, logger=m_logger](boost::system::error_code const& error) {
62  if (error) {
63  // Timer was cancelled. This may mean the operation is no longer valid.
64  LOG4CPLUS_DEBUG(logger, "Timer cancelled: Doing nothing.");
65  return;
66  }
67  if (m_aborted) {
68  // Operation has been aborted. This may mean the operation is no longer valid.
69  LOG4CPLUS_INFO(logger, "Operation aborted: Doing nothing.");
70  return;
71  }
72  try {
73  // It is only considered a timeout if condition is still not satisfied
74  bool timeout = !IsConditionSatisfied();
75  LOG4CPLUS_DEBUG(
76  m_logger,
77  fmt::format("AwaitStateAsync: {}: Timer expired waiting for target state '{}'. "
78  "Current state is '{}'",
79  m_status->GetId(),
80  m_target,
81  m_status->GetState()));
82  m_promise.set_value(ResultType{timeout, m_status->GetStatus()});
83  } catch (boost::promise_already_satisfied const&) {
84  // May happen due to race-to-complete
85  LOG4CPLUS_DEBUG(m_logger, "Promise already satisfied");
86  }
87  });
88 
89  return m_promise.get_future();
90 }
91 
92 void AwaitStateAsync::Abort() noexcept {
93  try {
94  LOG4CPLUS_INFO(m_logger, "Aborting operation.");
95  m_promise.set_exception(DaqOperationAborted(
96  fmt::format("AwaitStateAsync: {}: Operation aborted while waiting for target state {}. "
97  "Current state is {}",
98  m_status->GetId(),
99  m_target,
100  m_status->GetState())));
101  m_aborted = true;
102  // Might as well cancel timer and disconnect observer
103  m_timer.cancel();
104  m_connection.disconnect();
105  } catch (boost::promise_already_satisfied const&) {
106  }
107 }
108 
109 bool AwaitStateAsync::IsConditionSatisfied() const {
110  return !IsSubsequentState(m_target, m_status->GetState());
111 }
112 
113 } // namespace daq::op
Contains declaration for the AwaitStateAsync operation.
Started operation was aborted.
Definition: error.hpp:47
Stores data acquisition status and allows subscription to status changes.
Definition: status.hpp:165
Contains error related declarations for DAQ.
bool IsSubsequentState(State state1, State state2) noexcept
Compares states and returns whether state1 occurs after state2.
Definition: state.cpp:26
State
Observable states of the data acquisition process.
Definition: state.hpp:39
Utility class that represents a result and an error.
Definition: utility.hpp:17
Definition: main.cpp:23
boost::future< ResultType > Initiate()
Initiates operation that await state.
Definition: awaitState.cpp:33
void Abort() noexcept
Aborts the operation and completes the operation with DaqOperationAborted.
Definition: awaitState.cpp:92
AwaitStateAsync(boost::asio::io_context &io_ctx, std::shared_ptr< ObservableStatus > status, State state, std::chrono::milliseconds timeout, log4cplus::Logger const &logger)
Constructs operation with the privided parameters.
Definition: awaitState.cpp:18