xref: /titanic_51/usr/src/lib/libnisdb/nisdb_rw.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 by Sun Microsystems, Inc.
24*7c478bd9Sstevel@tonic-gate  * All rights reserved.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <rpc/types.h>
31*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
32*7c478bd9Sstevel@tonic-gate #include "db_dictionary_c.h"
33*7c478bd9Sstevel@tonic-gate #include "nisdb_rw.h"
34*7c478bd9Sstevel@tonic-gate #include "nisdb_ldap.h"
35*7c478bd9Sstevel@tonic-gate 
36*7c478bd9Sstevel@tonic-gate /*
37*7c478bd9Sstevel@tonic-gate  * Nesting-safe RW locking functions. Return 0 when successful, an
38*7c478bd9Sstevel@tonic-gate  * error number from the E-series when not.
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate int
42*7c478bd9Sstevel@tonic-gate __nisdb_rwinit(__nisdb_rwlock_t *rw) {
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate 	int	ret;
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
47*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
48*7c478bd9Sstevel@tonic-gate 		abort();
49*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
50*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
51*7c478bd9Sstevel@tonic-gate 	}
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_init(&rw->mutex, USYNC_THREAD, 0)) != 0)
54*7c478bd9Sstevel@tonic-gate 		return (ret);
55*7c478bd9Sstevel@tonic-gate 	if ((ret = cond_init(&rw->cv, USYNC_THREAD, 0)) != 0)
56*7c478bd9Sstevel@tonic-gate 		return (ret);
57*7c478bd9Sstevel@tonic-gate 	rw->destroyed = 0;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 	/*
60*7c478bd9Sstevel@tonic-gate 	 * If we allow read-to-write lock migration, there's a potential
61*7c478bd9Sstevel@tonic-gate 	 * race condition if two or more threads want to upgrade at the
62*7c478bd9Sstevel@tonic-gate 	 * same time. The simple and safe (but crude and possibly costly)
63*7c478bd9Sstevel@tonic-gate 	 * method to fix this is to always use exclusive locks, and so
64*7c478bd9Sstevel@tonic-gate 	 * that has to be the default.
65*7c478bd9Sstevel@tonic-gate 	 *
66*7c478bd9Sstevel@tonic-gate 	 * There are two conditions under which it is safe to set
67*7c478bd9Sstevel@tonic-gate 	 * 'force_write' to zero for a certain lock structure:
68*7c478bd9Sstevel@tonic-gate 	 *
69*7c478bd9Sstevel@tonic-gate 	 * (1)	The lock will never be subject to migration, or
70*7c478bd9Sstevel@tonic-gate 	 *
71*7c478bd9Sstevel@tonic-gate 	 * (2)	It's OK if the data protected by the lock has changed
72*7c478bd9Sstevel@tonic-gate 	 *	(a)	Every time the lock (read or write) has been
73*7c478bd9Sstevel@tonic-gate 	 *		acquired (even if the lock already was held by
74*7c478bd9Sstevel@tonic-gate 	 *		the thread), and
75*7c478bd9Sstevel@tonic-gate 	 *	(b)	After every call to a function that might have
76*7c478bd9Sstevel@tonic-gate 	 *		acquired the lock.
77*7c478bd9Sstevel@tonic-gate 	 */
78*7c478bd9Sstevel@tonic-gate 	rw->force_write = NISDB_FORCE_WRITE;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate 	rw->writer_count = rw->reader_count = rw->reader_blocked = 0;
81*7c478bd9Sstevel@tonic-gate 	rw->writer.id = rw->reader.id = INV_PTHREAD_ID;
82*7c478bd9Sstevel@tonic-gate 	rw->writer.count = rw->reader.count = 0;
83*7c478bd9Sstevel@tonic-gate 	rw->writer.next = rw->reader.next = 0;
84*7c478bd9Sstevel@tonic-gate 
85*7c478bd9Sstevel@tonic-gate 	return (0);
86*7c478bd9Sstevel@tonic-gate }
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate 
89*7c478bd9Sstevel@tonic-gate static __nisdb_rl_t *
90*7c478bd9Sstevel@tonic-gate find_reader(pthread_t id, __nisdb_rwlock_t *rw) {
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate 	for (rr = &rw->reader; rr != 0; rr = rr->next) {
95*7c478bd9Sstevel@tonic-gate 		if (rr->id == INV_PTHREAD_ID) {
96*7c478bd9Sstevel@tonic-gate 			rr = 0;
97*7c478bd9Sstevel@tonic-gate 			break;
98*7c478bd9Sstevel@tonic-gate 		}
99*7c478bd9Sstevel@tonic-gate 		if (rr->id == id)
100*7c478bd9Sstevel@tonic-gate 			break;
101*7c478bd9Sstevel@tonic-gate 	}
102*7c478bd9Sstevel@tonic-gate 
103*7c478bd9Sstevel@tonic-gate 	return (rr);
104*7c478bd9Sstevel@tonic-gate }
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate int
108*7c478bd9Sstevel@tonic-gate __nisdb_rw_readlock_ok(__nisdb_rwlock_t *rw) {
109*7c478bd9Sstevel@tonic-gate 	int		ret;
110*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
111*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if (rw == 0)
114*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
117*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
120*7c478bd9Sstevel@tonic-gate 		return (ret);
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate 	/*
123*7c478bd9Sstevel@tonic-gate 	 * Only allow changing 'force_write' when it's really safe; i.e.,
124*7c478bd9Sstevel@tonic-gate 	 * the lock hasn't been destroyed, and there are no readers.
125*7c478bd9Sstevel@tonic-gate 	 */
126*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed == 0 && rw->reader_count == 0) {
127*7c478bd9Sstevel@tonic-gate 		rw->force_write = 0;
128*7c478bd9Sstevel@tonic-gate 		ret = 0;
129*7c478bd9Sstevel@tonic-gate 	} else {
130*7c478bd9Sstevel@tonic-gate 		ret = EBUSY;
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&rw->mutex);
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	return (ret);
136*7c478bd9Sstevel@tonic-gate }
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate int
140*7c478bd9Sstevel@tonic-gate __nisdb_rw_force_writelock(__nisdb_rwlock_t *rw) {
141*7c478bd9Sstevel@tonic-gate 	int		ret;
142*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
143*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	if (rw == 0 || rw->destroyed != 0)
146*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
149*7c478bd9Sstevel@tonic-gate 		return (ret);
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate 	/*
152*7c478bd9Sstevel@tonic-gate 	 * Only allow changing 'force_write' when it's really safe; i.e.,
153*7c478bd9Sstevel@tonic-gate 	 * the lock hasn't been destroyed, and there are no readers.
154*7c478bd9Sstevel@tonic-gate 	 */
155*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed == 0 && rw->reader_count == 0) {
156*7c478bd9Sstevel@tonic-gate 		rw->force_write = 1;
157*7c478bd9Sstevel@tonic-gate 		ret = 0;
158*7c478bd9Sstevel@tonic-gate 	} else {
159*7c478bd9Sstevel@tonic-gate 		ret = EBUSY;
160*7c478bd9Sstevel@tonic-gate 	}
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&rw->mutex);
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	return (ret);
165*7c478bd9Sstevel@tonic-gate }
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 
168*7c478bd9Sstevel@tonic-gate int
169*7c478bd9Sstevel@tonic-gate __nisdb_wlock_trylock(__nisdb_rwlock_t *rw, int trylock) {
170*7c478bd9Sstevel@tonic-gate 
171*7c478bd9Sstevel@tonic-gate 	int		ret;
172*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
173*7c478bd9Sstevel@tonic-gate 	int		all_readers_blocked = 0;
174*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr = 0;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
177*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
178*7c478bd9Sstevel@tonic-gate 		/* This shouldn't happen */
179*7c478bd9Sstevel@tonic-gate 		abort();
180*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
181*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
182*7c478bd9Sstevel@tonic-gate 	}
183*7c478bd9Sstevel@tonic-gate 
184*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
185*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
188*7c478bd9Sstevel@tonic-gate 		return (ret);
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
191*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
192*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
193*7c478bd9Sstevel@tonic-gate 	}
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	/* Simplest (and probably most common) case: no readers or writers */
196*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count == 0 && rw->writer_count == 0) {
197*7c478bd9Sstevel@tonic-gate 		rw->writer_count = 1;
198*7c478bd9Sstevel@tonic-gate 		rw->writer.id = myself;
199*7c478bd9Sstevel@tonic-gate 		rw->writer.count = 1;
200*7c478bd9Sstevel@tonic-gate 		return (mutex_unlock(&rw->mutex));
201*7c478bd9Sstevel@tonic-gate 	}
202*7c478bd9Sstevel@tonic-gate 
203*7c478bd9Sstevel@tonic-gate 	/*
204*7c478bd9Sstevel@tonic-gate 	 * Need to know if we're holding a read lock already, and if
205*7c478bd9Sstevel@tonic-gate 	 * all other readers are blocked waiting for the mutex.
206*7c478bd9Sstevel@tonic-gate 	 */
207*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count > 0) {
208*7c478bd9Sstevel@tonic-gate 		if ((rr = find_reader(myself, rw)) != 0) {
209*7c478bd9Sstevel@tonic-gate 			if (rr->count)
210*7c478bd9Sstevel@tonic-gate 				/*
211*7c478bd9Sstevel@tonic-gate 				 * We're already holding a read lock, so
212*7c478bd9Sstevel@tonic-gate 				 * if the number of readers equals the number
213*7c478bd9Sstevel@tonic-gate 				 * of blocked readers plus one, all other
214*7c478bd9Sstevel@tonic-gate 				 * readers are blocked.
215*7c478bd9Sstevel@tonic-gate 				 */
216*7c478bd9Sstevel@tonic-gate 				if (rw->reader_count ==
217*7c478bd9Sstevel@tonic-gate 						(rw->reader_blocked + 1))
218*7c478bd9Sstevel@tonic-gate 					all_readers_blocked = 1;
219*7c478bd9Sstevel@tonic-gate 			else
220*7c478bd9Sstevel@tonic-gate 				/*
221*7c478bd9Sstevel@tonic-gate 				 * We're not holding a read lock, so the
222*7c478bd9Sstevel@tonic-gate 				 * number of readers should equal the number
223*7c478bd9Sstevel@tonic-gate 				 * of blocked readers if all readers are
224*7c478bd9Sstevel@tonic-gate 				 * blocked.
225*7c478bd9Sstevel@tonic-gate 				 */
226*7c478bd9Sstevel@tonic-gate 				if (rw->reader_count == rw->reader_blocked)
227*7c478bd9Sstevel@tonic-gate 					all_readers_blocked = 1;
228*7c478bd9Sstevel@tonic-gate 		}
229*7c478bd9Sstevel@tonic-gate 	}
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/* Wait for reader(s) or writer to finish */
232*7c478bd9Sstevel@tonic-gate 	while (1) {
233*7c478bd9Sstevel@tonic-gate 		/*
234*7c478bd9Sstevel@tonic-gate 		 * We can stop looping if one of the following holds:
235*7c478bd9Sstevel@tonic-gate 		 *	- No readers, no writers
236*7c478bd9Sstevel@tonic-gate 		 *	- No writers (or writer is myself), and one of:
237*7c478bd9Sstevel@tonic-gate 		 *		- No readers
238*7c478bd9Sstevel@tonic-gate 		 *		- One reader, and it's us
239*7c478bd9Sstevel@tonic-gate 		 *		- N readers, but all blocked on the mutex
240*7c478bd9Sstevel@tonic-gate 		 */
241*7c478bd9Sstevel@tonic-gate 		if (
242*7c478bd9Sstevel@tonic-gate 			(rw->writer_count == 0 && rw->reader_count == 0) ||
243*7c478bd9Sstevel@tonic-gate 			((rw->writer_count == 0 || rw->writer.id == myself) &&
244*7c478bd9Sstevel@tonic-gate 				(rw->reader_count == 0) ||
245*7c478bd9Sstevel@tonic-gate 				(rw->reader_count == 1 &&
246*7c478bd9Sstevel@tonic-gate 					rw->reader.id == myself))) {
247*7c478bd9Sstevel@tonic-gate 			break;
248*7c478bd9Sstevel@tonic-gate 		}
249*7c478bd9Sstevel@tonic-gate 		/*
250*7c478bd9Sstevel@tonic-gate 		 * Provided that all readers are blocked on the mutex
251*7c478bd9Sstevel@tonic-gate 		 * we break a potential dead-lock by acquiring the
252*7c478bd9Sstevel@tonic-gate 		 * write lock.
253*7c478bd9Sstevel@tonic-gate 		 */
254*7c478bd9Sstevel@tonic-gate 		if (all_readers_blocked) {
255*7c478bd9Sstevel@tonic-gate 			if (rw->writer_count == 0 || rw->writer.id == myself) {
256*7c478bd9Sstevel@tonic-gate 				break;
257*7c478bd9Sstevel@tonic-gate 			}
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 
260*7c478bd9Sstevel@tonic-gate 		/*
261*7c478bd9Sstevel@tonic-gate 		 * If 'trylock' is set, tell the caller that we'd have to
262*7c478bd9Sstevel@tonic-gate 		 * block to obtain the lock.
263*7c478bd9Sstevel@tonic-gate 		 */
264*7c478bd9Sstevel@tonic-gate 		if (trylock) {
265*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rw->mutex);
266*7c478bd9Sstevel@tonic-gate 			return (EBUSY);
267*7c478bd9Sstevel@tonic-gate 		}
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 		/* If we're also a reader, indicate that we're blocking */
270*7c478bd9Sstevel@tonic-gate 		if (rr != 0) {
271*7c478bd9Sstevel@tonic-gate 			rr->wait = 1;
272*7c478bd9Sstevel@tonic-gate 			rw->reader_blocked++;
273*7c478bd9Sstevel@tonic-gate 		}
274*7c478bd9Sstevel@tonic-gate 		if ((ret = cond_wait(&rw->cv, &rw->mutex)) != 0) {
275*7c478bd9Sstevel@tonic-gate 			if (rr != 0) {
276*7c478bd9Sstevel@tonic-gate 				rr->wait = 0;
277*7c478bd9Sstevel@tonic-gate 				if (rw->reader_blocked > 0)
278*7c478bd9Sstevel@tonic-gate 					rw->reader_blocked--;
279*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
280*7c478bd9Sstevel@tonic-gate 				else
281*7c478bd9Sstevel@tonic-gate 					abort();
282*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
283*7c478bd9Sstevel@tonic-gate 			}
284*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rw->mutex);
285*7c478bd9Sstevel@tonic-gate 			return (ret);
286*7c478bd9Sstevel@tonic-gate 		}
287*7c478bd9Sstevel@tonic-gate 		if (rr != 0) {
288*7c478bd9Sstevel@tonic-gate 			rr->wait = 0;
289*7c478bd9Sstevel@tonic-gate 			if (rw->reader_blocked > 0)
290*7c478bd9Sstevel@tonic-gate 				rw->reader_blocked--;
291*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
292*7c478bd9Sstevel@tonic-gate 			else
293*7c478bd9Sstevel@tonic-gate 				abort();
294*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
295*7c478bd9Sstevel@tonic-gate 		}
296*7c478bd9Sstevel@tonic-gate 	}
297*7c478bd9Sstevel@tonic-gate 
298*7c478bd9Sstevel@tonic-gate 	/* OK to grab the write lock */
299*7c478bd9Sstevel@tonic-gate 	rw->writer.id = myself;
300*7c478bd9Sstevel@tonic-gate 	/* Increment lock depth */
301*7c478bd9Sstevel@tonic-gate 	rw->writer.count++;
302*7c478bd9Sstevel@tonic-gate 	/* Set number of writers (doesn't increase with lock depth) */
303*7c478bd9Sstevel@tonic-gate 	if (rw->writer_count == 0)
304*7c478bd9Sstevel@tonic-gate 		rw->writer_count = 1;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	return (mutex_unlock(&rw->mutex));
307*7c478bd9Sstevel@tonic-gate }
308*7c478bd9Sstevel@tonic-gate 
309*7c478bd9Sstevel@tonic-gate int
310*7c478bd9Sstevel@tonic-gate __nisdb_wlock(__nisdb_rwlock_t *rw) {
311*7c478bd9Sstevel@tonic-gate 	return (__nisdb_wlock_trylock(rw, 0));
312*7c478bd9Sstevel@tonic-gate }
313*7c478bd9Sstevel@tonic-gate 
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate static __nisdb_rl_t *
316*7c478bd9Sstevel@tonic-gate increment_reader(pthread_t id, __nisdb_rwlock_t *rw) {
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	for (rr = &rw->reader; rr != 0; rr = rr->next) {
321*7c478bd9Sstevel@tonic-gate 		if (rr->id == id || rr->id == INV_PTHREAD_ID)
322*7c478bd9Sstevel@tonic-gate 			break;
323*7c478bd9Sstevel@tonic-gate 	}
324*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count == 0 && rr == &rw->reader) {
325*7c478bd9Sstevel@tonic-gate 		/* No previous reader */
326*7c478bd9Sstevel@tonic-gate 		rr->id = id;
327*7c478bd9Sstevel@tonic-gate 		rw->reader_count = 1;
328*7c478bd9Sstevel@tonic-gate 	} else if (rr == 0) {
329*7c478bd9Sstevel@tonic-gate 		if ((rr = malloc(sizeof (__nisdb_rl_t))) == 0)
330*7c478bd9Sstevel@tonic-gate 			return (0);
331*7c478bd9Sstevel@tonic-gate 		rr->id = id;
332*7c478bd9Sstevel@tonic-gate 		rr->count = 0;
333*7c478bd9Sstevel@tonic-gate 		/*
334*7c478bd9Sstevel@tonic-gate 		 * For insertion simplicity, make it the second item
335*7c478bd9Sstevel@tonic-gate 		 * on the list.
336*7c478bd9Sstevel@tonic-gate 		 */
337*7c478bd9Sstevel@tonic-gate 		rr->next = rw->reader.next;
338*7c478bd9Sstevel@tonic-gate 		rw->reader.next = rr;
339*7c478bd9Sstevel@tonic-gate 		rw->reader_count++;
340*7c478bd9Sstevel@tonic-gate 	}
341*7c478bd9Sstevel@tonic-gate 	rr->count++;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	return (rr);
344*7c478bd9Sstevel@tonic-gate }
345*7c478bd9Sstevel@tonic-gate 
346*7c478bd9Sstevel@tonic-gate 
347*7c478bd9Sstevel@tonic-gate int
348*7c478bd9Sstevel@tonic-gate __nisdb_rlock(__nisdb_rwlock_t *rw) {
349*7c478bd9Sstevel@tonic-gate 
350*7c478bd9Sstevel@tonic-gate 	int		ret;
351*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
352*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
355*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
356*7c478bd9Sstevel@tonic-gate 		/* This shouldn't happen */
357*7c478bd9Sstevel@tonic-gate 		abort();
358*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
359*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
360*7c478bd9Sstevel@tonic-gate 	}
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
363*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	if (rw->force_write)
366*7c478bd9Sstevel@tonic-gate 		return (__nisdb_wlock(rw));
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
369*7c478bd9Sstevel@tonic-gate 		return (ret);
370*7c478bd9Sstevel@tonic-gate 
371*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
372*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
373*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
374*7c478bd9Sstevel@tonic-gate 	}
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate 	rr = find_reader(myself, rw);
377*7c478bd9Sstevel@tonic-gate 
378*7c478bd9Sstevel@tonic-gate 	/* Wait for writer to complete; writer == myself also OK */
379*7c478bd9Sstevel@tonic-gate 	while (rw->writer_count > 0 && rw->writer.id != myself) {
380*7c478bd9Sstevel@tonic-gate 		if (rr != 0) {
381*7c478bd9Sstevel@tonic-gate 			rr->wait = 1;
382*7c478bd9Sstevel@tonic-gate 			rw->reader_blocked++;
383*7c478bd9Sstevel@tonic-gate 		}
384*7c478bd9Sstevel@tonic-gate 		if ((ret = cond_wait(&rw->cv, &rw->mutex)) != 0) {
385*7c478bd9Sstevel@tonic-gate 			if (rr != 0) {
386*7c478bd9Sstevel@tonic-gate 				rr->wait = 0;
387*7c478bd9Sstevel@tonic-gate 				if (rw->reader_blocked > 0)
388*7c478bd9Sstevel@tonic-gate 					rw->reader_blocked--;
389*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
390*7c478bd9Sstevel@tonic-gate 				else
391*7c478bd9Sstevel@tonic-gate 					abort();
392*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
393*7c478bd9Sstevel@tonic-gate 			}
394*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rw->mutex);
395*7c478bd9Sstevel@tonic-gate 			return (ret);
396*7c478bd9Sstevel@tonic-gate 		}
397*7c478bd9Sstevel@tonic-gate 		if (rr != 0) {
398*7c478bd9Sstevel@tonic-gate 			rr->wait = 0;
399*7c478bd9Sstevel@tonic-gate 			if (rw->reader_blocked > 0)
400*7c478bd9Sstevel@tonic-gate 				rw->reader_blocked--;
401*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
402*7c478bd9Sstevel@tonic-gate 			else
403*7c478bd9Sstevel@tonic-gate 				abort();
404*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
405*7c478bd9Sstevel@tonic-gate 		}
406*7c478bd9Sstevel@tonic-gate 	}
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate 	rr = increment_reader(myself, rw);
409*7c478bd9Sstevel@tonic-gate 	ret = mutex_unlock(&rw->mutex);
410*7c478bd9Sstevel@tonic-gate 	return ((rr == 0) ? ENOMEM : ret);
411*7c478bd9Sstevel@tonic-gate }
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate int
415*7c478bd9Sstevel@tonic-gate __nisdb_wulock(__nisdb_rwlock_t *rw) {
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate 	int		ret;
418*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
421*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
422*7c478bd9Sstevel@tonic-gate 		/* This shouldn't happen */
423*7c478bd9Sstevel@tonic-gate 		abort();
424*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
425*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
426*7c478bd9Sstevel@tonic-gate 	}
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
429*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
430*7c478bd9Sstevel@tonic-gate 
431*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
432*7c478bd9Sstevel@tonic-gate 		return (ret);
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
435*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
436*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
437*7c478bd9Sstevel@tonic-gate 	}
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate 	/* Sanity check */
440*7c478bd9Sstevel@tonic-gate 	if (rw->writer_count == 0 ||
441*7c478bd9Sstevel@tonic-gate 		rw->writer.id != myself || rw->writer.count == 0) {
442*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
443*7c478bd9Sstevel@tonic-gate 		abort();
444*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
445*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
446*7c478bd9Sstevel@tonic-gate 		return (ENOLCK);
447*7c478bd9Sstevel@tonic-gate 	}
448*7c478bd9Sstevel@tonic-gate 
449*7c478bd9Sstevel@tonic-gate 	rw->writer.count--;
450*7c478bd9Sstevel@tonic-gate 	if (rw->writer.count == 0) {
451*7c478bd9Sstevel@tonic-gate 		rw->writer.id = INV_PTHREAD_ID;
452*7c478bd9Sstevel@tonic-gate 		rw->writer_count = 0;
453*7c478bd9Sstevel@tonic-gate 		if ((ret = cond_broadcast(&rw->cv)) != 0) {
454*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rw->mutex);
455*7c478bd9Sstevel@tonic-gate 			return (ret);
456*7c478bd9Sstevel@tonic-gate 		}
457*7c478bd9Sstevel@tonic-gate 	}
458*7c478bd9Sstevel@tonic-gate 
459*7c478bd9Sstevel@tonic-gate 	return (mutex_unlock(&rw->mutex));
460*7c478bd9Sstevel@tonic-gate }
461*7c478bd9Sstevel@tonic-gate 
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate int
464*7c478bd9Sstevel@tonic-gate __nisdb_rulock(__nisdb_rwlock_t *rw) {
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate 	int		ret;
467*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
468*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr, *prev;
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
471*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
472*7c478bd9Sstevel@tonic-gate 		abort();
473*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
474*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
475*7c478bd9Sstevel@tonic-gate 	}
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
478*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	if (rw->force_write)
481*7c478bd9Sstevel@tonic-gate 		return (__nisdb_wulock(rw));
482*7c478bd9Sstevel@tonic-gate 
483*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
484*7c478bd9Sstevel@tonic-gate 		return (ret);
485*7c478bd9Sstevel@tonic-gate 
486*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
487*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
488*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
489*7c478bd9Sstevel@tonic-gate 	}
490*7c478bd9Sstevel@tonic-gate 
491*7c478bd9Sstevel@tonic-gate 	/* Sanity check */
492*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count == 0 ||
493*7c478bd9Sstevel@tonic-gate 		(rw->writer_count > 0 && rw->writer.id != myself)) {
494*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
495*7c478bd9Sstevel@tonic-gate 		abort();
496*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
497*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
498*7c478bd9Sstevel@tonic-gate 		return (ENOLCK);
499*7c478bd9Sstevel@tonic-gate 	}
500*7c478bd9Sstevel@tonic-gate 
501*7c478bd9Sstevel@tonic-gate 	/* Find the reader record */
502*7c478bd9Sstevel@tonic-gate 	for (rr = &rw->reader, prev = 0; rr != 0; prev = rr, rr = rr->next) {
503*7c478bd9Sstevel@tonic-gate 		if (rr->id == myself)
504*7c478bd9Sstevel@tonic-gate 			break;
505*7c478bd9Sstevel@tonic-gate 	}
506*7c478bd9Sstevel@tonic-gate 
507*7c478bd9Sstevel@tonic-gate 	if (rr == 0 || rr->count == 0) {
508*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
509*7c478bd9Sstevel@tonic-gate 		abort();
510*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
511*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
512*7c478bd9Sstevel@tonic-gate 		return (ENOLCK);
513*7c478bd9Sstevel@tonic-gate 	}
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	rr->count--;
516*7c478bd9Sstevel@tonic-gate 	if (rr->count == 0) {
517*7c478bd9Sstevel@tonic-gate 		if (rr != &rw->reader) {
518*7c478bd9Sstevel@tonic-gate 			/* Remove item from list and free it */
519*7c478bd9Sstevel@tonic-gate 			prev->next = rr->next;
520*7c478bd9Sstevel@tonic-gate 			free(rr);
521*7c478bd9Sstevel@tonic-gate 		} else {
522*7c478bd9Sstevel@tonic-gate 			/*
523*7c478bd9Sstevel@tonic-gate 			 * First record: copy second to first, and free second
524*7c478bd9Sstevel@tonic-gate 			 * record.
525*7c478bd9Sstevel@tonic-gate 			 */
526*7c478bd9Sstevel@tonic-gate 			if (rr->next != 0) {
527*7c478bd9Sstevel@tonic-gate 				rr = rr->next;
528*7c478bd9Sstevel@tonic-gate 				rw->reader.id = rr->id;
529*7c478bd9Sstevel@tonic-gate 				rw->reader.count = rr->count;
530*7c478bd9Sstevel@tonic-gate 				rw->reader.next = rr->next;
531*7c478bd9Sstevel@tonic-gate 				free(rr);
532*7c478bd9Sstevel@tonic-gate 			} else {
533*7c478bd9Sstevel@tonic-gate 				/* Decomission the first record */
534*7c478bd9Sstevel@tonic-gate 				rr->id = INV_PTHREAD_ID;
535*7c478bd9Sstevel@tonic-gate 			}
536*7c478bd9Sstevel@tonic-gate 		}
537*7c478bd9Sstevel@tonic-gate 		rw->reader_count--;
538*7c478bd9Sstevel@tonic-gate 	}
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	/* If there are no readers, wake up any waiting writer */
541*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count == 0) {
542*7c478bd9Sstevel@tonic-gate 		if ((ret = cond_broadcast(&rw->cv)) != 0) {
543*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rw->mutex);
544*7c478bd9Sstevel@tonic-gate 			return (ret);
545*7c478bd9Sstevel@tonic-gate 		}
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	return (mutex_unlock(&rw->mutex));
549*7c478bd9Sstevel@tonic-gate }
550*7c478bd9Sstevel@tonic-gate 
551*7c478bd9Sstevel@tonic-gate 
552*7c478bd9Sstevel@tonic-gate /* Return zero if write lock held by this thread, non-zero otherwise */
553*7c478bd9Sstevel@tonic-gate int
554*7c478bd9Sstevel@tonic-gate __nisdb_assert_wheld(__nisdb_rwlock_t *rw) {
555*7c478bd9Sstevel@tonic-gate 
556*7c478bd9Sstevel@tonic-gate 	int	ret;
557*7c478bd9Sstevel@tonic-gate 
558*7c478bd9Sstevel@tonic-gate 
559*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
560*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
561*7c478bd9Sstevel@tonic-gate 		abort();
562*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
563*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
564*7c478bd9Sstevel@tonic-gate 	}
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
567*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
570*7c478bd9Sstevel@tonic-gate 		return (ret);
571*7c478bd9Sstevel@tonic-gate 
572*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
573*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
574*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
575*7c478bd9Sstevel@tonic-gate 	}
576*7c478bd9Sstevel@tonic-gate 
577*7c478bd9Sstevel@tonic-gate 	if (rw->writer_count == 0 || rw->writer.id != pthread_self()) {
578*7c478bd9Sstevel@tonic-gate 		ret = mutex_unlock(&rw->mutex);
579*7c478bd9Sstevel@tonic-gate 		return ((ret == 0) ? -1 : ret);
580*7c478bd9Sstevel@tonic-gate 	}
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate 	/*
583*7c478bd9Sstevel@tonic-gate 	 * We're holding the lock, so we should return zero. Since
584*7c478bd9Sstevel@tonic-gate 	 * that's what mutex_unlock() does if it succeeds, we just
585*7c478bd9Sstevel@tonic-gate 	 * return the value of mutex_unlock().
586*7c478bd9Sstevel@tonic-gate 	 */
587*7c478bd9Sstevel@tonic-gate 	return (mutex_unlock(&rw->mutex));
588*7c478bd9Sstevel@tonic-gate }
589*7c478bd9Sstevel@tonic-gate 
590*7c478bd9Sstevel@tonic-gate 
591*7c478bd9Sstevel@tonic-gate /* Return zero if read lock held by this thread, non-zero otherwise */
592*7c478bd9Sstevel@tonic-gate int
593*7c478bd9Sstevel@tonic-gate __nisdb_assert_rheld(__nisdb_rwlock_t *rw) {
594*7c478bd9Sstevel@tonic-gate 
595*7c478bd9Sstevel@tonic-gate 	int		ret;
596*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
597*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
601*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
602*7c478bd9Sstevel@tonic-gate 		abort();
603*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
604*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
605*7c478bd9Sstevel@tonic-gate 	}
606*7c478bd9Sstevel@tonic-gate 
607*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
608*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	if (rw->force_write)
611*7c478bd9Sstevel@tonic-gate 		return (__nisdb_assert_wheld(rw));
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
614*7c478bd9Sstevel@tonic-gate 		return (ret);
615*7c478bd9Sstevel@tonic-gate 
616*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
617*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
618*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
619*7c478bd9Sstevel@tonic-gate 	}
620*7c478bd9Sstevel@tonic-gate 
621*7c478bd9Sstevel@tonic-gate 	/* Write lock also OK */
622*7c478bd9Sstevel@tonic-gate 	if (rw->writer_count > 0 && rw->writer.id == myself) {
623*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
624*7c478bd9Sstevel@tonic-gate 		return (0);
625*7c478bd9Sstevel@tonic-gate 	}
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count == 0) {
628*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
629*7c478bd9Sstevel@tonic-gate 		return (EBUSY);
630*7c478bd9Sstevel@tonic-gate 	}
631*7c478bd9Sstevel@tonic-gate 
632*7c478bd9Sstevel@tonic-gate 	rr = &rw->reader;
633*7c478bd9Sstevel@tonic-gate 	do {
634*7c478bd9Sstevel@tonic-gate 		if (rr->id == myself) {
635*7c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&rw->mutex);
636*7c478bd9Sstevel@tonic-gate 			return (0);
637*7c478bd9Sstevel@tonic-gate 		}
638*7c478bd9Sstevel@tonic-gate 		rr = rr->next;
639*7c478bd9Sstevel@tonic-gate 	} while (rr != 0);
640*7c478bd9Sstevel@tonic-gate 
641*7c478bd9Sstevel@tonic-gate 	ret = mutex_unlock(&rw->mutex);
642*7c478bd9Sstevel@tonic-gate 	return ((ret == 0) ? EBUSY : ret);
643*7c478bd9Sstevel@tonic-gate }
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 
646*7c478bd9Sstevel@tonic-gate int
647*7c478bd9Sstevel@tonic-gate __nisdb_destroy_lock(__nisdb_rwlock_t *rw) {
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate 	int		ret;
650*7c478bd9Sstevel@tonic-gate 	pthread_t	myself = pthread_self();
651*7c478bd9Sstevel@tonic-gate 	__nisdb_rl_t	*rr;
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate 
654*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
655*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
656*7c478bd9Sstevel@tonic-gate 		abort();
657*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
658*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
659*7c478bd9Sstevel@tonic-gate 	}
660*7c478bd9Sstevel@tonic-gate 
661*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0)
662*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	if ((ret = mutex_lock(&rw->mutex)) != 0)
665*7c478bd9Sstevel@tonic-gate 		return (ret);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed != 0) {
668*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
669*7c478bd9Sstevel@tonic-gate 		return (ESHUTDOWN);
670*7c478bd9Sstevel@tonic-gate 	}
671*7c478bd9Sstevel@tonic-gate 
672*7c478bd9Sstevel@tonic-gate 	/*
673*7c478bd9Sstevel@tonic-gate 	 * Only proceed if if there are neither readers nor writers
674*7c478bd9Sstevel@tonic-gate 	 * other than this thread. Also, no nested locks may be in
675*7c478bd9Sstevel@tonic-gate 	 * effect.
676*7c478bd9Sstevel@tonic-gate 	 */
677*7c478bd9Sstevel@tonic-gate 	if ((rw->writer_count > 0 &&
678*7c478bd9Sstevel@tonic-gate 			(rw->writer.id != myself || rw->writer.count != 1) ||
679*7c478bd9Sstevel@tonic-gate 		(rw->reader_count > 0 &&
680*7c478bd9Sstevel@tonic-gate 			!(rw->reader_count == 1 && rw->reader.id == myself &&
681*7c478bd9Sstevel@tonic-gate 				rw->reader.count == 1))) ||
682*7c478bd9Sstevel@tonic-gate 		(rw->writer_count > 0 && rw->reader_count > 0)) {
683*7c478bd9Sstevel@tonic-gate #ifdef	NISDB_MT_DEBUG
684*7c478bd9Sstevel@tonic-gate 		abort();
685*7c478bd9Sstevel@tonic-gate #endif	/* NISDB_MT_DEBUG */
686*7c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&rw->mutex);
687*7c478bd9Sstevel@tonic-gate 		return (ENOLCK);
688*7c478bd9Sstevel@tonic-gate 	}
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 	/*
691*7c478bd9Sstevel@tonic-gate 	 * Mark lock destroyed, so that any thread waiting on the mutex
692*7c478bd9Sstevel@tonic-gate 	 * will know what's what. Of course, this is a bit iffy, since
693*7c478bd9Sstevel@tonic-gate 	 * we're probably being called from a destructor, and the structure
694*7c478bd9Sstevel@tonic-gate 	 * where we live will soon cease to exist (i.e., be freed and
695*7c478bd9Sstevel@tonic-gate 	 * perhaps re-used). Still, we can only do our best, and give
696*7c478bd9Sstevel@tonic-gate 	 * those other threads the best chance possible.
697*7c478bd9Sstevel@tonic-gate 	 */
698*7c478bd9Sstevel@tonic-gate 	rw->destroyed++;
699*7c478bd9Sstevel@tonic-gate 
700*7c478bd9Sstevel@tonic-gate 	return (mutex_unlock(&rw->mutex));
701*7c478bd9Sstevel@tonic-gate }
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate void
704*7c478bd9Sstevel@tonic-gate __nisdb_lock_report(__nisdb_rwlock_t *rw) {
705*7c478bd9Sstevel@tonic-gate 	char		*myself = "__nisdb_lock_report";
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	if (rw == 0) {
708*7c478bd9Sstevel@tonic-gate 		printf("%s: NULL argument\n", myself);
709*7c478bd9Sstevel@tonic-gate 		return;
710*7c478bd9Sstevel@tonic-gate 	}
711*7c478bd9Sstevel@tonic-gate 
712*7c478bd9Sstevel@tonic-gate 	if (rw->destroyed)
713*7c478bd9Sstevel@tonic-gate 		printf("0x%x: DESTROYED\n", rw);
714*7c478bd9Sstevel@tonic-gate 
715*7c478bd9Sstevel@tonic-gate 	printf("0x%x: Read locking %s\n",
716*7c478bd9Sstevel@tonic-gate 		rw, rw->force_write ? "disallowed" : "allowed");
717*7c478bd9Sstevel@tonic-gate 
718*7c478bd9Sstevel@tonic-gate 	if (rw->writer_count == 0)
719*7c478bd9Sstevel@tonic-gate 		printf("0x%x: No writer\n", rw);
720*7c478bd9Sstevel@tonic-gate 	else if (rw->writer_count == 1) {
721*7c478bd9Sstevel@tonic-gate 		printf("0x%x: Write locked by %d, depth = %d\n",
722*7c478bd9Sstevel@tonic-gate 			rw, rw->writer.id, rw->writer.count);
723*7c478bd9Sstevel@tonic-gate 		if (rw->writer.wait)
724*7c478bd9Sstevel@tonic-gate 			printf("0x%x:\tWriter blocked\n", rw);
725*7c478bd9Sstevel@tonic-gate 	} else
726*7c478bd9Sstevel@tonic-gate 		printf("0x%x: Invalid writer count = %d\n",
727*7c478bd9Sstevel@tonic-gate 			rw, rw->writer_count);
728*7c478bd9Sstevel@tonic-gate 
729*7c478bd9Sstevel@tonic-gate 	if (rw->reader_count == 0)
730*7c478bd9Sstevel@tonic-gate 		printf("0x%x: No readers\n", rw);
731*7c478bd9Sstevel@tonic-gate 	else {
732*7c478bd9Sstevel@tonic-gate 		__nisdb_rl_t	*r;
733*7c478bd9Sstevel@tonic-gate 
734*7c478bd9Sstevel@tonic-gate 		printf("0x%x: %d readers, %d blocked\n",
735*7c478bd9Sstevel@tonic-gate 			rw, rw->reader_count, rw->reader_blocked);
736*7c478bd9Sstevel@tonic-gate 		for (r = &rw->reader; r != 0; r = r->next) {
737*7c478bd9Sstevel@tonic-gate 			printf("0x%x:\tthread %d, depth = %d%s\n",
738*7c478bd9Sstevel@tonic-gate 				rw, r->id, r->count,
739*7c478bd9Sstevel@tonic-gate 				(r->wait ? " (blocked)" : ""));
740*7c478bd9Sstevel@tonic-gate 		}
741*7c478bd9Sstevel@tonic-gate 	}
742*7c478bd9Sstevel@tonic-gate }
743