Skip to content
Snippets Groups Projects
Commit 78660eec authored by Nicolas Pope's avatar Nicolas Pope
Browse files

Merge branch 'bug/handle-trigger' into 'main'

Fix blocking in handle trigger

See merge request beyondaka/beyond-protocol!69
parents 0680a05a 3fa2f1f7
No related branches found
No related tags found
No related merge requests found
...@@ -26,7 +26,7 @@ struct BaseHandler { ...@@ -26,7 +26,7 @@ struct BaseHandler {
inline Handle make_handle(BaseHandler*, int); inline Handle make_handle(BaseHandler*, int);
protected: protected:
std::mutex mutex_; std::shared_mutex mutex_;
int id_ = 0; int id_ = 0;
}; };
...@@ -110,7 +110,7 @@ struct Handler : BaseHandler { ...@@ -110,7 +110,7 @@ struct Handler : BaseHandler {
* remain in scope, the destructor of the `Handle` will remove the callback. * remain in scope, the destructor of the `Handle` will remove the callback.
*/ */
Handle on(const std::function<bool(ARGS...)> &f) { 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_++; int id = id_++;
callbacks_[id] = f; callbacks_[id] = f;
return make_handle(this, id); return make_handle(this, id);
...@@ -125,7 +125,7 @@ struct Handler : BaseHandler { ...@@ -125,7 +125,7 @@ struct Handler : BaseHandler {
void trigger(ARGS ...args) { void trigger(ARGS ...args) {
bool hadFault = false; bool hadFault = false;
std::string faultMsg; 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(); ) { for (auto i = callbacks_.begin(); i != callbacks_.end(); ) {
bool keep = true; bool keep = true;
try { try {
...@@ -134,10 +134,13 @@ struct Handler : BaseHandler { ...@@ -134,10 +134,13 @@ struct Handler : BaseHandler {
hadFault = true; hadFault = true;
faultMsg = e.what(); faultMsg = e.what();
} }
if (!keep) i = callbacks_.erase(i); if (!keep) {
else // i = callbacks_.erase(i);
throw FTL_Error("Return value callback removal not implemented");
} else {
++i; ++i;
} }
}
if (hadFault) throw FTL_Error("Callback exception: " << faultMsg); if (hadFault) throw FTL_Error("Callback exception: " << faultMsg);
} }
...@@ -150,7 +153,7 @@ struct Handler : BaseHandler { ...@@ -150,7 +153,7 @@ struct Handler : BaseHandler {
ftl::pool.push([this, args...](int id) { ftl::pool.push([this, args...](int id) {
bool hadFault = false; bool hadFault = false;
std::string faultMsg; 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(); ) { for (auto i = callbacks_.begin(); i != callbacks_.end(); ) {
bool keep = true; bool keep = true;
try { try {
...@@ -174,7 +177,7 @@ struct Handler : BaseHandler { ...@@ -174,7 +177,7 @@ struct Handler : BaseHandler {
* removal via the return value. * removal via the return value.
*/ */
void triggerParallel(ARGS ...args) { void triggerParallel(ARGS ...args) {
std::unique_lock<std::mutex> lk(mutex_); std::unique_lock<std::shared_mutex> lk(mutex_);
jobs_ += callbacks_.size(); jobs_ += callbacks_.size();
for (auto i = callbacks_.begin(); i != callbacks_.end(); ++i) { for (auto i = callbacks_.begin(); i != callbacks_.end(); ++i) {
ftl::pool.push([this, f = i->second, args...](int id) { ftl::pool.push([this, f = i->second, args...](int id) {
...@@ -195,7 +198,7 @@ struct Handler : BaseHandler { ...@@ -195,7 +198,7 @@ struct Handler : BaseHandler {
*/ */
void remove(const Handle &h) override { 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()); callbacks_.erase(h.id());
} }
// Make sure any possible call to removed callback has finished. // Make sure any possible call to removed callback has finished.
...@@ -230,7 +233,7 @@ struct SingletonHandler : BaseHandler { ...@@ -230,7 +233,7 @@ struct SingletonHandler : BaseHandler {
* remain in scope, the destructor of the `Handle` will remove the callback. * remain in scope, the destructor of the `Handle` will remove the callback.
*/ */
[[nodiscard]] Handle on(const std::function<bool(ARGS...)> &f) { [[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"); if (callback_) throw FTL_Error("Callback already bound");
callback_ = f; callback_ = f;
return make_handle(this, id_++); return make_handle(this, id_++);
...@@ -243,7 +246,7 @@ struct SingletonHandler : BaseHandler { ...@@ -243,7 +246,7 @@ struct SingletonHandler : BaseHandler {
* return true. * return true.
*/ */
bool trigger(ARGS ...args) { bool trigger(ARGS ...args) {
std::unique_lock<std::mutex> lk(mutex_); std::unique_lock<std::shared_mutex> lk(mutex_);
if (callback_) { if (callback_) {
bool keep = callback_(std::forward<ARGS>(args)...); bool keep = callback_(std::forward<ARGS>(args)...);
if (!keep) callback_ = nullptr; if (!keep) callback_ = nullptr;
...@@ -259,7 +262,7 @@ struct SingletonHandler : BaseHandler { ...@@ -259,7 +262,7 @@ struct SingletonHandler : BaseHandler {
* currently bound callback then the callback is not removed. * currently bound callback then the callback is not removed.
*/ */
void remove(const Handle &h) override { 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; if (h.id() == id_-1) callback_ = nullptr;
} }
......
...@@ -30,7 +30,8 @@ enum struct Error { ...@@ -30,7 +30,8 @@ enum struct Error {
kURIAlreadyExists, kURIAlreadyExists,
kURIDoesNotExist, kURIDoesNotExist,
kBadURI, kBadURI,
kBadVersion kBadVersion,
kBandwidth // Send was delayed
}; };
} // namespace protocol } // namespace protocol
......
...@@ -23,7 +23,8 @@ TEST_CASE( "Handle release on cancel" ) { ...@@ -23,7 +23,8 @@ TEST_CASE( "Handle release on cancel" ) {
REQUIRE(calls == 5); REQUIRE(calls == 5);
} }
TEST_CASE( "Handle release on false return" ) { // Not needed or supported
/*TEST_CASE( "Handle release on false return" ) {
Handler<int> handler; Handler<int> handler;
int calls = 0; int calls = 0;
...@@ -37,7 +38,7 @@ TEST_CASE( "Handle release on false return" ) { ...@@ -37,7 +38,7 @@ TEST_CASE( "Handle release on false return" ) {
REQUIRE(calls == 5); REQUIRE(calls == 5);
handler.trigger(5); handler.trigger(5);
REQUIRE(calls == 5); REQUIRE(calls == 5);
} }*/
TEST_CASE( "Handle multiple triggers" ) { TEST_CASE( "Handle multiple triggers" ) {
Handler<int> handler; Handler<int> handler;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment