summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2024-11-26 23:08:04 +0500
committerMike Kaganski <mike.kaganski@collabora.com>2024-11-27 05:05:49 +0100
commit68699d3699fed08956e37e53664fa92e70487b8d (patch)
tree32032aefc33369614e2bee012143962393e19cbd
parent03a701516ea94b786ba6e1b35bf6dad22cceced5 (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.hxx2
-rw-r--r--vcl/win/dtrans/XNotifyingDataObject.cxx24
-rw-r--r--vcl/win/dtrans/XNotifyingDataObject.hxx2
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