1/* 2 * Copyright (c) 2001 Alexander Kabaev 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer 10 * in this position and unchanged. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. The name of the author may not be used to endorse or promote products 15 * derived from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30#include <sys/cdefs.h> 31#include <stdlib.h> 32 33#include "rtld_lock.h" 34#include "thr_private.h" 35 36static int _thr_rtld_clr_flag(int); 37static void *_thr_rtld_lock_create(void); 38static void _thr_rtld_lock_destroy(void *); 39static void _thr_rtld_lock_release(void *); 40static void _thr_rtld_rlock_acquire(void *); 41static int _thr_rtld_set_flag(int); 42static void _thr_rtld_wlock_acquire(void *); 43 44#ifdef NOTYET 45static void * 46_thr_rtld_lock_create(void) 47{ 48 pthread_rwlock_t prwlock; 49 if (_pthread_rwlock_init(&prwlock, NULL)) 50 return (NULL); 51 return (prwlock); 52} 53 54static void 55_thr_rtld_lock_destroy(void *lock) 56{ 57 pthread_rwlock_t prwlock; 58 59 prwlock = (pthread_rwlock_t)lock; 60 if (prwlock != NULL) 61 _pthread_rwlock_destroy(&prwlock); 62} 63 64static void 65_thr_rtld_rlock_acquire(void *lock) 66{ 67 pthread_rwlock_t prwlock; 68 69 prwlock = (pthread_rwlock_t)lock; 70 _thr_rwlock_rdlock(&prwlock); 71} 72 73static void 74_thr_rtld_wlock_acquire(void *lock) 75{ 76 pthread_rwlock_t prwlock; 77 78 prwlock = (pthread_rwlock_t)lock; 79 _thr_rwlock_wrlock(&prwlock); 80} 81 82static void 83_thr_rtld_lock_release(void *lock) 84{ 85 pthread_rwlock_t prwlock; 86 87 prwlock = (pthread_rwlock_t)lock; 88 _thr_rwlock_unlock(&prwlock); 89} 90 91 92static int 93_thr_rtld_set_flag(int mask) 94{ 95 struct pthread *curthread; 96 int bits; 97 98 curthread = _get_curthread(); 99 if (curthread != NULL) { 100 bits = curthread->rtld_bits; 101 curthread->rtld_bits |= mask; 102 } else { 103 bits = 0; 104 PANIC("No current thread in rtld call"); 105 } 106 107 return (bits); 108} 109 110static int 111_thr_rtld_clr_flag(int mask) 112{ 113 struct pthread *curthread; 114 int bits; 115 116 curthread = _get_curthread(); 117 if (curthread != NULL) { 118 bits = curthread->rtld_bits; 119 curthread->rtld_bits &= ~mask; 120 } else { 121 bits = 0; 122 PANIC("No current thread in rtld call"); 123 } 124 return (bits); 125} 126 127void 128_thr_rtld_init(void) 129{ 130 struct RtldLockInfo li; 131 132 li.lock_create = _thr_rtld_lock_create; 133 li.lock_destroy = _thr_rtld_lock_destroy; 134 li.rlock_acquire = _thr_rtld_rlock_acquire; 135 li.wlock_acquire = _thr_rtld_wlock_acquire; 136 li.lock_release = _thr_rtld_lock_release; 137 li.thread_set_flag = _thr_rtld_set_flag; 138 li.thread_clr_flag = _thr_rtld_clr_flag; 139 li.at_fork = NULL; 140 _rtld_thread_init(&li); 141} 142 143void 144_thr_rtld_fini(void) 145{ 146 _rtld_thread_init(NULL); 147} 148#endif 149 150struct rtld_kse_lock { 151 struct lock lck; 152 struct kse *owner; 153 kse_critical_t crit; 154 int count; 155 int write; 156}; 157 158static void * 159_thr_rtld_lock_create(void) 160{ 161 struct rtld_kse_lock *l; 162 163 if ((l = malloc(sizeof(struct rtld_kse_lock))) != NULL) { 164 _lock_init(&l->lck, LCK_ADAPTIVE, _kse_lock_wait, 165 _kse_lock_wakeup, calloc); 166 l->owner = NULL; 167 l->count = 0; 168 l->write = 0; 169 } 170 return (l); 171} 172 173static void 174_thr_rtld_lock_destroy(void *lock __unused) 175{ 176 /* XXX We really can not free memory after a fork() */ 177#if 0 178 struct rtld_kse_lock *l; 179 180 l = (struct rtld_kse_lock *)lock; 181 _lock_destroy(&l->lck); 182 free(l); 183#endif 184 return; 185} 186 187static void 188_thr_rtld_rlock_acquire(void *lock) 189{ 190 struct rtld_kse_lock *l; 191 kse_critical_t crit; 192 struct kse *curkse; 193 194 l = (struct rtld_kse_lock *)lock; 195 crit = _kse_critical_enter(); 196 curkse = _get_curkse(); 197 if (l->owner == curkse) { 198 l->count++; 199 _kse_critical_leave(crit); /* probably not necessary */ 200 } else { 201 KSE_LOCK_ACQUIRE(curkse, &l->lck); 202 l->crit = crit; 203 l->owner = curkse; 204 l->count = 1; 205 l->write = 0; 206 } 207} 208 209static void 210_thr_rtld_wlock_acquire(void *lock) 211{ 212 struct rtld_kse_lock *l; 213 kse_critical_t crit; 214 struct kse *curkse; 215 216 l = (struct rtld_kse_lock *)lock; 217 crit = _kse_critical_enter(); 218 curkse = _get_curkse(); 219 if (l->owner == curkse) { 220 _kse_critical_leave(crit); 221 PANIC("Recursive write lock attempt on rtld lock"); 222 } else { 223 KSE_LOCK_ACQUIRE(curkse, &l->lck); 224 l->crit = crit; 225 l->owner = curkse; 226 l->count = 1; 227 l->write = 1; 228 } 229} 230 231static void 232_thr_rtld_lock_release(void *lock) 233{ 234 struct rtld_kse_lock *l; 235 kse_critical_t crit; 236 struct kse *curkse; 237 238 l = (struct rtld_kse_lock *)lock; 239 crit = _kse_critical_enter(); 240 curkse = _get_curkse(); 241 if (l->owner != curkse) { 242 /* 243 * We might want to forcibly unlock the rtld lock 244 * and/or disable threaded mode so there is better 245 * chance that the panic will work. Otherwise, 246 * we could end up trying to take the rtld lock 247 * again. 248 */ 249 _kse_critical_leave(crit); 250 PANIC("Attempt to unlock rtld lock when not owner."); 251 } else { 252 l->count--; 253 if (l->count == 0) { 254 /* 255 * If there ever is a count associated with 256 * _kse_critical_leave(), we'll need to add 257 * another call to it here with the crit 258 * value from above. 259 */ 260 crit = l->crit; 261 l->owner = NULL; 262 l->write = 0; 263 KSE_LOCK_RELEASE(curkse, &l->lck); 264 } 265 _kse_critical_leave(crit); 266 } 267} 268 269 270static int 271_thr_rtld_set_flag(int mask __unused) 272{ 273 return (0); 274} 275 276static int 277_thr_rtld_clr_flag(int mask __unused) 278{ 279 return (0); 280} 281 282void 283_thr_rtld_init(void) 284{ 285 struct RtldLockInfo li; 286 287 li.lock_create = _thr_rtld_lock_create; 288 li.lock_destroy = _thr_rtld_lock_destroy; 289 li.rlock_acquire = _thr_rtld_rlock_acquire; 290 li.wlock_acquire = _thr_rtld_wlock_acquire; 291 li.lock_release = _thr_rtld_lock_release; 292 li.thread_set_flag = _thr_rtld_set_flag; 293 li.thread_clr_flag = _thr_rtld_clr_flag; 294 li.at_fork = NULL; 295 _rtld_thread_init(&li); 296} 297 298void 299_thr_rtld_fini(void) 300{ 301 _rtld_thread_init(NULL); 302} 303