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 78 /* Call pthread_atfork() child handlers */ 79 for (cursor = atfork_head.cqh_first; 80 cursor != (void*)&atfork_head; 81 cursor = cursor->entries.cqe_next) { 82 if (cursor->child != NULL) { 83 cursor->child(); 84 } 85 } 86 87 pthread_mutex_unlock(&handler_mutex); 88 } 89 90 void __bionic_atfork_run_parent() 91 { 92 struct atfork_t *cursor; 93 94 /* Call pthread_atfork() parent handlers */ 95 for (cursor = atfork_head.cqh_first; 96 cursor != (void*)&atfork_head; 97 cursor = cursor->entries.cqe_next) { 98 if (cursor->parent != NULL) { 99 cursor->parent(); 100 } 101 } 102 103 pthread_mutex_unlock(&handler_mutex); 104 } 105 106 int pthread_atfork(void (*prepare)(void), void (*parent)(void), void(*child)(void)) 107 { 108 struct atfork_t *entry = malloc(sizeof(struct atfork_t)); 109 110 if (entry == NULL) { 111 return ENOMEM; 112 } 113 114 entry->prepare = prepare; 115 entry->parent = parent; 116 entry->child = child; 117 118 pthread_mutex_lock(&handler_mutex); 119 CIRCLEQ_INSERT_TAIL(&atfork_head, entry, entries); 120 pthread_mutex_unlock(&handler_mutex); 121 122 return 0; 123 } 124