Skip to content

Commit e6c4a9f

Browse files
committed
Pre-init NSSpellCHecker to avoid SolarMutex deadlock
in headless vclplug too. Same deadlock can happen in that mode as seen originally as: commit d193d65 Date: Thu Sep 8 17:30:38 2022 +0200 tdf#151894 Pre-init NSSpellCHecker to avoid SolarMutex deadlock current example bts are main on thread 1, vcl launched to run on its event loop on 'lo_startmain' side thread. (lldb) thread backtrace 1 * thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP * frame #0: 0x00000001966f489c libsystem_kernel.dylib`__psynch_mutexwait + 8 frame #1: 0x0000000196730e58 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_wait + 84 frame #2: 0x000000019672e840 libsystem_pthread.dylib`_pthread_mutex_firstfit_lock_slow + 220 frame #3: 0x0000000105ad554c libuno_sal.dylib.3`osl_acquireMutex(pMutex=<unavailable>) at mutex.cxx:99:20 frame #4: 0x000000015a6e8370 libmergedlo.dylib`SvpSalYieldMutex::doAcquire(unsigned int) [inlined] osl::Mutex::acquire(this=0x00000001497e7ec8) at mutex.hxx:63:20 frame #5: 0x000000015a6e8368 libmergedlo.dylib`SvpSalYieldMutex::doAcquire(this=0x00000001497e7ec0, nLockCount=1) at svpinst.cxx:357:18 frame #6: 0x000000015952fda8 libmergedlo.dylib`doc_saveAs(_LibreOfficeKitDocument*, char const*, char const*, char const*) [inlined] comphelper::SolarMutex::acquire(this=0x00000001497e7ec0, nLockCount=1) at solarmutex.hxx:86:5 frame #7: 0x000000015952fd98 libmergedlo.dylib`doc_saveAs(_LibreOfficeKitDocument*, char const*, char const*, char const*) [inlined] osl::Guard<comphelper::SolarMutex>::Guard(this=<unavailable>, t=0x00000001497e7ec0) at mutex.hxx:144:17 frame #8: 0x000000015952fd98 libmergedlo.dylib`doc_saveAs(_LibreOfficeKitDocument*, char const*, char const*, char const*) [inlined] SolarMutexGuard::SolarMutexGuard(this=<unavailable>) at svapp.hxx:1344:11 frame #9: 0x000000015952fd90 libmergedlo.dylib`doc_saveAs(_LibreOfficeKitDocument*, char const*, char const*, char const*) [inlined] SolarMutexGuard::SolarMutexGuard(this=<unavailable>) at svapp.hxx:1344:78 frame #10: 0x000000015952fd90 libmergedlo.dylib`doc_saveAs(pThis=0x000060000124a9a0, sUrl="/tmp/ErrareHumanumEst.fodg", pFormat="fodg", pFilterOptions="{\"DecomposePDF\":{\"type\":\"boolean\",\"value\":\"true\"}}") at init.cxx:3698:21 ... frame #32: 0x0000000102965334 main + 228 (lldb) thread backtrace 11 thread #11, name = 'lo_startmain' frame #0: 0x00000001966f53cc libsystem_kernel.dylib`__psynch_cvwait + 8 frame #1: 0x00000001967340e0 libsystem_pthread.dylib`_pthread_cond_wait + 984 frame #2: 0x0000000197ddefd0 Foundation`-[NSOperation waitUntilFinished] + 488 frame #3: 0x00000001967e28f8 CoreFoundation`_CFXNotificationPost + 804 frame #4: 0x0000000197d9c680 Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] + 88 frame #5: 0x000000019a737554 AppKit`-[NSMenu insertItem:atIndex:] + 892 frame #6: 0x000000019a8f1e00 AppKit`-[NSApplication(NSServicesMenuPrivate) _fillSpellCheckerPopupButton:] + 1380 frame #7: 0x000000019a8f1550 AppKit`-[NSSpellChecker _fillSpellCheckerPopupButton:] + 76 frame #8: 0x000000019a8f0688 AppKit`-[NSSpellChecker init] + 248 frame #9: 0x000000019a8f0580 AppKit`__36+[NSSpellChecker sharedSpellChecker]_block_invoke + 20 frame #10: 0x000000019659585c libdispatch.dylib`_dispatch_client_callout + 16 frame #11: 0x000000019657ea28 libdispatch.dylib`_dispatch_once_callout + 32 frame #12: 0x000000019a8f0568 AppKit`+[NSSpellChecker sharedSpellChecker] + 140 frame #13: 0x0000000158dbb054 libmergedlo.dylib`MacSpellChecker::getLocales(this=0x00006000006fc500) at macspellimp.mm:118:42 frame #14: 0x0000000158da1e94 libmergedlo.dylib`LngSvcMgr::GetAvailableSpellSvcs_Impl(this=0x000000014966e020) at lngsvcmgr.cxx:975:63 frame #15: 0x0000000158da46f8 libmergedlo.dylib`LngSvcMgr::getAvailableServices(this=0x000000014966e020, rServiceName=0x000000015c044600, rLocale=0x000000016e3ae1d0) at lngsvcmgr.cxx:1369:9 frame #16: 0x0000000158d9c434 libmergedlo.dylib`LngSvcMgr::UpdateAll(this=0x000000014966e020) at lngsvcmgr.cxx:655:46 frame #17: 0x0000000158d9bd38 libmergedlo.dylib`LngSvcMgr::LngSvcMgr(this=0x000000014966e020) at lngsvcmgr.cxx:414:5 frame #18: 0x0000000158da7a70 libmergedlo.dylib`::linguistic_LngSvcMgr_get_implementation(com::sun::star::uno::XComponentContext *, const com::sun::star::uno::Sequence<com::sun::star::uno::Any> &) [inlined] LngSvcMgr::LngSvcMgr(this=0x000000014966e020) at lngsvcmgr.cxx:402:1 frame #19: 0x0000000158da7a6c libmergedlo.dylib`linguistic_LngSvcMgr_get_implementation((null)=<unavailable>, (null)=<unavailable>) at lngsvcmgr.cxx:1816:30 frame #20: 0x000000012dc30ee0 libuno_cppuhelpergcc3.dylib.3`cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) [inlined] std::__1::__function::__value_func<com::sun::star::uno::XInterface* (com::sun::star::uno::XComponentContext*, com::sun::star::uno::Sequence<com::sun::star::uno::Any> const&)>::operator()[abi:ne190102](this=0x0000000149747c90, __args=0x000000016e3ae310, __args=0x000000016e3ae308) const at function.h:430:12 frame #21: 0x000000012dc30ec4 libuno_cppuhelpergcc3.dylib.3`cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) [inlined] std::__1::function<com::sun::star::uno::XInterface* (com::sun::star::uno::XComponentContext*, com::sun::star::uno::Sequence<com::sun::star::uno::Any> const&)>::operator()(this= Function = linguistic_LngSvcMgr_get_implementation , __arg=0x0000600000cc86b8, __arg=0x000000016e3ae308) const at function.h:989:10 frame #22: 0x000000012dc30ec4 libuno_cppuhelpergcc3.dylib.3`cppuhelper::ServiceManager::Data::Implementation::doCreateInstance(this=0x0000000149747c18, context=0x000000015c487110) at servicemanager.cxx:701:13 frame #23: 0x000000012dc30d4c libuno_cppuhelpergcc3.dylib.3`cppuhelper::ServiceManager::Data::Implementation::createInstance(this=0x0000000149747c18, context=0x000000015c487110, singletonRequest=false) at servicemanager.cxx:666:30 frame #24: 0x000000012dc34ed8 libuno_cppuhelpergcc3.dylib.3`non-virtual thunk to cppuhelper::ServiceManager::createInstanceWithContext(rtl::OUString const&, com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) [inlined] cppuhelper::ServiceManager::createInstanceWithContext(this=<unavailable>, aServiceSpecifier=<unavailable>, Context=0x000000015c487110) at servicemanager.cxx:1002:36 frame #25: 0x000000012dc34eb4 libuno_cppuhelpergcc3.dylib.3`non-virtual thunk to cppuhelper::ServiceManager::createInstanceWithContext(rtl::OUString const&, com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext> const&) at servicemanager.cxx:0 frame #26: 0x00000001588b29c8 libmergedlo.dylib`com::sun::star::linguistic2::LinguServiceManager::create(the_context=0x000000015c487110) at LinguServiceManager.hpp:38:129 frame #27: 0x00000001588b3444 libmergedlo.dylib`(anonymous namespace)::SpellDummy_Impl::GetSpell_Impl() [inlined] GetLngSvcMgr_Impl() at unolingu.cxx:60:52 frame #28: 0x00000001588b3438 libmergedlo.dylib`(anonymous namespace)::SpellDummy_Impl::GetSpell_Impl(this=0x0000600002df4300) at unolingu.cxx:216:61 frame #29: 0x00000001588b3314 libmergedlo.dylib`non-virtual thunk to (anonymous namespace)::SpellDummy_Impl::isValid(rtl::OUString const&, short, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) [inlined] (anonymous namespace)::SpellDummy_Impl::isValid(this=<unavailable>, rWord=<unavailable>, nLanguage=<unavailable>, rProperties=<unavailable>) at unolingu.cxx:248:5 frame #30: 0x00000001588b3310 libmergedlo.dylib`non-virtual thunk to (anonymous namespace)::SpellDummy_Impl::isValid(rtl::OUString const&, short, com::sun::star::uno::Sequence<com::sun::star::beans::PropertyValue> const&) at unolingu.cxx:0 frame #31: 0x00000001588405ec libmergedlo.dylib`ImpEditEngine::DoOnlineSpelling(this=0x0000000149859800, pThisNodeOnly=<unavailable>, bSpellAtCursorPos=<unavailable>, bInterruptible=<unavailable>) at impedit4.cxx:2480:37 frame #32: 0x0000000134059498 libsdlo.dylib`SdDrawDocument::SpellObject(this=0x000000014961cb20, pObj=0x0000000149646150) at drawdoc4.cxx:885:16 frame #33: 0x00000001340591b0 libsdlo.dylib`SdDrawDocument::OnlineSpellingHdl(this=0x000000014961cb20, (null)=<unavailable>) at drawdoc4.cxx:823:17 frame #34: 0x000000015a52b9b0 libmergedlo.dylib`Scheduler::CallbackTaskScheduling() at scheduler.cxx:584:20 frame #35: 0x000000015a6e7bf8 libmergedlo.dylib`SvpSalInstance::CheckTimeout(bool) [inlined] SalTimer::CallCallback(this=<unavailable>) at saltimer.hxx:53:13 frame #36: 0x000000015a6e7bec libmergedlo.dylib`SvpSalInstance::CheckTimeout(this=<unavailable>, bExecuteTimers=true) at svpinst.cxx:167:53 frame #37: 0x000000015a6e863c libmergedlo.dylib`SvpSalInstance::ImplYield(this=0x00006000008c50e0, bWait=true, bHandleAllCurrentEvents=false) at svpinst.cxx:430:17 frame #38: 0x000000015a6e8950 libmergedlo.dylib`SvpSalInstance::DoYield(this=0x00006000008c50e0, bWait=true, bHandleAllCurrentEvents=false) at svpinst.cxx:504:21 frame #39: 0x000000015a53d920 libmergedlo.dylib`ImplYield(i_bWait=true, i_bAllEvents=false) at svapp.cxx:389:48 frame #40: 0x000000015a53d328 libmergedlo.dylib`Application::Yield() at svapp.cxx:492:5 [artificial] frame #41: 0x000000015a53d210 libmergedlo.dylib`Application::Execute() at svapp.cxx:364:13 frame #42: 0x00000001594ffeb4 libmergedlo.dylib`desktop::Desktop::Main(this=0x000000016e3aeed0) at app.cxx:1680:13 frame #43: 0x000000015a5475d0 libmergedlo.dylib`ImplSVMain() at svmain.cxx:228:35 frame #44: 0xffffffffffffffff libmergedlo.dylib`SVMain() frame #45: 0x000000015951e5e4 libmergedlo.dylib`soffice_main at sofficemain.cxx:121:12 frame #46: 0x00000001595669bc libmergedlo.dylib`lo_startmain((null)=<unavailable>) at init.cxx:7860:5 frame #47: 0x0000000105ae59d8 libuno_sal.dylib.3`osl_thread_start_Impl(pData=0x00006000005cb330) at thread.cxx:240:9 frame #48: 0x0000000196733c0c libsystem_pthread.dylib`_pthread_start + 136 Change-Id: I8d25ed364f131434ce4f738604ddcf3f586cf6d9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192060 Tested-by: Jenkins Reviewed-by: Caolán McNamara <[email protected]>
1 parent d0e9367 commit e6c4a9f

