Skip to content

Commit

Permalink
iox-eclipse-iceoryx#751 Implemented semaphore interface
Browse files Browse the repository at this point in the history
Signed-off-by: Christian Eltzschig <me@elchris.org>
  • Loading branch information
elfenpiff committed May 20, 2022
1 parent 27c857e commit 1798043
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 36 deletions.
1 change: 1 addition & 0 deletions iceoryx_hoofs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 <typename SemaphoreChild>
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<SemaphoreError> postUnsafe() noexcept;

SemaphoreState getState() noexcept;
cxx::expected<SemaphoreState, SemaphoreError> getStateUnsafe() noexcept;

SemaphoreWaitState timedWait(const units::Duration& timeout) noexcept;
cxx::expected<SemaphoreWaitState, SemaphoreError> timedWaitUnsafe(const units::Duration& timeout) noexcept;

bool tryWait() noexcept;
cxx::expected<bool, SemaphoreError> tryWaitUnsafe() noexcept;

protected:
SemaphoreInterface() noexcept = default;

private:
iox_sem_t* getHandle() noexcept;
};
} // namespace internal
} // namespace posix
} // namespace iox

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename SemaphoreChild>
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<SemaphoreError> postUnsafe() noexcept;

uint32_t getValue() const noexcept;
cxx::expected<uint32_t, SemaphoreError> getValueUnsafe() const noexcept;

void timedWait() noexcept;
cxx::expected<SemaphoreError> timedWaitUnsafe() noexcept;

void tryWait() noexcept;
cxx::expected<SemaphoreError> tryWaitUnsafe() noexcept;

protected:
SemaphoreInterface() noexcept = default;
};

class UnnamedSemaphore : SemaphoreInterface<UnnamedSemaphore>
class UnnamedSemaphore final : internal::SemaphoreInterface<UnnamedSemaphore>
{
public:
UnnamedSemaphore(const UnnamedSemaphore&) noexcept = delete;
Expand All @@ -67,7 +41,6 @@ class UnnamedSemaphore : SemaphoreInterface<UnnamedSemaphore>
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;
Expand Down
172 changes: 172 additions & 0 deletions iceoryx_hoofs/source/posix_wrapper/semaphore_interface.cpp
Original file line number Diff line number Diff line change
@@ -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 <typename SemaphoreChild>
iox_sem_t* SemaphoreInterface<SemaphoreChild>::getHandle() noexcept
{
return static_cast<SemaphoreChild*>(this)->getHandle();
}

template <typename SemaphoreChild>
void SemaphoreInterface<SemaphoreChild>::post() noexcept
{
postUnsafe().expect("Fatal semaphore failure occurred.");
}

template <typename SemaphoreChild>
cxx::expected<SemaphoreError> SemaphoreInterface<SemaphoreChild>::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>(SemaphoreError::INVALID_SEMAPHORE_HANDLE);
case EOVERFLOW:
LogError() << "Semaphore overflow.";
return cxx::error<SemaphoreError>(SemaphoreError::SEMAPHORE_OVERFLOW);
default:
LogError() << "This should never happen. An unknown error occurred.";
break;
}
return cxx::error<SemaphoreError>(SemaphoreError::UNDEFINED);
}

return cxx::success<>();
}

template <typename SemaphoreChild>
SemaphoreState SemaphoreInterface<SemaphoreChild>::getState() noexcept
{
return getStateUnsafe().expect("Fatal semaphore failure occurred.");
}

template <typename SemaphoreChild>
cxx::expected<SemaphoreState, SemaphoreError> SemaphoreInterface<SemaphoreChild>::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>(SemaphoreError::INVALID_SEMAPHORE_HANDLE);
default:
LogError() << "This should never happen. An unknown error occurred.";
break;
}
return cxx::error<SemaphoreError>(SemaphoreError::UNDEFINED);
}

SemaphoreState state;
state.value = (value > 0) ? static_cast<uint32_t>(value) : 0U;
state.numberOfBlockedWait = (value < 0) ? static_cast<uint32_t>(-value) : 0U;

return cxx::success<SemaphoreState>(state);
}

template <typename SemaphoreChild>
SemaphoreWaitState SemaphoreInterface<SemaphoreChild>::timedWait(const units::Duration& timeout) noexcept
{
return timedWaitUnsafe(timeout).expect("Fatal semaphore failure occurred.");
}

template <typename SemaphoreChild>
cxx::expected<SemaphoreWaitState, SemaphoreError>
SemaphoreInterface<SemaphoreChild>::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>(SemaphoreWaitState::TIMEOUT);
case EINVAL:
LogError() << "The semaphore handle is no longer valid. This can indicate a corrupted system.";
return cxx::error<SemaphoreError>(SemaphoreError::INVALID_SEMAPHORE_HANDLE);
case EINTR:
LogError() << "The sem_timedwait was interrupted multiple times by the operating system. Abort operation!";
return cxx::error<SemaphoreError>(SemaphoreError::INTERRUPTED_BY_SIGNAL_HANDLER);
default:
LogError() << "This should never happen. An unknown error occurred.";
break;
}
return cxx::error<SemaphoreError>(SemaphoreError::UNDEFINED);
}

return cxx::success<SemaphoreWaitState>(SemaphoreWaitState::NO_TIMEOUT);
}

template <typename SemaphoreChild>
bool SemaphoreInterface<SemaphoreChild>::tryWait() noexcept
{
return tryWaitUnsafe().expect("Fatal semaphore failure occurred.");
}

template <typename SemaphoreChild>
cxx::expected<bool, SemaphoreError> SemaphoreInterface<SemaphoreChild>::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<bool>(false);
case EINVAL:
LogError() << "The semaphore handle is no longer valid. This can indicate a corrupted system.";
return cxx::error<SemaphoreError>(SemaphoreError::INVALID_SEMAPHORE_HANDLE);
case EINTR:
LogError() << "The sem_trywait was interrupted multiple times by the operating system. Abort operation!";
return cxx::error<SemaphoreError>(SemaphoreError::INTERRUPTED_BY_SIGNAL_HANDLER);
default:
LogError() << "This should never happen. An unknown error occurred.";
break;
}
return cxx::error<SemaphoreError>(SemaphoreError::UNDEFINED);
}

return cxx::success<bool>(true);
}

template class SemaphoreInterface<UnnamedSemaphore>;
} // namespace internal
} // namespace posix
} // namespace iox
7 changes: 0 additions & 7 deletions iceoryx_hoofs/source/posix_wrapper/unnamed_semaphore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit 1798043

Please sign in to comment.