Implemented pthread_atfork()

Change-Id: Ie6c0bf593315d3507b3c4a6c8903a74a1fa053db
diff --git a/libc/Android.mk b/libc/Android.mk
index 7a7d9e3..568cc94 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -324,6 +324,7 @@
 # up any thumb code.
 libc_common_src_files += \
 	bionic/pthread.c.arm \
+	bionic/pthread-atfork.c.arm \
 	bionic/pthread-timers.c.arm \
 	bionic/ptrace.c.arm
 
@@ -358,6 +359,7 @@
 	arch-x86/string/strncmp_wrapper.S \
 	arch-x86/string/strlen.S \
 	bionic/pthread.c \
+	bionic/pthread-atfork.c \
 	bionic/pthread-timers.c \
 	bionic/ptrace.c
 
@@ -394,6 +396,7 @@
 	string/memcmp.c \
 	string/strlen.c \
 	bionic/pthread.c \
+	bionic/pthread-atfork.c \
 	bionic/pthread-timers.c \
 	bionic/ptrace.c \
 	unistd/socketcalls.c
diff --git a/libc/bionic/fork.c b/libc/bionic/fork.c
index e20f548..8d3ea4b 100644
--- a/libc/bionic/fork.c
+++ b/libc/bionic/fork.c
@@ -40,9 +40,12 @@
      * of error, or in the parent process
      */
     __timer_table_start_stop(1);
+    __bionic_atfork_run_prepare();
+
     ret = __fork();
     if (ret != 0) {  /* not a child process */
         __timer_table_start_stop(0);
+        __bionic_atfork_run_parent();
     } else {
         /*
          * Newly created process must update cpu accounting.
@@ -51,6 +54,7 @@
          * as a parameter.
          */
         cpuacct_add(getuid());
+        __bionic_atfork_run_child();
     }
     return ret;
 }
diff --git a/libc/bionic/pthread-atfork.c b/libc/bionic/pthread-atfork.c
new file mode 100644
index 0000000..3a5189d
--- /dev/null
+++ b/libc/bionic/pthread-atfork.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+#include <stdlib.h>
+#include <errno.h>
+#include <pthread.h>
+#include <sys/queue.h>
+
+static pthread_mutex_t handler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
+
+struct atfork_t
+{
+    CIRCLEQ_ENTRY(atfork_t) entries;
+
+    void (*prepare)(void);
+    void (*child)(void);
+    void (*parent)(void);
+};
+static CIRCLEQ_HEAD(atfork_head_t, atfork_t) atfork_head = \
+    CIRCLEQ_HEAD_INITIALIZER(atfork_head);
+
+void __bionic_atfork_run_prepare()
+{
+    struct atfork_t *cursor;
+
+    /* We will lock this here, and unlock it in the parent and child functions.
+     * This ensures that nobody can modify the handler array between the calls
+     * to the prepare and parent/child handlers.
+     *
+     * TODO: If a handler mucks with the list, it could cause problems.  Right
+     *       now it's ok because all they can do is add new items to the end
+     *       of the list, but if/when we implement cleanup in dlclose() things
+     *       will get more interesting...
+     */
+    pthread_mutex_lock(&handler_mutex);
+
+    /* Call pthread_atfork() prepare handlers.  Posix states that the prepare
+     * handlers should be called in the reverse order of the parent/child
+     * handlers, so we iterate backwards.
+     */
+    for (cursor = atfork_head.cqh_last;
+         cursor != (void*)&atfork_head;
+         cursor = cursor->entries.cqe_prev) {
+        if (cursor->prepare != NULL) {
+            cursor->prepare();
+        }
+    }
+}
+
+void __bionic_atfork_run_child()
+{
+    struct atfork_t *cursor;
+
+    /* Call pthread_atfork() child handlers */
+    for (cursor = atfork_head.cqh_first;
+         cursor != (void*)&atfork_head;
+         cursor = cursor->entries.cqe_next) {
+        if (cursor->child != NULL) {
+            cursor->child();
+        }
+    }
+
+    pthread_mutex_unlock(&handler_mutex);
+}
+
+void __bionic_atfork_run_parent()
+{
+    struct atfork_t *cursor;
+
+    /* Call pthread_atfork() parent handlers */
+    for (cursor = atfork_head.cqh_first;
+         cursor != (void*)&atfork_head;
+         cursor = cursor->entries.cqe_next) {
+        if (cursor->parent != NULL) {
+            cursor->parent();
+        }
+    }
+
+    pthread_mutex_unlock(&handler_mutex);
+}
+
+int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void))
+{
+    struct atfork_t *entry = malloc(sizeof(struct atfork_t));
+
+    if (entry == NULL) {
+        return ENOMEM;
+    }
+
+    entry->prepare = prepare;
+    entry->parent = parent;
+    entry->child = child;
+
+    pthread_mutex_lock(&handler_mutex);
+    CIRCLEQ_INSERT_TAIL(&atfork_head, entry, entries);
+    pthread_mutex_unlock(&handler_mutex);
+
+    return 0;
+}
diff --git a/libc/bionic/pthread_internal.h b/libc/bionic/pthread_internal.h
index eb4e80c..655b8f3 100644
--- a/libc/bionic/pthread_internal.h
+++ b/libc/bionic/pthread_internal.h
@@ -109,6 +109,9 @@
 
 /* needed by fork.c */
 extern void __timer_table_start_stop(int  stop);
+extern void __bionic_atfork_run_prepare();
+extern void __bionic_atfork_run_child();
+extern void __bionic_atfork_run_parent();
 
 __END_DECLS
 
diff --git a/libc/docs/CHANGES.TXT b/libc/docs/CHANGES.TXT
index 9080685..b0725ed 100644
--- a/libc/docs/CHANGES.TXT
+++ b/libc/docs/CHANGES.TXT
@@ -1,7 +1,13 @@
 Bionic ChangeLog:
 -----------------
 
-Differences between current and Android 2.1:
+Differences between current and Android 2.2:
+
+- Added an implementation of pthread_atfork()
+
+
+-------------------------------------------------------------------------------
+Differences between Android 2.2 and Android 2.1:
 
 - Add support for SH-4 CPU architecture !
 
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 944bb68..ecabdb1 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -233,6 +233,8 @@
 
 int pthread_setname_np(pthread_t thid, const char *thname);
 
+int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void));
+
 typedef void  (*__pthread_cleanup_func_t)(void*);
 
 typedef struct __pthread_cleanup_t {