File tree

5 files changed

+39
-21
lines changed

5 files changed

+39
-21
lines changed

vcl/headless/svpinst.cxx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ SvpSalInstance::SvpSalInstance( std::unique_ptr<SalYieldMutex> pMutex )
105105
#endif
106106
}
107107

108+
void SvpSalInstance::AfterAppInit()
109+
{
110+
#if defined(MACOSX)
111+
SalInstance::MacStartupWorkarounds();
112+
#endif
113+
}
114+
108115
SvpSalInstance::~SvpSalInstance()
109116
{
110117
if( s_pDefaultInstance == this )

vcl/inc/headless/svpinst.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ public:
106106
static SvpSalInstance* s_pDefaultInstance;
107107

108108
SvpSalInstance( std::unique_ptr<SalYieldMutex> pMutex );
109+
virtual void AfterAppInit() override;
109110
virtual ~SvpSalInstance() override;
110111

111112
SAL_DLLPRIVATE bool ImplYield(bool bWait, bool bHandleAllCurrentEvents);

vcl/inc/salinst.hxx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,10 @@ private:
8585
protected:
8686
bool m_bSupportsOpenGL = false;
8787

88+
#ifdef MACOSX
89+
static void MacStartupWorkarounds();
90+
#endif
91+
8892
public:
8993
SalInstance(std::unique_ptr<comphelper::SolarMutex> pMutex);
9094
virtual ~SalInstance();

vcl/osx/salinst.cxx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -213,27 +213,7 @@ void AquaSalInstance::AfterAppInit()
213213
object: nil ];
214214
#endif
215215

