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