1115399Skan/* 2115399Skan * Copyright (c) 2001 Alexander Kabaev 3115399Skan * All rights reserved. 4115399Skan * 5115399Skan * Redistribution and use in source and binary forms, with or without 6115399Skan * modification, are permitted provided that the following conditions 7115399Skan * are met: 8115399Skan * 1. Redistributions of source code must retain the above copyright 9115399Skan * notice, this list of conditions and the following disclaimer 10115399Skan * in this position and unchanged. 11115399Skan * 2. Redistributions in binary form must reproduce the above copyright 12115399Skan * notice, this list of conditions and the following disclaimer in the 13115399Skan * documentation and/or other materials provided with the distribution. 14115399Skan * 3. The name of the author may not be used to endorse or promote products 15115399Skan * derived from this software without specific prior written permission. 16115399Skan * 17115399Skan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18115399Skan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19115399Skan * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20115399Skan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21115399Skan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22115399Skan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23115399Skan * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24115399Skan * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25115399Skan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26115399Skan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27115399Skan * 28115399Skan * $FreeBSD$ 29115399Skan */ 30115399Skan#include <sys/cdefs.h> 31116975Sdavidxu#include <stdlib.h> 32122131Sdeischen 33122131Sdeischen#include "rtld_lock.h" 34115399Skan#include "thr_private.h" 35115399Skan 36122131Sdeischenstatic int _thr_rtld_clr_flag(int); 37122131Sdeischenstatic void *_thr_rtld_lock_create(void); 38122131Sdeischenstatic void _thr_rtld_lock_destroy(void *); 39122131Sdeischenstatic void _thr_rtld_lock_release(void *); 40122131Sdeischenstatic void _thr_rtld_rlock_acquire(void *); 41122131Sdeischenstatic int _thr_rtld_set_flag(int); 42122131Sdeischenstatic void _thr_rtld_wlock_acquire(void *); 43115399Skan 44116975Sdavidxu#ifdef NOTYET 45115399Skanstatic void * 46122131Sdeischen_thr_rtld_lock_create(void) 47115399Skan{ 48115399Skan pthread_rwlock_t prwlock; 49115399Skan if (_pthread_rwlock_init(&prwlock, NULL)) 50115399Skan return (NULL); 51115399Skan return (prwlock); 52115399Skan} 53115399Skan 54115399Skanstatic void 55115399Skan_thr_rtld_lock_destroy(void *lock) 56115399Skan{ 57122131Sdeischen pthread_rwlock_t prwlock; 58122131Sdeischen 59122131Sdeischen prwlock = (pthread_rwlock_t)lock; 60115399Skan if (prwlock != NULL) 61115399Skan _pthread_rwlock_destroy(&prwlock); 62115399Skan} 63115399Skan 64115399Skanstatic void 65115399Skan_thr_rtld_rlock_acquire(void *lock) 66115399Skan{ 67122131Sdeischen pthread_rwlock_t prwlock; 68122131Sdeischen 69122131Sdeischen prwlock = (pthread_rwlock_t)lock; 70115399Skan _thr_rwlock_rdlock(&prwlock); 71115399Skan} 72115399Skan 73115399Skanstatic void 74115399Skan_thr_rtld_wlock_acquire(void *lock) 75115399Skan{ 76122131Sdeischen pthread_rwlock_t prwlock; 77122131Sdeischen 78122131Sdeischen prwlock = (pthread_rwlock_t)lock; 79115399Skan _thr_rwlock_wrlock(&prwlock); 80115399Skan} 81115399Skan 82115399Skanstatic void 83115399Skan_thr_rtld_lock_release(void *lock) 84115399Skan{ 85122131Sdeischen pthread_rwlock_t prwlock; 86122131Sdeischen 87122131Sdeischen prwlock = (pthread_rwlock_t)lock; 88115399Skan _thr_rwlock_unlock(&prwlock); 89115399Skan} 90115399Skan 91115399Skan 92115399Skanstatic int 93115399Skan_thr_rtld_set_flag(int mask) 94115399Skan{ 95115399Skan struct pthread *curthread; 96115399Skan int bits; 97115399Skan 98115399Skan curthread = _get_curthread(); 99115399Skan if (curthread != NULL) { 100115399Skan bits = curthread->rtld_bits; 101115399Skan curthread->rtld_bits |= mask; 102115399Skan } else { 103115399Skan bits = 0; 104115399Skan PANIC("No current thread in rtld call"); 105115399Skan } 106115399Skan 107115399Skan return (bits); 108115399Skan} 109115399Skan 110115399Skanstatic int 111115399Skan_thr_rtld_clr_flag(int mask) 112115399Skan{ 113115399Skan struct pthread *curthread; 114115399Skan int bits; 115115399Skan 116115399Skan curthread = _get_curthread(); 117115399Skan if (curthread != NULL) { 118115399Skan bits = curthread->rtld_bits; 119115399Skan curthread->rtld_bits &= ~mask; 120115399Skan } else { 121115399Skan bits = 0; 122115399Skan PANIC("No current thread in rtld call"); 123115399Skan } 124115399Skan return (bits); 125115399Skan} 126115399Skan 127115399Skanvoid 128122131Sdeischen_thr_rtld_init(void) 129115399Skan{ 130115399Skan struct RtldLockInfo li; 131122131Sdeischen 132122131Sdeischen li.lock_create = _thr_rtld_lock_create; 133122131Sdeischen li.lock_destroy = _thr_rtld_lock_destroy; 134122131Sdeischen li.rlock_acquire = _thr_rtld_rlock_acquire; 135122131Sdeischen li.wlock_acquire = _thr_rtld_wlock_acquire; 136122131Sdeischen li.lock_release = _thr_rtld_lock_release; 137122131Sdeischen li.thread_set_flag = _thr_rtld_set_flag; 138122131Sdeischen li.thread_clr_flag = _thr_rtld_clr_flag; 139122131Sdeischen li.at_fork = NULL; 140115399Skan _rtld_thread_init(&li); 141115399Skan} 142115399Skan 143115399Skanvoid 144122131Sdeischen_thr_rtld_fini(void) 145115399Skan{ 146115399Skan _rtld_thread_init(NULL); 147115399Skan} 148116975Sdavidxu#endif 149116975Sdavidxu 150116975Sdavidxustruct rtld_kse_lock { 151118745Sdavidxu struct lock lck; 152118745Sdavidxu struct kse *owner; 153118745Sdavidxu kse_critical_t crit; 154118745Sdavidxu int count; 155118745Sdavidxu int write; 156116975Sdavidxu}; 157116975Sdavidxu 158116975Sdavidxustatic void * 159122131Sdeischen_thr_rtld_lock_create(void) 160116975Sdavidxu{ 161122131Sdeischen struct rtld_kse_lock *l; 162116975Sdavidxu 163149578Sdeischen if ((l = malloc(sizeof(struct rtld_kse_lock))) != NULL) { 164149578Sdeischen _lock_init(&l->lck, LCK_ADAPTIVE, _kse_lock_wait, 165173967Sjasone _kse_lock_wakeup, calloc); 166149578Sdeischen l->owner = NULL; 167149578Sdeischen l->count = 0; 168149578Sdeischen l->write = 0; 169149578Sdeischen } 170116975Sdavidxu return (l); 171116975Sdavidxu} 172116975Sdavidxu 173116975Sdavidxustatic void 174174112Sdeischen_thr_rtld_lock_destroy(void *lock __unused) 175116975Sdavidxu{ 176118745Sdavidxu /* XXX We really can not free memory after a fork() */ 177118745Sdavidxu#if 0 178122131Sdeischen struct rtld_kse_lock *l; 179122131Sdeischen 180122131Sdeischen l = (struct rtld_kse_lock *)lock; 181116975Sdavidxu _lock_destroy(&l->lck); 182116975Sdavidxu free(l); 183118745Sdavidxu#endif 184118745Sdavidxu return; 185116975Sdavidxu} 186116975Sdavidxu 187116975Sdavidxustatic void 188116975Sdavidxu_thr_rtld_rlock_acquire(void *lock) 189116975Sdavidxu{ 190122131Sdeischen struct rtld_kse_lock *l; 191116975Sdavidxu kse_critical_t crit; 192118745Sdavidxu struct kse *curkse; 193116975Sdavidxu 194122131Sdeischen l = (struct rtld_kse_lock *)lock; 195116975Sdavidxu crit = _kse_critical_enter(); 196118745Sdavidxu curkse = _get_curkse(); 197118745Sdavidxu if (l->owner == curkse) { 198118745Sdavidxu l->count++; 199118745Sdavidxu _kse_critical_leave(crit); /* probably not necessary */ 200118745Sdavidxu } else { 201118745Sdavidxu KSE_LOCK_ACQUIRE(curkse, &l->lck); 202118745Sdavidxu l->crit = crit; 203118745Sdavidxu l->owner = curkse; 204118745Sdavidxu l->count = 1; 205118745Sdavidxu l->write = 0; 206118745Sdavidxu } 207116975Sdavidxu} 208116975Sdavidxu 209116975Sdavidxustatic void 210116975Sdavidxu_thr_rtld_wlock_acquire(void *lock) 211116975Sdavidxu{ 212122131Sdeischen struct rtld_kse_lock *l; 213116975Sdavidxu kse_critical_t crit; 214118745Sdavidxu struct kse *curkse; 215116975Sdavidxu 216122131Sdeischen l = (struct rtld_kse_lock *)lock; 217116975Sdavidxu crit = _kse_critical_enter(); 218118745Sdavidxu curkse = _get_curkse(); 219118745Sdavidxu if (l->owner == curkse) { 220118745Sdavidxu _kse_critical_leave(crit); 221118745Sdavidxu PANIC("Recursive write lock attempt on rtld lock"); 222118745Sdavidxu } else { 223118745Sdavidxu KSE_LOCK_ACQUIRE(curkse, &l->lck); 224118745Sdavidxu l->crit = crit; 225118745Sdavidxu l->owner = curkse; 226118745Sdavidxu l->count = 1; 227118745Sdavidxu l->write = 1; 228118745Sdavidxu } 229116975Sdavidxu} 230116975Sdavidxu 231116975Sdavidxustatic void 232116975Sdavidxu_thr_rtld_lock_release(void *lock) 233116975Sdavidxu{ 234122131Sdeischen struct rtld_kse_lock *l; 235118745Sdavidxu kse_critical_t crit; 236118745Sdavidxu struct kse *curkse; 237116975Sdavidxu 238122131Sdeischen l = (struct rtld_kse_lock *)lock; 239118745Sdavidxu crit = _kse_critical_enter(); 240118745Sdavidxu curkse = _get_curkse(); 241118745Sdavidxu if (l->owner != curkse) { 242118745Sdavidxu /* 243118745Sdavidxu * We might want to forcibly unlock the rtld lock 244118745Sdavidxu * and/or disable threaded mode so there is better 245118745Sdavidxu * chance that the panic will work. Otherwise, 246118745Sdavidxu * we could end up trying to take the rtld lock 247118745Sdavidxu * again. 248118745Sdavidxu */ 249118745Sdavidxu _kse_critical_leave(crit); 250118745Sdavidxu PANIC("Attempt to unlock rtld lock when not owner."); 251118745Sdavidxu } else { 252118745Sdavidxu l->count--; 253118745Sdavidxu if (l->count == 0) { 254118745Sdavidxu /* 255118745Sdavidxu * If there ever is a count associated with 256118745Sdavidxu * _kse_critical_leave(), we'll need to add 257118745Sdavidxu * another call to it here with the crit 258118745Sdavidxu * value from above. 259118745Sdavidxu */ 260118745Sdavidxu crit = l->crit; 261118745Sdavidxu l->owner = NULL; 262118745Sdavidxu l->write = 0; 263118745Sdavidxu KSE_LOCK_RELEASE(curkse, &l->lck); 264118745Sdavidxu } 265118745Sdavidxu _kse_critical_leave(crit); 266118745Sdavidxu } 267116975Sdavidxu} 268116975Sdavidxu 269116975Sdavidxu 270116975Sdavidxustatic int 271174112Sdeischen_thr_rtld_set_flag(int mask __unused) 272116975Sdavidxu{ 273116975Sdavidxu return (0); 274116975Sdavidxu} 275116975Sdavidxu 276116975Sdavidxustatic int 277174112Sdeischen_thr_rtld_clr_flag(int mask __unused) 278116975Sdavidxu{ 279116975Sdavidxu return (0); 280116975Sdavidxu} 281116975Sdavidxu 282116975Sdavidxuvoid 283122072Sdeischen_thr_rtld_init(void) 284116975Sdavidxu{ 285116975Sdavidxu struct RtldLockInfo li; 286122072Sdeischen 287122131Sdeischen li.lock_create = _thr_rtld_lock_create; 288122131Sdeischen li.lock_destroy = _thr_rtld_lock_destroy; 289122131Sdeischen li.rlock_acquire = _thr_rtld_rlock_acquire; 290122131Sdeischen li.wlock_acquire = _thr_rtld_wlock_acquire; 291122131Sdeischen li.lock_release = _thr_rtld_lock_release; 292122131Sdeischen li.thread_set_flag = _thr_rtld_set_flag; 293122131Sdeischen li.thread_clr_flag = _thr_rtld_clr_flag; 294122131Sdeischen li.at_fork = NULL; 295116975Sdavidxu _rtld_thread_init(&li); 296116975Sdavidxu} 297116975Sdavidxu 298116975Sdavidxuvoid 299122072Sdeischen_thr_rtld_fini(void) 300116975Sdavidxu{ 301116975Sdavidxu _rtld_thread_init(NULL); 302116975Sdavidxu} 303