diff --git a/include/circ_elem_array.h b/include/circ_elem_array.h index 80c79b8..c1e2e5d 100644 --- a/include/circ_elem_array.h +++ b/include/circ_elem_array.h @@ -18,29 +18,30 @@ struct alignas(std::max_align_t) elem_array_head { std::atomic cc_ { 0 }; // connection counter, using for broadcast std::atomic wt_ { 0 }; // write index - static u1_t index_of(u2_t c) { return static_cast(c); } + static u1_t index_of(u2_t c) noexcept { return static_cast(c); } - std::size_t connect() { + std::size_t connect() noexcept { + // connect should be called before cursor return cc_.fetch_add(1, std::memory_order_relaxed); } - std::size_t disconnect() { - return cc_.fetch_sub(1, std::memory_order_relaxed); + std::size_t disconnect() noexcept { + return cc_.fetch_sub(1, std::memory_order_release); } - std::size_t conn_count() const { - return cc_.load(std::memory_order_relaxed); + std::size_t conn_count() const noexcept { + return cc_.load(std::memory_order_acquire); } - u2_t cursor() const { - return wt_.load(std::memory_order_relaxed); + u2_t cursor() const noexcept { + return wt_.load(std::memory_order_acquire); } - auto acquire() { - return index_of(wt_.load(std::memory_order_acquire)); + auto acquire() noexcept { + return index_of(wt_.load(std::memory_order_relaxed)); } - void commit() { + void commit() noexcept { wt_.fetch_add(1, std::memory_order_release); } }; @@ -79,12 +80,12 @@ private: }; elem_t block_[elem_max]; - elem_t* elem_start() { + elem_t* elem_start() noexcept { return block_; } - static elem_t* elem(void* ptr) { return reinterpret_cast(static_cast(ptr) - sizeof(head_t)); } - elem_t* elem(u1_t i ) { return elem_start() + i; } + static elem_t* elem(void* ptr) noexcept { return reinterpret_cast(static_cast(ptr) - sizeof(head_t)); } + elem_t* elem(u1_t i ) noexcept { return elem_start() + i; } public: elem_array() = default; @@ -99,32 +100,31 @@ public: using base_t::conn_count; using base_t::cursor; - void* acquire() { + void* acquire() noexcept { elem_t* el = elem(base_t::acquire()); // check all consumers have finished reading while(1) { - uint_t<32> expected = 0; + uint_t<32> expected = 0, + conn_cnt = cc_.load(std::memory_order_acquire); if (el->head_.rc_.compare_exchange_weak( - expected, - static_cast>(conn_count()), - std::memory_order_relaxed)) { + expected, conn_cnt, std::memory_order_relaxed)) { break; } std::this_thread::yield(); - std::atomic_thread_fence(std::memory_order_acquire); } return el->data_; } - void commit(void* /*ptr*/) { + void commit(void* /*ptr*/) noexcept { base_t::commit(); } - void* take(u2_t cursor) { + void* take(u2_t cursor) noexcept { + std::atomic_thread_fence(std::memory_order_acquire); return elem(base_t::index_of(cursor))->data_; } - void put(void* ptr) { + void put(void* ptr) noexcept { elem(ptr)->head_.rc_.fetch_sub(1, std::memory_order_release); } }; diff --git a/include/circ_queue.h b/include/circ_queue.h index b3099af..eaaa88a 100644 --- a/include/circ_queue.h +++ b/include/circ_queue.h @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -38,11 +37,11 @@ public: queue(queue&&) = delete; queue& operator=(queue&&) = delete; - constexpr array_t * elems() const { + constexpr array_t * elems() const noexcept { return elems_; } - std::size_t connect() { + std::size_t connect() noexcept { if (elems_ == nullptr) return invalid_value; if (connected_.exchange(true, std::memory_order_relaxed)) { // if it's already connected, just return an error count @@ -51,7 +50,7 @@ public: return elems_->connect(); } - std::size_t disconnect() { + std::size_t disconnect() noexcept { if (elems_ == nullptr) return invalid_value; if (!connected_.exchange(false, std::memory_order_relaxed)) { // if it's already disconnected, just return an error count @@ -60,15 +59,15 @@ public: return elems_->disconnect(); } - std::size_t conn_count() const { + std::size_t conn_count() const noexcept { return (elems_ == nullptr) ? invalid_value : elems_->conn_count(); } - bool connected() const { + bool connected() const noexcept { return connected_.load(std::memory_order_relaxed); } - array_t* attach(array_t* arr) { + array_t* attach(array_t* arr) noexcept { if (arr == nullptr) return nullptr; auto old = elems_; elems_ = arr; @@ -76,14 +75,14 @@ public: return old; } - array_t* detach() { + array_t* detach() noexcept { if (elems_ == nullptr) return nullptr; auto old = elems_; elems_ = nullptr; return old; } - bool push(T const & item) { + bool push(T const & item) noexcept { if (elems_ == nullptr) return false; auto ptr = elems_->acquire(); ::new (ptr) T(item); @@ -92,7 +91,7 @@ public: } template - auto push(P&& param) // disable this if P is as same as T + auto push(P&& param) noexcept // disable this if P is as same as T -> Requires, T>::value, bool> { if (elems_ == nullptr) return false; auto ptr = elems_->acquire(); @@ -102,7 +101,7 @@ public: } template - auto push(P&&... params) // some compilers are not support this well + auto push(P&&... params) noexcept // some compilers are not support this well -> Requires<(sizeof...(P) != 1), bool> { if (elems_ == nullptr) return false; auto ptr = elems_->acquire(); @@ -112,15 +111,13 @@ public: } template - static queue* multi_wait_for(F&& upd) { + static queue* multi_wait_for(F&& upd) noexcept { for (unsigned k = 0;; ++k) { auto [ques, size] = upd(); for (std::size_t i = 0; i < static_cast(size); ++i) { queue* que = ques[i]; if (que == nullptr) continue; - if (que->elems_ == nullptr) throw std::logic_error { - "This queue hasn't attached any elem_array." - }; + if (que->elems_ == nullptr) return nullptr; if (que->cursor_ != que->elems_->cursor()) { return que; } @@ -131,20 +128,16 @@ public: } } - static T pop(queue* que) { - if (que == nullptr) throw std::invalid_argument { - "Invalid ques pointer." - }; - if (que->elems_ == nullptr) throw std::logic_error { - "This queue hasn't attached any elem_array." - }; + static T pop(queue* que) noexcept { + if (que == nullptr) return {}; + if (que->elems_ == nullptr) return {}; auto item_ptr = static_cast(que->elems_->take(que->cursor_++)); T item = std::move(*item_ptr); que->elems_->put(item_ptr); return item; } - T pop() { + T pop() noexcept { return pop(multi_wait_for([que = this] { return std::make_tuple(&que, 1); })); diff --git a/include/rw_lock.h b/include/rw_lock.h index d14a114..7226c5c 100644 --- a/include/rw_lock.h +++ b/include/rw_lock.h @@ -56,7 +56,7 @@ namespace ipc { -inline void yield(unsigned k) { +inline void yield(unsigned k) noexcept { if (k < 4) { /* Do nothing */ } else if (k < 16) { IPC_LOCK_PAUSE_(); } @@ -80,7 +80,7 @@ class rw_lock { }; public: - void lock() { + void lock() noexcept { for (unsigned k = 0;; ++k) { auto old = lc_.fetch_or(w_flag, std::memory_order_acquire); if (!old) return; // got w-lock @@ -93,11 +93,11 @@ public: } } - void unlock() { + void unlock() noexcept { lc_.store(0, std::memory_order_release); } - void lock_shared() { + void lock_shared() noexcept { auto old = lc_.load(std::memory_order_relaxed); for (unsigned k = 0;; ++k) { // if w_flag set, just continue @@ -113,7 +113,7 @@ public: } } - void unlock_shared() { + void unlock_shared() noexcept { lc_.fetch_sub(1, std::memory_order_release); } }; diff --git a/src/channel.inc b/src/channel.inc index a813ef4..be905b7 100644 --- a/src/channel.inc +++ b/src/channel.inc @@ -134,7 +134,7 @@ std::size_t channel::recv_count() const { template inline bool channel_send(route& rt, P&&... params) { - for (int k = 0; rt.recv_count() == 0; ++k) { + for (unsigned k = 0; rt.recv_count() == 0; ++k) { if (k >= 1024) return false; std::this_thread::yield(); } diff --git a/test/test_circ.cpp b/test/test_circ.cpp index 1c72b49..1e4e85a 100644 --- a/test/test_circ.cpp +++ b/test/test_circ.cpp @@ -20,6 +20,10 @@ struct msg_t { int dat_; }; +bool operator==(msg_t const & m1, msg_t const & m2) { + return (m1.pid_ == m2.pid_) && (m1.dat_ == m2.dat_); +} + } // internal-linkage template <> @@ -254,34 +258,10 @@ void Unit::test_prod_cons_performance() { test_prod_cons <1, 10>(); // test & verify } -#ifndef QVERIFY_EXCEPTION_THROWN -#define QVERIFY_EXCEPTION_THROWN(expression, exceptiontype) \ -do {\ - QT_TRY {\ - QT_TRY {\ - expression;\ - QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ - " but no exception caught", __FILE__, __LINE__);\ - return;\ - } QT_CATCH (const exceptiontype &) {\ - }\ - } QT_CATCH (const std::exception &e) {\ - QByteArray msg = QByteArray() + "Expected exception of type " #exceptiontype \ - " to be thrown but std::exception caught with message: " + e.what(); \ - QTest::qFail(msg.constData(), __FILE__, __LINE__);\ - return;\ - } QT_CATCH (...) {\ - QTest::qFail("Expected exception of type " #exceptiontype " to be thrown" \ - " but unknown exception caught", __FILE__, __LINE__);\ - return;\ - }\ -} while (false) -#endif/*!QVERIFY_EXCEPTION_THROWN*/ - void Unit::test_queue() { ipc::circ::queue queue; queue.push(1, 2); - QVERIFY_EXCEPTION_THROWN(queue.pop(), std::exception); + QCOMPARE(queue.pop(), msg_t{}); QVERIFY(sizeof(decltype(queue)::array_t) <= sizeof(*cq__)); auto cq = ::new (cq__) decltype(queue)::array_t;