Skip to content

Commit

Permalink
[fiber] Implement std concurrency interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
salkinium committed Apr 13, 2024
1 parent b521355 commit 97c4cb4
Show file tree
Hide file tree
Showing 9 changed files with 812 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/modm/processing/fiber.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@
#include "fiber/fiber.hpp"
#include "fiber/scheduler.hpp"
#include "fiber/functions.hpp"
#include "fiber/mutex.hpp"
#include "fiber/shared_mutex.hpp"
#include "fiber/semaphore.hpp"
3 changes: 3 additions & 0 deletions src/modm/processing/fiber/module.lb
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ def build(env):
env.copy("context.h")
env.template("stack.hpp.in")
env.template("scheduler.hpp.in")
env.template("mutex.hpp.in")
env.template("semaphore.hpp.in")
env.template("shared_mutex.hpp.in")
env.copy("task.hpp")
env.copy("functions.hpp")
env.copy("fiber.hpp")
154 changes: 154 additions & 0 deletions src/modm/processing/fiber/mutex.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
/*
* Copyright (c) 2023, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include "functions.hpp"
%% if multicore
#include <modm/platform/core/multicore.hpp>
%% endif

namespace modm::fiber
{

/// @ingroup modm_processing_fiber
/// @{

/// Implements the `std::mutex` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/mutex
class mutex
{
mutex(const mutex&) = delete;
mutex& operator=(const mutex&) = delete;

volatile bool locked{false};
public:
constexpr mutex() = default;

[[nodiscard]] bool inline
try_lock()
{
%% if multicore
modm::platform::multicore::SystemSpinLockGuard g;
%% endif
if (locked) return false;
locked = true;
return true;
}

void inline
lock()
{
while(not try_lock()) modm::this_fiber::yield();
}

void inline
unlock()
{
locked = false;
}
};

/// Implements the `std::timed_mutex` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/timed_mutex
class timed_mutex : public mutex
{
public:
template< typename Rep, typename Period >
[[nodiscard]] bool
try_lock_for(std::chrono::duration<Rep, Period> sleep_duration)
{
return this_fiber::sleep_condition_for(sleep_duration, [this](){ return try_lock(); });
}

template< class Clock, class Duration >
[[nodiscard]] bool
try_lock_until(std::chrono::time_point<Clock, Duration> sleep_time)
{
return this_fiber::sleep_condition_until(sleep_time, [this](){ return try_lock(); });
}
};

/// Implements the `std::recursive_mutex` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/recursive_mutex
class recursive_mutex
{
recursive_mutex(const recursive_mutex&) = delete;
recursive_mutex& operator=(const recursive_mutex&) = delete;
using count_t = uint16_t;

static constexpr fiber::id NoOwner{fiber::id(-1)};
volatile fiber::id owner{NoOwner};
static constexpr count_t countMax{count_t(-1)};
volatile count_t count{1};

public:
constexpr recursive_mutex() = default;

[[nodiscard]] bool inline
try_lock()
{
%% if multicore
modm::platform::multicore::SystemSpinLockGuard g;
%% endif
const auto id = modm::this_fiber::get_id();
if (owner == NoOwner) {
owner = id;
// count = 1; is implicit
return true;
}
if (owner == id and count < countMax) {
count++;
return true;
}
return false;
}

void inline
lock()
{
while(not try_lock()) modm::this_fiber::yield();
}

void inline
unlock()
{
if (count > 1) count--;
else {
// count = 1; is implicit
owner = NoOwner;
}
}
};

/// Implements the `std::timed_recursive_mutex` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/recursive_mutex
class timed_recursive_mutex : public recursive_mutex
{
public:
template< typename Rep, typename Period >
[[nodiscard]] bool
try_lock_for(std::chrono::duration<Rep, Period> sleep_duration)
{
return this_fiber::sleep_condition_for(sleep_duration, [this](){ return try_lock(); });
}

template< class Clock, class Duration >
[[nodiscard]] bool
try_lock_until(std::chrono::time_point<Clock, Duration> sleep_time)
{
return this_fiber::sleep_condition_until(sleep_time, [this](){ return try_lock(); });
}
};

/// @}

}
88 changes: 88 additions & 0 deletions src/modm/processing/fiber/semaphore.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/*
* Copyright (c) 2023, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include "functions.hpp"
%% if multicore
#include <modm/platform/core/multicore.hpp>
%% endif

namespace modm::fiber
{

/// @ingroup modm_processing_fiber
/// @{

/// Implements the `std::counting_semaphore` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/counting_semaphore
template< std::ptrdiff_t LeastMaxValue = 255 >
class counting_semaphore
{
counting_semaphore(const counting_semaphore&) = delete;
counting_semaphore& operator=(const counting_semaphore&) = delete;
using count_t = std::conditional_t<LeastMaxValue < 256, uint8_t, uint16_t>;

volatile count_t count{};
static_assert(LeastMaxValue < 65'536, "counting_semaphore uses a 16-bit counter!");
public:
constexpr explicit
counting_semaphore(count_t desired)
: count(desired) {}

[[nodiscard]] static constexpr std::ptrdiff_t
max() { return count_t(-1); }

[[nodiscard]] bool inline
try_acquire()
{
%% if multicore
modm::platform::multicore::SystemSpinLockGuard g;
%% endif
if (count == 0) return false;
count--;
return true;
}

void inline
acquire()
{
while(not try_acquire()) modm::this_fiber::yield();
}

void inline
release()
{
count++;
}

template< typename Rep, typename Period >
[[nodiscard]] bool
try_acquire_for(std::chrono::duration<Rep, Period> sleep_duration)
{
return this_fiber::sleep_condition_for(sleep_duration, [this](){ return try_acquire(); });
}

template< class Clock, class Duration >
[[nodiscard]] bool
try_acquire_until(std::chrono::time_point<Clock, Duration> sleep_time)
{
return this_fiber::sleep_condition_until(sleep_time, [this](){ return try_acquire(); });
}
};

/// Implements the `std::binary_semaphore` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/counting_semaphore
using binary_semaphore = counting_semaphore<1>;

/// @}

}
121 changes: 121 additions & 0 deletions src/modm/processing/fiber/shared_mutex.hpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2023, Niklas Hauser
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#pragma once

#include "functions.hpp"
%% if multicore
#include <modm/platform/core/multicore.hpp>
%% endif

namespace modm::fiber
{

/// @ingroup modm_processing_fiber
/// @{

/// Implements the `std::shared_mutex` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/shared_mutex
class shared_mutex
{
shared_mutex(const shared_mutex&) = delete;
shared_mutex& operator=(const shared_mutex&) = delete;

static constexpr fiber::id NoOwner{fiber::id(-1)};
static constexpr fiber::id SharedOwner{fiber::id(-2)};
volatile fiber::id owner{NoOwner};
public:
constexpr shared_mutex() = default;

[[nodiscard]] bool inline
try_lock()
{
%% if multicore
modm::platform::multicore::SystemSpinLockGuard g;
%% endif
if (owner != NoOwner) return false;
owner = modm::this_fiber::get_id();
return true;
}

void inline
lock()
{
while(not try_lock()) modm::this_fiber::yield();
}

void inline
unlock()
{
owner = NoOwner;
}

[[nodiscard]] bool inline
try_lock_shared()
{
%% if multicore
modm::platform::multicore::SystemSpinLockGuard g;
%% endif
if (owner < SharedOwner) return false;
owner = SharedOwner;
return true;
}

void inline
lock_shared()
{
while(not try_lock_shared()) modm::this_fiber::yield();
}

void inline
unlock_shared()
{
owner = NoOwner;
}
};

/// Implements the `std::timed_shared_mutex` interface for fibers.
/// @see https://en.cppreference.com/w/cpp/thread/timed_shared_mutex
class timed_shared_mutex : public shared_mutex
{
public:
template< typename Rep, typename Period >
[[nodiscard]] bool
try_lock_for(std::chrono::duration<Rep, Period> sleep_duration)
{
return this_fiber::sleep_condition_for(sleep_duration, [this](){ return try_lock(); });
}

template< class Clock, class Duration >
[[nodiscard]] bool
try_lock_until(std::chrono::time_point<Clock, Duration> sleep_time)
{
return this_fiber::sleep_condition_until(sleep_time, [this](){ return try_lock(); });
}

template< typename Rep, typename Period >
[[nodiscard]] bool
try_lock_shared_for(std::chrono::duration<Rep, Period> sleep_duration)
{
return this_fiber::sleep_condition_for(sleep_duration, [this](){ return try_lock_shared(); });
}

template< class Clock, class Duration >
[[nodiscard]] bool
try_lock_shared_until(std::chrono::time_point<Clock, Duration> sleep_time)
{
return this_fiber::sleep_condition_until(sleep_time, [this](){ return try_lock_shared(); });
}
};

/// @}

}
Loading

0 comments on commit 97c4cb4

Please sign in to comment.