Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
elBoberido committed Sep 15, 2024
1 parent 72a8dfd commit 25556ee
Show file tree
Hide file tree
Showing 5 changed files with 297 additions and 10 deletions.
120 changes: 120 additions & 0 deletions iceoryx_hoofs/posix/sync/include/iox/spin_lock_mutex.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2024 by ekxide IO GmbH. 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_POXIX_SYNC_SPIN_LOCK_MUTEX_HPP
#define IOX_HOOFS_POXIX_SYNC_SPIN_LOCK_MUTEX_HPP

#include "iox/atomic.hpp"
#include "iox/detail/adaptive_wait.hpp"
#include "iox/mutex.hpp"

namespace iox
{
class SpinlockMutex
{
public:
SpinlockMutex()
: m_flag(ATOMIC_FLAG_INIT)
, m_recursive{Recursive{0, 0}}
{
}

expected<void, MutexLockError> lock() noexcept
{
pid_t tid = gettid();

auto recursive = m_recursive.load();

if (recursive.tid == tid)
{
recursive.count += 1;
m_recursive.store(recursive);

return ok();
}

detail::adaptive_wait spinner;
spinner.wait_loop([this] { return this->m_flag.test_and_set(std::memory_order_acquire); });

m_recursive.store(Recursive{tid, 1});

return ok();
}

expected<void, MutexUnlockError> unlock() noexcept
{
pid_t tid = gettid();

auto recursive = m_recursive.load();

if (recursive.tid == tid)
{
recursive.count -= 1;

if (recursive.count == 0)
{
recursive.tid = 0;
m_recursive.store(recursive);
m_flag.clear(std::memory_order_release);
}
else
{
m_recursive.store(recursive);
}

return ok();
}


return err(MutexUnlockError::UNKNOWN_ERROR);
}

expected<MutexTryLock, MutexTryLockError> try_lock() noexcept
{
pid_t tid = gettid();

auto recursive = m_recursive.load();

if (recursive.tid == tid)
{
recursive.count += 1;
m_recursive.store(recursive);
return ok(MutexTryLock::LOCK_SUCCEEDED);
}

if (!m_flag.test_and_set(std::memory_order_acquire))
{
m_recursive.store(Recursive{tid, 1});

return ok(MutexTryLock::LOCK_SUCCEEDED);
}
return ok(MutexTryLock::FAILED_TO_ACQUIRE_LOCK);
}

struct Recursive
{
pid_t tid;
uint32_t count;
};

private:
concurrent::AtomicFlag m_flag;
concurrent::Atomic<Recursive> m_recursive;
};

} // namespace iox

#endif // IOX_HOOFS_POXIX_SYNC_SPIN_LOCK_MUTEX_HPP
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,83 @@
#define IOX_POSH_POPO_BUILDING_BLOCKS_CONDITION_VARIABLE_DATA_HPP

#include "iceoryx_posh/iceoryx_posh_types.hpp"
#include "iceoryx_posh/internal/popo/building_blocks/locking_policy.hpp"
#include "iceoryx_posh/internal/posh_error_reporting.hpp"
#include "iox/atomic.hpp"
#include "iox/deadline_timer.hpp"
#include "iox/detail/adaptive_wait.hpp"
#include "iox/unnamed_semaphore.hpp"

