Bug 737084 - Do pthread_atfork in jemalloc on mac and android. r=blassey,r=khuey
authorMike Hommey <mh+mozilla@glandium.org>
Thu, 22 Mar 2012 08:01:51 +0100
changeset 93344 c6634316f474856b670e0c58f3b3432571e3abc0
parent 93343 789724668df4f9a0a9f3a479271665e38ab43164
child 93345 d51faf4c97f0ef0d8a9f0ef5ddb562814cb9bba8
push id886
push userlsblakk@mozilla.com
push dateMon, 04 Jun 2012 19:57:52 +0000
treeherdermozilla-beta@bbd8d5efd6d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersblassey, khuey
bugs737084
milestone14.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 737084 - Do pthread_atfork in jemalloc on mac and android. r=blassey,r=khuey
configure.in
memory/jemalloc/jemalloc.c
memory/jemalloc/jemalloc.h
mozglue/android/APKOpen.cpp
mozglue/build/Makefile.in
--- a/configure.in
+++ b/configure.in
@@ -7228,16 +7228,17 @@ dnl We need to wrap dlopen and related f
 dnl our own linker.
 if test "$OS_TARGET" = Android; then
     WRAP_LDFLAGS="${WRAP_LDFLAGS} -L$_objdir/dist/lib -lmozglue"
     if test "$MOZ_WIDGET_TOOLKIT" = android; then
         if test -n "$MOZ_OLD_LINKER"; then
             WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=dlopen,--wrap=dlclose,--wrap=dlerror,--wrap=dlsym,--wrap=dladdr"
         fi
         WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=getaddrinfo,--wrap=freeaddrinfo,--wrap=gai_strerror"
