iceoryx_hoofs  2.0.2
timer.hpp
1 // Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
2 // Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 // SPDX-License-Identifier: Apache-2.0
17 #ifndef IOX_HOOFS_POSIX_WRAPPER_TIMER_HPP
18 #define IOX_HOOFS_POSIX_WRAPPER_TIMER_HPP
19 
20 #include "iceoryx_hoofs/cxx/optional.hpp"
21 #include "iceoryx_hoofs/cxx/vector.hpp"
22 #include "iceoryx_hoofs/design_pattern/creation.hpp"
23 #include "iceoryx_hoofs/internal/units/duration.hpp"
24 #include "iceoryx_hoofs/platform/signal.hpp"
25 #include "iceoryx_hoofs/platform/time.hpp"
26 
27 #include <atomic>
28 #include <condition_variable>
29 #include <cstdint>
30 #include <ctime>
31 #include <functional>
32 #include <limits>
33 
34 
35 namespace iox
36 {
37 namespace posix
38 {
39 enum class TimerError
40 {
41  NO_ERROR,
42  TIMER_NOT_INITIALIZED,
43  NO_VALID_CALLBACK,
44  KERNEL_ALLOC_FAILED,
45  INVALID_ARGUMENTS,
46  ALLOC_MEM_FAILED,
47  NO_PERMISSION,
48  INVALID_POINTER,
49  NO_TIMER_TO_DELETE,
50  TIMEOUT_IS_ZERO,
51  INTERNAL_LOGIC_ERROR
52 };
53 
54 using namespace iox::units::duration_literals;
55 
56 
73 
81 class Timer
82 {
83  public:
84  enum class RunMode
85  {
86  ONCE,
87  PERIODIC
88  };
89 
97  enum class CatchUpPolicy
98  {
99  SKIP_TO_NEXT_BEAT,
100  IMMEDIATE,
101  TERMINATE
102  };
103 
104  private:
105  static constexpr size_t SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR = sizeof(uint32_t);
106  static constexpr size_t SIZE_OF_SIGVAL_INT = sizeof(int);
107  static_assert(SIZE_OF_SIGVAL_INT >= SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR, "size of sigval_int is to low");
108 
109  static constexpr uint32_t MAX_NUMBER_OF_CALLBACK_HANDLES = 100u;
110  static_assert(MAX_NUMBER_OF_CALLBACK_HANDLES <= std::numeric_limits<uint8_t>::max(),
111  "number of callback handles exceeds max index value");
112  class OsTimer;
113  struct OsTimerCallbackHandle
114  {
115  static constexpr uint32_t MAX_DESCRIPTOR_VALUE{(1u << 24u) - 1u};
116  static sigval indexAndDescriptorToSigval(uint8_t index, uint32_t descriptor) noexcept;
117  static uint8_t sigvalToIndex(sigval intVal) noexcept;
118  static uint32_t sigvalToDescriptor(sigval intVal) noexcept;
119 
120  void incrementDescriptor() noexcept;
121 
122  std::mutex m_accessMutex;
123 
126  std::atomic<uint32_t> m_descriptor{0u};
127  // must be operator= otherwise it is undefined, see https://en.cppreference.com/w/cpp/atomic/ATOMIC_FLAG_INIT
128  std::atomic_flag m_callbackIsAboutToBeExecuted = ATOMIC_FLAG_INIT;
129 
130  std::atomic<bool> m_inUse{false};
131  std::atomic<bool> m_isTimerActive{false};
132  std::atomic<uint64_t> m_timerInvocationCounter{0u};
133  CatchUpPolicy m_catchUpPolicy{CatchUpPolicy::TERMINATE};
134  OsTimer* m_timer{nullptr};
135  };
136 
138  class OsTimer
139  {
140 #ifdef __QNX__
141  static constexpr timer_t INVALID_TIMER_ID = 0;
142 #else
143  static constexpr timer_t INVALID_TIMER_ID = nullptr;
144 #endif
145  public:
147  static void callbackHelper(sigval data) noexcept;
148 
149  OsTimer(const units::Duration timeToWait, const std::function<void()>& callback) noexcept;
150 
151  OsTimer(const OsTimer&) = delete;
152  OsTimer(OsTimer&&) = delete;
153  OsTimer& operator=(const OsTimer&) = delete;
154  OsTimer& operator=(OsTimer&&) = delete;
155 
157  virtual ~OsTimer() noexcept;
158 
167  cxx::expected<TimerError> start(const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
168 
172  cxx::expected<TimerError> stop() noexcept;
173 
179  cxx::expected<TimerError>
180  restart(const units::Duration timeToWait, const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
181 
182  // @brief Returns the time until the timer expires the next time
184  cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;
185 
189  cxx::expected<uint64_t, TimerError> getOverruns() noexcept;
190 
192  bool hasError() const noexcept;
193 
195  TimerError getError() const noexcept;
196 
197  private:
200  void executeCallback() noexcept;
201 
202  private:
204  units::Duration m_timeToWait;
205 
207  std::function<void()> m_callback;
208 
210  timer_t m_timerId{INVALID_TIMER_ID};
211 
212  uint8_t m_callbackHandleIndex{0u};
213 
216  bool m_isInitialized{false};
217 
220  TimerError m_errorValue{TimerError::NO_ERROR};
221 
222  static OsTimerCallbackHandle s_callbackHandlePool[MAX_NUMBER_OF_CALLBACK_HANDLES];
223  };
224 
225  public:
235  Timer(const units::Duration timeToWait) noexcept;
236 
245  Timer(const units::Duration timeToWait, const std::function<void()>& callback) noexcept;
246 
250  static cxx::expected<units::Duration, TimerError> now() noexcept;
251 
253  Timer(const Timer& other) = delete;
254 
256  Timer(Timer&& other) = delete;
257 
259  Timer& operator=(const Timer& other) = delete;
260 
262  Timer& operator=(Timer&& other) = delete;
263 
265  virtual ~Timer() noexcept = default;
266 
274  cxx::expected<TimerError> start(const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
275 
279  cxx::expected<TimerError> stop() noexcept;
280 
286  cxx::expected<TimerError>
287  restart(const units::Duration timeToWait, const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
288 
289  // @brief Returns the time until the timer expires the next time
291  cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;
292 
296  cxx::expected<uint64_t, TimerError> getOverruns() noexcept;
297 
299  bool hasError() const noexcept;
300 
302  TimerError getError() const noexcept;
303 
304  private:
305  cxx::optional<OsTimer> m_osTimer;
306 
308  static cxx::error<TimerError> createErrorFromErrno(const int32_t errnum) noexcept;
309 
311  units::Duration m_timeToWait;
312 
314  units::Duration m_creationTime;
315 
317  TimerError m_errorValue{TimerError::NO_ERROR};
318 };
319 
320 } // namespace posix
321 } // namespace iox
322 
323 #endif // IOX_HOOFS_POSIX_WRAPPER_TIMER_HPP
Interface for timers on POSIX operating systems.
Definition: timer.hpp:82
Timer(const units::Duration timeToWait, const std::function< void()> &callback) noexcept
Creates a timer with an operating system callback.
CatchUpPolicy
defines the behavior of the timer when the callback runtime is greater than the periodic trigger time...
Definition: timer.hpp:98
static cxx::expected< units::Duration, TimerError > now() noexcept
creates Duration from the result of clock_gettime(CLOCK_REALTIME, ...)
Timer(const units::Duration timeToWait) noexcept
Creates a timer without an operating system callback.
building block to easily create free function for logging in a library context
Definition: lockfree_queue.hpp:29