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 #include "thr_uberdata.h" 28 #include "mtlib.h" 29 30 /* 31 * fork handlers are run in LIFO order. 32 * The libc fork handler is expected to be the first handler installed, 33 * hence would be the last fork handler run in preparation for fork1(). 34 * It is essential that this be so, for other libraries depend on libc 35 * and may grab their own locks before calling into libc. By special 36 * arrangement, the loader runs libc's init section (libc_init()) first. 37 */ 38 39 /* 40 * pthread_atfork(): installs handlers to be called during fork1(). 41 * There is no POSIX API that provides for deletion of atfork handlers. 42 * Collaboration between the loader and libc ensures that atfork 43 * handlers installed by a library are deleted when that library 44 * is unloaded (see _preexec_atfork_unload() in atexit.c). 45 */ 46 int 47 pthread_atfork(void (*prepare)(void), 48 void (*parent)(void), void (*child)(void)) 49 { 50 ulwp_t *self = curthread; 51 uberdata_t *udp = self->ul_uberdata; 52 atfork_t *atfp; 53 atfork_t *head; 54 int error = 0; 55 56 (void) mutex_lock(&udp->atfork_lock); 57 if (self->ul_fork) { 58 /* 59 * Cannot call pthread_atfork() from a fork handler. 60 */ 61 error = EDEADLK; 62 } else if ((atfp = lmalloc(sizeof (atfork_t))) == NULL) { 63 error = ENOMEM; 64 } else { 65 atfp->prepare = prepare; 66 atfp->parent = parent; 67 atfp->child = child; 68 if ((head = udp->atforklist) == NULL) { 69 udp->atforklist = atfp; 70 atfp->forw = atfp->back = atfp; 71 } else { 72 head->back->forw = atfp; 73 atfp->forw = head; 74 atfp->back = head->back; 75 head->back = atfp; 76 } 77 } 78 79 (void) mutex_unlock(&udp->atfork_lock); 80 return (error); 81 } 82 83 /* 84 * _prefork_handler() is called by fork1() before it starts processing. 85 * It executes the user installed "prepare" routines in LIFO order (POSIX) 86 */ 87 void 88 _prefork_handler(void) 89 { 90 uberdata_t *udp = curthread->ul_uberdata; 91 atfork_t *atfork_q; 92 atfork_t *atfp; 93 94 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 95 if ((atfork_q = udp->atforklist) != NULL) { 96 atfp = atfork_q = atfork_q->back; 97 do { 98 if (atfp->prepare) 99 (*atfp->prepare)(); 100 } while ((atfp = atfp->back) != atfork_q); 101 } 102 } 103 104 /* 105 * _postfork_parent_handler() is called by fork1() after it retuns as parent. 106 * It executes the user installed "parent" routines in FIFO order (POSIX). 107 */ 108 void 109 _postfork_parent_handler(void) 110 { 111 uberdata_t *udp = curthread->ul_uberdata; 112 atfork_t *atfork_q; 113 atfork_t *atfp; 114 115 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 116 if ((atfork_q = udp->atforklist) != NULL) { 117 atfp = atfork_q; 118 do { 119 if (atfp->parent) 120 (*atfp->parent)(); 121 } while ((atfp = atfp->forw) != atfork_q); 122 } 123 } 124 125 /* 126 * _postfork_child_handler() is called by fork1() after it returns as child. 127 * It executes the user installed "child" routines in FIFO order (POSIX). 128 */ 129 void 130 _postfork_child_handler(void) 131 { 132 uberdata_t *udp = curthread->ul_uberdata; 133 atfork_t *atfork_q; 134 atfork_t *atfp; 135 136 ASSERT(MUTEX_OWNED(&udp->atfork_lock, curthread)); 137 if ((atfork_q = udp->atforklist) != NULL) { 138 atfp = atfork_q; 139 do { 140 if (atfp->child) 141 (*atfp->child)(); 142 } while ((atfp = atfp->forw) != atfork_q); 143 } 144 } 145