tdf#103852 avoid clipboard deadlock
Deallocate the XTransferable object async using AsyncCallback (that uses Application::PostUserEvent) which executes the callback in a thread-safe way on the main thread. This avoids a deadlock at deallocation so that the XTransferable. Modify AsyncCallback to not hold the SolarMutexGuard because Application::PostUserEvent is considered thread-safe. Document Application::PostUserEvent thread-safety Change-Id: I4237a1cf380e8be66b3eefc393a58bb4853bf4e1 Reviewed-on: https://gerrit.libreoffice.org/31126 Tested-by: Jenkins <ci@libreoffice.org> Reviewed-by: Tomaž Vajngerl <quikee@gmail.com>
This commit is contained in:
committed by
Tomaž Vajngerl
parent
e190825b73
commit
bdd108cd72
@@ -25,8 +25,11 @@
|
||||
#include "DTransHelper.hxx"
|
||||
#include "TxtCnvtHlp.hxx"
|
||||
#include <com/sun/star/datatransfer/clipboard/XClipboardEx.hpp>
|
||||
#include "com/sun/star/awt/AsyncCallback.hpp"
|
||||
#include "com/sun/star/awt/XCallback.hpp"
|
||||
#include "FmtFilter.hxx"
|
||||
#include <comphelper/processfactory.hxx>
|
||||
#include <cppuhelper/implbase.hxx>
|
||||
|
||||
#if defined _MSC_VER
|
||||
#pragma warning(push,1)
|
||||
@@ -82,6 +85,28 @@ void SAL_CALL setupStgMedium( const FORMATETC& fetc,
|
||||
OSL_ASSERT( false );
|
||||
}
|
||||
|
||||
/**
|
||||
We need to destroy XTransferable in the main thread to avoid dead lock
|
||||
when locking in the clipboard thread. So we transfer the ownership of the
|
||||
XTransferable reference to this object and release it when the callback
|
||||
is executed in main thread.
|
||||
*/
|
||||
class AsyncDereference : public cppu::WeakImplHelper<css::awt::XCallback>
|
||||
{
|
||||
Reference<XTransferable> maTransferable;
|
||||
|
||||
public:
|
||||
AsyncDereference(css::uno::Reference<css::datatransfer::XTransferable> const & rTransferable)
|
||||
: maTransferable(rTransferable)
|
||||
{}
|
||||
|
||||
virtual void SAL_CALL notify(css::uno::Any const &)
|
||||
throw (css::uno::RuntimeException, std::exception) override
|
||||
{
|
||||
maTransferable.set(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
// a helper class that will be thrown by the function validateFormatEtc
|
||||
|
||||
class CInvalidFormatEtcException
|
||||
@@ -174,12 +199,20 @@ CXTDataObject::CXTDataObject( const Reference< XComponentContext >& rxContext,
|
||||
const Reference< XTransferable >& aXTransferable )
|
||||
: m_nRefCnt( 0 )
|
||||
, m_XTransferable( aXTransferable )
|
||||
, m_XComponentContext( rxContext )
|
||||
, m_bFormatEtcContainerInitialized( false )
|
||||
, m_DataFormatTranslator( rxContext )
|
||||
, m_FormatRegistrar( rxContext, m_DataFormatTranslator )
|
||||
{
|
||||
}
|
||||
|
||||
CXTDataObject::~CXTDataObject()
|
||||
{
|
||||
css::awt::AsyncCallback::create(m_XComponentContext)->addCallback(
|
||||
new AsyncDereference(m_XTransferable),
|
||||
css::uno::Any());
|
||||
}
|
||||
|
||||
// IUnknown->QueryInterface
|
||||
|
||||
STDMETHODIMP CXTDataObject::QueryInterface( REFIID iid, LPVOID* ppvObject )
|
||||
|
@@ -64,7 +64,7 @@ class CXTDataObject : public IDataObject
|
||||
public:
|
||||
CXTDataObject( const css::uno::Reference< css::uno::XComponentContext >& rxContext,
|
||||
const css::uno::Reference< css::datatransfer::XTransferable >& aXTransferable );
|
||||
virtual ~CXTDataObject() {}
|
||||
virtual ~CXTDataObject();
|
||||
|
||||
// ole interface implementation
|
||||
|
||||
@@ -103,6 +103,7 @@ private:
|
||||
private:
|
||||
LONG m_nRefCnt;
|
||||
css::uno::Reference< css::datatransfer::XTransferable > m_XTransferable;
|
||||
css::uno::Reference< css::uno::XComponentContext> m_XComponentContext;
|
||||
CFormatEtcContainer m_FormatEtcContainer;
|
||||
bool m_bFormatEtcContainerInitialized;
|
||||
CDataFormatTranslator m_DataFormatTranslator;
|
||||
|
@@ -776,9 +776,13 @@ public:
|
||||
|
||||
User events allow for the deferreal of work to later in the main-loop - at idle.
|
||||
|
||||
Execution of the deferred work is thread-safe which means all the tasks are executed
|
||||
serially, so no thread-safety locks between tasks are necessary.
|
||||
|
||||
@param rLink Link to event callback function
|
||||
@param pCaller Pointer to data sent to the event by the caller. Optional.
|
||||
@param bReferenceLink If true - hold a VclPtr<> reference on the Link's instance.
|
||||
Taking the reference is guarded by a SolarMutexGuard.
|
||||
|
||||
@return the event ID used to post the event.
|
||||
*/
|
||||
|
@@ -88,8 +88,7 @@ void SAL_CALL AsyncCallback::addCallback(const css::uno::Reference< css::awt::XC
|
||||
{
|
||||
if ( Application::IsInMain() )
|
||||
{
|
||||
SolarMutexGuard aSolarGuard;
|
||||
|
||||
// NOTE: We don't need SolarMutexGuard here as Application::PostUserEvent is thread-safe
|
||||
CallbackData* pCallbackData = new CallbackData( xCallback, aData );
|
||||
Application::PostUserEvent( LINK( this, AsyncCallback, Notify_Impl ), pCallbackData );
|
||||
}
|
||||
|
Reference in New Issue
Block a user