diff --git a/iceoryx_hoofs/CMakeLists.txt b/iceoryx_hoofs/CMakeLists.txt index 7f75907c0c..0de0e6aa33 100644 --- a/iceoryx_hoofs/CMakeLists.txt +++ b/iceoryx_hoofs/CMakeLists.txt @@ -71,7 +71,6 @@ iox_add_library( source/posix_wrapper/named_pipe.cpp source/posix_wrapper/named_semaphore.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 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 index 102db14242..95a3cbc946 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/internal/posix_wrapper/semaphore_interface.hpp @@ -19,12 +19,34 @@ #include "iceoryx_hoofs/cxx/expected.hpp" #include "iceoryx_hoofs/internal/units/duration.hpp" #include "iceoryx_hoofs/platform/semaphore.hpp" -#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" namespace iox { namespace posix { +enum class SemaphoreError +{ + CREATION_FAILED, + NAME_TOO_LONG, + UNABLE_TO_OPEN_HANDLE, + INVALID_SEMAPHORE_HANDLE, + SEMAPHORE_OVERFLOW, + INTERRUPTED_BY_SIGNAL_HANDLER, + INVALID_NAME, + PERMISSION_DENIED, + ALREADY_EXIST, + FILE_DESCRIPTOR_LIMIT_REACHED, + NO_SEMAPHORE_WITH_THAT_NAME_EXISTS, + OUT_OF_MEMORY, + UNDEFINED +}; + +enum class SemaphoreWaitState +{ + TIMEOUT, + NO_TIMEOUT, +}; + namespace internal { /// @brief Defines the interface of a named and unnamed semaphore. diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/named_pipe.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/named_pipe.hpp index c414a244f7..17448d5caa 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/named_pipe.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/named_pipe.hpp @@ -22,7 +22,8 @@ #include "iceoryx_hoofs/internal/posix_wrapper/ipc_channel.hpp" #include "iceoryx_hoofs/internal/posix_wrapper/shared_memory_object.hpp" #include "iceoryx_hoofs/internal/units/duration.hpp" -#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" +#include "iceoryx_hoofs/platform/semaphore.hpp" +#include "iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp" #include @@ -36,7 +37,10 @@ class NamedPipe : public DesignPattern::Creation // no system restrictions at all, except available memory. MAX_MESSAGE_SIZE and MAX_NUMBER_OF_MESSAGES can be // increased as long as there is enough memory available static constexpr uint64_t MAX_MESSAGE_SIZE = 4U * 1024U; - static constexpr uint64_t MAX_NUMBER_OF_MESSAGES = 10U; + static constexpr uint32_t MAX_NUMBER_OF_MESSAGES = 10U; + static_assert( + MAX_NUMBER_OF_MESSAGES < 51, + "The maximum number of supported messages must be less or equal to the maximum allowed semaphore value"); static constexpr uint64_t NULL_TERMINATOR_SIZE = 0U; static constexpr units::Duration CYCLE_TIME = units::Duration::fromMilliseconds(10); @@ -122,16 +126,15 @@ class NamedPipe : public DesignPattern::Creation class NamedPipeData { public: - NamedPipeData(bool& isInitialized, IpcChannelError& error, const uint64_t maxMsgNumber) noexcept; + NamedPipeData(bool& isInitialized, IpcChannelError& error, const uint32_t maxMsgNumber) noexcept; NamedPipeData(const NamedPipeData&) = delete; NamedPipeData(NamedPipeData&& rhs) = delete; - ~NamedPipeData() noexcept; NamedPipeData& operator=(const NamedPipeData&) = delete; NamedPipeData& operator=(NamedPipeData&& rhs) = delete; - Semaphore& sendSemaphore() noexcept; - Semaphore& receiveSemaphore() noexcept; + UnnamedSemaphore& sendSemaphore() noexcept; + UnnamedSemaphore& receiveSemaphore() noexcept; bool waitForInitialization() const noexcept; bool hasValidState() const noexcept; @@ -148,8 +151,7 @@ class NamedPipe : public DesignPattern::Creation static constexpr units::Duration WAIT_FOR_INIT_SLEEP_TIME = units::Duration::fromMilliseconds(1); std::atomic initializationGuard{INVALID_DATA}; - using semaphoreMemory_t = uint8_t[sizeof(Semaphore)]; - alignas(Semaphore) semaphoreMemory_t semaphores[2U]; + cxx::optional semaphores[2U]; }; diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/semaphore.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/semaphore.hpp deleted file mode 100644 index 3e545b1fc5..0000000000 --- a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/semaphore.hpp +++ /dev/null @@ -1,333 +0,0 @@ -// 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_SEMAPHORE_HPP -#define IOX_HOOFS_POSIX_WRAPPER_SEMAPHORE_HPP - -#include "iceoryx_hoofs/cxx/expected.hpp" -#include "iceoryx_hoofs/cxx/helplets.hpp" -#include "iceoryx_hoofs/cxx/string.hpp" -#include "iceoryx_hoofs/design_pattern/creation.hpp" -#include "iceoryx_hoofs/internal/relocatable_pointer/relative_pointer.hpp" -#include "iceoryx_hoofs/internal/units/duration.hpp" -#include "iceoryx_hoofs/platform/fcntl.hpp" -#include "iceoryx_hoofs/platform/semaphore.hpp" -#include "iceoryx_hoofs/platform/stat.hpp" - -#include - -namespace iox -{ -namespace posix -{ -enum class SemaphoreError -{ - CREATION_FAILED, - NAME_TOO_LONG, - UNABLE_TO_OPEN_HANDLE, - INVALID_SEMAPHORE_HANDLE, - SEMAPHORE_OVERFLOW, - INTERRUPTED_BY_SIGNAL_HANDLER, - INVALID_NAME, - PERMISSION_DENIED, - ALREADY_EXIST, - FILE_DESCRIPTOR_LIMIT_REACHED, - NO_SEMAPHORE_WITH_THAT_NAME_EXISTS, - OUT_OF_MEMORY, - UNDEFINED -}; - -enum class SemaphoreWaitState -{ - TIMEOUT, - NO_TIMEOUT, -}; - -struct CreateUnnamedSingleProcessSemaphore_t -{ -}; -struct CreateUnnamedSharedMemorySemaphore_t -{ -}; -struct CreateNamedSemaphore_t -{ -}; -struct OpenNamedSemaphore_t -{ -}; -static constexpr CreateUnnamedSingleProcessSemaphore_t CreateUnnamedSingleProcessSemaphore = - CreateUnnamedSingleProcessSemaphore_t(); -static constexpr CreateUnnamedSharedMemorySemaphore_t CreateUnnamedSharedMemorySemaphore = - CreateUnnamedSharedMemorySemaphore_t(); -static constexpr CreateNamedSemaphore_t CreateNamedSemaphore = CreateNamedSemaphore_t(); -static constexpr OpenNamedSemaphore_t OpenNamedSemaphore = OpenNamedSemaphore_t(); - -/// @brief Posix semaphore C++ Wrapping class -/// @code -/// auto semaphore = posix::Semaphore::CreateUnnamed(false, 5); -/// int value; -/// if ( semaphore.getValue(value) ) // no error has occurred -/// { -/// std::cout << value << std::endl; -/// } -/// @endcode -class Semaphore : public DesignPattern::Creation -{ - public: - /// @brief Default constructor which creates an uninitialized semaphore. - /// This semaphore object is unusable you need to reassign it with - /// an object created by the semaphore factory methods - Semaphore() noexcept; - - /// @brief Move constructor. - Semaphore(Semaphore&& rhs) noexcept; - - /// @brief Move assignment operator. - Semaphore& operator=(Semaphore&& rhs) noexcept; - - /// @brief We are denying Semaphore copy since it manages the semaphore resource - /// and the underlying concept did not include copying - Semaphore(const Semaphore&) = delete; - - /// @brief We are denying Semaphore copy since it manages the semaphore resource - /// and the underlying concept did not include copying - Semaphore& operator=(const Semaphore&) = delete; - - /// @brief Destructor - ~Semaphore() noexcept; - - /// @brief calls sem_getvalue which gets the value of a semaphore - /// From the sem_getvalue manpage: sem_getvalue() places the current value - /// of the semaphore pointed to sem into the integer pointed to by sval. - /// - /// If one or more processes or threads are blocked waiting to lock the - /// semaphore with sem_wait(3), POSIX.1 permits two possibilities for the - /// value returned in sval: either 0 is returned; or a negative number whose - /// absolute value is the count of the number of processes and threads - /// currently blocked in sem_wait(3). Linux adopts the former behavior. - /// - /// @param[in] value reference in which the value of the semaphore is - /// written to - /// - /// @return expected which contains either the value of the semaphore or - /// the cause why the value could not be retrieved - cxx::expected getValue() const noexcept; - - /// @brief calls sem_post which unlocks a semaphore - /// From the sem_post manpage: sem_post() increments (unlocks) the - /// semaphore pointed to by sem. If the semaphore's value consequently - /// becomes greater than zero, then another process or thread blocked in a - /// sem_wait(3) call will be woken up and proceed to lock the semaphore. - /// - /// @return if post fails the expected contains the error which occurred - cxx::expected post() noexcept; - - /// @brief see wait() - /// @param[in] abs_timeout timeout of the wait - /// @return when successful the SemaphoreWaitState states if a timeout happened - /// or not otherwise the SemaphoreError contains the error - cxx::expected timedWait(const units::Duration abs_timeout) noexcept; - - /// @brief see wait() - /// @return if the semaphore was decremented the expected contains the value true - /// otherwise false. if an error occurred it is stored inside the expected - cxx::expected tryWait() noexcept; - - /// @brief calls sem_wait which locks a semaphore - /// From the sem_wait manpage: sem_wait() decrements (locks) the semaphore - /// pointed to by sem. If the semaphore's value is greater than zero, then - /// the decrement proceeds, and the function returns, immediately. If the - /// semaphore - /// currently has the value zero, then the call blocks until either it - /// becomes possible to perform the decrement (i.e., the semaphore value - /// rises above zero), or a signal handler interrupts the call. - /// - /// iox_sem_trywait() is the same as sem_wait(), except that if the decrement - /// cannot be immediately performed, then call returns an error (errno set - /// to EAGAIN) instead of blocking. - /// - /// iox_sem_timedwait() is the same as sem_wait(), except that abs_timeout - /// specifies a limit on the amount of time that the call should block if - /// the decrement cannot be immediately performed. - /// - /// If the timeout has already expired by the time of the call, and the - /// semaphore could not be locked immediately, then iox_sem_timedwait() fails - /// with a timeout error (errno set to ETIMEDOUT). - /// - /// If the operation can be performed immediately, then iox_sem_timedwait() - /// never fails with a timeout error, regardless of the value of - /// abs_timeout. Furthermore, the validity of abs_timeout is not checked in - /// this case. - /// - /// @return if an error during the call occurs the error value is set - cxx::expected wait() noexcept; - - private: - cxx::string<128> m_name; - bool m_isCreated = true; - bool m_isNamedSemaphore = true; - bool m_isShared = false; - - mutable iox_sem_t m_handle{}; - mutable iox_sem_t* m_handlePtr = nullptr; - - private: - friend class DesignPattern::Creation; - - /// @brief Creates a local unnamed semaphore. - /// The Semaphore should be initialized but that has to be verified - /// via IsInitialized() - /// For details see man sem_init. - /// @param[in] value initial value of the semaphore - Semaphore(CreateUnnamedSingleProcessSemaphore_t, const unsigned int value) noexcept; - - /// @brief Creates unnamed semaphore in the shared memory. - /// The Semaphore should be initialized but that has to be verified - /// via IsInitialized() - /// For details see man sem_init. - /// @param[in] value initial value of the semaphore - Semaphore(CreateUnnamedSharedMemorySemaphore_t, const unsigned int value) noexcept; - - /// @brief Opens an already existing named semaphore. If a semaphore with - /// name does not exist an uninitialized Semaphore is returned - /// otherwise the Semaphore can be initialized but that has to be - /// verified via IsInitialized(). - /// For details see man sem_open. - /// @param[in] name name of the semaphore - /// @param[in] oflag specifies flags that control the operation of the call - /// O_CREAT flag is not allowed here - Semaphore(OpenNamedSemaphore_t, const char* name, const int oflag) noexcept; - - /// @brief Creates an exclusive named semaphore. If a semaphore with name - /// already exists then the Semaphore returned is not initialized - /// and not usable! - /// You always have to verify if the semaphore returned by this - /// factory is initialized via the IsInitialized() method. - /// For details see man sem_open. - /// @param[in] name name of the semaphore - /// @param[in] mode specifies the permissions to be placed on the new - /// semaphore, see man 2 open to get a detailed description - /// on mode_t - /// @param[in] value the initial value of the semaphore - /// @return Semaphore object which can be initialized, if a semaphore - /// named name exists it is definitly an uninitialized semaphore. - Semaphore(CreateNamedSemaphore_t, const char* name, const mode_t mode, const unsigned int value) noexcept; - - /// @brief calls sem_close which closes a named semaphore - /// From the sem_close manpage: sem_close() closes the named semaphore - /// referred to by sem, allowing any resources that the system has allocated - /// to the calling process for this semaphore to be freed. - /// - /// @return returns false when sem_close fails otherwise true - bool close() noexcept; - - /// @brief calls sem_destroy which destroys a unnamed semaphore - /// From the sem_destroy manpage: sem_destroy() destroys the unnamed - /// semaphore at the address pointed to by sem. - /// - /// Only a semaphore that has been initialized by sem_init(3) should be - /// destroyed using sem_destroy(). - /// - /// Destroying a semaphore that other processes or threads are currently - /// blocked on (in sem_wait(3)) produces undefined behavior. - /// - /// Using a semaphore that has been destroyed produces undefined results, - /// until the semaphore has been reinitialized using sem_init(3). - /// - /// @return returns false when sem_destroy fails otherwise true - bool destroy() noexcept; - - /// @brief calls sem_init which initializes an unnamed semaphore - /// From the sem_init manpage: sem_init() initializes the unnamed semaphore - /// at the address pointed to by sem. The value argument specifies the - /// initial value for the semaphore. - /// - /// The pshared argument indicates whether this semaphore is to be shared - /// between the threads of a process, or between processes. - /// - /// If pshared has the value 0, then the semaphore is shared between the - /// threads of a process, and should be located at some address that is - /// visible to all threads (e.g., a global variable, or a vari‐ able - /// allocated dynamically on the heap). - /// - /// If pshared is nonzero, then the semaphore is shared between processes, - /// and should be located in a region of shared memory (see shm_open(3), - /// mmap(2), and shmget(2)). (Since a child created by fork(2) - /// inherits its parent's memory mappings, it can also access the - /// semaphore.) Any process that can access the shared memory region can - /// operate on the semaphore using sem_post(3), sem_wait(3), and so on. - /// - /// Initializing a semaphore that has already been initialized results in - /// undefined behavior. - /// - /// @return returns false when sem_init fails otherwise true - static bool init(iox_sem_t* handle, const int pshared, const unsigned int value) noexcept; - - /// @brief calls sem_open which initializes and opens a named semaphore - /// From the sem_open manpage: sem_open() creates a new POSIX semaphore or - /// opens an existing semaphore. The semaphore is identified by name. For - /// details of the construction of name, see sem_overview(7). - /// - /// The oflag argument specifies flags that control the operation of the - /// call. (Definitions of the flags values can be obtained by including - /// .) If O_CREAT is specified in oflag, then the sem‐ aphore is - /// created if it does not already exist. The owner (user ID) of the - /// semaphore is set to the effective user ID of the calling process. The - /// group ownership (group ID) is set to the effective group ID of the - /// calling process. If both O_CREAT and O_EXCL are specified in oflag, - /// then an error is returned if a semaphore with the given name already - /// exists. - /// - /// If O_CREAT is specified in oflag, then two additional arguments must - /// be supplied. The mode argument specifies the permissions to be placed - /// on the new semaphore, as for open(2). (Symbolic defini‐ tions for the - /// permissions bits can be obtained by including .) The - /// permissions settings are masked against the process umask. Both read and - /// write permission should be granted to each class of user that will - /// access the semaphore. The value argument specifies the initial value for - /// the new semaphore. If O_CREAT is specified, and a semaphore with the - /// given name already exists, then mode and value are ignored. - /// - /// @return returns false when sem_open fails otherwise true - bool open(const int oflag) noexcept; - - /// @brief returns the pointer to the managed semaphore. You can use this - /// pointer with all the sem_** functions. - iox_sem_t* getHandle() const noexcept; - - bool open(const int oflag, const mode_t mode, const unsigned int value) noexcept; - - /// @brief calls sem_unlink which removes a named semaphore - /// From the sem_unlink manpage: sem_unlink() removes the named semaphore - /// referred to by name. The semaphore name is removed immediately. The - /// semaphore is destroyed once all other processes that have the semaphore - /// open close it. - /// - /// @return returns false when sem_unlink fails otherwise true - static bool unlink(const char* name) noexcept; - - /// @brief Returns true if the semaphore was created with CreateNamed or - /// OpenNamed otherwise it returns false. - bool isNamedSemaphore() const noexcept; - - void closeHandle() noexcept; - - static SemaphoreError errnoToEnum(const int errnoValue) noexcept; -}; -} // namespace posix -} // namespace iox - -#endif // IOX_HOOFS_POSIX_WRAPPER_SEMAPHORE_HPP diff --git a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/signal_watcher.hpp b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/signal_watcher.hpp index ca99ef8427..180acaa852 100644 --- a/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/signal_watcher.hpp +++ b/iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/signal_watcher.hpp @@ -16,8 +16,8 @@ #ifndef IOX_HOOFS_POSIX_WRAPPER_SIGNAL_WATCHER_HPP #define IOX_HOOFS_POSIX_WRAPPER_SIGNAL_WATCHER_HPP -#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" #include "iceoryx_hoofs/posix_wrapper/signal_handler.hpp" +#include "iceoryx_hoofs/posix_wrapper/unnamed_semaphore.hpp" #include @@ -69,7 +69,7 @@ class SignalWatcher private: friend void internalSignalHandler(int) noexcept; mutable std::atomic m_numberOfWaiters{0U}; - mutable Semaphore m_semaphore; + mutable cxx::optional m_semaphore; std::atomic_bool m_hasSignalOccurred{false}; SignalGuard m_sigTermGuard; diff --git a/iceoryx_hoofs/source/posix_wrapper/named_pipe.cpp b/iceoryx_hoofs/source/posix_wrapper/named_pipe.cpp index c25f1ef457..0e154e7c74 100644 --- a/iceoryx_hoofs/source/posix_wrapper/named_pipe.cpp +++ b/iceoryx_hoofs/source/posix_wrapper/named_pipe.cpp @@ -111,7 +111,7 @@ NamedPipe::NamedPipe(const IpcChannelName_t& name, m_isInitialized = true; if (m_sharedMemory->hasOwnership()) { - new (m_data) NamedPipeData(m_isInitialized, m_errorValue, maxMsgNumber); + new (m_data) NamedPipeData(m_isInitialized, m_errorValue, static_cast(maxMsgNumber)); } else { @@ -324,7 +324,7 @@ cxx::expected NamedPipe::timedReceive(const units: // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) semaphores are initalized via placementCreate call NamedPipe::NamedPipeData::NamedPipeData(bool& isInitialized, IpcChannelError& error, - const uint64_t maxMsgNumber) noexcept + const uint32_t maxMsgNumber) noexcept { auto signalError = [&](const char* name) { std::cerr << "Unable to create " << name << " semaphore for named pipe \"" << 'x' << "\""; @@ -332,8 +332,10 @@ NamedPipe::NamedPipeData::NamedPipeData(bool& isInitialized, error = IpcChannelError::INTERNAL_LOGIC_ERROR; }; - Semaphore::placementCreate( - &semaphores[SEND_SEMAPHORE], CreateUnnamedSharedMemorySemaphore, static_cast(maxMsgNumber)) + UnnamedSemaphoreBuilder() + .initialValue(maxMsgNumber) + .isInterProcessCapable(true) + .create(semaphores[SEND_SEMAPHORE]) .or_else([&](auto) { signalError("send"); }); if (!isInitialized) @@ -341,7 +343,10 @@ NamedPipe::NamedPipeData::NamedPipeData(bool& isInitialized, return; } - Semaphore::placementCreate(&semaphores[RECEIVE_SEMAPHORE], CreateUnnamedSharedMemorySemaphore, 0U) + UnnamedSemaphoreBuilder() + .initialValue(0U) + .isInterProcessCapable(true) + .create(semaphores[RECEIVE_SEMAPHORE]) .or_else([&](auto) { signalError("receive"); }); if (!isInitialized) @@ -352,23 +357,14 @@ NamedPipe::NamedPipeData::NamedPipeData(bool& isInitialized, initializationGuard.store(VALID_DATA); } -NamedPipe::NamedPipeData::~NamedPipeData() noexcept +UnnamedSemaphore& NamedPipe::NamedPipeData::sendSemaphore() noexcept { - if (hasValidState()) - { - sendSemaphore().~Semaphore(); - receiveSemaphore().~Semaphore(); - } -} - -Semaphore& NamedPipe::NamedPipeData::sendSemaphore() noexcept -{ - return reinterpret_cast(semaphores[SEND_SEMAPHORE]); + return *semaphores[SEND_SEMAPHORE]; } -Semaphore& NamedPipe::NamedPipeData::receiveSemaphore() noexcept +UnnamedSemaphore& NamedPipe::NamedPipeData::receiveSemaphore() noexcept { - return reinterpret_cast(semaphores[RECEIVE_SEMAPHORE]); + return *semaphores[RECEIVE_SEMAPHORE]; } bool NamedPipe::NamedPipeData::waitForInitialization() const noexcept diff --git a/iceoryx_hoofs/source/posix_wrapper/semaphore.cpp b/iceoryx_hoofs/source/posix_wrapper/semaphore.cpp deleted file mode 100644 index 304fff36b4..0000000000 --- a/iceoryx_hoofs/source/posix_wrapper/semaphore.cpp +++ /dev/null @@ -1,298 +0,0 @@ -// 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 - -#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" -#include "iceoryx_hoofs/cxx/helplets.hpp" -#include "iceoryx_hoofs/platform/platform_correction.hpp" -#include "iceoryx_hoofs/posix_wrapper/posix_call.hpp" - -namespace iox -{ -namespace posix -{ -Semaphore::Semaphore() noexcept = default; - -Semaphore::Semaphore(Semaphore&& rhs) noexcept -{ - *this = std::move(rhs); -} - -Semaphore& Semaphore::operator=(Semaphore&& rhs) noexcept -{ - if (this != &rhs) - { - closeHandle(); - - CreationPattern_t::operator=(std::move(rhs)); - - m_name = std::move(rhs.m_name); - m_isCreated = std::move(rhs.m_isCreated); - m_isNamedSemaphore = std::move(rhs.m_isNamedSemaphore); - m_handle = std::move(rhs.m_handle); - m_isShared = std::move(rhs.m_isShared); - if (m_isNamedSemaphore || m_isShared) - { - m_handlePtr = std::move(rhs.m_handlePtr); - } - else - { - m_handlePtr = &m_handle; - } - - rhs.m_handlePtr = nullptr; - rhs.m_isInitialized = false; - } - - return *this; -} - -Semaphore::~Semaphore() noexcept -{ - closeHandle(); -} - -void Semaphore::closeHandle() noexcept -{ - if (m_isInitialized) - { - if (isNamedSemaphore()) - { - close(); - if (m_isCreated) - { - unlink(m_name.c_str()); - } - } - else - { - destroy(); - } - m_isInitialized = false; - } -} - -cxx::expected Semaphore::getValue() const noexcept -{ - int value{0}; - auto call = posixCall(iox_sem_getvalue)(getHandle(), &value).failureReturnValue(-1).evaluate(); - if (call.has_error()) - { - return cxx::error(errnoToEnum(call.get_error().errnum)); - } - - return cxx::success(value); -} - -cxx::expected Semaphore::post() noexcept -{ - auto call = posixCall(iox_sem_post)(getHandle()).failureReturnValue(-1).evaluate(); - if (call.has_error()) - { - return cxx::error(errnoToEnum(call.get_error().errnum)); - } - - return cxx::success<>(); -} - -cxx::expected Semaphore::timedWait(const units::Duration abs_timeout) noexcept -{ - const struct timespec timeout = abs_timeout.timespec(units::TimeSpecReference::Epoch); - auto call = - posixCall(iox_sem_timedwait)(getHandle(), &timeout).failureReturnValue(-1).ignoreErrnos(ETIMEDOUT).evaluate(); - - if (call.has_error()) - { - return cxx::error(errnoToEnum(call.get_error().errnum)); - } - else if (call->errnum == ETIMEDOUT) - { - return cxx::success(SemaphoreWaitState::TIMEOUT); - } - else - { - return cxx::success(SemaphoreWaitState::NO_TIMEOUT); - } -} - -cxx::expected Semaphore::tryWait() noexcept -{ - auto call = posixCall(iox_sem_trywait)(getHandle()).failureReturnValue(-1).ignoreErrnos(EAGAIN).evaluate(); - - if (call.has_error()) - { - return cxx::error(errnoToEnum(call.get_error().errnum)); - } - - return cxx::success(call->errnum != EAGAIN); -} - -cxx::expected Semaphore::wait() noexcept -{ - auto call = posixCall(iox_sem_wait)(getHandle()).failureReturnValue(-1).evaluate(); - - if (call.has_error()) - { - return cxx::error(errnoToEnum(call.get_error().errnum)); - } - - return cxx::success<>(); -} - -iox_sem_t* Semaphore::getHandle() const noexcept -{ - return (isNamedSemaphore()) ? m_handlePtr : &m_handle; -} - -Semaphore::Semaphore(CreateUnnamedSingleProcessSemaphore_t, const unsigned int value) noexcept - : m_isNamedSemaphore(false) -{ - if (init(&m_handle, 0, value)) - { - m_isInitialized = true; - } - else - { - m_isInitialized = false; - m_errorValue = SemaphoreError::CREATION_FAILED; - } -} - -Semaphore::Semaphore(CreateUnnamedSharedMemorySemaphore_t, const unsigned int value) noexcept - : m_isNamedSemaphore(false) -{ - if (init(&m_handle, 1, value)) - { - m_isInitialized = true; - } - else - { - m_isInitialized = false; - m_errorValue = SemaphoreError::CREATION_FAILED; - } -} - -Semaphore::Semaphore(OpenNamedSemaphore_t, const char* name, const int oflag) noexcept - : m_isCreated(false) -{ - if (!m_name.unsafe_assign(name)) - { - m_isInitialized = false; - m_errorValue = SemaphoreError::NAME_TOO_LONG; - return; - } - - if (open(oflag)) - { - m_isInitialized = true; - } - else - { - m_errorValue = SemaphoreError::UNABLE_TO_OPEN_HANDLE; - m_isInitialized = false; - } -} - -// NOLINTNEXTLINE(readability-function-size) todo(iox-#832): make a struct out of arguments -Semaphore::Semaphore(CreateNamedSemaphore_t, const char* name, const mode_t mode, const unsigned int value) noexcept - : m_isCreated(true) -{ - if (!m_name.unsafe_assign(name)) - { - m_isInitialized = false; - m_errorValue = SemaphoreError::NAME_TOO_LONG; - return; - } - - if (open(O_CREAT | O_EXCL, mode, value)) - { - m_isInitialized = true; - } - else - { - m_errorValue = SemaphoreError::CREATION_FAILED; - m_isInitialized = false; - } -} - -bool Semaphore::close() noexcept -{ - return !posixCall(iox_sem_close)(getHandle()).failureReturnValue(-1).evaluate().has_error(); -} - -bool Semaphore::destroy() noexcept -{ - return !posixCall(iox_sem_destroy)(getHandle()).failureReturnValue(-1).evaluate().has_error(); -} - -bool Semaphore::init(iox_sem_t* handle, const int pshared, const unsigned int value) noexcept -{ - return !posixCall(iox_sem_init)(handle, pshared, value).failureReturnValue(-1).evaluate().has_error(); -} - -bool Semaphore::open(const int oflag) noexcept -{ - return !posixCall(iox_sem_open)(m_name.c_str(), oflag) - .failureReturnValue(IOX_SEM_FAILED) - .evaluate() - .and_then([this](auto& r) { this->m_handlePtr = r.value; }) - .or_else([this](auto&) { this->m_errorValue = SemaphoreError::CREATION_FAILED; }) - .has_error(); -} - -bool Semaphore::open(const int oflag, const mode_t mode, const unsigned int value) noexcept -{ - return !posixCall(iox_sem_open_ext)(m_name.c_str(), oflag, mode, value) - .failureReturnValue(IOX_SEM_FAILED) - .evaluate() - .and_then([this](auto& r) { this->m_handlePtr = r.value; }) - .or_else([this](auto&) { this->m_errorValue = SemaphoreError::CREATION_FAILED; }) - .has_error(); -} - -bool Semaphore::unlink(const char* name) noexcept -{ - return !posixCall(iox_sem_unlink)(name).failureReturnValue(-1).evaluate().has_error(); -} - -bool Semaphore::isNamedSemaphore() const noexcept -{ - return m_isNamedSemaphore; -} - -SemaphoreError Semaphore::errnoToEnum(const int errnoValue) noexcept -{ - switch (errnoValue) - { - case EINVAL: - std::cerr << "semaphore object is in an inconsistent state" << std::endl; - return SemaphoreError::INVALID_SEMAPHORE_HANDLE; - case EOVERFLOW: - std::cerr << "semaphore is overflowing" << std::endl; - return SemaphoreError::SEMAPHORE_OVERFLOW; - case EINTR: - std::cerr << "call was interrupted by signal handler" << std::endl; - return SemaphoreError::INTERRUPTED_BY_SIGNAL_HANDLER; - default: - std::cerr << "an unexpected error occurred in semaphore - this should never happen! errno: " - // NOLINTNEXTLINE(concurrency-mt-unsafe) impossible case - << strerror(errnoValue) << std::endl; - return SemaphoreError::UNDEFINED; - } -} - -} // namespace posix -} // namespace iox diff --git a/iceoryx_hoofs/source/posix_wrapper/signal_watcher.cpp b/iceoryx_hoofs/source/posix_wrapper/signal_watcher.cpp index 88e6a46e32..a8c5317b83 100644 --- a/iceoryx_hoofs/source/posix_wrapper/signal_watcher.cpp +++ b/iceoryx_hoofs/source/posix_wrapper/signal_watcher.cpp @@ -29,26 +29,18 @@ void internalSignalHandler(int) noexcept for (uint64_t remainingNumberOfWaiters = instance.m_numberOfWaiters.load(); remainingNumberOfWaiters > 0; --remainingNumberOfWaiters) { - instance.m_semaphore.post().or_else([](auto) { - constexpr const char MSG[] = "Unable to increment semaphore in signal handler"; - auto result = write(STDERR_FILENO, MSG, sizeof(MSG)); - IOX_DISCARD_RESULT(result); - std::abort(); - }); + instance.m_semaphore->post().expect("Unable to increment semaphore in signal handler"); } } SignalWatcher::SignalWatcher() noexcept - : m_semaphore{std::move(Semaphore::create(CreateUnnamedSingleProcessSemaphore, 0U) - .or_else([](auto) { - std::cerr << "Unable to create semaphore for signal watcher" << std::endl; - constexpr bool UNABLE_TO_CREATE_SEMAPHORE_FOR_SIGNAL_WATCHER = false; - cxx::Ensures(UNABLE_TO_CREATE_SEMAPHORE_FOR_SIGNAL_WATCHER); - }) - .value())} - , m_sigTermGuard(registerSignalHandler(Signal::TERM, internalSignalHandler)) + : m_sigTermGuard(registerSignalHandler(Signal::TERM, internalSignalHandler)) , m_sigIntGuard(registerSignalHandler(Signal::INT, internalSignalHandler)) { + UnnamedSemaphoreBuilder() + .isInterProcessCapable(false) + .create(m_semaphore) + .expect("Unable to create semaphore for signal watcher"); } SignalWatcher& SignalWatcher::getInstance() noexcept @@ -65,11 +57,7 @@ void SignalWatcher::waitForSignal() const noexcept return; } - m_semaphore.wait().or_else([](auto) { - std::cerr << "Unable to wait on semaphore in signal watcher" << std::endl; - constexpr bool UNABLE_TO_WAIT_ON_SEMAPHORE_IN_SIGNAL_WATCHER = false; - cxx::Ensures(UNABLE_TO_WAIT_ON_SEMAPHORE_IN_SIGNAL_WATCHER); - }); + m_semaphore->wait().expect("Unable to wait on semaphore in signal watcher"); } bool SignalWatcher::wasSignalTriggered() const noexcept diff --git a/iceoryx_hoofs/test/moduletests/test_semaphore_module.cpp b/iceoryx_hoofs/test/moduletests/test_semaphore_module.cpp deleted file mode 100644 index ba63ce08b0..0000000000 --- a/iceoryx_hoofs/test/moduletests/test_semaphore_module.cpp +++ /dev/null @@ -1,374 +0,0 @@ -// Copyright (c) 2019, 2021 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 - -#include "iceoryx_hoofs/cxx/convert.hpp" -#include "iceoryx_hoofs/internal/units/duration.hpp" -#include "iceoryx_hoofs/platform/time.hpp" -#include "iceoryx_hoofs/posix_wrapper/semaphore.hpp" -#include "iceoryx_hoofs/testing/test.hpp" -#include "iceoryx_hoofs/testing/timing_test.hpp" -#include "test_posix_semaphore_common.hpp" - -#include -#include -#include - -namespace -{ -using namespace ::testing; -using namespace iox::units::duration_literals; - -typedef iox::posix::Semaphore* CreateSemaphore(); - -iox::posix::Semaphore* createNamedSemaphore() -{ - static int i = 10; - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateNamedSemaphore, - std::string("/fuuSem" + iox::cxx::convert::toString(i++)).c_str(), - S_IRUSR | S_IWUSR, - 0); - return (semaphore.has_error()) ? nullptr : new iox::posix::Semaphore(std::move(*semaphore)); -} - -iox::posix::Semaphore* createUnnamedSemaphore() -{ - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateUnnamedSingleProcessSemaphore, 0); - return (semaphore.has_error()) ? nullptr : new iox::posix::Semaphore(std::move(*semaphore)); -} - -class Semaphore_test : public TestWithParam -{ - public: - Semaphore_test() - : sut((*GetParam())()) - { - } - - ~Semaphore_test() - { - delete sut; - delete syncSemaphore; - } - - void SetUp() - { - internal::CaptureStderr(); - ASSERT_THAT(sut, Ne(nullptr)); - ASSERT_THAT(syncSemaphore, Ne(nullptr)); - } - - void TearDown() - { - std::string output = internal::GetCapturedStderr(); - if (Test::HasFailure()) - { - std::cout << output << std::endl; - } - } - - static constexpr unsigned long long TIMING_TEST_TIMEOUT{(100_ms).toNanoseconds()}; - - iox::posix::Semaphore* sut{nullptr}; - iox::posix::Semaphore* syncSemaphore = [] { - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateUnnamedSingleProcessSemaphore, 0); - return (semaphore.has_error()) ? nullptr : new iox::posix::Semaphore(std::move(*semaphore)); - }(); -}; - -class SemaphoreCreate_test : public Test -{ - public: - void SetUp() - { - internal::CaptureStderr(); - } - - void TearDown() - { - std::string output = internal::GetCapturedStderr(); - if (Test::HasFailure()) - { - std::cout << output << std::endl; - } - } -}; - -INSTANTIATE_TEST_SUITE_P(Semaphore_test, Semaphore_test, Values(&createNamedSemaphore, &createUnnamedSemaphore)); - -TEST_F(SemaphoreCreate_test, CreateNamedSemaphore) -{ - ::testing::Test::RecordProperty("TEST_ID", "80f5fba8-c6db-4948-86e1-9e23d413d1ac"); - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateNamedSemaphore, "/fuuSem", S_IRUSR | S_IWUSR, 10); - EXPECT_THAT(semaphore.has_error(), Eq(false)); -} - -TEST_F(SemaphoreCreate_test, CreateExistingNamedSemaphore) -{ - ::testing::Test::RecordProperty("TEST_ID", "bee46586-bcf2-42e6-9dda-ab2611fc973f"); - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateNamedSemaphore, "/fuuSem1", S_IRUSR | S_IWUSR, 10); - auto semaphore2 = - iox::posix::Semaphore::create(iox::posix::CreateNamedSemaphore, "/fuuSem1", S_IRUSR | S_IWUSR, 10); - ASSERT_EQ(semaphore.has_error(), false); - ASSERT_EQ(semaphore2.has_error(), true); -} - -TEST_F(SemaphoreCreate_test, CreateLocalUnnamedSemaphore) -{ - ::testing::Test::RecordProperty("TEST_ID", "42099e77-9ac9-425f-8e53-056dc3b73d71"); - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateUnnamedSingleProcessSemaphore, 10); - EXPECT_THAT(semaphore.has_error(), Eq(false)); -} - -TEST_F(SemaphoreCreate_test, OpenNamedSemaphore) -{ - ::testing::Test::RecordProperty("TEST_ID", "349cdf0d-987e-4e2f-aa35-98a40fdf979b"); - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateNamedSemaphore, "/fuuSem", S_IRUSR | S_IWUSR, 10); - auto semaphore2 = iox::posix::Semaphore::create(iox::posix::OpenNamedSemaphore, "/fuuSem", 0); - EXPECT_THAT(semaphore.has_error(), Eq(false)); - EXPECT_THAT(semaphore2.has_error(), Eq(false)); -} - -TEST_F(SemaphoreCreate_test, OpenNamedSemaphoreWithEmptyNameFails) -{ - ::testing::Test::RecordProperty("TEST_ID", "5dab9f61-8b27-4684-8e9d-bbd50430b9fa"); - auto semaphore = iox::posix::Semaphore::create(iox::posix::CreateNamedSemaphore, "", S_IRUSR | S_IWUSR, 10); - EXPECT_THAT(semaphore.has_error(), Eq(true)); -} - -TEST_F(SemaphoreCreate_test, OpenNonExistingNamedSemaphore) -{ - ::testing::Test::RecordProperty("TEST_ID", "0034b274-5a3b-49dc-a5d2-1715d068809f"); - auto semaphore2 = iox::posix::Semaphore::create(iox::posix::OpenNamedSemaphore, "/fuuSem", S_IRUSR | S_IWUSR); - EXPECT_THAT(semaphore2.has_error(), Eq(true)); -} - -TEST_P(Semaphore_test, PostIncreasesSemaphoreValue) -{ - ::testing::Test::RecordProperty("TEST_ID", "af3013ef-683e-4ad4-874f-5c7e1a3f41fd"); - for (int i = 0; i < 12; ++i) - { - ASSERT_FALSE(sut->post().has_error()); - } - - EXPECT_TRUE(setSemaphoreToZeroAndVerifyValue(*sut, 12)); -} - -TEST_P(Semaphore_test, WaitDecreasesSemaphoreValue) -{ - ::testing::Test::RecordProperty("TEST_ID", "29a63157-caee-4d28-a477-c4fa7048911c"); - for (int i = 0; i < 18; ++i) - { - ASSERT_FALSE(sut->post().has_error()); - } - for (int i = 0; i < 7; ++i) - { - ASSERT_FALSE(sut->wait().has_error()); - } - - EXPECT_TRUE(setSemaphoreToZeroAndVerifyValue(*sut, 11)); -} - -TEST_P(Semaphore_test, SuccessfulTryWaitDecreasesSemaphoreValue) -{ - ::testing::Test::RecordProperty("TEST_ID", "a98d1c45-d538-4abc-9633-f4868163785d"); - for (int i = 0; i < 15; ++i) - { - ASSERT_FALSE(sut->post().has_error()); - } - for (int i = 0; i < 9; ++i) - { - auto call = sut->tryWait(); - ASSERT_THAT(call.has_error(), Eq(false)); - ASSERT_THAT(*call, Eq(true)); - } - - EXPECT_TRUE(setSemaphoreToZeroAndVerifyValue(*sut, 6)); -} - -TEST_P(Semaphore_test, FailingTryWaitDoesNotChangeSemaphoreValue) -{ - ::testing::Test::RecordProperty("TEST_ID", "8bad3784-888b-44cd-ad5d-1c4662b26b17"); - for (int i = 0; i < 4; ++i) - { - auto call = sut->tryWait(); - ASSERT_THAT(call.has_error(), Eq(false)); - ASSERT_THAT(*call, Eq(false)); - } - - auto result = sut->getValue(); - ASSERT_THAT(result.has_error(), Eq(false)); - EXPECT_THAT(*result, Eq(0)); -} - -TEST_P(Semaphore_test, SuccessfulTimedWaitDecreasesSemaphoreValue) -{ - ::testing::Test::RecordProperty("TEST_ID", "e3bd3f5d-967c-4a5b-9f22-a8f92f73b3c3"); - const iox::units::Duration timeToWait = 2_ms; - for (int i = 0; i < 19; ++i) - { - ASSERT_FALSE(sut->post().has_error()); - } - - for (int i = 0; i < 12; ++i) - { - auto call = sut->timedWait(timeToWait); - ASSERT_FALSE(call.has_error()); - ASSERT_TRUE(call.value() == iox::posix::SemaphoreWaitState::NO_TIMEOUT); - } - - EXPECT_TRUE(setSemaphoreToZeroAndVerifyValue(*sut, 7)); -} - -TEST_P(Semaphore_test, FailingTimedWaitDoesNotChangeSemaphoreValue) -{ - ::testing::Test::RecordProperty("TEST_ID", "5a630be5-aef6-493e-a8ee-4dfabe642258"); - const iox::units::Duration timeToWait = 2_us; - for (int i = 0; i < 4; ++i) - { - auto call = sut->timedWait(timeToWait); - ASSERT_FALSE(call.has_error()); - ASSERT_TRUE(call.value() == iox::posix::SemaphoreWaitState::TIMEOUT); - } - - auto result = sut->getValue(); - ASSERT_THAT(result.has_error(), Eq(false)); - EXPECT_THAT(*result, Eq(0)); -} - - -TEST_P(Semaphore_test, TryWaitAfterPostIsSuccessful) -{ - ::testing::Test::RecordProperty("TEST_ID", "22354447-c44d-443c-97a5-f5fdffb09748"); - ASSERT_FALSE(sut->post().has_error()); - auto call = sut->tryWait(); - ASSERT_THAT(call.has_error(), Eq(false)); - ASSERT_THAT(*call, Eq(true)); -} - -TEST_P(Semaphore_test, TryWaitWithNoPostIsNotSuccessful) -{ - ::testing::Test::RecordProperty("TEST_ID", "0e5d6817-88a9-4fca-889e-4dbfe2c30e48"); - ASSERT_FALSE(sut->post().has_error()); - auto call = sut->tryWait(); - ASSERT_THAT(call.has_error(), Eq(false)); - ASSERT_THAT(*call, Eq(true)); -} - -TEST_P(Semaphore_test, WaitValidAfterPostIsNonBlocking) -{ - ::testing::Test::RecordProperty("TEST_ID", "d4b1de28-89c4-4dfa-a465-8c7cfc652d67"); - ASSERT_FALSE(sut->post().has_error()); - // this call should not block and should be successful - EXPECT_THAT(sut->wait().has_error(), Eq(false)); -} - -TEST_P(Semaphore_test, WaitIsBlocking) -{ - ::testing::Test::RecordProperty("TEST_ID", "5869a475-6be3-4b55-aa58-2ebf11d46081"); - std::atomic counter{0}; - std::thread t1([&] { - ASSERT_FALSE(syncSemaphore->wait().has_error()); - ASSERT_FALSE(sut->post().has_error()); - ASSERT_FALSE(syncSemaphore->wait().has_error()); - counter++; - ASSERT_FALSE(sut->post().has_error()); - }); - - EXPECT_THAT(counter.load(), Eq(0)); - - ASSERT_FALSE(syncSemaphore->post().has_error()); - ASSERT_FALSE(sut->wait().has_error()); - EXPECT_THAT(counter.load(), Eq(0)); - - ASSERT_FALSE(syncSemaphore->post().has_error()); - ASSERT_FALSE(sut->wait().has_error()); - EXPECT_THAT(counter.load(), Eq(1)); - - t1.join(); -} - -TEST_P(Semaphore_test, MoveAssignment) -{ - ::testing::Test::RecordProperty("TEST_ID", "bf7277fd-4e5c-49dd-b48b-f5d1ed6e4c01"); - iox::posix::Semaphore b; - { - b = std::move(*sut); - } - - EXPECT_THAT(b.post().has_error(), Eq(false)); -} - -TEST_P(Semaphore_test, MoveCTor) -{ - ::testing::Test::RecordProperty("TEST_ID", "e8083f97-c3c0-4e79-9948-395a837bde84"); - iox::posix::Semaphore b(std::move(*sut)); - - EXPECT_THAT(b.post().has_error(), Eq(false)); -} - -TIMING_TEST_P(Semaphore_test, TimedWaitWithTimeout, Repeat(3), [&] { - using namespace iox::units; - std::atomic_bool timedWaitFinish{false}; - - std::thread t([&] { - auto timeout = Duration::fromNanoseconds(TIMING_TEST_TIMEOUT); - ASSERT_FALSE(syncSemaphore->post().has_error()); - ASSERT_FALSE(sut->wait().has_error()); - auto call = sut->timedWait(timeout); - TIMING_TEST_ASSERT_FALSE(call.has_error()); - TIMING_TEST_EXPECT_TRUE(call.value() == iox::posix::SemaphoreWaitState::TIMEOUT); - timedWaitFinish.store(true); - }); - - ASSERT_FALSE(syncSemaphore->wait().has_error()); - ASSERT_FALSE(sut->post().has_error()); - std::this_thread::sleep_for(std::chrono::nanoseconds(TIMING_TEST_TIMEOUT / 3 * 2)); - TIMING_TEST_EXPECT_FALSE(timedWaitFinish.load()); - - std::this_thread::sleep_for(std::chrono::nanoseconds(TIMING_TEST_TIMEOUT / 3 * 2)); - TIMING_TEST_EXPECT_TRUE(timedWaitFinish.load()); - - t.join(); -}); - - -TIMING_TEST_P(Semaphore_test, TimedWaitWithoutTimeout, Repeat(3), [&] { - using namespace iox::units; - std::atomic_bool timedWaitFinish{false}; - - std::thread t([&] { - auto timeout = Duration::fromNanoseconds(TIMING_TEST_TIMEOUT); - ASSERT_FALSE(syncSemaphore->post().has_error()); - ASSERT_FALSE(sut->wait().has_error()); - auto call = sut->timedWait(timeout); - TIMING_TEST_ASSERT_FALSE(call.has_error()); - TIMING_TEST_EXPECT_TRUE(call.value() == iox::posix::SemaphoreWaitState::NO_TIMEOUT); - timedWaitFinish.store(true); - }); - - ASSERT_FALSE(syncSemaphore->wait().has_error()); - ASSERT_FALSE(sut->post().has_error()); - std::this_thread::sleep_for(std::chrono::nanoseconds(TIMING_TEST_TIMEOUT / 3 * 2)); - TIMING_TEST_EXPECT_FALSE(timedWaitFinish.load()); - - ASSERT_FALSE(sut->post().has_error()); - std::this_thread::sleep_for(std::chrono::nanoseconds(TIMING_TEST_TIMEOUT / 3 * 2)); - TIMING_TEST_EXPECT_TRUE(timedWaitFinish.load()); - - t.join(); -}); -} // namespace