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