Avoid malloc lock while calling pthread_atfork.

Expecting the memory in a forked child process to be sane wrt threading
is a bad idea. An example of a problem is when the parent process has
the malloc lock and a child process is forked. The malloc lock in the
child will appear locked by a thread that doesn't exist.

This change aims to make bionic more compatible with glibc by reseting
the malloc lock in the child forked process, as well as holding it
during the fork. This is a feature in dlmalloc 2.8.6 called
LOCK_AT_FORK. In general this feature isn't necessary as a forked
process will then exec. Some bad applications rely on being able to use
features like malloc before the exec and having multiple threads running
in the parent program. This isn't a problem with glibc and this patch
makes it not a problem for bionic.

Unfortunately for use in bionic, LOCK_AT_FORK has an issue as internally
it uses pthread_atfork that in bionic uses malloc. This leads to the
LOCK_AT_FORK initialization deadlocking with pthread_atfork's call to
malloc due to the malloc lock. This change moves the pthread_atfork logic
in LOCK_AT_FORK to be called without the malloc lock held.

Change-Id: Id68175a564a6abb936ee4488b44d9479f7311f69
diff --git a/libc/upstream-dlmalloc/malloc.c b/libc/upstream-dlmalloc/malloc.c
index 5e675b4..c6a32c8 100644
--- a/libc/upstream-dlmalloc/malloc.c
+++ b/libc/upstream-dlmalloc/malloc.c
@@ -3099,6 +3099,9 @@
 
 /* Initialize mparams */
 static int init_mparams(void) {
+  /* BEGIN android-added: move pthread_atfork outside of lock */
+  int first_run = 0;
+  /* END android-added */
 #ifdef NEED_GLOBAL_LOCK_INIT
   if (malloc_global_mutex_status <= 0)
     init_malloc_global_mutex();
@@ -3109,6 +3112,9 @@
     size_t magic;
     size_t psize;
     size_t gsize;
+    /* BEGIN android-added: move pthread_atfork outside of lock */
+    first_run = 1;
+    /* END android-added */
 
 #ifndef WIN32
     psize = malloc_getpagesize;
@@ -3153,9 +3159,11 @@
     gm->mflags = mparams.default_mflags;
     (void)INITIAL_LOCK(&gm->mutex);
 #endif
-#if LOCK_AT_FORK
+    /* BEGIN android-removed: move pthread_atfork outside of lock */
+#if 0 && LOCK_AT_FORK
     pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
 #endif
+    /* END android-removed */
 
     {
 #if USE_DEV_RANDOM
@@ -3184,6 +3192,13 @@
   }
 
   RELEASE_MALLOC_GLOBAL_LOCK();
+  /* BEGIN android-added: move pthread_atfork outside of lock */
+#if LOCK_AT_FORK
+  if (first_run != 0) {
+    pthread_atfork(&pre_fork, &post_fork_parent, &post_fork_child);
+  }
+#endif
+  /* END android-added */
   return 1;
 }