1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "thr_uberdata.h" 30 #include "mtlib.h" 31 32 /* 33 * fork handlers are run in LIFO order. 34 * The libc fork handler is expected to be the first handler installed, 35 * hence would be the last fork handler run in preparation for fork1(). 36 * It is essential that this be so, for other libraries depend on libc 37 * and may grab their own locks before calling into libc. By special 38 * arrangement, the loader runs libc's init section (libc_init()) first. 39 */ 40 41 /* 42 * pthread_atfork(): installs handlers to be called during fork1(). 43 * There is no POSIX API that provides for deletion of atfork handlers. 44 * Collaboration between the loader and libc ensures that atfork 45 * handlers installed by a library are deleted when that library 46 * is unloaded (see _preexec_atfork_unload() in atexit.c). 47 */ 48 #pragma weak _private_pthread_atfork = _pthread_atfork 49 #pragma weak pthread_atfork = _pthread_atfork 50 int 51 _pthread_atfork(void (*prepare)(void), 52 void (*parent)(void), void (*child)(void)) 53 { 54 ulwp_t *self = curthread; 55 uberdata_t *udp = self->ul_uberdata; 56 atfork_t *atfp; 57 atfork_t *head; 58 int error = 0; 59 60 (void) _private_mutex_lock(&udp->atfork_lock); 61 if (self->ul_fork) { 62 /* 63 * Cannot call pthread_atfork() from a fork handler. 64 */ 65 error = EDEADLK; 66 } else if ((atfp = lmalloc(sizeof (atfork_t))) == NULL) { 67 error = ENOMEM; 68 } else { 69 atfp->prepare = prepare; 70 atfp->parent = parent; 71 atfp->child = child; 72 if ((head = udp->atforklist) == NULL) { 73 udp->atforklist = atfp; 74 atfp->forw = atfp->back = atfp; 75 } else { 76 head->back->forw = atfp; 77 atfp->forw = head; 78 atfp->back = head->back; 79 head->back = atfp; 80 } 81 } 82 83 (void) _private_mutex_unlock(&udp->atfork_lock); 84 return (error); 85 } 86 87 /* 88 * _prefork_handler() is called by fork1() before it starts processing. 89 * It executes the user installed "prepare" routines in LIFO order (POSIX) 90 */ 91 void 92 _prefork_handler(void) 93 { 94 uberdata_t *udp = curthread->ul_uberdata; 95 atfork_t *atfork_q; 96 atfork_t *atfp; 97 98 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 99 if ((atfork_q = udp->atforklist) != NULL) { 100 atfp = atfork_q = atfork_q->back; 101 do { 102 if (atfp->prepare) 103 (*atfp->prepare)(); 104 } while ((atfp = atfp->back) != atfork_q); 105 } 106 } 107 108 /* 109 * _postfork_parent_handler() is called by fork1() after it retuns as parent. 110 * It executes the user installed "parent" routines in FIFO order (POSIX). 111 */ 112 void 113 _postfork_parent_handler(void) 114 { 115 uberdata_t *udp = curthread->ul_uberdata; 116 atfork_t *atfork_q; 117 atfork_t *atfp; 118 119 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 120 if ((atfork_q = udp->atforklist) != NULL) { 121 atfp = atfork_q; 122 do { 123 if (atfp->parent) 124 (*atfp->parent)(); 125 } while ((atfp = atfp->forw) != atfork_q); 126 } 127 } 128 129 /* 130 * _postfork_child_handler() is called by fork1() after it returns as child. 131 * It executes the user installed "child" routines in FIFO order (POSIX). 132 */ 133 void 134 _postfork_child_handler(void) 135 { 136 uberdata_t *udp = curthread->ul_uberdata; 137 atfork_t *atfork_q; 138 atfork_t *atfp; 139 140 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 141 if ((atfork_q = udp->atforklist) != NULL) { 142 atfp = atfork_q; 143 do { 144 if (atfp->child) 145 (*atfp->child)(); 146 } while ((atfp = atfp->forw) != atfork_q); 147 } 148 } 149