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

Commit b6bdb32

Browse files
authored
Merge pull request #19 from arthurprs/rust-2017-07-26
CheryPick: Fix deadlock in multithreaded fork in OS X.
2 parents 3288e06 + 1f5a287 commit b6bdb32

File tree

1 file changed

+28
-9
lines changed

1 file changed

+28
-9
lines changed

src/zone.c

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ JEMALLOC_ATTR(weak_import);
8585
static malloc_zone_t *default_zone, *purgeable_zone;
8686
static malloc_zone_t jemalloc_zone;
8787
static struct malloc_introspection_t jemalloc_zone_introspect;
88+
static pid_t zone_force_lock_pid = -1;
8889

8990
/******************************************************************************/
9091
/* Function prototypes for non-inline static functions. */
@@ -288,24 +289,42 @@ zone_log(malloc_zone_t *zone, void *address)
288289
static void
289290
zone_force_lock(malloc_zone_t *zone)
290291
{
291-
292-
if (isthreaded)
292+
if (isthreaded) {
293+
/*
294+
* See the note in zone_force_unlock, below, to see why we need
295+
* this.
296+
*/
297+
assert(zone_force_lock_pid == -1);
298+
zone_force_lock_pid = getpid();
293299
jemalloc_prefork();
300+
}
294301
}
295302

296303
static void
297304
zone_force_unlock(malloc_zone_t *zone)
298305
{
299306

300307
/*
301-
* Call jemalloc_postfork_child() rather than
302-
* jemalloc_postfork_parent(), because this function is executed by both
303-
* parent and child. The parent can tolerate having state
304-
* reinitialized, but the child cannot unlock mutexes that were locked
305-
* by the parent.
308+
* zone_force_lock and zone_force_unlock are the entry points to the
309+
* forking machinery on OS X. The tricky thing is, the child is not
310+
* allowed to unlock mutexes locked in the parent, even if owned by the
311+
* forking thread (and the mutex type we use in OS X will fail an assert
312+
* if we try). In the child, we can get away with reinitializing all
313+
* the mutexes, which has the effect of unlocking them. In the parent,
314+
* doing this would mean we wouldn't wake any waiters blocked on the
315+
* mutexes we unlock. So, we record the pid of the current thread in
316+
* zone_force_lock, and use that to detect if we're in the parent or
317+
* child here, to decide which unlock logic we need.
306318
*/
307-
if (isthreaded)
308-
jemalloc_postfork_child();
319+
if (isthreaded) {
320+
assert(zone_force_lock_pid != -1);
321+
if (getpid() == zone_force_lock_pid) {
322+
jemalloc_postfork_parent();
323+
} else {
324+
jemalloc_postfork_child();
325+
}
326+
zone_force_lock_pid = -1;
327+
}
309328
}
310329

311330
static void

0 commit comments

Comments
 (0)