namespace iox
{
namespace popo
{
class SpinLockSemaphore : public detail::SemaphoreInterface<SpinLockSemaphore>
{
public:
SpinLockSemaphore()
: m_count(0)
{
}

~SpinLockSemaphore()
{
m_to_be_destroyed = true;
}

expected<void, SemaphoreError> post()
{
std::lock_guard<SpinlockMutex> lock(spinlock);
++m_count;
return ok();
}

expected<void, SemaphoreError> wait()
{
detail::adaptive_wait spinner;
spinner.wait_loop([this] { return !this->tryWait(); });
return ok();
}

expected<bool, SemaphoreError> tryWait()
{
std::lock_guard<SpinlockMutex> lock(spinlock);
if (m_to_be_destroyed == true)
{
return ok(true);
}
if (m_count > 0)
{
--m_count;
return ok(true);
}
return ok(false);
}

expected<SemaphoreWaitState, SemaphoreError> timedWait(const units::Duration& timeout)
{
iox::deadline_timer deadline_timer(timeout);
detail::adaptive_wait spinner;

auto ret_val = SemaphoreWaitState::TIMEOUT;
spinner.wait_loop([this, &deadline_timer, &ret_val] {
if (this->tryWait())
{
ret_val = SemaphoreWaitState::NO_TIMEOUT;
return false;
}
return !deadline_timer.hasExpired();
});

return ok(ret_val);
}

private:
concurrent::Atomic<int32_t> m_count{0};
concurrent::Atomic<bool> m_to_be_destroyed{false};
SpinlockMutex spinlock;
};

struct ConditionVariableData
{
ConditionVariableData() noexcept;
Expand All @@ -37,7 +106,7 @@ struct ConditionVariableData
ConditionVariableData& operator=(ConditionVariableData&& rhs) = delete;
~ConditionVariableData() noexcept = default;

optional<UnnamedSemaphore> m_semaphore;
optional<SpinLockSemaphore> m_semaphore;
RuntimeName_t m_runtimeName;
concurrent::Atomic<bool> m_toBeDestroyed{false};
concurrent::Atomic<bool> m_activeNotifications[MAX_NUMBER_OF_NOTIFIERS];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,106 @@
#ifndef IOX_POSH_POPO_BUILDING_BLOCKS_LOCKING_POLICY_HPP
#define IOX_POSH_POPO_BUILDING_BLOCKS_LOCKING_POLICY_HPP

#include "iox/detail/adaptive_wait.hpp"
#include "iox/mutex.hpp"
#include "iox/spin_lock_mutex.hpp"

namespace iox
{
namespace popo
{
class SpinlockMutex
{
public:
SpinlockMutex()
: m_flag(ATOMIC_FLAG_INIT)
, m_recursive{Recursive{0, 0}}
{
}

expected<void, MutexLockError> lock() noexcept
{
pid_t tid = gettid();

auto recursive = m_recursive.load();

if (recursive.tid == tid)
{
recursive.count += 1;
m_recursive.store(recursive);

return ok();
}

detail::adaptive_wait spinner;
spinner.wait_loop([this] { return this->m_flag.test_and_set(std::memory_order_acquire); });

m_recursive.store(Recursive{tid, 1});

return ok();
}

expected<void, MutexUnlockError> unlock() noexcept
{
pid_t tid = gettid();

auto recursive = m_recursive.load();

if (recursive.tid == tid)
{
recursive.count -= 1;

if (recursive.count == 0)
{
recursive.tid = 0;
m_recursive.store(recursive);
m_flag.clear(std::memory_order_release);
}
else
{
m_recursive.store(recursive);
}

return ok();
}


return err(MutexUnlockError::UNKNOWN_ERROR);
}

expected<MutexTryLock, MutexTryLockError> try_lock() noexcept
{
pid_t tid = gettid();

auto recursive = m_recursive.load();

if (recursive.tid == tid)
{
recursive.count += 1;
m_recursive.store(recursive);
return ok(MutexTryLock::LOCK_SUCCEEDED);
}

if (!m_flag.test_and_set(std::memory_order_acquire))
{
m_recursive.store(Recursive{tid, 1});

return ok(MutexTryLock::LOCK_SUCCEEDED);
}
return ok(MutexTryLock::FAILED_TO_ACQUIRE_LOCK);
}

struct Recursive
{
pid_t tid;
uint32_t count;
};

private:
concurrent::AtomicFlag m_flag;
concurrent::Atomic<Recursive> m_recursive;
};

class ThreadSafePolicy
{
public:
Expand All @@ -33,7 +127,7 @@ class ThreadSafePolicy
bool tryLock() const noexcept;

private:
mutable optional<mutex> m_mutex;
mutable optional<SpinlockMutex> m_mutex;
};

class SingleThreadedPolicy
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ ConditionVariableData::ConditionVariableData() noexcept
ConditionVariableData::ConditionVariableData(const RuntimeName_t& runtimeName) noexcept
: m_runtimeName(runtimeName)
{
UnnamedSemaphoreBuilder().initialValue(0U).isInterProcessCapable(true).create(m_semaphore).or_else([](auto) {
IOX_REPORT_FATAL(PoshError::POPO__CONDITION_VARIABLE_DATA_FAILED_TO_CREATE_SEMAPHORE);
});
/// @todo iox-#2301 fix this with a proper spin-lock implementation
// UnnamedSemaphoreBuilder().initialValue(0U).isInterProcessCapable(true).create(m_semaphore).or_else([](auto) {
// IOX_REPORT_FATAL(PoshError::POPO__CONDITION_VARIABLE_DATA_FAILED_TO_CREATE_SEMAPHORE);
// });
m_semaphore.emplace();

for (auto& id : m_activeNotifications)
{
Expand Down
12 changes: 7 additions & 5 deletions iceoryx_posh/source/popo/building_blocks/locking_policy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ namespace popo
{
ThreadSafePolicy::ThreadSafePolicy() noexcept
{
MutexBuilder()
.isInterProcessCapable(true)
.mutexType(MutexType::RECURSIVE)
.create(m_mutex)
.expect("Failed to create Mutex");
/// @todo iox-#2301 fix this with a proper spin-lock implementation
// MutexBuilder()
// .isInterProcessCapable(true)
// .mutexType(MutexType::RECURSIVE)
// .create(m_mutex)
// .expect("Failed to create Mutex");
m_mutex.emplace();
}

void ThreadSafePolicy::lock() const noexcept
Expand Down

0 comments on commit 25556ee

Please sign in to comment.