216-
// HACK: When the first call to [NSSpellChecker sharedSpellChecker] (in
217-
// lingucomponent/source/spellcheck/macosxspell/macspellimp.mm) is done both on a thread other
218-
// than the main thread and with the SolarMutex erroneously locked, then that can lead to
219-
// deadlock as [NSSpellChecker sharedSpellChecker] internally calls
220-
// AppKit`-[NSSpellChecker init] ->
221-
// AppKit`-[NSSpellChecker _fillSpellCheckerPopupButton:] ->
222-
// AppKit`-[NSApplication(NSServicesMenuPrivate) _fillSpellCheckerPopupButton:] ->
223-
// AppKit`-[NSMenu insertItem:atIndex:] ->
224-
// Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] ->
225-
// CoreFoundation`_CFXNotificationPost ->
226-
// Foundation`-[NSOperation waitUntilFinished]
227-
// waiting for work to be done on the main thread, but the main thread is typically already
228-
// blocked (in some event handling loop) waiting to acquire the SolarMutex. The real solution
229-
// would be to fix all the cases where a call to [NSSpellChecker sharedSpellChecker] in
230-
// lingucomponent/source/spellcheck/macosxspell/macspellimp.mm is done while the SolarMutex is
231-
// locked (somewhere up the call chain), but that appears to be rather difficult (see e.g.
232-
// <https://bugs.documentfoundation.org/show_bug.cgi?id=151894> "FILEOPEN a Base Document with
233-
// customized event for open a startform by 'open document' LO stuck"). So, at least for now,
234-
// chicken out and do that first call to [NSSpellChecker sharedSpellChecker] upfront in a
235-
// controlled environment:
236-
[NSSpellChecker sharedSpellChecker];
216+
SalInstance::MacStartupWorkarounds();
237217
}
238218

