sal/osl/w32/conditn.cxx        |   11 +++++++++--
 vcl/win/dtrans/MtaOleClipb.cxx |   15 +++++++--------
 2 files changed, 16 insertions(+), 10 deletions(-)

New commits:
commit 1e2e51607a163021ef1fb1fb0d217266bd448173
Author:     Mike Kaganski <[email protected]>
AuthorDate: Fri Jan 10 11:52:51 2025 +0500
Commit:     Mike Kaganski <[email protected]>
CommitDate: Fri Jan 10 10:09:54 2025 +0100

    Try to use CoWaitForMultipleHandles magic to handle COM message loop
    
    A customer reports a freeze problem, with the call stacks seemengly 
indicating
    a shuck COM re-entry, even though osl_waitCondition should be prepared for 
COM
    re-entry. The two relevant threads are:
    
    1. VCL Main
    
      win32u.dll!NtUserMsgWaitForMultipleObjectsEx()
      user32.dll!RealMsgWaitForMultipleObjectsEx()
      combase.dll!CCliModalLoop::BlockFn(void * * ahEvent, unsigned long 
cEvents, unsigned long * lpdwSignaled) Line 2156
      [Inlineframe] combase.dll!ModalLoop(CSyncClientCall *) Line 164
      combase.dll!ClassicSTAThreadWaitForCall(CSyncClientCall * pClientCall, 
WaitForCallReason reason, unsigned long dwRetryTimeout) Line 172
      [Inlineframe] combase.dll!ThreadSendReceive(tagRPCOLEMESSAGE *) Line 7355
      [Inlineframe] 
combase.dll!CSyncClientCall::SwitchAptAndDispatchCall(tagRPCOLEMESSAGE * 
pMessage) Line 5900
      combase.dll!CSyncClientCall::SendReceive2(tagRPCOLEMESSAGE * pMessage, 
unsigned long * pstatus) Line 5459
      [Inlineframe] 
combase.dll!SyncClientCallRetryContext::SendReceiveWithRetry(tagRPCOLEMESSAGE 
*) Line 1542
      [Inlineframe] 
combase.dll!CSyncClientCall::SendReceiveInRetryContext(SyncClientCallRetryContext
 *) Line 565
      combase.dll!ClassicSTAThreadSendReceive(CSyncClientCall * pClientCall, 
tagRPCOLEMESSAGE * pMsg, unsigned long * pulStatus) Line 547
      combase.dll!CSyncClientCall::SendReceive(tagRPCOLEMESSAGE * pMessage, 
unsigned long * pulStatus) Line 783
      combase.dll!CClientChannel::SendReceive(tagRPCOLEMESSAGE * pMessage, 
unsigned long * pulStatus) Line 655
      combase.dll!NdrExtpProxySendReceive(void * pThis, _MIDL_STUB_MESSAGE * 
pStubMsg) Line 2002
      rpcrt4.dll!NdrpClientCall3()
      rpcrt4.dll!NdrClientCall3()
      [Inlineframe] combase.dll!IDataObject_RemoteGetData_Proxy(IDataObject *) 
Line 2082
      combase.dll!IDataObject_GetData_Proxy(IDataObject * This, tagFORMATETC * 
pformatetcIn, tagSTGMEDIUM * pMedium) Line 1267
      ole32.dll!CDefObject::GetData(tagFORMATETC * pformatetcIn, tagSTGMEDIUM * 
pmedium) Line 1316
      [Inlineframe] emboleobj.dll!rtl::OUString::indexOf(const char[13] &) Line 
2030
      [Inlineframe] emboleobj.dll!GetAspectFromFlavor(const 
com::sun::star::datatransfer::DataFlavor &) Line 215
      emboleobj.dll!OleComponent::getTransferData(const 
com::sun::star::datatransfer::DataFlavor & aFlavor) Line 1556
      [Inlineframe] emboleobj.dll!com::sun::star::uno::Type::{ctor}() Line 46
      [Inlineframe] 
emboleobj.dll!com::sun::star::datatransfer::DataFlavor::{ctor}() Line 20
      [Inlineframe] 
emboleobj.dll!com::sun::star::embed::VisualRepresentation::{ctor}() Line 19
      emboleobj.dll!OleEmbeddedObject::getPreferredVisualRepresentation(__int64 
nAspect) Line 372
      
