PVA server avoid lock order violation

There is a lock order violation when a server force disconnects it's clients while sending a final message to it (or concurrent close, or probably others). The entry points are channelStateChange() and operation send().

Fix is not to hold the channel mutex when destroy()ing operations.

epics::pvAccess::ServerChannelRPCRequesterImpl::destroy
  locks RPC requester mutex
epics::pvAccess::ServerChannel::destroy
  locks channel mutex
epics::pvAccess::ServerChannelRequesterImpl::channelStateChange


epics::pvAccess::ServerChannel::unregisterRequest
  locks channel mutex
epics::pvAccess::ServerChannelRPCRequesterImpl::destroy
  locks RPC requester mutex
epics::pvAccess::ServerChannelRPCRequesterImpl::send
This commit is contained in:
Michael Davidsaver
2018-06-25 19:46:01 -07:00
parent 4b3237a20d
commit 1ba48868f6
+22 -17
View File
@@ -64,16 +64,29 @@ Destroyable::shared_pointer ServerChannel::getRequest(const pvAccessID id)
void ServerChannel::destroy()
{
Lock guard(_mutex);
if (_destroyed) return;
_destroyed = true;
// destroy all requests
// take ownership of _requests locally to prevent
// removal via unregisterRequest() during iteration
_requests_t reqs;
_requests.swap(reqs);
{
Lock guard(_mutex);
if (_destroyed) return;
_destroyed = true;
// destroy all requests
// take ownership of _requests locally to prevent
// removal via unregisterRequest() during iteration
_requests.swap(reqs);
// close channel security session
// TODO try catch
_channelSecuritySession->close();
// ... and the channel
// TODO try catch
_channel->destroy();
}
// unlock our before destroy.
// our mutex is subordinate to operation mutex
for(_requests_t::const_iterator it=reqs.begin(), end=reqs.end(); it!=end; ++it)
{
const _requests_t::mapped_type& req = it->second;
@@ -81,14 +94,6 @@ void ServerChannel::destroy()
req->destroy();
// May still be in the send queue
}
// close channel security session
// TODO try catch
_channelSecuritySession->close();
// ... and the channel
// TODO try catch
_channel->destroy();
}
ServerChannel::~ServerChannel()