239219
SalYieldMutex::SalYieldMutex()

vcl/quartz/cgutils.mm

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <quartz/cgutils.h>
2121

2222
#include <salbmp.hxx>
23+
#include <salinst.hxx>
2324
#ifdef MACOSX
2425
#include <osx/saldata.hxx>
2526
#else
@@ -136,6 +137,31 @@ bool DefaultMTLDeviceIsSupported()
136137
return bRet;
137138
}
138139

140+
void SalInstance::MacStartupWorkarounds()
141+
{
142+
// HACK: When the first call to [NSSpellChecker sharedSpellChecker] (in
143+
// lingucomponent/source/spellcheck/macosxspell/macspellimp.mm) is done both on a thread other
144+
// than the main thread and with the SolarMutex erroneously locked, then that can lead to
145+
// deadlock as [NSSpellChecker sharedSpellChecker] internally calls
146+
// AppKit`-[NSSpellChecker init] ->
147+
// AppKit`-[NSSpellChecker _fillSpellCheckerPopupButton:] ->
148+
// AppKit`-[NSApplication(NSServicesMenuPrivate) _fillSpellCheckerPopupButton:] ->
149+
// AppKit`-[NSMenu insertItem:atIndex:] ->
150+
// Foundation`-[NSNotificationCenter postNotificationName:object:userInfo:] ->
151+
// CoreFoundation`_CFXNotificationPost ->
152+
// Foundation`-[NSOperation waitUntilFinished]
153+
// waiting for work to be done on the main thread, but the main thread is typically already
154+
// blocked (in some event handling loop) waiting to acquire the SolarMutex. The real solution
155+
// would be to fix all the cases where a call to [NSSpellChecker sharedSpellChecker] in
156+
// lingucomponent/source/spellcheck/macosxspell/macspellimp.mm is done while the SolarMutex is
157+
// locked (somewhere up the call chain), but that appears to be rather difficult (see e.g.
158+
// <https://bugs.documentfoundation.org/show_bug.cgi?id=151894> "FILEOPEN a Base Document with
159+
// customized event for open a startform by 'open document' LO stuck"). So, at least for now,
160+
// chicken out and do that first call to [NSSpellChecker sharedSpellChecker] upfront in a
161+
// controlled environment:
162+
[NSSpellChecker sharedSpellChecker];
163+
}
164+
139165
#endif
140166

141167
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

0 commit comments

Comments
 (0)