iceoryx_hoofs 2.0.3
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
35namespace iox
36{
37namespace posix
38{
39enum 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
54using namespace iox::units::duration_literals;
55
56
73
81class 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
bool hasError() const noexcept
Returns true if the construction of the object was successful.
Timer(const units::Duration timeToWait, const std::function< void()> &callback) noexcept
Creates a timer with an operating system callback.
cxx::expected< TimerError > start(const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept
Starts the timer.
CatchUpPolicy
defines the behavior of the timer when the callback runtime is greater than the periodic trigger time...
Definition: timer.hpp:98
Timer & operator=(const Timer &other)=delete
Move or semantics are forbidden as address of object is not allowed to change.
static cxx::expected< units::Duration, TimerError > now() noexcept
creates Duration from the result of clock_gettime(CLOCK_REALTIME, ...)
cxx::expected< TimerError > stop() noexcept
Disarms the timer.
cxx::expected< units::Duration, TimerError > timeUntilExpiration() noexcept
cxx::expected< uint64_t, TimerError > getOverruns() noexcept
In case the callback is not immediately called by the operating system, getOverruns() returns the add...
TimerError getError() const noexcept
Returns the error that occured on constructing the object.
Timer(const units::Duration timeToWait) noexcept
Creates a timer without an operating system callback.
cxx::expected< TimerError > restart(const units::Duration timeToWait, const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept
Disarms the timer, assigns a new timeToWait value and arms the timer.
building block to easily create free function for logging in a library context
Definition: lockfree_queue.hpp:29