OSDN Git Service

Implemented pthread_atfork()
authorMatt Fischer <matt.fischer@garmin.com>
Fri, 25 Jun 2010 19:36:39 +0000 (14:36 -0500)
committerJean-Baptiste Queru <jbq@google.com>
Fri, 23 Jul 2010 20:10:16 +0000 (13:10 -0700)
Change-Id: Ie6c0bf593315d3507b3c4a6c8903a74a1fa053db

libc/Android.mk
libc/bionic/fork.c
libc/bionic/pthread-atfork.c [new file with mode: 0644]
libc/bionic/pthread_internal.h
libc/docs/CHANGES.TXT
libc/include/pthread.h

index 7a7d9e3..568cc94 100644 (file)
@@ -324,6 +324,7 @@ libc_common_src_files += \
 # 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 @@ libc_common_src_files += \
        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 @@ libc_common_src_files += \
        string/memcmp.c \
        string/strlen.c \
        bionic/pthread.c \
+       bionic/pthread-atfork.c \
        bionic/pthread-timers.c \
        bionic/ptrace.c \
        unistd/socketcalls.c
index e20f548..8d3ea4b 100644 (file)
@@ -40,9 +40,12 @@ int  fork(void)
      * 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 @@ int  fork(void)
          * 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 (file)
index 0000000..3a5189d
--- /dev/null
@@ -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;
+}
index eb4e80c..655b8f3 100644 (file)
@@ -109,6 +109,9 @@ extern int  __pthread_cond_timedwait_relative(pthread_cond_t*,
 
 /* 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
 
index 9080685..b0725ed 100644 (file)
@@ -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 !
 
index 944bb68..ecabdb1 100644 (file)
@@ -233,6 +233,8 @@ int pthread_once(pthread_once_t  *once_control, void (*init_routine)(void));
 
 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 {