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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 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 "mtlib.h" 30 #include "umem_base.h" 31 #include "vmem_base.h" 32 33 #include <unistd.h> 34 35 /* 36 * The following functions are for pre- and post-fork1(2) handling. 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 } 106 (void) mutex_lock(&umem_cache_lock); 107 (void) mutex_lock(&umem_update_lock); 108 (void) mutex_lock(&umem_flags_lock); 109 110 umem_lockup_cache(&umem_null_cache); 111 for (cp = umem_null_cache.cache_prev; cp != &umem_null_cache; 112 cp = cp->cache_prev) 113 umem_lockup_cache(cp); 114 115 umem_lockup_log_header(umem_transaction_log); 116 umem_lockup_log_header(umem_content_log); 117 umem_lockup_log_header(umem_failure_log); 118 umem_lockup_log_header(umem_slab_log); 119 120 (void) cond_broadcast(&umem_update_cv); 121 122 vmem_sbrk_lockup(); 123 vmem_lockup(); 124 } 125 126 static void 127 umem_release(void) 128 { 129 umem_cache_t *cp; 130 131 vmem_release(); 132 vmem_sbrk_release(); 133 134 umem_release_log_header(umem_slab_log); 135 umem_release_log_header(umem_failure_log); 136 umem_release_log_header(umem_content_log); 137 umem_release_log_header(umem_transaction_log); 138 139 for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; 140 cp = cp->cache_next) 141 umem_release_cache(cp); 142 umem_release_cache(&umem_null_cache); 143 144 (void) mutex_unlock(&umem_flags_lock); 145 (void) mutex_unlock(&umem_update_lock); 146 (void) mutex_unlock(&umem_cache_lock); 147 (void) mutex_unlock(&umem_init_lock); 148 } 149 150 static void 151 umem_release_child(void) 152 { 153 umem_cache_t *cp; 154 155 /* 156 * Clean up the update state 157 */ 158 umem_update_thr = 0; 159 160 if (umem_st_update_thr != thr_self()) { 161 umem_st_update_thr = 0; 162 umem_reaping = UMEM_REAP_DONE; 163 164 for (cp = umem_null_cache.cache_next; cp != &umem_null_cache; 165 cp = cp->cache_next) { 166 if (cp->cache_uflags & UMU_NOTIFY) 167 cp->cache_uflags &= ~UMU_NOTIFY; 168 169 /* 170 * If the cache is active, we just re-add it to 171 * the update list. This will re-do any active 172 * updates on the cache, but that won't break 173 * anything. 174 * 175 * The worst that can happen is a cache has 176 * its magazines rescaled twice, instead of once. 177 */ 178 if (cp->cache_uflags & UMU_ACTIVE) { 179 umem_cache_t *cnext, *cprev; 180 181 ASSERT(cp->cache_unext == NULL && 182 cp->cache_uprev == NULL); 183 184 cp->cache_uflags &= ~UMU_ACTIVE; 185 cp->cache_unext = cnext = &umem_null_cache; 186 cp->cache_uprev = cprev = 187 umem_null_cache.cache_uprev; 188 cnext->cache_uprev = cp; 189 cprev->cache_unext = cp; 190 } 191 } 192 } 193 194 umem_release(); 195 } 196 197 void 198 umem_forkhandler_init(void) 199 { 200 /* 201 * There is no way to unregister these atfork functions, 202 * but we don't need to. The dynamic linker and libc take 203 * care of unregistering them if/when the library is unloaded. 204 */ 205 (void) pthread_atfork(umem_lockup, umem_release, umem_release_child); 206 } 207