-
Notifications
You must be signed in to change notification settings - Fork 147
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[fiber] Implement std concurrency interfaces
- Loading branch information
Showing
9 changed files
with
812 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); }); | ||
} | ||
}; | ||
|
||
/// @} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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>; | ||
|
||
/// @} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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(); }); | ||
} | ||
}; | ||
|
||
/// @} | ||
|
||
} |
Oops, something went wrong.