diff options
author | Ivan Maidanski <ivmai@mail.ru> | 2023-04-04 09:21:28 +0300 |
---|---|---|
committer | Ivan Maidanski <ivmai@mail.ru> | 2023-04-06 13:16:52 +0300 |
commit | 68d419a51fa73765ac66beb348a6c577ca1963ac (patch) | |
tree | 67402be765bbb6006354696b70ad4a6c7d21b708 /include | |
parent | 5f16c0ab09760910e8995317ebc51b4fae198101 (diff) | |
download | bdwgc-68d419a51fa73765ac66beb348a6c577ca1963ac.tar.gz |
Fix signals delivery fail in find-leak mode if init from non-main thread
Issue #542 (bdwgc).
The scenario of the failure (on Linux):
- Find-leak mode is on
- pthread_create/join primitives are not redirected
- GC is initialized from a thread other than primordial
- that thread is terminated (but not unregistered as the 1st one in GC)
- the primordial thread exits and launches GC_exit_check
- GC_gcollect tries to suspend the terminated thread by sending a signal
- the signal is not delivered but pthread_kill just returns zero
- the signal sending is retried until aborting with the proper message.
The proposed solution (workaround) is not to call GC_gcollect at
the process exit (in the find-leak mode) if GC_init was called from
a thread other than primordial one.
Check in GC_exit_check() (which is called if GC_find_leak) that the
thread executing at-exit functions is the same as the one performed
the GC initialization, otherwise the latter thread might already be
dead but still registered and this, as a consequence, might cause
a signal delivery fail when suspending the threads on platforms that
do not guarantee ESRCH returned if the signal is not delivered (as
observed on Ubuntu 22).
* include/private/gc_priv.h [THREADS && !DONT_USE_ATEXIT]
(GC_is_main_thread): Declare GC_INNER function.
* include/private/pthread_support.h [GC_WIN32_THREADS
&& !DONT_USE_ATEXIT] (GC_main_thread_id): Declare variable.
* include/private/pthread_support.h [GC_WIN32_THREADS
&& !GC_NO_THREADS_DISCOVERY] (GC_main_thread_id): Do not depend on
GC_ASSERTIONS.
* misc.c [!DONT_USE_ATEXIT && THREADS] (GC_exit_check): If not
GC_is_main_thread() or not GC_thread_is_registered() then do not call
GC_gcollect(); add comment; do not set and clear GC_in_thread_creation.
* pthread_support.c [!GC_NO_THREADS_DISCOVERY && GC_WIN32_THREADS
|| !DONT_USE_ATEXIT] (GC_main_thread_id): Define variable.
* pthread_support.c [!DONT_USE_ATEXIT] (GC_is_main_thread): Implement.
* pthread_support.c [!GC_WIN32_THREADS] (GC_thr_init): Define self_id
local variable.
* pthread_support.c [!GC_WIN32_THREADS && !DONT_USE_ATEXIT]
(GC_thr_init): Set GC_main_thread_id.
* win32_threads.c [!DONT_USE_ATEXIT] (GC_thr_init): Likewise.
* win32_threads.c [!GC_NO_THREADS_DISCOVERY] (GC_main_thread_id): Do
not define variable.
Diffstat (limited to 'include')
-rw-r--r-- | include/private/gc_priv.h | 3 | ||||
-rw-r--r-- | include/private/pthread_support.h | 7 |
2 files changed, 7 insertions, 3 deletions
diff --git a/include/private/gc_priv.h b/include/private/gc_priv.h index 75266d2c..ec0cda5c 100644 --- a/include/private/gc_priv.h +++ b/include/private/gc_priv.h @@ -2176,6 +2176,9 @@ void GC_register_data_segments(void); /* Both are invoked from GC_init only. */ GC_INNER void GC_thr_init(void); GC_INNER void GC_init_parallel(void); +# ifndef DONT_USE_ATEXIT + GC_INNER GC_bool GC_is_main_thread(void); +# endif #else GC_INNER GC_bool GC_is_static_root(void *p); /* Is the address p in one of the registered static */ diff --git a/include/private/pthread_support.h b/include/private/pthread_support.h index 091e153e..fa0d0789 100644 --- a/include/private/pthread_support.h +++ b/include/private/pthread_support.h @@ -341,10 +341,11 @@ GC_EXTERN GC_thread GC_threads[THREAD_TABLE_SZ]; GC_INNER void GC_setup_atfork(void); # endif +# if !defined(DONT_USE_ATEXIT) || !defined(GC_NO_THREADS_DISCOVERY) + GC_EXTERN thread_id_t GC_main_thread_id; +# endif + # ifndef GC_NO_THREADS_DISCOVERY -# ifdef GC_ASSERTIONS - GC_EXTERN thread_id_t GC_main_thread_id; -# endif GC_INNER GC_thread GC_win32_dll_lookup_thread(thread_id_t); # endif |