1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in 12 * the documentation and/or other materials provided with the 13 * distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 #include <stdlib.h> 29 #include <errno.h> 30 #include <pthread.h> 31 #include <sys/queue.h> 32 33 static pthread_mutex_t handler_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER; 34 35 struct atfork_t 36 { 37 CIRCLEQ_ENTRY(atfork_t) entries; 38 39 void (*prepare)(void); 40 void (*child)(void); 41 void (*parent)(void); 42 }; 43 static CIRCLEQ_HEAD(atfork_head_t, atfork_t) atfork_head = \ 44 CIRCLEQ_HEAD_INITIALIZER(atfork_head); 45 46 void __bionic_atfork_run_prepare() 47 { 48 struct atfork_t *cursor; 49 50 /* We will lock this here, and unlock it in the parent and child functions. 51 * This ensures that nobody can modify the handler array between the calls 52 * to the prepare and parent/child handlers. 53 * 54 * TODO: If a handler mucks with the list, it could cause problems. Right 55 * now it's ok because all they can do is add new items to the end 56 * of the list, but if/when we implement cleanup in dlclose() things 57 * will get more interesting... 58 */ 59 pthread_mutex_lock(&handler_mutex); 60 61 /* Call pthread_atfork() prepare handlers. Posix states that the prepare 62 * handlers should be called in the reverse order of the parent/child 63 * handlers, so we iterate backwards. 64 */ 65 for (cursor = atfork_head.cqh_last; 66 cursor != (void*)&atfork_head; 67 cursor = cursor->entries.cqe_prev) { 68 if (cursor->prepare != NULL) { 69 cursor->prepare(); 70 } 71 } 72 } 73 74 void __bionic_atfork_run_child() 75 { 76 struct atfork_t *cursor; 77 pthread_mutexattr_t attr; 78 79 /* Call pthread_atfork() child handlers */ 80 for (cursor = atfork_head.cqh_first; 81 cursor != (void*)&atfork_head; 82 cursor = cursor->entries.cqe_next) { 83 if (cursor->child != NULL) { 84 cursor->child(); 85 } 86 } 87 88 pthread_mutexattr_init(&attr); 89 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 90 pthread_mutex_init(&handler_mutex, &attr); 91 } 92 93 void __bionic_atfork_run_parent() 94 { 95 struct atfork_t *cursor; 96 97 /* Call pthread_atfork() parent handlers */ 98 for (cursor = atfork_head.cqh_first; 99 cursor != (void*)&atfork_head; 100 cursor = cursor->entries.cqe_next) { 101 if (cursor->parent != NULL) { 102 cursor->parent(); 103 } 104 } 105 106 pthread_mutex_unlock(&handler_mutex); 107 } 108 109 int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)) 110 { 111 struct atfork_t *entry = malloc(sizeof(struct atfork_t)); 112 113 if (entry == NULL) { 114 return ENOMEM; 115 } 116 117 entry->prepare = prepare; 118 entry->parent = parent; 119 entry->child = child; 120 121 pthread_mutex_lock(&handler_mutex); 122 CIRCLEQ_INSERT_TAIL(&atfork_head, entry, entries); 123 pthread_mutex_unlock(&handler_mutex); 124 125 return 0; 126 } 127