-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Transfer and improve Transactions (#99)
* Transfer and improve opencmw::TimingCtx This is by large a port of the opencmw TimingCtx, but with some improvements: * The most significant change is that the parse and match functions are not hardcoded anymore, but can instead be passed over from the outside via a predicate. This is necessary to ensure that TimingCtx stays generic enough so that it can be used for arbitrary use-cases. * Furthermore, we no longer hardcode any ids but instead use a `pmtv::map_t` to allow the user to store arbitrary identifiers for their usecase. * Transfer opencmw::ReaderWriterLock * Transfer and improve opencmw Transaction SettingBase This required some extensive changes and adaptions to work with the more general version of TimingCtx and to use the circular buffer instead of the opencmw::RingBuffer. * This also adds a new Utils function to find out the true cache line size. It uses `std::hardware_destructive_interference_size` and falls back to 64, which is the cache line size for most x86_64 targets. * The old implementation used redundant locking mechanisms and unnecessarily complicated circular buffers. Instead this now uses just a single recursive lock and a normal collection, which simplifies this a lot and hopefully makes emscripten more happy as well. * This also integrates the multiplexed settings into the Node as a drop-in replacement for the basic settings. * Call the matching predicate over multiple rounds This allows for hierarchical matching, where in the first round only very refined matching is performed and then the condition becomes increasingly looser.
- Loading branch information
Showing
8 changed files
with
798 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
#ifndef READER_WRITER_LOCK_HPP | ||
#define READER_WRITER_LOCK_HPP | ||
|
||
#include "utils.hpp" | ||
#include <atomic> | ||
#include <cstdint> | ||
|
||
namespace fair::graph { | ||
|
||
enum class ReaderWriterLockType { READ, WRITE }; | ||
|
||
/** | ||
* @brief ReaderWriterLock is multi-reader-multi-writer atomic lock meant to protect a resource | ||
* in situations where the thread is not allowed to block. | ||
* | ||
* The lock is implemented using atomic CAS-loops on a counter, which is | ||
* incremented (/decremented) when a thread acquires a read (/write) lock, and | ||
* decremented (/incremented) when the thread releases the read (/write) lock. | ||
* | ||
* N.B. The lock is unlocked when the counter reaches 0. | ||
*/ | ||
class ReaderWriterLock { | ||
alignas(fair::meta::kCacheLine) mutable std::atomic<std::int64_t> _activeReaderCount{ 0 }; | ||
|
||
public: | ||
ReaderWriterLock() = default; | ||
|
||
[[nodiscard]] std::int64_t | ||
value() const noexcept { | ||
return std::atomic_load_explicit(&_activeReaderCount, std::memory_order_acquire); | ||
} | ||
|
||
template<ReaderWriterLockType lockType> | ||
std::int64_t | ||
tryLock() const noexcept { | ||
std::int64_t expected = _activeReaderCount.load(std::memory_order_relaxed); | ||
if constexpr (lockType == ReaderWriterLockType::READ) { | ||
if (expected < 0L) { | ||
expected = 0L; | ||
} | ||
return std::atomic_compare_exchange_strong(&_activeReaderCount, &expected, expected + 1L); | ||
} else { | ||
if (expected > 0L) { | ||
expected = 0L; | ||
} | ||
return std::atomic_compare_exchange_strong(&_activeReaderCount, &expected, expected - 1L); | ||
} | ||
} | ||
|
||
template<ReaderWriterLockType lockType> | ||
std::int64_t | ||
lock() const noexcept { | ||
if constexpr (lockType == ReaderWriterLockType::READ) { | ||
std::int64_t expected = _activeReaderCount.load(std::memory_order_relaxed); | ||
do { | ||
if (expected < 0L) { | ||
expected = 0L; | ||
} | ||
} while (!std::atomic_compare_exchange_strong(&_activeReaderCount, &expected, expected + 1L)); | ||
return expected + 1L; | ||
} else { | ||
std::int64_t expected = _activeReaderCount.load(std::memory_order_relaxed); | ||
do { | ||
if (expected > 0L) { | ||
expected = 0L; | ||
} | ||
} while (!std::atomic_compare_exchange_strong(&_activeReaderCount, &expected, expected - 1L)); | ||
return expected - 1L; | ||
} | ||
} | ||
|
||
template<ReaderWriterLockType lockType> | ||
std::int64_t | ||
unlock() const noexcept { | ||
if constexpr (lockType == ReaderWriterLockType::READ) { | ||
return std::atomic_fetch_sub(&_activeReaderCount, 1L) - 1L; | ||
} else { | ||
return std::atomic_fetch_add(&_activeReaderCount, 1L) + 1L; | ||
} | ||
} | ||
|
||
template<ReaderWriterLockType lockType> | ||
auto | ||
scopedGuard() { | ||
return ScopedLock<lockType>(*this); | ||
} | ||
|
||
template<ReaderWriterLockType lockType> | ||
class ScopedLock { // NOSONAR - class destructor is needed for guard functionality | ||
ReaderWriterLock *_readWriteLock; | ||
|
||
public: | ||
ScopedLock() = delete; | ||
ScopedLock(const ScopedLock &) = delete; | ||
ScopedLock(ScopedLock &&) = delete; | ||
ScopedLock & | ||
operator=(const ScopedLock &) | ||
= delete; | ||
ScopedLock & | ||
operator=(ScopedLock &&) | ||
= delete; | ||
|
||
explicit constexpr ScopedLock(ReaderWriterLock &parent) noexcept : _readWriteLock(&parent) { _readWriteLock->lock<lockType>(); } | ||
|
||
~ScopedLock() { _readWriteLock->unlock<lockType>(); } | ||
}; | ||
}; | ||
|
||
} // namespace fair::graph | ||
|
||
#endif // READER_WRITER_LOCK_HPP |
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
Oops, something went wrong.