+        WRAP_LDFLAGS="${WRAP_LDFLAGS} -Wl,--wrap=fork,--wrap=pthread_atfork"
     fi
 fi
 
 dnl ========================================================
 dnl = Use malloc wrapper lib
 dnl ========================================================
 MOZ_ARG_ENABLE_BOOL(wrap-malloc,
 [  --enable-wrap-malloc    Wrap malloc calls (gnu linker only)],
--- a/memory/jemalloc/jemalloc.c
+++ b/memory/jemalloc/jemalloc.c
@@ -1414,23 +1414,18 @@ static void	*huge_palloc(size_t alignmen
 static void	*huge_ralloc(void *ptr, size_t size, size_t oldsize);
 static void	huge_dalloc(void *ptr);
 static void	malloc_print_stats(void);
 #ifndef MOZ_MEMORY_WINDOWS
 static
 #endif
 bool		malloc_init_hard(void);
 
-#ifdef MOZ_MEMORY_ANDROID
-void	_malloc_prefork(void);
-void	_malloc_postfork(void);
-#else
 static void	_malloc_prefork(void);
 static void	_malloc_postfork(void);
-#endif
 
 #ifdef MOZ_MEMORY_DARWIN
 /*
  * MALLOC_ZONE_T_NOTE
  *
  * On Darwin, we hook into the memory allocator using a malloc_zone_t struct.
  * We must be very careful around this struct because of different behaviour on
  * different versions of OSX.
@@ -5918,20 +5913,18 @@ MALLOC_OUT:
 	/* Take care to call atexit() only once. */
 	if (opt_print_stats) {
 #ifndef MOZ_MEMORY_WINDOWS
 		/* Print statistics at exit. */
 		atexit(malloc_print_stats);
 #endif
 	}
 
-#if (!defined(MOZ_MEMORY_WINDOWS) && !defined(MOZ_MEMORY_DARWIN) && !defined(MOZ_MEMORY_ANDROID))
+#if !defined(MOZ_MEMORY_WINDOWS)
 	/* Prevent potential deadlock on malloc locks after fork. */
-	/* XXX on Android there is no pthread_atfork, so we specifically
-	   call _malloc_prefork and _malloc_postfork in process_util_linux.cc */
 	pthread_atfork(_malloc_prefork, _malloc_postfork, _malloc_postfork);
 #endif
 
 #ifndef MALLOC_STATIC_SIZES
 	/* Set variables according to the value of opt_small_max_2pow. */
 	if (opt_small_max_2pow < opt_quantum_2pow)
 		opt_small_max_2pow = opt_quantum_2pow;
 	small_max = (1U << opt_small_max_2pow);
@@ -6844,21 +6837,17 @@ size_t
 /******************************************************************************/
 /*
  * Begin library-private functions, used by threading libraries for protection
  * of malloc during fork().  These functions are only called if the program is
  * running in threaded mode, so there is no need to check whether the program
  * is threaded here.
  */
 
-#ifdef MOZ_MEMORY_ANDROID
-void
-#else
 static void
-#endif
 _malloc_prefork(void)
 {
 	unsigned i;
 
 	/* Acquire all mutexes in a safe order. */
 
 	malloc_spin_lock(&arenas_lock);
 	for (i = 0; i < narenas; i++) {
@@ -6866,21 +6855,17 @@ static void
 			malloc_spin_lock(&arenas[i]->lock);
 	}
 
 	malloc_mutex_lock(&base_mtx);
 
 	malloc_mutex_lock(&huge_mtx);
 }
 
-#ifdef MOZ_MEMORY_ANDROID
-void
-#else
 static void
-#endif
 _malloc_postfork(void)
 {
 	unsigned i;
 
 	/* Release all mutexes, now that fork() has completed. */
 
 	malloc_mutex_unlock(&huge_mtx);
 
--- a/memory/jemalloc/jemalloc.h
+++ b/memory/jemalloc/jemalloc.h
@@ -48,20 +48,16 @@ void	*calloc(size_t num, size_t size);
 void	*realloc(void *ptr, size_t size);
 void	free(void *ptr);
 int	posix_memalign(void **memptr, size_t alignment, size_t size);
 #endif /* MOZ_MEMORY_DARWIN, MOZ_MEMORY_LINUX */
 
 /* Android doesn't have posix_memalign */
 #ifdef MOZ_MEMORY_ANDROID
 int	posix_memalign(void **memptr, size_t alignment, size_t size);
-/* Android < 2.3 doesn't have pthread_atfork, so we need to call these
- * when forking the child process. See bug 680190 */
-void    _malloc_prefork(void);
-void    _malloc_postfork(void);
 #endif
 
 #if defined(MOZ_MEMORY_DARWIN) || defined(MOZ_MEMORY_WINDOWS)
 void	*je_malloc(size_t size);
 void	*je_valloc(size_t size);
 void	*je_calloc(size_t num, size_t size);
 void	*je_realloc(void *ptr, size_t size);
 void	je_free(void *ptr);
--- a/mozglue/android/APKOpen.cpp
+++ b/mozglue/android/APKOpen.cpp
@@ -1032,8 +1032,51 @@ ChildProcessInit(int argc, char* argv[])
   XRE_InitChildProcess_t fXRE_InitChildProcess =
     (XRE_InitChildProcess_t)__wrap_dlsym(xul_handle, "XRE_InitChildProcess");
 
   GeckoProcessType proctype = fXRE_StringToChildProcessType(argv[--argc]);
 
   return fXRE_InitChildProcess(argc, argv, proctype);
 }
 
+/* Android doesn't have pthread_atfork(), so we need to use our own. */
+struct AtForkFuncs {
+  void (*prepare)(void);
+  void (*parent)(void);
+  void (*child)(void);
+};
+static std::vector<AtForkFuncs> atfork;
+
+extern "C" NS_EXPORT int
+__wrap_pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void))
+{
+  AtForkFuncs funcs;
+  funcs.prepare = prepare;
+  funcs.parent = parent;
+  funcs.child = child;
+  atfork.push_back(funcs);
+  return 0;
+}
+
+extern "C" NS_EXPORT pid_t
+__wrap_fork(void)
+{
+  pid_t pid;
+  for (std::vector<AtForkFuncs>::reverse_iterator it = atfork.rbegin();
+       it < atfork.rend(); ++it)
+    if (it->prepare)
+      it->prepare();
+
+  switch ((pid = fork())) {
+  case 0:
+    for (std::vector<AtForkFuncs>::iterator it = atfork.begin();
+         it < atfork.end(); ++it)
+      if (it->child)
+        it->child();
+    break;
+  default:
+    for (std::vector<AtForkFuncs>::iterator it = atfork.begin();
+         it < atfork.end(); ++it)
+      if (it->parent)
+        it->parent();
+  }
+  return pid;
+}
--- a/mozglue/build/Makefile.in
+++ b/mozglue/build/Makefile.in
@@ -79,16 +79,20 @@ ifneq (,$(filter -DEFAULTLIB:mozcrt,$(MO
 # Don't install the import library if we use mozcrt
 NO_INSTALL_IMPORT_LIBRARY = 1
 endif
 endif
 
 ifeq (android, $(MOZ_WIDGET_TOOLKIT))
 # Add Android specific code
 EXTRA_DSO_LDOPTS += $(ZLIB_LIBS)
+ifdef MOZ_MEMORY
+# To properly wrap jemalloc's pthread_atfork call.
+EXTRA_DSO_LDOPTS += -Wl,--wrap=pthread_atfork
+endif
 SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,android,$(DEPTH)/other-licenses/android)
 SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,android,../android)
 endif
 
 ifdef MOZ_LINKER
 # Add custom dynamic linker
 SHARED_LIBRARY_LIBS += $(call EXPAND_LIBNAME_PATH,linker,../linker)