diff --git a/.editorconfig b/.editorconfig index 8cfde3d91e659c9f110ae5ff52626185e5b51c38..5af1ee3129d262509b76e728eb3c3ff1bc977176 100644 --- a/.editorconfig +++ b/.editorconfig @@ -10,3 +10,11 @@ insert_final_newline = true [*.{c,h,cpp,hpp}] indent_style = tab indent_size = 2 + +[*.yml] +indent_style = space +indent_size = 2 + +[meson_options.txt] +indent_style = space +indent_size = 2 diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 94f24b0c47c6175a962c59c273d2e2201c40d95d..9ffdfe9964ec3afd789fa5e0f63b0938b06adb53 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -56,6 +56,12 @@ fast-static-analysis: variables: EMPER_IO: "true" +.fast-variant-check: + stage: test + script: make fast-static-analysis smoke-test-suite + variables: + EMPER_IO: "true" + iwyu: stage: smoke-test script: IWYU_TOOL="${CI_PROJECT_DIR}/tools/iwyu_tool.py" make iwyu @@ -361,3 +367,27 @@ test-io-stealing-pipe-no-completer-lockless: - .emper-no-completer - .emper-io-stealing - .emper-lockless-cq + +smoke-test-locked-queue-rwlock: + extends: + - .fast-variant-check + variables: + EMPER_LOCKED_UNBOUNDED_QUEUE_IMPLEMENTATION: "rwlock" + +smoke-test-locked-queue-shared-mutex: + extends: + - .fast-variant-check + variables: + EMPER_LOCKED_UNBOUNDED_QUEUE_IMPLEMENTATION: "shared_mutex" + +smoke-test-locked-queue-boost-shared-mutex: + extends: + - .fast-variant-check + variables: + EMPER_LOCKED_UNBOUNDED_QUEUE_IMPLEMENTATION: "boost_shared_mutex" + +smoke-test-locked-queue-boost-userspace-rcu: + extends: + - .fast-variant-check + variables: + EMPER_USERSPACE_RCU: "true" diff --git a/emper/lib/adt/RwLockUnboundedQueue.hpp b/emper/lib/adt/RwLockUnboundedQueue.hpp index b52b938e0270a57332f670f9576ef57e43482e92..5d091c9da577843fbff4ddad18feac05bf80fa25 100644 --- a/emper/lib/adt/RwLockUnboundedQueue.hpp +++ b/emper/lib/adt/RwLockUnboundedQueue.hpp @@ -11,13 +11,6 @@ namespace lib::adt { -static void aquire_wrlock(pthread_rwlock_t& lock) { - int err = pthread_rwlock_wrlock(&lock); - if (unlikely(err)) { - DIE_MSG("pthread_rwlock_wrlock failed: " << strerror(err)); - } -} - template <typename I> class RwLockUnboundedQueue { private: @@ -25,6 +18,27 @@ class RwLockUnboundedQueue { std::queue<I*> queue; + void acquireWriteLock() { + int err = pthread_rwlock_wrlock(&lock); + if (unlikely(err)) { + DIE_MSG("pthread_rwlock_wrlock failed: " << strerror(err)); + } + } + + void acquireReadLock() { + int err = pthread_rwlock_rdlock(&lock); + if (unlikely(err)) { + DIE_MSG("pthread_rwlock_rdlock failed: " << strerror(err)); + } + } + + void unlock() { pthread_rwlock_unlock(&lock); } + + void upgradeLock() { + unlock(); + acquireWriteLock(); + } + public: RwLockUnboundedQueue() { int err = pthread_rwlock_init(&lock, nullptr); @@ -41,89 +55,60 @@ class RwLockUnboundedQueue { } void enqueue(I* item) { - aquire_wrlock(lock); + acquireWriteLock(); queue.push(item); - pthread_rwlock_unlock(&lock); + unlock(); } template <class InputIt> void insert(InputIt begin, InputIt end) { - aquire_wrlock(lock); + acquireWriteLock(); for (; begin != end; ++begin) { queue.push(*begin); } - pthread_rwlock_unlock(&lock); + unlock(); } void insert(I** items, unsigned count) { - aquire_wrlock(lock); + acquireWriteLock(); for (unsigned i = 0; i < count; ++i) { queue.push(items[i]); } - pthread_rwlock_unlock(&lock); + unlock(); } auto dequeue() -> I* { I* res = nullptr; - int err = pthread_rwlock_rdlock(&lock); - if (unlikely(err)) { - DIE_MSG("pthread_rwlock_rdlock failed: " << strerror(err)); - } - + acquireReadLock(); if (queue.empty()) { - goto unlock_and_return; + goto done; } - // try to upgrade to wrlock - err = pthread_rwlock_trywrlock(&lock); - if (err) { - if (unlikely(err != EBUSY)) { - DIE_MSG("pthread_rwlock_trylock failed: " << strerror(err)); - } - - // drop the read lock and aquire a write lock - aquire_wrlock(lock); - - if (queue.empty()) { - goto unlock_and_return; - } + upgradeLock(); + if (queue.empty()) { + goto done; } - // we certainly hold the wrlock here res = queue.front(); queue.pop(); - unlock_and_return: - pthread_rwlock_unlock(&lock); + done: + unlock(); return res; } template <class OutputIt> auto dequeue(OutputIt begin, OutputIt end) -> size_t { - int err = pthread_rwlock_rdlock(&lock); - if (unlikely(err)) { - DIE_MSG("pthread_rwlock_rdlock failed: " << strerror(err)); - } - + acquireReadLock(); OutputIt cur = begin; if (queue.empty()) { - goto unlock; + goto done; } - // try to upgrade to wrlock - err = pthread_rwlock_trywrlock(&lock); - if (err) { - if (unlikely(err != EBUSY)) { - DIE_MSG("pthread_rwlock_trylock failed: " << strerror(err)); - } - - // drop the read lock and aquire a write lock - aquire_wrlock(lock); - - if (queue.empty()) { - goto unlock; - } + upgradeLock(); + if (queue.empty()) { + goto done; } for (; !queue.empty() && cur != end; ++cur) { @@ -131,8 +116,8 @@ class RwLockUnboundedQueue { queue.pop(); } - unlock: - pthread_rwlock_unlock(&lock); + done: + unlock(); return cur - begin; } }; diff --git a/emper/lib/adt/SharedMutexUnboundedQueue.hpp b/emper/lib/adt/SharedMutexUnboundedQueue.hpp index 5f98ff0c60caf780f80621b1060847186f1d440e..089eb276dfd35aaf7d605f6611a6000db6915c01 100644 --- a/emper/lib/adt/SharedMutexUnboundedQueue.hpp +++ b/emper/lib/adt/SharedMutexUnboundedQueue.hpp @@ -2,6 +2,7 @@ // Copyright © 2020-2021 Florian Schmaus, Florian Fischer #pragma once +#include <mutex> #include <queue> #include <shared_mutex>