iceoryx_hoofs/posix_wrapper/timer.hpp🔗
Namespaces🔗
Name |
---|
iox building block to easily create free function for logging in a library context |
iox::posix |
iox::units::duration_literals |
Classes🔗
Name | |
---|---|
class | iox::posix::Timer Interface for timers on POSIX operating systems. |
Source code🔗
// Copyright (c) 2019 by Robert Bosch GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// SPDX-License-Identifier: Apache-2.0
#ifndef IOX_HOOFS_POSIX_WRAPPER_TIMER_HPP
#define IOX_HOOFS_POSIX_WRAPPER_TIMER_HPP
#include "iceoryx_hoofs/cxx/optional.hpp"
#include "iceoryx_hoofs/cxx/vector.hpp"
#include "iceoryx_hoofs/design_pattern/creation.hpp"
#include "iceoryx_hoofs/internal/units/duration.hpp"
#include "iceoryx_hoofs/platform/signal.hpp"
#include "iceoryx_hoofs/platform/time.hpp"
#include <atomic>
#include <condition_variable>
#include <cstdint>
#include <ctime>
#include <functional>
#include <limits>
namespace iox
{
namespace posix
{
enum class TimerError
{
NO_ERROR,
TIMER_NOT_INITIALIZED,
NO_VALID_CALLBACK,
KERNEL_ALLOC_FAILED,
INVALID_ARGUMENTS,
ALLOC_MEM_FAILED,
NO_PERMISSION,
INVALID_POINTER,
NO_TIMER_TO_DELETE,
TIMEOUT_IS_ZERO,
INTERNAL_LOGIC_ERROR
};
using namespace iox::units::duration_literals;
class Timer
{
public:
enum class RunMode
{
ONCE,
PERIODIC
};
enum class CatchUpPolicy
{
SKIP_TO_NEXT_BEAT,
IMMEDIATE,
TERMINATE
};
private:
static constexpr size_t SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR = sizeof(uint32_t);
static constexpr size_t SIZE_OF_SIGVAL_INT = sizeof(int);
static_assert(SIZE_OF_SIGVAL_INT >= SIZE_OF_COMBINDED_INDEX_AND_DESCRIPTOR, "size of sigval_int is to low");
static constexpr uint32_t MAX_NUMBER_OF_CALLBACK_HANDLES = 100u;
static_assert(MAX_NUMBER_OF_CALLBACK_HANDLES <= std::numeric_limits<uint8_t>::max(),
"number of callback handles exceeds max index value");
class OsTimer;
struct OsTimerCallbackHandle
{
static constexpr uint32_t MAX_DESCRIPTOR_VALUE{(1u << 24u) - 1u};
static sigval indexAndDescriptorToSigval(uint8_t index, uint32_t descriptor) noexcept;
static uint8_t sigvalToIndex(sigval intVal) noexcept;
static uint32_t sigvalToDescriptor(sigval intVal) noexcept;
void incrementDescriptor() noexcept;
std::mutex m_accessMutex;
std::atomic<uint32_t> m_descriptor{0u};
// must be operator= otherwise it is undefined, see https://en.cppreference.com/w/cpp/atomic/ATOMIC_FLAG_INIT
std::atomic_flag m_callbackIsAboutToBeExecuted = ATOMIC_FLAG_INIT;
std::atomic<bool> m_inUse{false};
std::atomic<bool> m_isTimerActive{false};
std::atomic<uint64_t> m_timerInvocationCounter{0u};
CatchUpPolicy m_catchUpPolicy{CatchUpPolicy::TERMINATE};
OsTimer* m_timer{nullptr};
};
class OsTimer
{
#ifdef __QNX__
static constexpr timer_t INVALID_TIMER_ID = 0;
#else
static constexpr timer_t INVALID_TIMER_ID = nullptr;
#endif
public:
static void callbackHelper(sigval data) noexcept;
OsTimer(const units::Duration timeToWait, const std::function<void()>& callback) noexcept;
OsTimer(const OsTimer&) = delete;
OsTimer(OsTimer&&) = delete;
OsTimer& operator=(const OsTimer&) = delete;
OsTimer& operator=(OsTimer&&) = delete;
virtual ~OsTimer() noexcept;
cxx::expected<TimerError> start(const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
cxx::expected<TimerError> stop() noexcept;
cxx::expected<TimerError>
restart(const units::Duration timeToWait, const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
// @brief Returns the time until the timer expires the next time
cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;
cxx::expected<uint64_t, TimerError> getOverruns() noexcept;
bool hasError() const noexcept;
TimerError getError() const noexcept;
private:
void executeCallback() noexcept;
private:
units::Duration m_timeToWait;
std::function<void()> m_callback;
timer_t m_timerId{INVALID_TIMER_ID};
uint8_t m_callbackHandleIndex{0u};
bool m_isInitialized{false};
TimerError m_errorValue{TimerError::NO_ERROR};
static OsTimerCallbackHandle s_callbackHandlePool[MAX_NUMBER_OF_CALLBACK_HANDLES];
};
public:
Timer(const units::Duration timeToWait) noexcept;
Timer(const units::Duration timeToWait, const std::function<void()>& callback) noexcept;
static cxx::expected<units::Duration, TimerError> now() noexcept;
Timer(const Timer& other) = delete;
Timer(Timer&& other) = delete;
Timer& operator=(const Timer& other) = delete;
Timer& operator=(Timer&& other) = delete;
virtual ~Timer() noexcept = default;
cxx::expected<TimerError> start(const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
cxx::expected<TimerError> stop() noexcept;
cxx::expected<TimerError>
restart(const units::Duration timeToWait, const RunMode runMode, const CatchUpPolicy catchUpPolicy) noexcept;
// @brief Returns the time until the timer expires the next time
cxx::expected<units::Duration, TimerError> timeUntilExpiration() noexcept;
cxx::expected<uint64_t, TimerError> getOverruns() noexcept;
bool hasError() const noexcept;
TimerError getError() const noexcept;
private:
cxx::optional<OsTimer> m_osTimer;
static cxx::error<TimerError> createErrorFromErrno(const int32_t errnum) noexcept;
units::Duration m_timeToWait;
units::Duration m_creationTime;
TimerError m_errorValue{TimerError::NO_ERROR};
};
} // namespace posix
} // namespace iox
#endif // IOX_HOOFS_POSIX_WRAPPER_TIMER_HPP
Updated on 2 April 2022 at 16:37:47 CEST