Permalink
Browse files

Fix GC allocation mutex in child after a fork

Even though after a fork the child only inherits the single thread
that called the fork(), if another thread in the parent was attempting
to lock the mutex while being held in fork_child_prepare(), the mutex
will be left in an inconsistent state in the child after the UNLOCK().
This is the case, at least, in Mac OS X and leads to an unusable GC in
the child which will block when attempting to perform any GC operation
that acquires the mutex.

* pthread_support.c [CAN_HANDLE_FORK && USE_PTHREAD_LOCKS]
(fork_child_proc): Add assertion (after UNLOCK) that the lock is not
held actually, and, then, re-initialize GC_allocate_ml; add comments.
  • Loading branch information...
ggiraldez authored and ivmai committed Jan 18, 2018
1 parent 8a6a5d5 commit 5f73f2dae9fddf2a64dc6b9c8dcdaf171c148412
Showing with 20 additions and 0 deletions.
  1. +20 −0 pthread_support.c
@@ -1084,6 +1084,26 @@ static void fork_child_proc(void)
# endif /* PARALLEL_MARK */
RESTORE_CANCEL(fork_cancel_state);
UNLOCK();
/* Even though after a fork the child only inherits the single */
/* thread that called the fork(), if another thread in the parent */
/* was attempting to lock the mutex while being held in */
/* fork_child_prepare(), the mutex will be left in an inconsistent */
/* state in the child after the UNLOCK. This is the case, at */
/* least, in Mac OS X and leads to an unusable GC in the child */
/* which will block when attempting to perform any GC operation */
/* that acquires the allocation mutex. */
# ifdef USE_PTHREAD_LOCKS
GC_ASSERT(I_DONT_HOLD_LOCK());
/* Reinitialize the mutex. It should be safe since we are */
/* running this in the child which only inherits a single thread. */
/* mutex_destroy() may return EBUSY, which makes no sense, but */
/* that is the reason for the need of the reinitialization. */
(void)pthread_mutex_destroy(&GC_allocate_ml);
/* TODO: Probably some targets might need the default mutex */
/* attribute to be passed instead of NULL. */
if (0 != pthread_mutex_init(&GC_allocate_ml, NULL))
ABORT("pthread_mutex_init failed (in child)");
# endif
}
/* Routines for fork handling by client (no-op if pthread_atfork works). */

0 comments on commit 5f73f2d

Please sign in to comment.