Skip to content

iceoryx_hoofs/posix_wrapper/posix_call.hpp🔗

Namespaces🔗

Name
iox
building block to easily create free function for logging in a library context
iox::posix
iox::posix::internal

Classes🔗

Name
class iox::posix::PosixCallBuilder
struct iox::posix::PosixCallResult
result of a posix call
class iox::posix::PosixCallEvaluator
class which is created by the verificator to evaluate the result of a posix call
class iox::posix::PosixCallVerificator
class which verifies the return value of a posix function call
class iox::posix::PosixCallBuilder

Defines🔗

Name
posixCall(f)
Calling a posix function with automated error handling. If the posix function returns void you do not need to use posixCall since it cannot fail, (see: man errno). We use a builder pattern to create a design which sets the usage contract so that it cannot be used in the wrong way.

Macro Documentation🔗

define posixCall🔗

#define posixCall(
    f
)
internal::createPosixCallBuilder(f, #f, __FILE__, __LINE__, __PRETTY_FUNCTION__)

Calling a posix function with automated error handling. If the posix function returns void you do not need to use posixCall since it cannot fail, (see: man errno). We use a builder pattern to create a design which sets the usage contract so that it cannot be used in the wrong way.

iox::posix::posixCall(sem_timedwait)(handle, timeout)
     .successReturnValue(0)
     .ignoreErrnos(ETIMEDOUT) // can be a comma separated list of errnos
     .evaluate()
     .and_then([](auto & result){
         std::cout << result.value << std::endl; // return value of sem_timedwait
         std::cout << result.errno << std::endl; // errno which was set by sem_timedwait
         std::cout << result.getHumanReadableErrnum() << std::endl; // get string returned by strerror(errno)
     })
     .or_else([](auto & result){
         std::cout << result.value << std::endl; // return value of sem_timedwait
         std::cout << result.errno << std::endl; // errno which was set by sem_timedwait
         std::cout << result.getHumanReadableErrnum() << std::endl; // get string returned by strerror(errno)
     })

// when your posix call signals failure with one specific return value use
// .failureReturnValue(_) instead of .successReturnValue(_)
// when your posix call signals failure by returning the errno value instead of setting the errno use
// .returnValueMatchesErrno() instead of .successReturnValue(_)

Source code🔗

// 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_POSIX_CALL_HPP
#define IOX_HOOFS_POSIX_WRAPPER_POSIX_CALL_HPP

#include "iceoryx_hoofs/cxx/algorithm.hpp"
#include "iceoryx_hoofs/cxx/attributes.hpp"
#include "iceoryx_hoofs/cxx/expected.hpp"
#include "iceoryx_hoofs/cxx/string.hpp"

#include <cstdint>
#include <cstring>

namespace iox
{
namespace posix
{
static constexpr uint32_t POSIX_CALL_ERROR_STRING_SIZE = 128U;
static constexpr uint64_t POSIX_CALL_EINTR_REPETITIONS = 5U;
static constexpr int32_t POSIX_CALL_INVALID_ERRNO = -1;

template <typename ReturnType, typename... FunctionArguments>
class PosixCallBuilder;

template <typename T>
struct PosixCallResult
{
    PosixCallResult() noexcept = default;

    cxx::string<POSIX_CALL_ERROR_STRING_SIZE> getHumanReadableErrnum() const noexcept;

    T value{};

    int32_t errnum = POSIX_CALL_INVALID_ERRNO;
};

namespace internal
{
template <typename ReturnType, typename... FunctionArguments>
PosixCallBuilder<ReturnType, FunctionArguments...> createPosixCallBuilder(ReturnType (*posixCall)(FunctionArguments...),
                                                                          const char* posixFunctionName,
                                                                          const char* file,
                                                                          const int32_t line,
                                                                          const char* callingFunction) noexcept;

template <typename ReturnType>
struct PosixCallDetails
{
    PosixCallDetails(const char* posixFunctionName, const char* file, int line, const char* callingFunction) noexcept;
    const char* posixFunctionName = nullptr;
    const char* file = nullptr;
    const char* callingFunction = nullptr;
    int32_t line = 0;
    bool hasSuccess = true;
    bool hasIgnoredErrno = false;
    bool hasSilentErrno = false;

    PosixCallResult<ReturnType> result;
};
} // namespace internal

#define posixCall(f) internal::createPosixCallBuilder(f, #f, __FILE__, __LINE__, __PRETTY_FUNCTION__)

template <typename ReturnType>
class IOX_NO_DISCARD PosixCallEvaluator
{
  public:
    template <typename... IgnoredErrnos>
    PosixCallEvaluator<ReturnType> ignoreErrnos(const IgnoredErrnos... ignoredErrnos) const&& noexcept;

    template <typename... SilentErrnos>
    PosixCallEvaluator<ReturnType> suppressErrorMessagesForErrnos(const SilentErrnos... silentErrnos) const&& noexcept;

    cxx::expected<PosixCallResult<ReturnType>, PosixCallResult<ReturnType>> evaluate() const&& noexcept;

  private:
    template <typename>
    friend class PosixCallVerificator;

    explicit PosixCallEvaluator(internal::PosixCallDetails<ReturnType>& details) noexcept;

  private:
    internal::PosixCallDetails<ReturnType>& m_details;
};

template <typename ReturnType>
class IOX_NO_DISCARD PosixCallVerificator
{
  public:
    template <typename... SuccessReturnValues>
    PosixCallEvaluator<ReturnType> successReturnValue(const SuccessReturnValues... successReturnValues) && noexcept;

    template <typename... FailureReturnValues>
    PosixCallEvaluator<ReturnType> failureReturnValue(const FailureReturnValues... failureReturnValues) && noexcept;

    PosixCallEvaluator<ReturnType> returnValueMatchesErrno() && noexcept;

  private:
    template <typename, typename...>
    friend class PosixCallBuilder;

    explicit PosixCallVerificator(internal::PosixCallDetails<ReturnType>& details) noexcept;

  private:
    internal::PosixCallDetails<ReturnType>& m_details;
};

template <typename ReturnType, typename... FunctionArguments>
class IOX_NO_DISCARD PosixCallBuilder
{
  public:
    using FunctionType_t = ReturnType (*)(FunctionArguments...);

    PosixCallVerificator<ReturnType> operator()(FunctionArguments... arguments) && noexcept;

  private:
    template <typename ReturnTypeFriend, typename... FunctionArgumentsFriend>
    friend PosixCallBuilder<ReturnTypeFriend, FunctionArgumentsFriend...>
    internal::createPosixCallBuilder(ReturnTypeFriend (*posixCall)(FunctionArgumentsFriend...),
                                     const char* posixFunctionName,
                                     const char* file,
                                     const int32_t line,
                                     const char* callingFunction) noexcept;

    PosixCallBuilder(FunctionType_t posixCall,
                     const char* posixFunctionName,
                     const char* file,
                     const int32_t line,
                     const char* callingFunction) noexcept;

  private:
    FunctionType_t m_posixCall = nullptr;
    internal::PosixCallDetails<ReturnType> m_details;
};
} // namespace posix
} // namespace iox

#include "iceoryx_hoofs/internal/posix_wrapper/posix_call.inl"

#endif // IOX_HOOFS_POSIX_WRAPPER_POSIX_CALL_HPP

Updated on 18 December 2023 at 13:02:35 CET