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
pthread_atfork(void (* prepare)(void),void (* parent)(void),void (* child)(void))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
_prefork_handler(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
_postfork_parent_handler(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
_postfork_child_handler(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