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
__nisdb_rwinit(__nisdb_rwlock_t * rw)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 *
find_reader(pthread_t id,__nisdb_rwlock_t * rw)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
__nisdb_rw_readlock_ok(__nisdb_rwlock_t * rw)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
__nisdb_rw_force_writelock(__nisdb_rwlock_t * rw)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
__nisdb_wlock_trylock(__nisdb_rwlock_t * rw,int trylock)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
__nisdb_wlock(__nisdb_rwlock_t * rw)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 *
increment_reader(pthread_t id,__nisdb_rwlock_t * rw)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
__nisdb_rlock(__nisdb_rwlock_t * rw)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
__nisdb_wulock(__nisdb_rwlock_t * rw)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
__nisdb_rulock(__nisdb_rwlock_t * rw)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
__nisdb_assert_wheld(__nisdb_rwlock_t * rw)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
__nisdb_assert_rheld(__nisdb_rwlock_t * rw)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
__nisdb_destroy_lock(__nisdb_rwlock_t * rw)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
__nisdb_lock_report(__nisdb_rwlock_t * rw)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