salhelper/source/timer.cxx |    4 ++++
 1 file changed, 4 insertions(+)

New commits:
commit a27a5dda1cb92b0eb46f41dfad596e34988737cd
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Tue Aug 20 11:32:03 2024 +0500
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Tue Aug 20 11:14:01 2024 +0200

    Do not try to notify, if the thread is already killed
    
    On a particular system, I see unit tests reliably hung at the exit time
    (at a DLL unload), when it waits indefinitely in notify_all. It is the
    only thread in the process left; TimerManager thread was likely killed
    by that time.
    
    This is the call stack of the hung state:
    
     ntdll.dll!ZwReleaseKeyedEvent()
     ntdll.dll!string "Enabling heap debug options
"()
     
msvcp140d.dll!Concurrency::details::stl_condition_variable_win7::notify_all() 
Line 178
     msvcp140d.dll!_Cnd_broadcast(_Cnd_internal_imp_t * cond) Line 93
     salhelper3MSC.dll!std::condition_variable::notify_all() Line 590
     salhelper3MSC.dll!salhelper::TimerManager::~TimerManager() Line 221
     salhelper3MSC.dll!``anonymous namespace'::getTimerManager'::`2'::`dynamic 
atexit destructor for 'aManager''()
     ucrtbased.dll!_execute_onexit_table::__l2::<lambda>() Line 206
     ucrtbased.dll!__crt_seh_guarded_call<int>::operator()<void 
<lambda>(void),int <lambda>(void) &,void 
<lambda>(void)>(__acrt_lock_and_call::__l2::void <lambda>(void) && setup, 
_execute_onexit_table::__l2::int <lambda>(void) & action, 
__acrt_lock_and_call::__l2::void <lambda>(void) && cleanup) Line 204
     ucrtbased.dll!__acrt_lock_and_call<int <lambda>(void)>(const 
__acrt_lock_id lock_id, _execute_onexit_table::__l2::int <lambda>(void) && 
action) Line 974
     ucrtbased.dll!_execute_onexit_table(_onexit_table_t * table) Line 231
     salhelper3MSC.dll!__scrt_dllmain_uninitialize_c() Line 399
     salhelper3MSC.dll!dllmain_crt_process_detach(const bool is_terminating) 
Line 182
     salhelper3MSC.dll!dllmain_crt_dispatch(HINSTANCE__ * const instance, const 
unsigned long reason, void * const reserved) Line 220
     salhelper3MSC.dll!dllmain_dispatch(HINSTANCE__ * const instance, const 
unsigned long reason, void * const reserved) Line 293
     salhelper3MSC.dll!_DllMainCRTStartup(HINSTANCE__ * const instance, const 
unsigned long reason, void * const reserved) Line 335
     ntdll.dll!LdrShutdownProcess()
     ntdll.dll!RtlExitUserProcess()
     ucrtbased.dll!exit_or_terminate_process(const unsigned int return_code) 
Line 144
     ucrtbased.dll!common_exit(const int return_code, const 
_crt_exit_cleanup_mode cleanup_mode, const _crt_exit_return_mode return_mode) 
Line 280
     ucrtbased.dll!exit(int return_code) Line 294
     cppunittester.exe!__scrt_common_main_seh() Line 297
     cppunittester.exe!__scrt_common_main() Line 331
     cppunittester.exe!mainCRTStartup(void * __formal) Line 17
     kernel32.dll!BaseThreadInitThunk()
     ntdll.dll!RtlUserThreadStart()
    
    This check prevents that hang.
    The behavior is *possibly* related to my commit
    8a0c43fa86bd32b4d47fd7e46d3ed414c9282ffa (Use _beginthreadex instead of
    CreateThread, 2023-08-09), which put the threads under control of CRT;
    and also to the specific version of CRT on the affected system, which
    might affect the order of statics destruction and thread termination.
    
    Change-Id: I6da95ea369ac9433a426a12d62cbd2a09cb4ce4a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/172093
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins

diff --git a/salhelper/source/timer.cxx b/salhelper/source/timer.cxx
index 3c6c0a00d922..07510f228cde 100644
--- a/salhelper/source/timer.cxx
+++ b/salhelper/source/timer.cxx
@@ -215,6 +215,10 @@ TimerManager::TimerManager() :
 TimerManager::~TimerManager() {
     {
         std::scoped_lock g(m_Lock);
+        // Sometimes, the TimerManager thread gets killed before the static's 
destruction;
+        // in that case, notify_all could hang in unit tests
+        if (!isRunning())
+            return;
         m_terminate = true;
     }
     m_notEmpty.notify_all();

Reply via email to