thr_rtld.c revision 211833
1142425Snectar/* 2160814Ssimon * Copyright (c) 2006, David Xu <davidxu@freebsd.org> 3142425Snectar * All rights reserved. 4142425Snectar * 5142425Snectar * Redistribution and use in source and binary forms, with or without 6142425Snectar * modification, are permitted provided that the following conditions 7142425Snectar * are met: 8142425Snectar * 1. Redistributions of source code must retain the above copyright 9142425Snectar * notice unmodified, this list of conditions, and the following 10142425Snectar * disclaimer. 11142425Snectar * 2. Redistributions in binary form must reproduce the above copyright 12142425Snectar * notice, this list of conditions and the following disclaimer in the 13142425Snectar * documentation and/or other materials provided with the distribution. 14142425Snectar * 15142425Snectar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16142425Snectar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17142425Snectar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18142425Snectar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19142425Snectar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20142425Snectar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21142425Snectar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22142425Snectar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23142425Snectar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24142425Snectar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25238405Sjkim * 26142425Snectar * $FreeBSD: head/lib/libthr/thread/thr_rtld.c 211833 2010-08-26 07:09:48Z davidxu $ 27142425Snectar * 28238405Sjkim */ 29142425Snectar 30238405Sjkim /* 31238405Sjkim * A lockless rwlock for rtld. 32142425Snectar */ 33142425Snectar#include <sys/cdefs.h> 34142425Snectar#include <stdlib.h> 35142425Snectar 36142425Snectar#include "rtld_lock.h" 37142425Snectar#include "thr_private.h" 38238405Sjkim 39142425Snectar#undef errno 40142425Snectarextern int errno; 41238405Sjkim 42142425Snectarstatic int _thr_rtld_clr_flag(int); 43238405Sjkimstatic void *_thr_rtld_lock_create(void); 44238405Sjkimstatic void _thr_rtld_lock_destroy(void *); 45142425Snectarstatic void _thr_rtld_lock_release(void *); 46142425Snectarstatic void _thr_rtld_rlock_acquire(void *); 47142425Snectarstatic int _thr_rtld_set_flag(int); 48142425Snectarstatic void _thr_rtld_wlock_acquire(void *); 49142425Snectar 50238405Sjkimstruct rtld_lock { 51142425Snectar struct urwlock lock; 52142425Snectar char _pad[CACHE_LINE_SIZE - sizeof(struct urwlock)]; 53142425Snectar}; 54142425Snectar 55142425Snectarstatic struct rtld_lock lock_place[MAX_RTLD_LOCKS] __aligned(CACHE_LINE_SIZE); 56142425Snectarstatic int busy_places; 57142425Snectar 58142425Snectarstatic void * 59142425Snectar_thr_rtld_lock_create(void) 60142425Snectar{ 61142425Snectar int locki; 62142425Snectar struct rtld_lock *l; 63142425Snectar static const char fail[] = "_thr_rtld_lock_create failed\n"; 64142425Snectar 65142425Snectar for (locki = 0; locki < MAX_RTLD_LOCKS; locki++) { 66142425Snectar if ((busy_places & (1 << locki)) == 0) 67142425Snectar break; 68238405Sjkim } 69142425Snectar if (locki == MAX_RTLD_LOCKS) { 70142425Snectar write(2, fail, sizeof(fail) - 1); 71142425Snectar return (NULL); 72142425Snectar } 73142425Snectar busy_places |= (1 << locki); 74142425Snectar 75142425Snectar l = &lock_place[locki]; 76142425Snectar l->lock.rw_flags = URWLOCK_PREFER_READER; 77142425Snectar return (l); 78142425Snectar} 79142425Snectar 80142425Snectarstatic void 81160814Ssimon_thr_rtld_lock_destroy(void *lock) 82160814Ssimon{ 83142425Snectar int locki; 84142425Snectar 85142425Snectar locki = (struct rtld_lock *)lock - &lock_place[0]; 86142425Snectar busy_places &= ~(1 << locki); 87142425Snectar} 88142425Snectar 89142425Snectar#define SAVE_ERRNO() { \ 90142425Snectar if (curthread != _thr_initial) \ 91142425Snectar errsave = curthread->error; \ 92142425Snectar else \ 93142425Snectar errsave = errno; \ 94142425Snectar} 95142425Snectar 96142425Snectar#define RESTORE_ERRNO() { \ 97160814Ssimon if (curthread != _thr_initial) \ 98142425Snectar curthread->error = errsave; \ 99142425Snectar else \ 100142425Snectar errno = errsave; \ 101142425Snectar} 102142425Snectar 103142425Snectarstatic void 104142425Snectar_thr_rtld_rlock_acquire(void *lock) 105142425Snectar{ 106142425Snectar struct pthread *curthread; 107142425Snectar struct rtld_lock *l; 108142425Snectar int errsave; 109142425Snectar 110142425Snectar curthread = _get_curthread(); 111160814Ssimon SAVE_ERRNO(); 112160814Ssimon l = (struct rtld_lock *)lock; 113160814Ssimon 114160814Ssimon THR_CRITICAL_ENTER(curthread); 115142425Snectar while (_thr_rwlock_rdlock(&l->lock, 0, NULL) != 0) 116142425Snectar ; 117142425Snectar curthread->rdlock_count++; 118142425Snectar RESTORE_ERRNO(); 119142425Snectar} 120160814Ssimon 121160814Ssimonstatic void 122160814Ssimon_thr_rtld_wlock_acquire(void *lock) 123160814Ssimon{ 124160814Ssimon struct pthread *curthread; 125160814Ssimon struct rtld_lock *l; 126142425Snectar int errsave; 127160814Ssimon 128160814Ssimon curthread = _get_curthread(); 129160814Ssimon SAVE_ERRNO(); 130160814Ssimon l = (struct rtld_lock *)lock; 131160814Ssimon 132160814Ssimon _thr_signal_block(curthread); 133160814Ssimon while (_thr_rwlock_wrlock(&l->lock, NULL) != 0) 134142425Snectar ; 135142425Snectar RESTORE_ERRNO(); 136160814Ssimon} 137160814Ssimon 138160814Ssimonstatic void 139142425Snectar_thr_rtld_lock_release(void *lock) 140142425Snectar{ 141142425Snectar struct pthread *curthread; 142160814Ssimon struct rtld_lock *l; 143160814Ssimon int32_t state; 144160814Ssimon int errsave; 145160814Ssimon 146160814Ssimon curthread = _get_curthread(); 147238405Sjkim SAVE_ERRNO(); 148238405Sjkim l = (struct rtld_lock *)lock; 149238405Sjkim 150142425Snectar state = l->lock.rw_state; 151160814Ssimon if (_thr_rwlock_unlock(&l->lock) == 0) { 152160814Ssimon if ((state & URWLOCK_WRITE_OWNER) == 0) { 153160814Ssimon curthread->rdlock_count--; 154160814Ssimon THR_CRITICAL_LEAVE(curthread); 155142425Snectar } else { 156160814Ssimon _thr_signal_unblock(curthread); 157160814Ssimon } 158160814Ssimon } 159160814Ssimon RESTORE_ERRNO(); 160160814Ssimon} 161160814Ssimon 162142425Snectarstatic int 163142425Snectar_thr_rtld_set_flag(int mask __unused) 164142425Snectar{ 165142425Snectar /* 166142425Snectar * The caller's code in rtld-elf is broken, it is not signal safe, 167142425Snectar * just return zero to fool it. 168142425Snectar */ 169142425Snectar return (0); 170142425Snectar} 171160814Ssimon 172160814Ssimonstatic int 173160814Ssimon_thr_rtld_clr_flag(int mask __unused) 174160814Ssimon{ 175160814Ssimon return (0); 176160814Ssimon} 177160814Ssimon 178142425Snectarvoid 179160814Ssimon_thr_rtld_init(void) 180160814Ssimon{ 181160814Ssimon struct RtldLockInfo li; 182160814Ssimon struct pthread *curthread; 183142425Snectar long dummy = -1; 184142425Snectar 185142425Snectar curthread = _get_curthread(); 186142425Snectar 187142425Snectar /* force to resolve _umtx_op PLT */ 188142425Snectar _umtx_op_err((struct umtx *)&dummy, UMTX_OP_WAKE, 1, 0, 0); 189142425Snectar 190142425Snectar /* force to resolve errno() PLT */ 191142425Snectar __error(); 192142425Snectar 193142425Snectar li.lock_create = _thr_rtld_lock_create; 194142425Snectar li.lock_destroy = _thr_rtld_lock_destroy; 195160814Ssimon li.rlock_acquire = _thr_rtld_rlock_acquire; 196160814Ssimon li.wlock_acquire = _thr_rtld_wlock_acquire; 197160814Ssimon li.lock_release = _thr_rtld_lock_release; 198160814Ssimon li.thread_set_flag = _thr_rtld_set_flag; 199160814Ssimon li.thread_clr_flag = _thr_rtld_clr_flag; 200160814Ssimon li.at_fork = NULL; 201160814Ssimon 202142425Snectar /* mask signals, also force to resolve __sys_sigprocmask PLT */ 203194206Ssimon _thr_signal_block(curthread); 204194206Ssimon _rtld_thread_init(&li); 205194206Ssimon _thr_signal_unblock(curthread); 206194206Ssimon} 207194206Ssimon 208142425Snectarvoid 209142425Snectar_thr_rtld_fini(void) 210142425Snectar{ 211142425Snectar struct pthread *curthread; 212160814Ssimon 213160814Ssimon curthread = _get_curthread(); 214160814Ssimon _thr_signal_block(curthread); 215160814Ssimon _rtld_thread_init(NULL); 216160814Ssimon _thr_signal_unblock(curthread); 217160814Ssimon} 218160814Ssimon