diff options
author | Mike Kaganski <mike.kaganski@collabora.com> | 2024-11-26 23:08:04 +0500 |
---|---|---|
committer | Mike Kaganski <mike.kaganski@collabora.com> | 2024-11-27 05:05:49 +0100 |
commit | 68699d3699fed08956e37e53664fa92e70487b8d (patch) | |
tree | 32032aefc33369614e2bee012143962393e19cbd | |
parent | 03a701516ea94b786ba6e1b35bf6dad22cceced5 (diff) |
Release CXNotifyingDataObject in separate thread
The reported deadlocking situation at paste was:
1. Thread CMtaOleClipboard::run() is handling CXNotifyingDataObject::Release,
which calls CWinClipboard::onReleaseDataObject before deleting self, and that
eventually tries to lock solar mutex:
sal3!osl_acquireMutex+0x49 [sal\osl\w32\mutex.cxx @ 65]
vclplug_winlo!osl::Mutex::acquire+0xa [include\osl\mutex.hxx @ 63]
vclplug_winlo!SalYieldMutex::doAcquire+0x91 [vcl\win\app\salinst.cxx @ 148]
vcllo!osl::Guard<comphelper::SolarMutex>::{ctor}+0xe [include\osl\mutex.hxx @ 144]
vcllo!SolarMutexGuard::{ctor}+0x1b [include\vcl\svapp.hxx @ 1340]
vcllo!TransferableHelper::lostOwnership+0x36 [vcl\source\treelist\transfer.cxx @ 487]
vclplug_winlo!CXNotifyingDataObject::lostOwnership+0x61 [vcl\win\dtrans\XNotifyingDataObject.cxx @ 140]
vclplug_winlo!CWinClipboard::onReleaseDataObject+0x57 [vcl\win\dtrans\WinClipboard.cxx @ 364]
vclplug_winlo!CXNotifyingDataObject::Release+0x36 [vcl\win\dtrans\XNotifyingDataObject.cxx @ 77]
combase!Ordinal230+0x1c9b
...
combase!Ordinal87+0x3d19
USER32!DispatchMessageW+0x741
USER32!DispatchMessageW+0x201
vclplug_winlo!CMtaOleClipboard::run+0x18f [vcl\win\dtrans\MtaOleClipb.cxx @ 657]
2. Thread CMtaOleClipboard::clipboardChangedNotifierThreadProc() is handling
the respective event, calling CWinClipboard::handleClipboardContentChanged,
which notifies listeners, including SwClipboardChangeListener, which, in its
changedContents, has locked solar mutex, and requests the clipboard content,
which eventually calls CMtaOleClipboard::getClipboard posting a message to
the CMtaOleClipboard::run() thread, and waiting the result:
vclplug_winlo!`anonymous-namespace'::Win32Condition::wait+0x3b [vcl\win\dtrans\MtaOleClipb.cxx @ 92]
vclplug_winlo!CMtaOleClipboard::getClipboard+0x220 [vcl\win\dtrans\MtaOleClipb.cxx @ 355]
vclplug_winlo!CWinClipboard::getIDataObject+0x84 [vcl\win\dtrans\WinClipboard.cxx @ 161]
vclplug_winlo!CDOTransferable::tryToGetIDataObjectIfAbsent+0x56 [vcl\win\dtrans\DOTransferable.cxx @ 413]
vclplug_winlo!CDOTransferable::getClipboardData+0x79 [vcl\win\dtrans\DOTransferable.cxx @ 425]
vclplug_winlo!CDOTransferable::getTransferData+0x163 [vcl\win\dtrans\DOTransferable.cxx @ 252]
sotlo!GetTransferableAction_Impl+0x13d [sot\source\base\formats.cxx @ 1352]
sotlo!SotExchange::GetExchangeAction+0xde [sot\source\base\formats.cxx @ 1429]
swlo!SwTransferable::IsPaste+0xba [sw\source\uibase\dochdl\swdtflvr.cxx @ 1402]
swlo!SwClipboardChangeListener::changedContents+0xac [sw\source\uibase\uiview\uivwimp.cxx @ 315]
vclplug_winlo!comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::NotifySingleListener<com::sun::star::datatransfer::clipboard::ClipboardEvent>::operator()+0xc [include\comphelper\interfacecontainer4.hxx @ 274]
vclplug_winlo!comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::forEach<comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::NotifySingleListener<com::sun::star::datatransfer::clipboard::ClipboardEvent> >+0xb6 [include\comphelper\interfacecontainer4.hxx @ 304]
vclplug_winlo!comphelper::OInterfaceContainerHelper4<com::sun::star::datatransfer::clipboard::XClipboardListener>::notifyEach+0x28 [include\comphelper\interfacecontainer4.hxx @ 325]
vclplug_winlo!CWinClipboard::handleClipboardContentChanged+0x156 [vcl\win\dtrans\WinClipboard.cxx @ 303]
vclplug_winlo!CWinClipboard::onClipboardContentChanged+0x5c [vcl\win\dtrans\WinClipboard.cxx @ 387]
vclplug_winlo!CMtaOleClipboard::clipboardChangedNotifierThreadProc+0x172 [vcl\win\dtrans\MtaOleClipb.cxx @ 699]
This change tries to untie this, by creating a dedicated thread to call
CWinClipboard::onReleaseDataObject and delete CXNotifyingDataObject outside
of its Release (and of the CMtaOleClipboard::run() thread), so that locking
happening in that process doesn't deadlock functional threads.
Change-Id: I93da6fe79225319a84b332c81716793f4d9fb05d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/177363
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r-- | vcl/win/dtrans/WinClipboard.hxx | 2 | ||||
-rw-r--r-- | vcl/win/dtrans/XNotifyingDataObject.cxx | 24 | ||||
-rw-r--r-- | vcl/win/dtrans/XNotifyingDataObject.hxx | 2 |
3 files changed, 22 insertions, 6 deletions
diff --git a/vcl/win/dtrans/WinClipboard.hxx b/vcl/win/dtrans/WinClipboard.hxx index aba9689cb7a0..098f0816c557 100644 --- a/vcl/win/dtrans/WinClipboard.hxx +++ b/vcl/win/dtrans/WinClipboard.hxx @@ -52,7 +52,7 @@ class CWinClipboard final css::datatransfer::clipboard::XFlushableClipboard, css::lang::XServiceInfo> { - friend STDMETHODIMP_(ULONG) CXNotifyingDataObject::Release(); + friend CXNotifyingDataObject::~CXNotifyingDataObject(); css::uno::Reference<css::uno::XComponentContext> m_xContext; const OUString m_itsName; diff --git a/vcl/win/dtrans/XNotifyingDataObject.cxx b/vcl/win/dtrans/XNotifyingDataObject.cxx index 9d7c563a5a28..cee9e63879ed 100644 --- a/vcl/win/dtrans/XNotifyingDataObject.cxx +++ b/vcl/win/dtrans/XNotifyingDataObject.cxx @@ -40,6 +40,12 @@ CXNotifyingDataObject::CXNotifyingDataObject( { } +CXNotifyingDataObject::~CXNotifyingDataObject() +{ + if (auto pWinClipImpl = m_pWinClipImpl.get()) + pWinClipImpl->onReleaseDataObject(*this); +} + STDMETHODIMP CXNotifyingDataObject::QueryInterface( REFIID iid, void** ppvObject ) { if ( nullptr == ppvObject ) @@ -64,6 +70,17 @@ STDMETHODIMP_(ULONG) CXNotifyingDataObject::AddRef( ) return static_cast< ULONG >( InterlockedIncrement( &m_nRefCnt ) ); } +namespace +{ +// delete CXNotifyingDataObject is a dedicated thread. It calls CWinClipboard::onReleaseDataObject, +// which may lock solar mutex, and if called in CMtaOleClipboard::run() thread, may deadlock. +unsigned __stdcall releaseAsyncProc(void* p) +{ + delete static_cast<CXNotifyingDataObject*>(p); + return 0; +} +} + STDMETHODIMP_(ULONG) CXNotifyingDataObject::Release( ) { ULONG nRefCnt = @@ -71,10 +88,9 @@ STDMETHODIMP_(ULONG) CXNotifyingDataObject::Release( ) if ( 0 == nRefCnt ) { - if (auto pWinClipImpl = m_pWinClipImpl.get()) - pWinClipImpl->onReleaseDataObject(*this); - - delete this; + auto handle = _beginthreadex(nullptr, 0, releaseAsyncProc, this, 0, nullptr); + assert(handle); + CloseHandle(reinterpret_cast<HANDLE>(handle)); } return nRefCnt; diff --git a/vcl/win/dtrans/XNotifyingDataObject.hxx b/vcl/win/dtrans/XNotifyingDataObject.hxx index 04fb5b93d49f..ba15b143cbf5 100644 --- a/vcl/win/dtrans/XNotifyingDataObject.hxx +++ b/vcl/win/dtrans/XNotifyingDataObject.hxx @@ -48,7 +48,7 @@ public: const css::uno::Reference< css::datatransfer::clipboard::XClipboardOwner >& aXClipOwner, CWinClipboard* const theWinClipoard); - virtual ~CXNotifyingDataObject() {} + virtual ~CXNotifyingDataObject(); // ole interface implementation |