diff --git a/src/groups/mqb/mqba/mqba_clientsession.cpp b/src/groups/mqb/mqba/mqba_clientsession.cpp index 6a5024cafe..d6d8d29f59 100644 --- a/src/groups/mqb/mqba/mqba_clientsession.cpp +++ b/src/groups/mqb/mqba/mqba_clientsession.cpp @@ -2816,16 +2816,41 @@ void ClientSession::initiateShutdown(const ShutdownCb& callback, BALL_LOG_INFO << description() << ": initiateShutdown"; - dispatcher()->execute( - bdlf::BindUtil::bind( - bdlf::MemFnUtil::memFn(&ClientSession::initiateShutdownDispatched, - d_self.acquire()), - callback, - timeout), - this, - mqbi::DispatcherEventType::e_DISPATCHER); - // Use 'mqbi::DispatcherEventType::e_DISPATCHER' to avoid (re)enabling - // 'd_flushList' + // The 'd_self.acquire()' return 'shared_ptr' but that does + // not relate to the 'shared_ptr' acquired by + // 'mqbnet::TransportManagerIterator'. The latter is bound to the + // 'initiateShutdown'. The former can be null after 'd_self.invalidate()' + // call. ('invalidate()' waits for all _acquired_ 'shared_ptr' references + // to drop). + // + // We have a choice, either 1) bind the latter to 'initiateShutdown' to + // make sure 'd_self.acquire()' returns not null, or 2) invoke the + // 'callback' earlier if fail to 'acquire()' because of 'invalidate()', or + // 3) bind _acquired_ 'shared_ptr' to 'initiateShutdown'. + // + // Choosing 2), assuming that calling the (completion) callback from a + // thread other than the *CLIENT* dispatcher thread is ok. The + // 'mwcu::OperationChainLink' expects the completion callback from multiple + // sessions anyway. + + bsl::shared_ptr ptr = d_self.acquire(); + + if (!ptr) { + callback(); + } + else { + dispatcher()->execute( + bdlf::BindUtil::bind( + bdlf::MemFnUtil::memFn( + &ClientSession::initiateShutdownDispatched, + d_self.acquire()), + callback, + timeout), + this, + mqbi::DispatcherEventType::e_DISPATCHER); + // Use 'mqbi::DispatcherEventType::e_DISPATCHER' to avoid (re)enabling + // 'd_flushList' + } } void ClientSession::invalidate()