comphelper.dll!comphelper::EmbeddedObjectContainer::GetGraphicReplacementStream(__int64
 nViewAspect, const 
com::sun::star::uno::Reference<com::sun::star::embed::XEmbeddedObject> & xObj, 
rtl::OUString * pMediaType) Line 1430
      [Inlineframe] 
svtlo.dll!svt::EmbeddedObjectRef::GetGraphicReplacementStream(__int64) Line 916
      svtlo.dll!svt::EmbeddedObjectRef::GetGraphicStream(bool bUpdate) Line 690
      svtlo.dll!svt::EmbeddedObjectRef::GetReplacement(bool bUpdate) Line 486
      svtlo.dll!svt::EmbeddedObjectRef::GetGraphic() Line 524
      swlo.dll!OutHTML_FrameFormatOLENodeGrf(SwHTMLWriter & rWrt, const 
SwFrameFormat & rFrameFormat, bool bInCntnr, bool bWriteReplacementGraphic) 
Line 1652
      swlo.dll!SwHTMLWriter::OutFrameFormat(AllHtmlFlags nMode, const 
SwFrameFormat & rFrameFormat, const SdrObject * pSdrObject) Line 464
      swlo.dll!OutHTML_SwFlyCnt(SwHTMLWriter & rWrt, const SfxPoolItem & rHt) 
Line 2974
      swlo.dll!Out(SwHTMLWriter &(*)(SwHTMLWriter &, const SfxPoolItem &) * 
pTab, const SfxPoolItem & rHt, SwHTMLWriter & rWrt) Line 40
      swlo.dll!OutHTML_SwTextNode(SwHTMLWriter & rWrt, const SwContentNode & 
rNode) Line 2477
      swlo.dll!SwHTMLWriter::Out_SwDoc(SwPaM * pPam) Line 960
      swlo.dll!SwHTMLWriter::WriteStream() Line 612
      swlo.dll!Writer::Write(SwPaM & rPaM, SvStream & rStrm, const 
rtl::OUString * pFName) Line 236
      swlo.dll!Writer::Write(SwPaM & rPam, SfxMedium & rMedium, const 
rtl::OUString * pFileName) Line 250
      swlo.dll!SwWriter::Write(const tools::SvRef<Writer> & rxWriter, const 
rtl::OUString * pRealFileName) Line 872
      swlo.dll!SwDocShell::ConvertTo(SfxMedium & rMedium) Line 778
      sfxlo.dll!SfxObjectShell::SaveTo_Impl(SfxMedium & rMedium, const 
SfxItemSet * pSet) Line 1633
      sfxlo.dll!SfxObjectShell::PreDoSaveAs_Impl(const rtl::OUString & 
rFileName, const rtl::OUString & aFilterName, const SfxItemSet & rItemSet, 
const com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & 
rArgs) Line 3120
      sfxlo.dll!SfxObjectShell::CommonSaveAs_Impl(const INetURLObject & aURL, 
const rtl::OUString & aFilterName, SfxItemSet & rItemSet, const 
com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & rArgs) 
Line 2910
      
sfxlo.dll!SfxObjectShell::APISaveAs_Impl(std::basic_string_view<char16_t,std::char_traits<char16_t>>
 aFileName, SfxItemSet & rItemSet, const 
com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & rArgs) 
Line 320
      sfxlo.dll!SfxBaseModel::impl_store(const rtl::OUString & sURL, const 
com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & 
seqArguments, bool bSaveTo) Line 3203
      [Inlineframe] 
sfxlo.dll!SfxBaseModel::storeToURL::__l7::<lambda_1>::operator()() Line 1813
      
sfxlo.dll!vcl::solarthread::detail::GenericSolarThreadExecutor<`SfxBaseModel::storeToURL'::`7'::<lambda_1>,void>::doIt()
 Line 114
      [Inlineframe] vcllo.dll!vcl::SolarThreadExecutor::worker(void *) Line 37
      vcllo.dll!vcl::SolarThreadExecutor::LinkStubworker(void * instance, void 
* data) Line 32
      [Inlineframe] vcllo.dll!Link<void *,void>::Call(void *) Line 111
      [Inlineframe] vcllo.dll!ImplHandleUserEvent(ImplSVEvent *) Line 2287
      vcllo.dll!ImplWindowFrameProc(vcl::Window * _pWindow, SalEvent nEvent, 
const void * pEvent) Line 2851
      vcllo.dll!SalFrame::CallCallback(SalEvent nEvent, const void * pEvent) 
