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 2008 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 pthread_atfork = _pthread_atfork 49 int 50 _pthread_atfork(void (*prepare)(void), 51 void (*parent)(void), void (*child)(void)) 52 { 53 ulwp_t *self = curthread; 54 uberdata_t *udp = self->ul_uberdata; 55 atfork_t *atfp; 56 atfork_t *head; 57 int error = 0; 58 59 (void) mutex_lock(&udp->atfork_lock); 60 if (self->ul_fork) { 61 /* 62 * Cannot call pthread_atfork() from a fork handler. 63 */ 64 error = EDEADLK; 65 } else if ((atfp = lmalloc(sizeof (atfork_t))) == NULL) { 66 error = ENOMEM; 67 } else { 68 atfp->prepare = prepare; 69 atfp->parent = parent; 70 atfp->child = child; 71 if ((head = udp->atforklist) == NULL) { 72 udp->atforklist = atfp; 73 atfp->forw = atfp->back = atfp; 74 } else { 75 head->back->forw = atfp; 76 atfp->forw = head; 77 atfp->back = head->back; 78 head->back = atfp; 79 } 80 } 81 82 (void) mutex_unlock(&udp->atfork_lock); 83 return (error); 84 } 85 86 /* 87 * _prefork_handler() is called by fork1() before it starts processing. 88 * It executes the user installed "prepare" routines in LIFO order (POSIX) 89 */ 90 void 91 _prefork_handler(void) 92 { 93 uberdata_t *udp = curthread->ul_uberdata; 94 atfork_t *atfork_q; 95 atfork_t *atfp; 96 97 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 98 if ((atfork_q = udp->atforklist) != NULL) { 99 atfp = atfork_q = atfork_q->back; 100 do { 101 if (atfp->prepare) 102 (*atfp->prepare)(); 103 } while ((atfp = atfp->back) != atfork_q); 104 } 105 } 106 107 /* 108 * _postfork_parent_handler() is called by fork1() after it retuns as parent. 109 * It executes the user installed "parent" routines in FIFO order (POSIX). 110 */ 111 void 112 _postfork_parent_handler(void) 113 { 114 uberdata_t *udp = curthread->ul_uberdata; 115 atfork_t *atfork_q; 116 atfork_t *atfp; 117 118 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 119 if ((atfork_q = udp->atforklist) != NULL) { 120 atfp = atfork_q; 121 do { 122 if (atfp->parent) 123 (*atfp->parent)(); 124 } while ((atfp = atfp->forw) != atfork_q); 125 } 126 } 127 128 /* 129 * _postfork_child_handler() is called by fork1() after it returns as child. 130 * It executes the user installed "child" routines in FIFO order (POSIX). 131 */ 132 void 133 _postfork_child_handler(void) 134 { 135 uberdata_t *udp = curthread->ul_uberdata; 136 atfork_t *atfork_q; 137 atfork_t *atfp; 138 139 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 140 if ((atfork_q = udp->atforklist) != NULL) { 141 atfp = atfork_q; 142 do { 143 if (atfp->child) 144 (*atfp->child)(); 145 } while ((atfp = atfp->forw) != atfork_q); 146 } 147 } 148