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