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