iceoryx_doc  1.0.1
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_UTILS_POSIX_WRAPPER_TIMER_HPP
18 #define IOX_UTILS_POSIX_WRAPPER_TIMER_HPP
19 
20 #include "iceoryx_utils/cxx/optional.hpp"
21 #include "iceoryx_utils/cxx/vector.hpp"
22 #include "iceoryx_utils/design_pattern/creation.hpp"
23 #include "iceoryx_utils/internal/units/duration.hpp"
24 #include "iceoryx_utils/platform/signal.hpp"
25 #include "iceoryx_utils/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  INVALID_STATE,
42  NO_ERROR,
43  TIMER_NOT_INITIALIZED,
44  NO_VALID_CALLBACK,
45  KERNEL_ALLOC_FAILED,
46  INVALID_ARGUMENTS,
47  ALLOC_MEM_FAILED,
48  NO_PERMISSION,
49  INVALID_POINTER,
50  NO_TIMER_TO_DELETE,
51  TIMEOUT_IS_ZERO,
52  INTERNAL_LOGIC_ERROR
53 };
54 
55 using namespace iox::units::duration_literals;
56 
57 
74 
82 class Timer
83 {
84  public:
85  enum class RunMode
86  {
87  ONCE,
88  PERIODIC
89  };
90 
98  enum class CatchUpPolicy
99  {
100  SKIP_TO_NEXT_BEAT,
101  IMMEDIATE,
102  TERMINATE
103  };
104 
105  private:
106  static constexpr size_t SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR = sizeof(uint32_t);
107  static constexpr size_t SIZE_OF_SIGVAL_INT = sizeof(int);
108  static_assert(SIZE_OF_SIGVAL_INT >= SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR, "size of sigval_int is to low");
109 
110  static constexpr uint32_t MAX_NUMBER_OF_CALLBACK_HANDLES = 100u;
111  static_assert(MAX_NUMBER_OF_CALLBACK_HANDLES <= std::numeric_limits<uint8_t>::max(),
112  "number of callback handles exceeds max index value");
113  class OsTimer;
114  struct OsTimerCallbackHandle
115  {
116  static constexpr uint32_t MAX_DESCRIPTOR_VALUE{(1u << 24u) - 1u};
117  static sigval indexAndDescriptorToSigval(uint8_t index, uint32_t descriptor) noexcept;
118  static uint8_t sigvalToIndex(sigval intVal) noexcept;
119  static uint32_t sigvalToDescriptor(sigval intVal) noexcept;
120 
121  void incrementDescriptor() noexcept;
122 
123  std::mutex m_accessMutex;
124 
127  std::atomic<uint32_t> m_descriptor{0u};
128  std::atomic_flag m_callbackIsAboutToBeExecuted{false};
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);
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_UTILS_POSIX_WRAPPER_TIMER_HPP
Interface for timers on POSIX operating systems.
Definition: timer.hpp:83
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:99
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.
Definition: duration.hpp:77
building block to easily create free function for logging in a library context
Definition: lockfree_queue.hpp:28