Skip to content

Commit

Permalink
Fix assertion violation about GC_mark_lock_holder in fork_child_proc
Browse files Browse the repository at this point in the history
PR #678 (bdwgc).

`GC_mark_lock_holder` value is computed based on `pthread_self()`, the
latter is not guaranteed to preserve the value in a child process
after forking, thus we should not check `GC_mark_lock_holder` value in
`fork_child_proc()`.

* pthread_support.c [GC_ASSERTIONS && GC_PTHREADS_PARAMARK]
(GC_mark_lock_holder): Move definition upper (to be before
`fork_cancel_state`).
* pthread_support.c [CAN_HANDLE_FORK && PARALLEL_MARK
&& !GC_WIN32_THREADS && !(THREAD_SANITIZER && GC_ASSERTIONS
&& CAN_CALL_ATFORK)] (fork_child_proc): Call `pthread_mutex_unlock()`
instead of `GC_release_mark_lock()`; add comment.
* pthread_support.c [CAN_HANDLE_FORK && PARALLEL_MARK
&& !GC_WIN32_THREADS && GC_ASSERTIONS && !(THREAD_SANITIZER
&& CAN_CALL_ATFORK)] (fork_child_proc): Set `GC_mark_lock_holder` to
`NO_THREAD`; add comment.

Co-authored-by: Augustin Cavalier <[email protected]>
  • Loading branch information
ivmai and waddlesplash committed Dec 6, 2024
1 parent 43f024a commit 6dcc828
Showing 1 changed file with 15 additions and 7 deletions.
22 changes: 15 additions & 7 deletions pthread_support.c
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,10 @@ GC_wait_for_gc_completion(GC_bool wait_for_all)
# endif
}

# if defined(GC_ASSERTIONS) && defined(GC_PTHREADS_PARAMARK)
STATIC unsigned long GC_mark_lock_holder = NO_THREAD;
# endif

# ifdef CAN_HANDLE_FORK

/* Procedures called before and after a fork. The goal here is to */
Expand Down Expand Up @@ -1510,15 +1514,20 @@ fork_child_proc(void)
# endif
# ifdef PARALLEL_MARK
if (GC_parallel) {
# if defined(THREAD_SANITIZER) && defined(GC_ASSERTIONS) \
&& defined(CAN_CALL_ATFORK)
(void)pthread_mutex_unlock(&mark_mutex);
# else
# ifdef GC_WIN32_THREADS
GC_release_mark_lock();
# endif
# else
# if !defined(GC_ASSERTIONS) \
|| (defined(THREAD_SANITIZER) && defined(CAN_CALL_ATFORK))
/* Do not change GC_mark_lock_holder. */
# else
GC_mark_lock_holder = NO_THREAD;
# endif
/* The unlock operation may fail on some targets, just ignore */
/* the error silently. */
(void)pthread_mutex_unlock(&mark_mutex);
/* Reinitialize the mark lock. The reason is the same as for */
/* GC_allocate_ml below. */
# ifndef GC_WIN32_THREADS
(void)pthread_mutex_destroy(&mark_mutex);
if (pthread_mutex_init(&mark_mutex, NULL) != 0)
ABORT("mark_mutex re-init failed in child");
Expand Down Expand Up @@ -2978,7 +2987,6 @@ GC_lock(void)
# endif

# ifdef GC_ASSERTIONS
STATIC unsigned long GC_mark_lock_holder = NO_THREAD;
# define SET_MARK_LOCK_HOLDER \
(void)(GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self()))
# define UNSET_MARK_LOCK_HOLDER \
Expand Down

0 comments on commit 6dcc828

Please sign in to comment.