Line 310
      [Inlineframe] vclplug_winlo.dll!ImplHandleAppCommand(HWND__ *) Line 5496
      vclplug_winlo.dll!SalFrameWndProc(HWND__ * hWnd, unsigned int nMsg, 
unsigned __int64 wParam, __int64 lParam, bool & rDef) Line 6159
      vclplug_winlo.dll!SalFrameWndProc(HWND__ * hWnd, unsigned int nMsg, 
unsigned __int64 wParam, __int64 lParam, bool & rDef) Line 6190
      user32.dll!UserCallWinProcCheckWow(struct _ACTIVATION_CONTEXT *,__int64 
(*)(struct tagWND *,unsigned int,unsigned __int64,__int64),struct HWND__ *,enum 
_WM_VALUE,unsigned __int64,__int64,void *,int)
      user32.dll!DispatchMessageWorker()
      vclplug_winlo.dll!ImplSalDispatchMessage(const tagMSG * pMsg) Line 476
      vclplug_winlo.dll!ImplSalYield(bool bWait, bool bHandleAllCurrentEvents) 
Line 544
      vclplug_winlo.dll!WinSalInstance::DoYield(bool bWait, bool 
bHandleAllCurrentEvents) Line 581
      vcllo.dll!ImplYield(bool i_bWait, bool i_bAllEvents) Line 393
      vcllo.dll!Application::Execute() Line 369
      sofficeapp.dll!desktop::Desktop::Main() Line 1605
      vcllo.dll!ImplSVMain() Line 229
      sofficeapp.dll!soffice_main() Line 94
      vText.dll!00007ff7f1bb105b()
      vText.dll!00007ff7f1bb1304()
      kernel32.dll!00007fff114b7374()
      ntdll.dll!00007fff128fcc91()
    
    2. cppu_threadpool::ORequestThread
    
      win32u.dll!NtUserMsgWaitForMultipleObjectsEx()
      user32.dll!RealMsgWaitForMultipleObjectsEx()
      sal3.dll!osl_waitCondition(void * Condition, const TimeValue * pTimeout) 
Line 82
      [Inlineframe] vcllo.dll!osl::Condition::wait(const TimeValue *) Line 123
      vcllo.dll!vcl::SolarThreadExecutor::execute() Line 63
      
