From 3fa2f1f7d12040d6c23fa6bf3380cce39440be1e Mon Sep 17 00:00:00 2001 From: Nicolas Pope <nicolas.pope@utu.fi> Date: Wed, 16 Nov 2022 07:03:53 +0000 Subject: [PATCH] Fix blocking in handle trigger --- include/ftl/handle.hpp | 25 ++++++++++++++----------- include/ftl/protocol/error.hpp | 3 ++- test/handle_unit.cpp | 5 +++-- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/include/ftl/handle.hpp b/include/ftl/handle.hpp index 75b7e78..534d788 100644 --- a/include/ftl/handle.hpp +++ b/include/ftl/handle.hpp @@ -26,7 +26,7 @@ struct BaseHandler { inline Handle make_handle(BaseHandler*, int); protected: - std::mutex mutex_; + std::shared_mutex mutex_; int id_ = 0; }; @@ -110,7 +110,7 @@ struct Handler : BaseHandler { * remain in scope, the destructor of the `Handle` will remove the callback. */ Handle on(const std::function<bool(ARGS...)> &f) { - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); int id = id_++; callbacks_[id] = f; return make_handle(this, id); @@ -125,7 +125,7 @@ struct Handler : BaseHandler { void trigger(ARGS ...args) { bool hadFault = false; std::string faultMsg; - std::unique_lock<std::mutex> lk(mutex_); + std::shared_lock<std::shared_mutex> lk(mutex_); for (auto i = callbacks_.begin(); i != callbacks_.end(); ) { bool keep = true; try { @@ -134,9 +134,12 @@ struct Handler : BaseHandler { hadFault = true; faultMsg = e.what(); } - if (!keep) i = callbacks_.erase(i); - else + if (!keep) { + // i = callbacks_.erase(i); + throw FTL_Error("Return value callback removal not implemented"); + } else { ++i; + } } if (hadFault) throw FTL_Error("Callback exception: " << faultMsg); } @@ -150,7 +153,7 @@ struct Handler : BaseHandler { ftl::pool.push([this, args...](int id) { bool hadFault = false; std::string faultMsg; - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); for (auto i = callbacks_.begin(); i != callbacks_.end(); ) { bool keep = true; try { @@ -174,7 +177,7 @@ struct Handler : BaseHandler { * removal via the return value. */ void triggerParallel(ARGS ...args) { - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); jobs_ += callbacks_.size(); for (auto i = callbacks_.begin(); i != callbacks_.end(); ++i) { ftl::pool.push([this, f = i->second, args...](int id) { @@ -195,7 +198,7 @@ struct Handler : BaseHandler { */ void remove(const Handle &h) override { { - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); callbacks_.erase(h.id()); } // Make sure any possible call to removed callback has finished. @@ -230,7 +233,7 @@ struct SingletonHandler : BaseHandler { * remain in scope, the destructor of the `Handle` will remove the callback. */ [[nodiscard]] Handle on(const std::function<bool(ARGS...)> &f) { - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); if (callback_) throw FTL_Error("Callback already bound"); callback_ = f; return make_handle(this, id_++); @@ -243,7 +246,7 @@ struct SingletonHandler : BaseHandler { * return true. */ bool trigger(ARGS ...args) { - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); if (callback_) { bool keep = callback_(std::forward<ARGS>(args)...); if (!keep) callback_ = nullptr; @@ -259,7 +262,7 @@ struct SingletonHandler : BaseHandler { * currently bound callback then the callback is not removed. */ void remove(const Handle &h) override { - std::unique_lock<std::mutex> lk(mutex_); + std::unique_lock<std::shared_mutex> lk(mutex_); if (h.id() == id_-1) callback_ = nullptr; } diff --git a/include/ftl/protocol/error.hpp b/include/ftl/protocol/error.hpp index 537987c..2a8b608 100644 --- a/include/ftl/protocol/error.hpp +++ b/include/ftl/protocol/error.hpp @@ -30,7 +30,8 @@ enum struct Error { kURIAlreadyExists, kURIDoesNotExist, kBadURI, - kBadVersion + kBadVersion, + kBandwidth // Send was delayed }; } // namespace protocol diff --git a/test/handle_unit.cpp b/test/handle_unit.cpp index 3139675..3bb23ed 100644 --- a/test/handle_unit.cpp +++ b/test/handle_unit.cpp @@ -23,7 +23,8 @@ TEST_CASE( "Handle release on cancel" ) { REQUIRE(calls == 5); } -TEST_CASE( "Handle release on false return" ) { +// Not needed or supported +/*TEST_CASE( "Handle release on false return" ) { Handler<int> handler; int calls = 0; @@ -37,7 +38,7 @@ TEST_CASE( "Handle release on false return" ) { REQUIRE(calls == 5); handler.trigger(5); REQUIRE(calls == 5); -} +}*/ TEST_CASE( "Handle multiple triggers" ) { Handler<int> handler; -- GitLab