Bug 1332508 - Reinitialize allocator mutexes in fork() child processes. r?njn draft
authorMike Hommey <mh+mozilla@glandium.org>
Fri, 20 Jan 2017 10:06:41 +0900
changeset 463922 88d0905a846b0cc3207f84345b2e5cb67dd78023
parent 463908 eecdfeaf112b2f43e5d8c9627767f426b2e5663b
child 542817 695f56cbc80d90eeb036cb9c61fe69cc871f7e1b
push id42225
push userbmo:mh+mozilla@glandium.org
push dateFri, 20 Jan 2017 01:10:21 +0000
reviewersnjn
bugs1332508
milestone53.0a1
Bug 1332508 - Reinitialize allocator mutexes in fork() child processes. r?njn Adapted from https://github.com/jemalloc/jemalloc/commit/4e2e3dd9cf19ed5991938a708a8b50611aa5bbf8 and https://github.com/jemalloc/jemalloc/commit/d9f7b2a4307f7ff9f7a139b33d366d44e8a8b83d As per the latter commit, it would seem unlocking, in fork() child processes, mutexes that were locked in the parent process is not really well supported on OSX 10.12. The addition of the zone_reinit_lock function in 10.12 supports this idea.
memory/build/zone.c
memory/mozjemalloc/jemalloc.c
--- a/memory/build/zone.c
+++ b/memory/build/zone.c
@@ -248,40 +248,40 @@ zone_force_lock(malloc_zone_t *zone)
   if (isthreaded)
     jemalloc_prefork();
 }
 
 static void
 zone_force_unlock(malloc_zone_t *zone)
 {
   /* /!\ This calls into jemalloc. It works because we're linked in the
-   * same library. Stolen from jemalloc's zone.c. */
+   * same library. Stolen from jemalloc's zone.c. See the comment there. */
   if (isthreaded)
-    jemalloc_postfork_parent();
+    jemalloc_postfork_child();
 }
 
 #else
 
 extern void _malloc_prefork(void);
-extern void _malloc_postfork(void);
+extern void _malloc_postfork_child(void);
 
 static void
 zone_force_lock(malloc_zone_t *zone)
 {
   /* /!\ This calls into mozjemalloc. It works because we're linked in the
    * same library. */
   _malloc_prefork();
 }
 
 static void
 zone_force_unlock(malloc_zone_t *zone)
 {
   /* /!\ This calls into mozjemalloc. It works because we're linked in the
    * same library. */
-  _malloc_postfork();
+  _malloc_postfork_child();
 }
 
 #endif
 
 static void
 zone_statistics(malloc_zone_t *zone, malloc_statistics_t *stats)
 {
   /* We make no effort to actually fill the values */
--- a/memory/mozjemalloc/jemalloc.c
+++ b/memory/mozjemalloc/jemalloc.c
@@ -1453,17 +1453,21 @@ bool		malloc_init_hard(void);
 
 #ifndef MOZ_MEMORY_DARWIN
 static
 #endif
 void	_malloc_prefork(void);
 #ifndef MOZ_MEMORY_DARWIN
 static
 #endif
-void	_malloc_postfork(void);
+void	_malloc_postfork_parent(void);
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void	_malloc_postfork_child(void);
 
 /*
  * End function prototypes.
  */
 /******************************************************************************/
 
 static inline size_t
 load_acquire_z(size_t *p)
@@ -6034,17 +6038,17 @@ MALLOC_OUT:
 	if (chunk_rtree == NULL)
 		return (true);
 #endif
 
 	malloc_initialized = true;
 
 #if !defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN)
 	/* Prevent potential deadlock on malloc locks after fork. */
-	pthread_atfork(_malloc_prefork, _malloc_postfork, _malloc_postfork);
+	pthread_atfork(_malloc_prefork, _malloc_postfork_parent, _malloc_postfork_child);
 #endif
 
 #if defined(NEEDS_PTHREAD_MMAP_UNALIGNED_TSD)
 	if (pthread_key_create(&mmap_unaligned_tsd, NULL) != 0) {
 		malloc_printf("<jemalloc>: Error in pthread_key_create()\n");
 	}
 #endif
 
@@ -6779,33 +6783,54 @@ void
 
 	malloc_mutex_lock(&huge_mtx);
 }
 
 #ifndef MOZ_MEMORY_DARWIN
 static
 #endif
 void
-_malloc_postfork(void)
+_malloc_postfork_parent(void)
 {
 	unsigned i;
 
 	/* Release all mutexes, now that fork() has completed. */
 
 	malloc_mutex_unlock(&huge_mtx);
 
 	malloc_mutex_unlock(&base_mtx);
 
 	for (i = 0; i < narenas; i++) {
 		if (arenas[i] != NULL)
 			malloc_spin_unlock(&arenas[i]->lock);
 	}
 	malloc_spin_unlock(&arenas_lock);
 }
 
+#ifndef MOZ_MEMORY_DARWIN
+static
+#endif
+void
+_malloc_postfork_child(void)
+{
+	unsigned i;
+
+	/* Reinitialize all mutexes, now that fork() has completed. */
+
+	malloc_mutex_init(&huge_mtx);
+
+	malloc_mutex_init(&base_mtx);
+
+	for (i = 0; i < narenas; i++) {
+		if (arenas[i] != NULL)
+			malloc_spin_init(&arenas[i]->lock);
+	}
+	malloc_spin_init(&arenas_lock);
+}
+
 /*
  * End library-private functions.
  */
 /******************************************************************************/
 
 #ifdef HAVE_DLOPEN
 #  include <dlfcn.h>
 #endif