sfxlo.dll!vcl::solarthread::detail::GenericSolarThreadExecutor<`SfxBaseModel::storeToURL'::`7'::<lambda_1>,void>::exec(const
 SfxBaseModel::storeToURL::__l7::<lambda_1> & func) Line 103
      [Inlineframe] sfxlo.dll!vcl::solarthread::syncExecute(const 
SfxBaseModel::storeToURL::__l7::<lambda_1> &) Line 167
      sfxlo.dll!SfxBaseModel::storeToURL(const rtl::OUString & rURL, const 
com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> & rArgs) 
Line 1813
      mscx_uno.dll!`anonymous 
namespace'::cpp_call(bridges::cpp_uno::shared::UnoInterfaceProxy * pThis, 
bridges::cpp_uno::shared::VtableSlot aVtableSlot, 
_typelib_TypeDescriptionReference * pReturnTypeRef, long nParams, 
_typelib_MethodParameter * pParams, void * pUnoReturn, void * * pUnoArgs, 
_uno_Any * * ppUnoExc) Line 214
      mscx_uno.dll!unoInterfaceProxyDispatch(_uno_Interface * pUnoI, const 
_typelib_TypeDescription * pMemberTD, void * pReturn, void * * pArgs, _uno_Any 
* * ppException) Line 430
      
binaryurplo.dll!binaryurp::IncomingRequest::execute_throw(binaryurp::BinaryAny 
* returnValue, 
std::vector<binaryurp::BinaryAny,std::allocator<binaryurp::BinaryAny>> * 
outArguments) Line 239
      binaryurplo.dll!binaryurp::IncomingRequest::execute() Line 79
      binaryurplo.dll!request(void * pThreadSpecificData) Line 84
      cppu3.dll!cppu_threadpool::JobQueue::enter(const void * nDisposeId, bool 
bReturnWhenNoJob) Line 101
      cppu3.dll!cppu_threadpool::ORequestThread::run() Line 169
      cppu3.dll!threadFunc(void * param) Line 190
      sal3.dll!oslWorkerWrapperFunction(void * pData) Line 67
      ucrtbase.dll!00007fff106f1bb2()
      kernel32.dll!00007fff114b7374()
      ntdll.dll!00007fff128fcc91()
    
    In fact, this is not even obvious that the problem is really re-entry; it 
could
    also turn out to be a call to an external COM server. I can't debug the 
problem
    myself, so this is just a guess.
    
    A nice summary of the problem is in 
https://stackoverflow.com/questions/34420920;
    my suspicion is that our MsgWaitForMultipleObjects call doesn't include some
    message types needed for proper COM message pumping, sufficiently defined as
    "a small set of special-cased messages" in COWAIT_FLAGS enumeration docs 
[1].
    
    Let me try if CoWaitForMultipleHandles in place of MsgWaitForMultipleObjects
    maybe resolves the issue.
    
    [1] 
https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/ne-combaseapi-cowait_flags
    
    Change-Id: I4eaac32cf08c7379a3f8b88bcdd851e70e97d757
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/180048
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <[email protected]>

diff --git a/sal/osl/w32/conditn.cxx b/sal/osl/w32/conditn.cxx
index 6bc6d9d3ed3a..0ad233ed9bff 100644
--- a/sal/osl/w32/conditn.cxx
+++ b/sal/osl/w32/conditn.cxx
@@ -78,8 +78,15 @@ oslConditionResult SAL_CALL osl_waitCondition(oslCondition 
Condition,
 
     while ( true )
     {
-        /* Only wake up if a SendMessage call to the threads message loop is 
detected */
-        switch( MsgWaitForMultipleObjects( 1, reinterpret_cast<HANDLE 
*>(&Condition), FALSE, timeout, QS_SENDMESSAGE ) )
+        DWORD index;
+        /* Only wake up if a SendMessage / COM call to the threads message 
loop is detected */
+        HRESULT hr = CoWaitForMultipleHandles(COWAIT_DISPATCH_CALLS, timeout, 
1,
+                                              
reinterpret_cast<HANDLE*>(&Condition), &index);
+        if (hr == RPC_S_CALLPENDING)
+            return osl_cond_result_timeout;
+        if (FAILED(hr))
+            return osl_cond_result_error;
+        switch (index)
         {
             case WAIT_OBJECT_0 + 1:
                 {
diff --git a/vcl/win/dtrans/MtaOleClipb.cxx b/vcl/win/dtrans/MtaOleClipb.cxx
index 9417f3053c28..b671578f5b45 100644
--- a/vcl/win/dtrans/MtaOleClipb.cxx
+++ b/vcl/win/dtrans/MtaOleClipb.cxx
@@ -66,11 +66,7 @@ namespace /* private */
     const bool MANUAL_RESET = true;
     const bool INIT_NONSIGNALED = false;
 
-    /*  Cannot use osl conditions because they are blocking
-        without waking up on messages sent by another thread
-        this leads to deadlocks because we are blocking the
-        communication between inter-thread marshalled COM
-        pointers.
+    /*  Similar to osl conditions, with two condition objects passed to the 
Wait function.
         COM Proxy-Stub communication uses SendMessages for
         synchronization purposes.
     */
@@ -85,11 +81,14 @@ namespace /* private */
         // leave messages sent through
         bool wait(HANDLE hEvtAbort)
         {
-            const HANDLE hWaitArray[2] = { m_hEvent, hEvtAbort };
+            HANDLE hWaitArray[2] = { m_hEvent, hEvtAbort };
             while (true)
             {
-                DWORD dwResult
-                    = MsgWaitForMultipleObjects(2, hWaitArray, FALSE, 
INFINITE, QS_SENDMESSAGE);
+                DWORD dwResult;
+                HRESULT hr = CoWaitForMultipleHandles(COWAIT_DISPATCH_CALLS, 
INFINITE, 2,
+                                                      hWaitArray, &dwResult);
+                if (FAILED(hr))
+                    return false;
 
                 switch (dwResult)
                 {

Reply via email to