]>
Commit | Line | Data |
---|---|---|
34dc7c2f BB |
1 | /* |
2 | * CDDL HEADER START | |
3 | * | |
4 | * The contents of this file are subject to the terms of the | |
b128c09f BB |
5 | * Common Development and Distribution License (the "License"). |
6 | * You may not use this file except in compliance with the License. | |
34dc7c2f BB |
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 | */ | |
b128c09f | 21 | |
34dc7c2f | 22 | /* |
b128c09f | 23 | * Copyright 2008 Sun Microsystems, Inc. All rights reserved. |
34dc7c2f BB |
24 | * Use is subject to license terms. |
25 | */ | |
34dc7c2f | 26 | |
b128c09f | 27 | #pragma ident "%Z%%M% %I% %E% SMI" |
34dc7c2f | 28 | |
34dc7c2f BB |
29 | #include "umem_base.h" |
30 | #include "vmem_base.h" | |
31 | ||
34dc7c2f BB |
32 | #include <unistd.h> |
33 | ||
34 | /* | |
b128c09f BB |
35 | * The following functions are for pre- and post-fork1(2) handling. See |
36 | * "Lock Ordering" in lib/libumem/common/umem.c for the lock ordering used. | |
34dc7c2f BB |
37 | */ |
38 | ||
39 | static void | |
40 | umem_lockup_cache(umem_cache_t *cp) | |
41 | { | |
42 | int idx; | |
43 | int ncpus = cp->cache_cpu_mask + 1; | |
44 | ||
45 | for (idx = 0; idx < ncpus; idx++) | |
46 | (void) mutex_lock(&cp->cache_cpu[idx].cc_lock); | |
47 | ||
48 | (void) mutex_lock(&cp->cache_depot_lock); | |
49 | (void) mutex_lock(&cp->cache_lock); | |
50 | } | |
51 | ||
52 | static void | |
53 | umem_release_cache(umem_cache_t *cp) | |
54 | { | |
55 | int idx; | |
56 | int ncpus = cp->cache_cpu_mask + 1; | |
57 | ||
58 | (void) mutex_unlock(&cp->cache_lock); | |
59 | (void) mutex_unlock(&cp->cache_depot_lock); | |
60 | ||
61 | for (idx = 0; idx < ncpus; idx++) | |
62 | (void) mutex_unlock(&cp->cache_cpu[idx].cc_lock); | |
63 | } | |
64 | ||
65 | static void | |
66 | umem_lockup_log_header(umem_log_header_t *lhp) | |
67 | { | |
68 | int idx; | |
69 | if (lhp == NULL) | |
70 | return; | |
71 | for (idx = 0; idx < umem_max_ncpus; idx++) | |
72 | (void) mutex_lock(&lhp->lh_cpu[idx].clh_lock); | |
73 | ||
74 | (void) mutex_lock(&lhp->lh_lock); | |
75 | } | |
76 | ||
77 | static void | |
78 | umem_release_log_header(umem_log_header_t *lhp) | |
79 | { | |
80 | int idx; | |
81 | if (lhp == NULL) | |
82 | return; | |
83 | ||
84 | (void) mutex_unlock(&lhp->lh_lock); | |
85 | ||
86 | for (idx = 0; idx < umem_max_ncpus; idx++) | |
87 | (void) mutex_unlock(&lhp->lh_cpu[idx].clh_lock); | |
88 | } | |
89 | ||
90 | static void | |
91 | umem_lockup(void) | |
92 | { | |
93 | umem_cache_t *cp; | |
94 | ||
95 | (void) mutex_lock(&umem_init_lock); | |
96 | /* | |
97 | * If another thread is busy initializing the library, we must | |
98 | * wait for it to complete (by calling umem_init()) before allowing | |
99 | * the fork() to proceed. | |
100 | */ | |
101 | if (umem_ready == UMEM_READY_INITING && umem_init_thr != thr_self()) { | |
102 | (void) mutex_unlock(&umem_init_lock); | |
103 | (void) umem_init(); | |
104 | (void) mutex_lock(&umem_init_lock); | |
105 | } | |
b128c09f BB |
106 | |
107 | vmem_lockup(); | |
108 | vmem_sbrk_lockup(); | |
109 | ||
34dc7c2f BB |
110 | (void) mutex_lock(&umem_cache_lock); |
111 | (void) mutex_lock(&umem_update_lock); | |
112 | (void) mutex_lock(&umem_flags_lock); | |
113 | ||
114 | umem_lockup_cache(&umem_null_cache); | |
115 | for (cp = umem_null_cache.cache_prev; cp != &umem_null_cache; | |
116 | cp = cp->cache_prev) | |
117 | umem_lockup_cache(cp); | |
118 | ||
119 | umem_lockup_log_header(umem_transaction_log); | |
120 | umem_lockup_log_header(umem_content_log); | |
121 | umem_lockup_log_header(umem_failure_log); | |
122 | umem_lockup_log_header(umem_slab_log); | |
123 | ||
124 | (void) cond_broadcast(&umem_update_cv); | |
125 | ||
34dc7c2f BB |
126 | } |
127 | ||
128 | static void | |
b128c09f | 129 | umem_do_release(int as_child) |
34dc7c2f BB |
130 | { |
131 | umem_cache_t *cp; | |
b128c09f | 132 | int cleanup_update = 0; |
34dc7c2f BB |
133 | |
134 | /* | |
b128c09f BB |
135 | * Clean up the update state if we are the child process and |
136 | * another thread was processing updates. | |
34dc7c2f | 137 | */ |
b128c09f BB |
138 | if (as_child) { |
139 | if (umem_update_thr != thr_self()) { | |
140 | umem_update_thr = 0; | |
141 | cleanup_update = 1; | |
142 | } | |
143 | if (umem_st_update_thr != thr_self()) { | |
144 | umem_st_update_thr = 0; | |
145 | cleanup_update = 1; | |
146 | } | |
147 | } | |
34dc7c2f | 148 | |
b128c09f | 149 | if (cleanup_update) { |
34dc7c2f BB |
150 | umem_reaping = UMEM_REAP_DONE; |
151 | ||
152 | for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; | |
153 | cp = cp->cache_next) { | |
154 | if (cp->cache_uflags & UMU_NOTIFY) | |
155 | cp->cache_uflags &= ~UMU_NOTIFY; | |
156 | ||
157 | /* | |
158 | * If the cache is active, we just re-add it to | |
159 | * the update list. This will re-do any active | |
160 | * updates on the cache, but that won't break | |
161 | * anything. | |
162 | * | |
163 | * The worst that can happen is a cache has | |
164 | * its magazines rescaled twice, instead of once. | |
165 | */ | |
166 | if (cp->cache_uflags & UMU_ACTIVE) { | |
167 | umem_cache_t *cnext, *cprev; | |
168 | ||
169 | ASSERT(cp->cache_unext == NULL && | |
170 | cp->cache_uprev == NULL); | |
171 | ||
172 | cp->cache_uflags &= ~UMU_ACTIVE; | |
173 | cp->cache_unext = cnext = &umem_null_cache; | |
174 | cp->cache_uprev = cprev = | |
175 | umem_null_cache.cache_uprev; | |
176 | cnext->cache_uprev = cp; | |
177 | cprev->cache_unext = cp; | |
178 | } | |
179 | } | |
180 | } | |
181 | ||
b128c09f BB |
182 | umem_release_log_header(umem_slab_log); |
183 | umem_release_log_header(umem_failure_log); | |
184 | umem_release_log_header(umem_content_log); | |
185 | umem_release_log_header(umem_transaction_log); | |
186 | ||
187 | for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; | |
188 | cp = cp->cache_next) | |
189 | umem_release_cache(cp); | |
190 | umem_release_cache(&umem_null_cache); | |
191 | ||
192 | (void) mutex_unlock(&umem_flags_lock); | |
193 | (void) mutex_unlock(&umem_update_lock); | |
194 | (void) mutex_unlock(&umem_cache_lock); | |
195 | ||
196 | vmem_sbrk_release(); | |
197 | vmem_release(); | |
198 | ||
199 | (void) mutex_unlock(&umem_init_lock); | |
200 | } | |
201 | ||
202 | static void | |
203 | umem_release(void) | |
204 | { | |
205 | umem_do_release(0); | |
206 | } | |
207 | ||
208 | static void | |
209 | umem_release_child(void) | |
210 | { | |
211 | umem_do_release(1); | |
34dc7c2f | 212 | } |
34dc7c2f BB |
213 | |
214 | void | |
215 | umem_forkhandler_init(void) | |
216 | { | |
34dc7c2f BB |
217 | /* |
218 | * There is no way to unregister these atfork functions, | |
219 | * but we don't need to. The dynamic linker and libc take | |
220 | * care of unregistering them if/when the library is unloaded. | |
221 | */ | |
222 | (void) pthread_atfork(umem_lockup, umem_release, umem_release_child); | |
34dc7c2f | 223 | } |