From 99c1534dfa089ff740214205d2099ce82a5404c8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Mon, 5 Jul 2021 08:29:01 -0700 Subject: [PATCH] client: add ConnectBuilder::syncCancel() --- src/client.cpp | 12 ++++++------ src/pvxs/client.h | 10 ++++++++++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index a5bc0c4..8e3cedb 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -204,26 +204,26 @@ std::shared_ptr ConnectBuilder::exec() if(!ctx) throw std::logic_error("NULL Builder"); + auto syncCancel(_syncCancel); auto context(ctx->impl->shared_from_this()); auto op(std::make_shared(context->tcp_loop, _pvname)); op->_onConn = std::move(_onConn); op->_onDis = std::move(_onDis); - std::shared_ptr external(op.get(), [op](ConnectImpl*) mutable { + std::shared_ptr external(op.get(), [op, syncCancel](ConnectImpl*) mutable { // from user thread - auto loop(op->loop); + auto temp(std::move(op)); + auto loop(temp->loop); // std::bind for lack of c++14 generalized capture // to move internal ref to worker for dtor - loop.call(std::bind([](std::shared_ptr& op) { + loop.tryInvoke(syncCancel, std::bind([](std::shared_ptr& op) { // on worker // ordering of dispatch()/call() ensures creation before destruction assert(op->chan); op->chan->connectors.remove(op.get()); - }, std::move(op))); - assert(!op); - op.reset(); + }, std::move(temp))); }); context->tcp_loop.dispatch([op, context]() { diff --git a/src/pvxs/client.h b/src/pvxs/client.h index f29a254..024fef1 100644 --- a/src/pvxs/client.h +++ b/src/pvxs/client.h @@ -829,6 +829,7 @@ class ConnectBuilder std::string _pvname; std::function _onConn; std::function _onDis; + bool _syncCancel = true; public: ConnectBuilder(const std::shared_ptr& ctx, const std::string& pvname) :ctx(ctx) @@ -840,6 +841,15 @@ public: //! Handler to be invoked when channel becomes disconnected. ConnectBuilder& onDisconnect(std::function&& cb) { _onDis = std::move(cb); return *this; } + /** Controls whether Connect::~Connect() synchronizes. + * + * When true (the default) explicit or implicit cancel blocks until any + * in progress callback has completed. This makes safe some use of + * references in callbacks. + * @since UNRELEASED + */ + ConnectBuilder& syncCancel(bool b) { this->_syncCancel = b; return *this; } + //! Submit request to connect PVXS_API std::shared_ptr exec();