From 1798043b0c49d7277f16e0834535027cdbe4426f Mon Sep 17 00:00:00 2001 From: Christian Eltzschig Date: Fri, 20 May 2022 12:05:07 +0200 Subject: [PATCH] iox-#751 Implemented semaphore interface Signed-off-by: Christian Eltzschig --- iceoryx_hoofs/CMakeLists.txt | 1 + .../posix_wrapper/semaphore_interface.hpp | 67 +++++++ .../posix_wrapper/unnamed_semaphore.hpp | 31 +--- .../posix_wrapper/semaphore_interface.cpp | 172 ++++++++++++++++++ .../posix_wrapper/unnamed_semaphore.cpp | 7 - 5 files changed, 242 insertions(+), 36 deletions(-) create mode 100644 iceoryx_hoofs/include/iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp create mode 100644 iceoryx_hoofs/source/posix_wrapper/semaphore_interface.cpp diff --git a/iceoryx_hoofs/CMakeLists.txt b/iceoryx_hoofs/CMakeLists.txt index 49932e53c72..3117e8845e9 100644 --- a/iceoryx_hoofs/CMakeLists.txt +++ b/iceoryx_hoofs/CMakeLists.txt @@ -103,6 +103,7 @@ add_library(iceoryx_hoofs source/posix_wrapper/named_pipe.cpp source/posix_wrapper/posix_access_rights.cpp source/posix_wrapper/semaphore.cpp + source/posix_wrapper/semaphore_interface.cpp source/posix_wrapper/shared_memory_object.cpp source/posix_wrapper/shared_memory_object/allocator.cpp source/posix_wrapper/shared_memory_object/memory_map.cpp diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp new file mode 100644 index 00000000000..80e34614ca0 --- /dev/null +++ b/iceoryx_hoofs/include/iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp @@ -0,0 +1,67 @@ +// Copyright (c) 2022 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_SEMAPHORE_INTERFACE_HPP +#define IOX_HOOFS_POSIX_WRAPPER_SEMAPHORE_INTERFACE_HPP + +#include "iceoryx_hoofs/cxx/expected.hpp" +#include "iceoryx_hoofs/internal/units/duration.hpp" +#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" + +namespace iox +{ +namespace posix +{ +namespace internal +{ +struct SemaphoreState +{ + uint32_t value = 0U; + uint32_t numberOfBlockedWait = 0U; +}; + +template +class SemaphoreInterface +{ + public: + SemaphoreInterface(const SemaphoreInterface&) noexcept = delete; + SemaphoreInterface(SemaphoreInterface&&) noexcept = delete; + SemaphoreInterface& operator=(const SemaphoreInterface&) noexcept = delete; + SemaphoreInterface& operator=(SemaphoreInterface&&) noexcept = delete; + ~SemaphoreInterface() noexcept = default; + + void post() noexcept; + cxx::expected postUnsafe() noexcept; + + SemaphoreState getState() noexcept; + cxx::expected getStateUnsafe() noexcept; + + SemaphoreWaitState timedWait(const units::Duration& timeout) noexcept; + cxx::expected timedWaitUnsafe(const units::Duration& timeout) noexcept; + + bool tryWait() noexcept; + cxx::expected tryWaitUnsafe() noexcept; + + protected: + SemaphoreInterface() noexcept = default; + + private: + iox_sem_t* getHandle() noexcept; +}; +} // namespace internal +} // namespace posix +} // namespace iox + +#endif diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp index 3eb5e3dc240..40ed36644b2 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp @@ -19,39 +19,13 @@ #include "iceoryx_hoofs/cxx/expected.hpp" #include "iceoryx_hoofs/cxx/optional.hpp" #include "iceoryx_hoofs/design_pattern/builder.hpp" -#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" +#include "iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp" namespace iox { namespace posix { -template -class SemaphoreInterface -{ - public: - SemaphoreInterface(const SemaphoreInterface&) noexcept = delete; - SemaphoreInterface(SemaphoreInterface&&) noexcept = delete; - SemaphoreInterface& operator=(const SemaphoreInterface&) noexcept = delete; - SemaphoreInterface& operator=(SemaphoreInterface&&) noexcept = delete; - ~SemaphoreInterface() noexcept = default; - - void post() noexcept; - cxx::expected postUnsafe() noexcept; - - uint32_t getValue() const noexcept; - cxx::expected getValueUnsafe() const noexcept; - - void timedWait() noexcept; - cxx::expected timedWaitUnsafe() noexcept; - - void tryWait() noexcept; - cxx::expected tryWaitUnsafe() noexcept; - - protected: - SemaphoreInterface() noexcept = default; -}; - -class UnnamedSemaphore : SemaphoreInterface +class UnnamedSemaphore final : internal::SemaphoreInterface { public: UnnamedSemaphore(const UnnamedSemaphore&) noexcept = delete; @@ -67,7 +41,6 @@ class UnnamedSemaphore : SemaphoreInterface private: UnnamedSemaphore() noexcept = default; iox_sem_t* getHandle() noexcept; - const iox_sem_t* getHandle() const noexcept; iox_sem_t m_handle; bool m_destroyHandle = true; diff --git a/iceoryx_hoofs/source/posix_wrapper/semaphore_interface.cpp b/iceoryx_hoofs/source/posix_wrapper/semaphore_interface.cpp new file mode 100644 index 00000000000..0497d28ba61 --- /dev/null +++ b/iceoryx_hoofs/source/posix_wrapper/semaphore_interface.cpp @@ -0,0 +1,172 @@ +// Copyright (c) 2022 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 + +#include "iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp" +#include "iceoryx_hoofs/internal/log/hoofs_logging.hpp" +#include "iceoryx_hoofs/posix_wrapper/posix_call.hpp" +#include "iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp" + +namespace iox +{ +namespace posix +{ +namespace internal +{ + +template +iox_sem_t* SemaphoreInterface::getHandle() noexcept +{ + return static_cast(this)->getHandle(); +} + +template +void SemaphoreInterface::post() noexcept +{ + postUnsafe().expect("Fatal semaphore failure occurred."); +} + +template +cxx::expected SemaphoreInterface::postUnsafe() noexcept +{ + auto result = posixCall(iox_sem_post)(getHandle()).failureReturnValue(-1).evaluate(); + + if (result.has_error()) + { + switch (result.get_error().errnum) + { + case EINVAL: + LogError() << "The semaphore handle is no longer valid. This can indicate a corrupted system."; + return cxx::error(SemaphoreError::INVALID_SEMAPHORE_HANDLE); + case EOVERFLOW: + LogError() << "Semaphore overflow."; + return cxx::error(SemaphoreError::SEMAPHORE_OVERFLOW); + default: + LogError() << "This should never happen. An unknown error occurred."; + break; + } + return cxx::error(SemaphoreError::UNDEFINED); + } + + return cxx::success<>(); +} + +template +SemaphoreState SemaphoreInterface::getState() noexcept +{ + return getStateUnsafe().expect("Fatal semaphore failure occurred."); +} + +template +cxx::expected SemaphoreInterface::getStateUnsafe() noexcept +{ + int value = 0; + auto result = posixCall(iox_sem_getvalue)(getHandle(), &value).failureReturnValue(-1).evaluate(); + if (result.has_error()) + { + switch (result.get_error().errnum) + { + case EINVAL: + LogError() << "The semaphore handle is no longer valid. This can indicate a corrupted system."; + return cxx::error(SemaphoreError::INVALID_SEMAPHORE_HANDLE); + default: + LogError() << "This should never happen. An unknown error occurred."; + break; + } + return cxx::error(SemaphoreError::UNDEFINED); + } + + SemaphoreState state; + state.value = (value > 0) ? static_cast(value) : 0U; + state.numberOfBlockedWait = (value < 0) ? static_cast(-value) : 0U; + + return cxx::success(state); +} + +template +SemaphoreWaitState SemaphoreInterface::timedWait(const units::Duration& timeout) noexcept +{ + return timedWaitUnsafe(timeout).expect("Fatal semaphore failure occurred."); +} + +template +cxx::expected +SemaphoreInterface::timedWaitUnsafe(const units::Duration& timeout) noexcept +{ + const timespec timeoutAsTimespec = timeout.timespec(units::TimeSpecReference::Epoch); + auto result = posixCall(iox_sem_timedwait)(getHandle(), &timeoutAsTimespec) + .failureReturnValue(-1) + .ignoreErrnos(ETIMEDOUT) + .evaluate(); + + if (result.has_error()) + { + switch (result.get_error().errnum) + { + case ETIMEDOUT: + return cxx::success(SemaphoreWaitState::TIMEOUT); + case EINVAL: + LogError() << "The semaphore handle is no longer valid. This can indicate a corrupted system."; + return cxx::error(SemaphoreError::INVALID_SEMAPHORE_HANDLE); + case EINTR: + LogError() << "The sem_timedwait was interrupted multiple times by the operating system. Abort operation!"; + return cxx::error(SemaphoreError::INTERRUPTED_BY_SIGNAL_HANDLER); + default: + LogError() << "This should never happen. An unknown error occurred."; + break; + } + return cxx::error(SemaphoreError::UNDEFINED); + } + + return cxx::success(SemaphoreWaitState::NO_TIMEOUT); +} + +template +bool SemaphoreInterface::tryWait() noexcept +{ + return tryWaitUnsafe().expect("Fatal semaphore failure occurred."); +} + +template +cxx::expected SemaphoreInterface::tryWaitUnsafe() noexcept +{ + auto result = posixCall(iox_sem_trywait)(getHandle()).failureReturnValue(-1).ignoreErrnos(EAGAIN).evaluate(); + + if (result.has_error()) + { + switch (result.get_error().errnum) + { + case EAGAIN: + return cxx::success(false); + case EINVAL: + LogError() << "The semaphore handle is no longer valid. This can indicate a corrupted system."; + return cxx::error(SemaphoreError::INVALID_SEMAPHORE_HANDLE); + case EINTR: + LogError() << "The sem_trywait was interrupted multiple times by the operating system. Abort operation!"; + return cxx::error(SemaphoreError::INTERRUPTED_BY_SIGNAL_HANDLER); + default: + LogError() << "This should never happen. An unknown error occurred."; + break; + } + return cxx::error(SemaphoreError::UNDEFINED); + } + + return cxx::success(true); +} + +template class SemaphoreInterface; +} // namespace internal +} // namespace posix +} // namespace iox diff --git a/iceoryx_hoofs/source/posix_wrapper/unnamed_semaphore.cpp b/iceoryx_hoofs/source/posix_wrapper/unnamed_semaphore.cpp index 88e1b9b10c2..d392911e14f 100644 --- a/iceoryx_hoofs/source/posix_wrapper/unnamed_semaphore.cpp +++ b/iceoryx_hoofs/source/posix_wrapper/unnamed_semaphore.cpp @@ -81,12 +81,5 @@ iox_sem_t* UnnamedSemaphore::getHandle() noexcept { return &m_handle; } - -const iox_sem_t* UnnamedSemaphore::getHandle() const noexcept -{ - return &m_handle; -} - - } // namespace posix } // namespace iox