Skip to content
This repository was archived by the owner on Feb 5, 2019. It is now read-only.

CheryPick: Fix deadlock in multithreaded fork in OS X. #19

Merged
merged 1 commit into from
Jul 27, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions src/zone.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ JEMALLOC_ATTR(weak_import);
static malloc_zone_t *default_zone, *purgeable_zone;
static malloc_zone_t jemalloc_zone;
static struct malloc_introspection_t jemalloc_zone_introspect;
static pid_t zone_force_lock_pid = -1;

/******************************************************************************/
/* Function prototypes for non-inline static functions. */
Expand Down Expand Up @@ -288,24 +289,42 @@ zone_log(malloc_zone_t *zone, void *address)
static void
zone_force_lock(malloc_zone_t *zone)
{

if (isthreaded)
if (isthreaded) {
/*
* See the note in zone_force_unlock, below, to see why we need
* this.
*/
assert(zone_force_lock_pid == -1);
zone_force_lock_pid = getpid();
jemalloc_prefork();
}
}

static void
zone_force_unlock(malloc_zone_t *zone)
{

/*
* Call jemalloc_postfork_child() rather than
* jemalloc_postfork_parent(), because this function is executed by both
* parent and child. The parent can tolerate having state
* reinitialized, but the child cannot unlock mutexes that were locked
* by the parent.
* zone_force_lock and zone_force_unlock are the entry points to the
* forking machinery on OS X. The tricky thing is, the child is not
* allowed to unlock mutexes locked in the parent, even if owned by the
* forking thread (and the mutex type we use in OS X will fail an assert
* if we try). In the child, we can get away with reinitializing all
* the mutexes, which has the effect of unlocking them. In the parent,
* doing this would mean we wouldn't wake any waiters blocked on the
* mutexes we unlock. So, we record the pid of the current thread in
* zone_force_lock, and use that to detect if we're in the parent or
* child here, to decide which unlock logic we need.
*/
if (isthreaded)
jemalloc_postfork_child();
if (isthreaded) {
assert(zone_force_lock_pid != -1);
if (getpid() == zone_force_lock_pid) {
jemalloc_postfork_parent();
} else {
jemalloc_postfork_child();
}
zone_force_lock_pid = -1;
}
}

static void
Expand Down