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 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 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 <string.h> 30*7c478bd9Sstevel@tonic-gate #include <pthread.h> 31*7c478bd9Sstevel@tonic-gate #include <syslog.h> 32*7c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h> 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate #include "nis_hashitem.h" 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate /* We're the magician, so undefine the define-magic */ 37*7c478bd9Sstevel@tonic-gate #undef NIS_HASH_ITEM 38*7c478bd9Sstevel@tonic-gate #undef NIS_HASH_TABLE 39*7c478bd9Sstevel@tonic-gate #undef nis_insert_item 40*7c478bd9Sstevel@tonic-gate #undef nis_find_item 41*7c478bd9Sstevel@tonic-gate #undef nis_pop_item 42*7c478bd9Sstevel@tonic-gate #undef nis_remove_item 43*7c478bd9Sstevel@tonic-gate 44*7c478bd9Sstevel@tonic-gate #define set_thread_status(msg, state) 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* 47*7c478bd9Sstevel@tonic-gate * The hash table routines below implement nested (or recursive) 48*7c478bd9Sstevel@tonic-gate * one-writer-or-many-readers locking. The following restrictions 49*7c478bd9Sstevel@tonic-gate * exist: 50*7c478bd9Sstevel@tonic-gate * 51*7c478bd9Sstevel@tonic-gate * Unless an item destructor has been established, an item 52*7c478bd9Sstevel@tonic-gate * MUST NOT be removed from a list (__nis_pop_item_mt() or 53*7c478bd9Sstevel@tonic-gate * (__nis_remove_item_mt()) when the thread performing 54*7c478bd9Sstevel@tonic-gate * the deletion is holding a read-only lock on the item. 55*7c478bd9Sstevel@tonic-gate * Doing so will result in the thread blocking in 56*7c478bd9Sstevel@tonic-gate * pthread_cond_wait() waiting for itself to signal on 57*7c478bd9Sstevel@tonic-gate * the condition variable. Deletion when the invoking 58*7c478bd9Sstevel@tonic-gate * thread is holding a write lock (any level of nesting), 59*7c478bd9Sstevel@tonic-gate * or no lock, is OK. 60*7c478bd9Sstevel@tonic-gate */ 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate void 63*7c478bd9Sstevel@tonic-gate __nis_init_hash_table(__nis_hash_table_mt *table, 64*7c478bd9Sstevel@tonic-gate void (*itemDestructor)(void *)) { 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate if (table != 0) { 67*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&table->lock, 0); 68*7c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&table->cond, 0); 69*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&table->traverser_id_lock, 0); 70*7c478bd9Sstevel@tonic-gate table->traversed = 0; 71*7c478bd9Sstevel@tonic-gate table->locked_items = 0; 72*7c478bd9Sstevel@tonic-gate (void) memset(table->keys, 0, sizeof (table->keys)); 73*7c478bd9Sstevel@tonic-gate table->first = 0; 74*7c478bd9Sstevel@tonic-gate table->destroyItem = itemDestructor; 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate } 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate int 79*7c478bd9Sstevel@tonic-gate __nis_lock_hash_table(__nis_hash_table_mt *table, int traverse, char *msg) { 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate pthread_t myself = pthread_self(); 82*7c478bd9Sstevel@tonic-gate 83*7c478bd9Sstevel@tonic-gate if (table != 0) { 84*7c478bd9Sstevel@tonic-gate if (traverse) { 85*7c478bd9Sstevel@tonic-gate /* 86*7c478bd9Sstevel@tonic-gate * We want exclusive access to everything in the 87*7c478bd9Sstevel@tonic-gate * table (list). Wait until there are no threads 88*7c478bd9Sstevel@tonic-gate * either traversing the list, or with exclusive 89*7c478bd9Sstevel@tonic-gate * access to an item. 90*7c478bd9Sstevel@tonic-gate */ 91*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "table WL"); 92*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->lock); 93*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "table L"); 94*7c478bd9Sstevel@tonic-gate while ((table->traversed != 0 && 95*7c478bd9Sstevel@tonic-gate table->traverser_id != myself) || 96*7c478bd9Sstevel@tonic-gate table->locked_items != 0) { 97*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverse cond_wait"); 98*7c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, 99*7c478bd9Sstevel@tonic-gate "%d: lh table 0x%x trav cond wait", 100*7c478bd9Sstevel@tonic-gate myself, table)); 101*7c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&table->cond, 102*7c478bd9Sstevel@tonic-gate &table->lock); 103*7c478bd9Sstevel@tonic-gate } 104*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id WL"); 105*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->traverser_id_lock); 106*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 107*7c478bd9Sstevel@tonic-gate table->traversed = 1; 108*7c478bd9Sstevel@tonic-gate table->traverser_id = myself; 109*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->traverser_id_lock); 110*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 111*7c478bd9Sstevel@tonic-gate } else { 112*7c478bd9Sstevel@tonic-gate /* 113*7c478bd9Sstevel@tonic-gate * Called from the nis_*_item() functions. If no one's 114*7c478bd9Sstevel@tonic-gate * locked the table, lock it. If the table already is 115*7c478bd9Sstevel@tonic-gate * being traversed by us, do nothing. Otherwise, wait 116*7c478bd9Sstevel@tonic-gate * for the lock. 117*7c478bd9Sstevel@tonic-gate */ 118*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "non-traverse TL"); 119*7c478bd9Sstevel@tonic-gate if (pthread_mutex_trylock(&table->lock) == EBUSY) { 120*7c478bd9Sstevel@tonic-gate int dolock = 1; 121*7c478bd9Sstevel@tonic-gate /* Already locked; find out if it's us */ 122*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 123*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock( 124*7c478bd9Sstevel@tonic-gate &table->traverser_id_lock); 125*7c478bd9Sstevel@tonic-gate if (table->traversed != 0 && 126*7c478bd9Sstevel@tonic-gate table->traverser_id == myself) { 127*7c478bd9Sstevel@tonic-gate /* It's us. No action. */ 128*7c478bd9Sstevel@tonic-gate dolock = 0; 129*7c478bd9Sstevel@tonic-gate } 130*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock( 131*7c478bd9Sstevel@tonic-gate &table->traverser_id_lock); 132*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 133*7c478bd9Sstevel@tonic-gate /* Not us. Wait for the lock */ 134*7c478bd9Sstevel@tonic-gate if (dolock) { 135*7c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, 136*7c478bd9Sstevel@tonic-gate "%d: lh table 0x%x cond wait", 137*7c478bd9Sstevel@tonic-gate myself, table)); 138*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "table WL"); 139*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->lock); 140*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "table L"); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, "%d: lh table %s lock acquired 0x%x", 145*7c478bd9Sstevel@tonic-gate myself, traverse?"traverse":"non-traverse", table)); 146*7c478bd9Sstevel@tonic-gate return (1); 147*7c478bd9Sstevel@tonic-gate } else { 148*7c478bd9Sstevel@tonic-gate return (0); 149*7c478bd9Sstevel@tonic-gate } 150*7c478bd9Sstevel@tonic-gate } 151*7c478bd9Sstevel@tonic-gate 152*7c478bd9Sstevel@tonic-gate int 153*7c478bd9Sstevel@tonic-gate __nis_ulock_hash_table(__nis_hash_table_mt *table, int traverse, char *msg) { 154*7c478bd9Sstevel@tonic-gate 155*7c478bd9Sstevel@tonic-gate int dounlock = 0; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate if (table != 0) { 158*7c478bd9Sstevel@tonic-gate if (traverse) { 159*7c478bd9Sstevel@tonic-gate /* 160*7c478bd9Sstevel@tonic-gate * Since we're keeping track of who's traversing the 161*7c478bd9Sstevel@tonic-gate * table in order to avoid recursive locking in the 162*7c478bd9Sstevel@tonic-gate * nis_*item() functions, we might as well sanity check 163*7c478bd9Sstevel@tonic-gate * here. 164*7c478bd9Sstevel@tonic-gate */ 165*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id WL"); 166*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->traverser_id_lock); 167*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 168*7c478bd9Sstevel@tonic-gate if (table->traversed != 0 && 169*7c478bd9Sstevel@tonic-gate table->traverser_id == pthread_self()) { 170*7c478bd9Sstevel@tonic-gate table->traversed = 0; 171*7c478bd9Sstevel@tonic-gate /* 172*7c478bd9Sstevel@tonic-gate * Leave traverser_id as it is, so that it 173*7c478bd9Sstevel@tonic-gate * possible to see which thread last held 174*7c478bd9Sstevel@tonic-gate * the traverser lock. 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate dounlock = 1; 177*7c478bd9Sstevel@tonic-gate /* Wake up other traversers-to-be */ 178*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "table cond_signal"); 179*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->traverser_id_lock); 182*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 183*7c478bd9Sstevel@tonic-gate } else { 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * Called from the nis_*_item() functions. If we're 186*7c478bd9Sstevel@tonic-gate * traversing the table, leave it locked. 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id WL"); 189*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->traverser_id_lock); 190*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 191*7c478bd9Sstevel@tonic-gate if (table->traversed == 0) { 192*7c478bd9Sstevel@tonic-gate dounlock = 1; 193*7c478bd9Sstevel@tonic-gate } 194*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->traverser_id_lock); 195*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 196*7c478bd9Sstevel@tonic-gate } 197*7c478bd9Sstevel@tonic-gate if (dounlock) { 198*7c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->lock); 199*7c478bd9Sstevel@tonic-gate set_thread_status(msg, "table U"); 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, "%d: lh table %s release 0x%x (%s)", 202*7c478bd9Sstevel@tonic-gate pthread_self(), traverse?"traverse":"non-traverse", table, 203*7c478bd9Sstevel@tonic-gate dounlock?"unlocked":"still held")); 204*7c478bd9Sstevel@tonic-gate return (1); 205*7c478bd9Sstevel@tonic-gate } else { 206*7c478bd9Sstevel@tonic-gate return (0); 207*7c478bd9Sstevel@tonic-gate } 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate static __nis_hash_item_mt ** 211*7c478bd9Sstevel@tonic-gate __find_item_mt(nis_name name, __nis_hash_table_mt *table, int *keyp) { 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate int key = 0; 214*7c478bd9Sstevel@tonic-gate unsigned char *s; 215*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *it, **pp; 216*7c478bd9Sstevel@tonic-gate 217*7c478bd9Sstevel@tonic-gate /* Assume table!=0, table lock held */ 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate for (s = (unsigned char *)name; *s != 0; s++) { 220*7c478bd9Sstevel@tonic-gate key += *s; 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate key %= (sizeof (table->keys) / sizeof (table->keys[0])); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate if (keyp != 0) { 225*7c478bd9Sstevel@tonic-gate *keyp = key; 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate for (pp = &table->keys[key]; (it = *pp) != 0; pp = &it->next) { 228*7c478bd9Sstevel@tonic-gate if (strcmp(name, it->name) == 0) { 229*7c478bd9Sstevel@tonic-gate break; 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate } 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate return (pp); 234*7c478bd9Sstevel@tonic-gate } 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * The 'readwrite' argument is interpreted as follows on a successful 238*7c478bd9Sstevel@tonic-gate * return: 239*7c478bd9Sstevel@tonic-gate * 240*7c478bd9Sstevel@tonic-gate * < 0 Exclusive access to item 241*7c478bd9Sstevel@tonic-gate * 0 Item must not be used or referenced in any way 242*7c478bd9Sstevel@tonic-gate * > 0 Non-exclusive access (read-only) to item 243*7c478bd9Sstevel@tonic-gate * 244*7c478bd9Sstevel@tonic-gate * Except when 'readwrite' == 0, the caller must explicitly release the 245*7c478bd9Sstevel@tonic-gate * item (__nis_release_item()). 246*7c478bd9Sstevel@tonic-gate */ 247*7c478bd9Sstevel@tonic-gate int 248*7c478bd9Sstevel@tonic-gate __nis_insert_item_mt(void *arg, __nis_hash_table_mt *table, int readwrite) { 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item = arg; 251*7c478bd9Sstevel@tonic-gate int key; 252*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt **pp; 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate if (item == 0 || __nis_lock_hash_table(table, 0, "nitmt") == 0) 255*7c478bd9Sstevel@tonic-gate return (0); 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate if ((*(pp = __find_item_mt(item->name, table, &key))) != 0) { 258*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nitmt"); 259*7c478bd9Sstevel@tonic-gate return (0); 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&item->lock, 0); 263*7c478bd9Sstevel@tonic-gate item->readers = item->writer = 0; 264*7c478bd9Sstevel@tonic-gate item->last_reader_id = item->writer_id = INV_PTHREAD_ID; 265*7c478bd9Sstevel@tonic-gate if (readwrite < 0) { 266*7c478bd9Sstevel@tonic-gate item->writer = 1; 267*7c478bd9Sstevel@tonic-gate item->writer_id = pthread_self(); 268*7c478bd9Sstevel@tonic-gate table->locked_items++; 269*7c478bd9Sstevel@tonic-gate } else if (readwrite > 0) { 270*7c478bd9Sstevel@tonic-gate item->readers = 1; 271*7c478bd9Sstevel@tonic-gate item->last_reader_id = pthread_self(); 272*7c478bd9Sstevel@tonic-gate table->locked_items++; 273*7c478bd9Sstevel@tonic-gate } 274*7c478bd9Sstevel@tonic-gate item->next = *pp; 275*7c478bd9Sstevel@tonic-gate *pp = item; 276*7c478bd9Sstevel@tonic-gate item->keychain = key; 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate if (table->first) 279*7c478bd9Sstevel@tonic-gate table->first->prv_item = item; 280*7c478bd9Sstevel@tonic-gate 281*7c478bd9Sstevel@tonic-gate item->nxt_item = table->first; 282*7c478bd9Sstevel@tonic-gate item->prv_item = NULL; 283*7c478bd9Sstevel@tonic-gate table->first = item; 284*7c478bd9Sstevel@tonic-gate 285*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nitmt"); 286*7c478bd9Sstevel@tonic-gate 287*7c478bd9Sstevel@tonic-gate return (1); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate void 291*7c478bd9Sstevel@tonic-gate __nis_insert_name_mt(nis_name name, __nis_hash_table_mt *table) { 292*7c478bd9Sstevel@tonic-gate 293*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item; 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate if (name == 0 || table == 0) 296*7c478bd9Sstevel@tonic-gate return; 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate if ((item = malloc(sizeof (*item))) == 0) { 299*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "__nis_insert_name_mt: malloc failed\n"); 300*7c478bd9Sstevel@tonic-gate return; 301*7c478bd9Sstevel@tonic-gate } 302*7c478bd9Sstevel@tonic-gate 303*7c478bd9Sstevel@tonic-gate if ((item->name = strdup(name)) == 0) { 304*7c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "__nis_insert_name_mt: strdup failed\n"); 305*7c478bd9Sstevel@tonic-gate free(item); 306*7c478bd9Sstevel@tonic-gate return; 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate if (! __nis_insert_item_mt(item, table, 0)) { 310*7c478bd9Sstevel@tonic-gate free(item->name); 311*7c478bd9Sstevel@tonic-gate free(item); 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate } 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate /* 316*7c478bd9Sstevel@tonic-gate * readwrite: < 0 Exclusive access 317*7c478bd9Sstevel@tonic-gate * 0 No access; must not use returned item in any way, 318*7c478bd9Sstevel@tonic-gate * other than to confirm existence indicated by a non-NULL 319*7c478bd9Sstevel@tonic-gate * return value. 320*7c478bd9Sstevel@tonic-gate * > 0 Non-exclusive (read-only) access 321*7c478bd9Sstevel@tonic-gate * 322*7c478bd9Sstevel@tonic-gate * If trylock != 0 and *trylock != 0 and the item exists but the requested 323*7c478bd9Sstevel@tonic-gate * lock type cannot be acquired, set *trylock = -1 and return 0. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate void * 326*7c478bd9Sstevel@tonic-gate __nis_find_item_mt(nis_name name, __nis_hash_table_mt *table, int readwrite, 327*7c478bd9Sstevel@tonic-gate int *trylock) { 328*7c478bd9Sstevel@tonic-gate 329*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item; 330*7c478bd9Sstevel@tonic-gate pthread_t me = pthread_self(); 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate if (name == 0 || __nis_lock_hash_table(table, 0, "nfimt") == 0) 333*7c478bd9Sstevel@tonic-gate return (0); 334*7c478bd9Sstevel@tonic-gate 335*7c478bd9Sstevel@tonic-gate /* 336*7c478bd9Sstevel@tonic-gate * Block waiting for more favorable conditions unless: 337*7c478bd9Sstevel@tonic-gate * 338*7c478bd9Sstevel@tonic-gate * The item doesn't exist anymore 339*7c478bd9Sstevel@tonic-gate * 340*7c478bd9Sstevel@tonic-gate * 'readwrite' == 0 (verify existence only) 341*7c478bd9Sstevel@tonic-gate * 342*7c478bd9Sstevel@tonic-gate * There's a writer, but it's us 343*7c478bd9Sstevel@tonic-gate * 344*7c478bd9Sstevel@tonic-gate * There are no writers, and we're satisfied by RO access 345*7c478bd9Sstevel@tonic-gate * 346*7c478bd9Sstevel@tonic-gate * A trylock was requested 347*7c478bd9Sstevel@tonic-gate */ 348*7c478bd9Sstevel@tonic-gate while ((item = *__find_item_mt(name, table, 0)) != 0) { 349*7c478bd9Sstevel@tonic-gate if (readwrite == 0 || 350*7c478bd9Sstevel@tonic-gate (item->writer == 0 && item->readers == 0)) 351*7c478bd9Sstevel@tonic-gate break; 352*7c478bd9Sstevel@tonic-gate if (item->writer == 0 && readwrite > 0) 353*7c478bd9Sstevel@tonic-gate break; 354*7c478bd9Sstevel@tonic-gate if ((item->writer != 0 && item->writer_id == me)) 355*7c478bd9Sstevel@tonic-gate break; 356*7c478bd9Sstevel@tonic-gate if (trylock != 0 && *trylock != 0) { 357*7c478bd9Sstevel@tonic-gate *trylock = -1; 358*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nfimt"); 359*7c478bd9Sstevel@tonic-gate return (0); 360*7c478bd9Sstevel@tonic-gate } 361*7c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&item->lock, &table->lock); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate if (item != 0) { 365*7c478bd9Sstevel@tonic-gate if (readwrite < 0) { 366*7c478bd9Sstevel@tonic-gate if (item->writer == 0) { 367*7c478bd9Sstevel@tonic-gate item->writer_id = me; 368*7c478bd9Sstevel@tonic-gate table->locked_items++; 369*7c478bd9Sstevel@tonic-gate } 370*7c478bd9Sstevel@tonic-gate item->writer++; 371*7c478bd9Sstevel@tonic-gate } else if (readwrite > 0) { 372*7c478bd9Sstevel@tonic-gate if (item->readers == 0) { 373*7c478bd9Sstevel@tonic-gate table->locked_items++; 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate item->last_reader_id = me; 376*7c478bd9Sstevel@tonic-gate item->readers++; 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nfimt"); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate return (item); 383*7c478bd9Sstevel@tonic-gate } 384*7c478bd9Sstevel@tonic-gate 385*7c478bd9Sstevel@tonic-gate void * 386*7c478bd9Sstevel@tonic-gate __nis_pop_item_mt(__nis_hash_table_mt *table) { 387*7c478bd9Sstevel@tonic-gate 388*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item, *cur, *prev; 389*7c478bd9Sstevel@tonic-gate pthread_t mtid; 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate if (__nis_lock_hash_table(table, 0, "npimt") == 0) 392*7c478bd9Sstevel@tonic-gate return (0); 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate /* Wait until the first item isn't in use by another thread */ 395*7c478bd9Sstevel@tonic-gate mtid = pthread_self(); 396*7c478bd9Sstevel@tonic-gate while ((item = table->first) != 0) { 397*7c478bd9Sstevel@tonic-gate if (table->destroyItem != 0) 398*7c478bd9Sstevel@tonic-gate break; 399*7c478bd9Sstevel@tonic-gate if (item->readers == 0 && item->writer == 0) 400*7c478bd9Sstevel@tonic-gate break; 401*7c478bd9Sstevel@tonic-gate if (item->writer != 0 && item->writer_id == mtid) 402*7c478bd9Sstevel@tonic-gate break; 403*7c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&item->lock, &table->lock); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* List might be empty now */ 407*7c478bd9Sstevel@tonic-gate if (item == 0) { 408*7c478bd9Sstevel@tonic-gate __nis_ulock_hash_table(table, 0, "npimt"); 409*7c478bd9Sstevel@tonic-gate return (0); 410*7c478bd9Sstevel@tonic-gate } 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate prev = 0; 413*7c478bd9Sstevel@tonic-gate for (cur = table->keys[item->keychain]; cur; 414*7c478bd9Sstevel@tonic-gate prev = cur, cur = cur->next) { 415*7c478bd9Sstevel@tonic-gate if (cur == item) { 416*7c478bd9Sstevel@tonic-gate if (prev) 417*7c478bd9Sstevel@tonic-gate prev->next = cur->next; 418*7c478bd9Sstevel@tonic-gate else 419*7c478bd9Sstevel@tonic-gate table->keys[cur->keychain] = cur->next; 420*7c478bd9Sstevel@tonic-gate if (cur->prv_item) 421*7c478bd9Sstevel@tonic-gate cur->prv_item->nxt_item = cur->nxt_item; 422*7c478bd9Sstevel@tonic-gate else 423*7c478bd9Sstevel@tonic-gate table->first = cur->nxt_item; 424*7c478bd9Sstevel@tonic-gate if (cur->nxt_item) 425*7c478bd9Sstevel@tonic-gate cur->nxt_item->prv_item = cur->prv_item; 426*7c478bd9Sstevel@tonic-gate break; 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate 430*7c478bd9Sstevel@tonic-gate /* 431*7c478bd9Sstevel@tonic-gate * We use keychain < 0 to indicate that the item isn't linked 432*7c478bd9Sstevel@tonic-gate * into the table anymore. 433*7c478bd9Sstevel@tonic-gate */ 434*7c478bd9Sstevel@tonic-gate item->keychain = -1; 435*7c478bd9Sstevel@tonic-gate 436*7c478bd9Sstevel@tonic-gate /* Adjust the count of locked items in the table */ 437*7c478bd9Sstevel@tonic-gate if (table->locked_items != 0 && 438*7c478bd9Sstevel@tonic-gate (item->writer > 0 || item->readers > 0)) { 439*7c478bd9Sstevel@tonic-gate table->locked_items--; 440*7c478bd9Sstevel@tonic-gate if (table->locked_items == 0) { 441*7c478bd9Sstevel@tonic-gate /* Wake up traversers-to-be */ 442*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 443*7c478bd9Sstevel@tonic-gate } 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate /* 447*7c478bd9Sstevel@tonic-gate * Wake up any threads that were waiting for this item. Obviously, 448*7c478bd9Sstevel@tonic-gate * such threads must start over scanning the list. 449*7c478bd9Sstevel@tonic-gate */ 450*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&item->lock); 451*7c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&item->lock); 452*7c478bd9Sstevel@tonic-gate 453*7c478bd9Sstevel@tonic-gate /* 454*7c478bd9Sstevel@tonic-gate * If the item isn't locked, and an item destructor has been 455*7c478bd9Sstevel@tonic-gate * established, invoke the destructor. 456*7c478bd9Sstevel@tonic-gate */ 457*7c478bd9Sstevel@tonic-gate if (item->readers == 0 && item->writer == 0 && 458*7c478bd9Sstevel@tonic-gate table->destroyItem != 0) { 459*7c478bd9Sstevel@tonic-gate (*table->destroyItem)(item); 460*7c478bd9Sstevel@tonic-gate item = 0; 461*7c478bd9Sstevel@tonic-gate } else { 462*7c478bd9Sstevel@tonic-gate item->next = 0; 463*7c478bd9Sstevel@tonic-gate item->prv_item = 0; 464*7c478bd9Sstevel@tonic-gate item->nxt_item = 0; 465*7c478bd9Sstevel@tonic-gate } 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "npimt"); 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate /* 470*7c478bd9Sstevel@tonic-gate * If we get here, and the 'item' is NULL, we've popped the 471*7c478bd9Sstevel@tonic-gate * item, but also destroyed it. Returning NULL would make 472*7c478bd9Sstevel@tonic-gate * our caller believe the list is empty, so instead, we invoke 473*7c478bd9Sstevel@tonic-gate * ourselves to pop the next item. 474*7c478bd9Sstevel@tonic-gate */ 475*7c478bd9Sstevel@tonic-gate return ((item != 0) ? item : __nis_pop_item_mt(table)); 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate void * 479*7c478bd9Sstevel@tonic-gate __nis_remove_item_mt(nis_name name, __nis_hash_table_mt *table) { 480*7c478bd9Sstevel@tonic-gate 481*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *nl, **pp; 482*7c478bd9Sstevel@tonic-gate pthread_t mtid; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate if (__nis_lock_hash_table(table, 0, "nrimt") == 0) 485*7c478bd9Sstevel@tonic-gate return (0); 486*7c478bd9Sstevel@tonic-gate 487*7c478bd9Sstevel@tonic-gate /* Find the item, and make sure it's not in use */ 488*7c478bd9Sstevel@tonic-gate mtid = pthread_self(); 489*7c478bd9Sstevel@tonic-gate while ((nl = *(pp = __find_item_mt(name, table, (int *)0))) != 0) { 490*7c478bd9Sstevel@tonic-gate if (table->destroyItem != 0) 491*7c478bd9Sstevel@tonic-gate break; 492*7c478bd9Sstevel@tonic-gate if (nl->readers == 0 && nl->writer == 0) 493*7c478bd9Sstevel@tonic-gate break; 494*7c478bd9Sstevel@tonic-gate if (nl->writer != 0 && nl->writer_id == mtid) 495*7c478bd9Sstevel@tonic-gate break; 496*7c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&nl->lock, &table->lock); 497*7c478bd9Sstevel@tonic-gate } 498*7c478bd9Sstevel@tonic-gate 499*7c478bd9Sstevel@tonic-gate if (nl == 0) { 500*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nrimt"); 501*7c478bd9Sstevel@tonic-gate return (0); 502*7c478bd9Sstevel@tonic-gate } 503*7c478bd9Sstevel@tonic-gate 504*7c478bd9Sstevel@tonic-gate /* Remove nl from the hash chain */ 505*7c478bd9Sstevel@tonic-gate *pp = nl->next; 506*7c478bd9Sstevel@tonic-gate nl->next = 0; 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate /* Remove nl from the linked list of all names */ 509*7c478bd9Sstevel@tonic-gate if (nl->prv_item) 510*7c478bd9Sstevel@tonic-gate nl->prv_item->nxt_item = nl->nxt_item; 511*7c478bd9Sstevel@tonic-gate else 512*7c478bd9Sstevel@tonic-gate table->first = nl->nxt_item; 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate if (nl->nxt_item) 515*7c478bd9Sstevel@tonic-gate nl->nxt_item->prv_item = nl->prv_item; 516*7c478bd9Sstevel@tonic-gate nl->prv_item = 0; 517*7c478bd9Sstevel@tonic-gate nl->nxt_item = 0; 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate /* keychain < 0 means not in table anymore */ 520*7c478bd9Sstevel@tonic-gate nl->keychain = -1; 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate /* 523*7c478bd9Sstevel@tonic-gate * If this item was locked, we can now decrement the count of 524*7c478bd9Sstevel@tonic-gate * locked items for the table. 525*7c478bd9Sstevel@tonic-gate */ 526*7c478bd9Sstevel@tonic-gate if (table->locked_items != 0 && 527*7c478bd9Sstevel@tonic-gate (nl->writer > 0 || nl->readers > 0)) { 528*7c478bd9Sstevel@tonic-gate table->locked_items--; 529*7c478bd9Sstevel@tonic-gate if (table->locked_items == 0) { 530*7c478bd9Sstevel@tonic-gate /* Wake up traversers-to-be */ 531*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate } 534*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&nl->lock); 535*7c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&nl->lock); 536*7c478bd9Sstevel@tonic-gate 537*7c478bd9Sstevel@tonic-gate /* 538*7c478bd9Sstevel@tonic-gate * If the item isn't locked, and an item destructor has been 539*7c478bd9Sstevel@tonic-gate * established, invoke the destructor. In that case, we return 540*7c478bd9Sstevel@tonic-gate * NULL, so that our caller doesn't try to reference the 541*7c478bd9Sstevel@tonic-gate * deleted item. 542*7c478bd9Sstevel@tonic-gate */ 543*7c478bd9Sstevel@tonic-gate if (nl->readers == 0 && nl->writer == 0 && table->destroyItem != 0) { 544*7c478bd9Sstevel@tonic-gate (*table->destroyItem)(nl); 545*7c478bd9Sstevel@tonic-gate nl = 0; 546*7c478bd9Sstevel@tonic-gate } 547*7c478bd9Sstevel@tonic-gate 548*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nrimt"); 549*7c478bd9Sstevel@tonic-gate 550*7c478bd9Sstevel@tonic-gate return (nl); 551*7c478bd9Sstevel@tonic-gate } 552*7c478bd9Sstevel@tonic-gate 553*7c478bd9Sstevel@tonic-gate /* 554*7c478bd9Sstevel@tonic-gate * Release an item that had been acquired exclusively or non-exclusively. 555*7c478bd9Sstevel@tonic-gate * Note that 'readwrite' can assume any integer value, and thus can be 556*7c478bd9Sstevel@tonic-gate * used to release any level of recursive locking. It's the responsibility 557*7c478bd9Sstevel@tonic-gate * of the caller to make sure that proper nesting is maintained. 558*7c478bd9Sstevel@tonic-gate */ 559*7c478bd9Sstevel@tonic-gate int 560*7c478bd9Sstevel@tonic-gate __nis_release_item(void *arg, __nis_hash_table_mt *table, int readwrite) { 561*7c478bd9Sstevel@tonic-gate 562*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item = arg; 563*7c478bd9Sstevel@tonic-gate int wakeup = 0; 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate if (item == 0 || __nis_lock_hash_table(table, 0, "nreli") == 0) 566*7c478bd9Sstevel@tonic-gate return (0); 567*7c478bd9Sstevel@tonic-gate 568*7c478bd9Sstevel@tonic-gate if ((readwrite < 0 && abs(readwrite) > item->writer) || 569*7c478bd9Sstevel@tonic-gate (readwrite < 0 && item->writer > 0 && 570*7c478bd9Sstevel@tonic-gate item->writer_id != pthread_self()) || 571*7c478bd9Sstevel@tonic-gate (readwrite > 0 && readwrite > item->readers)) { 572*7c478bd9Sstevel@tonic-gate /* Caller confused; ignore */ 573*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nreli"); 574*7c478bd9Sstevel@tonic-gate return (0); 575*7c478bd9Sstevel@tonic-gate } 576*7c478bd9Sstevel@tonic-gate 577*7c478bd9Sstevel@tonic-gate if (readwrite < 0) { 578*7c478bd9Sstevel@tonic-gate item->writer += readwrite; 579*7c478bd9Sstevel@tonic-gate if (item->writer == 0 && item->keychain >= 0) { 580*7c478bd9Sstevel@tonic-gate if (table->locked_items != 0) 581*7c478bd9Sstevel@tonic-gate table->locked_items--; 582*7c478bd9Sstevel@tonic-gate wakeup = 1; 583*7c478bd9Sstevel@tonic-gate } 584*7c478bd9Sstevel@tonic-gate } else if (readwrite > 0) { 585*7c478bd9Sstevel@tonic-gate item->readers -= readwrite; 586*7c478bd9Sstevel@tonic-gate item->last_reader_id = INV_PTHREAD_ID; 587*7c478bd9Sstevel@tonic-gate if (item->readers == 0 && item->keychain >= 0) { 588*7c478bd9Sstevel@tonic-gate if (table->locked_items != 0) 589*7c478bd9Sstevel@tonic-gate table->locked_items--; 590*7c478bd9Sstevel@tonic-gate wakeup = 1; 591*7c478bd9Sstevel@tonic-gate } 592*7c478bd9Sstevel@tonic-gate } 593*7c478bd9Sstevel@tonic-gate 594*7c478bd9Sstevel@tonic-gate if (table->locked_items == 0) { 595*7c478bd9Sstevel@tonic-gate /* Wake up traversers-to-be */ 596*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 597*7c478bd9Sstevel@tonic-gate } 598*7c478bd9Sstevel@tonic-gate if (wakeup) { 599*7c478bd9Sstevel@tonic-gate /* Wake up anyone else who wants this item */ 600*7c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&item->lock); 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate /* 604*7c478bd9Sstevel@tonic-gate * Delete if no references, not linked into list, and destructor 605*7c478bd9Sstevel@tonic-gate * established. 606*7c478bd9Sstevel@tonic-gate */ 607*7c478bd9Sstevel@tonic-gate if (item->keychain < 0 && 608*7c478bd9Sstevel@tonic-gate item->readers == 0 && item->writer == 0 && 609*7c478bd9Sstevel@tonic-gate item->next == 0 && 610*7c478bd9Sstevel@tonic-gate item->prv_item == 0 && item->nxt_item == 0 && 611*7c478bd9Sstevel@tonic-gate table->destroyItem != 0) 612*7c478bd9Sstevel@tonic-gate (*table->destroyItem)(item); 613*7c478bd9Sstevel@tonic-gate 614*7c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nreli"); 615*7c478bd9Sstevel@tonic-gate 616*7c478bd9Sstevel@tonic-gate return (1); 617*7c478bd9Sstevel@tonic-gate } 618*7c478bd9Sstevel@tonic-gate 619*7c478bd9Sstevel@tonic-gate /* 620*7c478bd9Sstevel@tonic-gate * Return -1 if item checked out for both reading and writing, 1 if 621*7c478bd9Sstevel@tonic-gate * readonly, and 0 otherwise. 622*7c478bd9Sstevel@tonic-gate */ 623*7c478bd9Sstevel@tonic-gate int 624*7c478bd9Sstevel@tonic-gate __nis_item_access(void *arg) { 625*7c478bd9Sstevel@tonic-gate 626*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item = arg; 627*7c478bd9Sstevel@tonic-gate 628*7c478bd9Sstevel@tonic-gate if (item != 0) { 629*7c478bd9Sstevel@tonic-gate if (item->writer > 0) { 630*7c478bd9Sstevel@tonic-gate if (item->writer_id != pthread_self()) 631*7c478bd9Sstevel@tonic-gate abort(); 632*7c478bd9Sstevel@tonic-gate return (-1); 633*7c478bd9Sstevel@tonic-gate } else if (item->readers > 0) { 634*7c478bd9Sstevel@tonic-gate return (1); 635*7c478bd9Sstevel@tonic-gate } 636*7c478bd9Sstevel@tonic-gate } 637*7c478bd9Sstevel@tonic-gate 638*7c478bd9Sstevel@tonic-gate return (0); 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate /* 642*7c478bd9Sstevel@tonic-gate * __nis_scan_table_mt() 643*7c478bd9Sstevel@tonic-gate * 644*7c478bd9Sstevel@tonic-gate * Iterate over all items in a __nis_hash_table_mt. We ignore 645*7c478bd9Sstevel@tonic-gate * first/prv_item/nxt_item and scan in hash-chain order. The iterator 646*7c478bd9Sstevel@tonic-gate * function should *not* insert or delete items. If the iterator 647*7c478bd9Sstevel@tonic-gate * function returns TRUE the scan terminates. For compatibility with 648*7c478bd9Sstevel@tonic-gate * the existing non-MT nis_scan_table() this function has no return 649*7c478bd9Sstevel@tonic-gate * value. 650*7c478bd9Sstevel@tonic-gate */ 651*7c478bd9Sstevel@tonic-gate void 652*7c478bd9Sstevel@tonic-gate __nis_scan_table_mt( 653*7c478bd9Sstevel@tonic-gate __nis_hash_table_mt *table, 654*7c478bd9Sstevel@tonic-gate bool_t (*func)(__nis_hash_item_mt *, void *), 655*7c478bd9Sstevel@tonic-gate void *funcarg) 656*7c478bd9Sstevel@tonic-gate { 657*7c478bd9Sstevel@tonic-gate int slot; 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate if (table == 0) { 660*7c478bd9Sstevel@tonic-gate return; 661*7c478bd9Sstevel@tonic-gate } 662*7c478bd9Sstevel@tonic-gate 663*7c478bd9Sstevel@tonic-gate if (__nis_lock_hash_table(table, 1, "nstmt") == 0) { 664*7c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "__nis_scan_table_mt: mutex lock failed "); 665*7c478bd9Sstevel@tonic-gate return; 666*7c478bd9Sstevel@tonic-gate } 667*7c478bd9Sstevel@tonic-gate 668*7c478bd9Sstevel@tonic-gate for (slot = 0; 669*7c478bd9Sstevel@tonic-gate slot < sizeof (table->keys) / sizeof (table->keys[0]); 670*7c478bd9Sstevel@tonic-gate slot++) { 671*7c478bd9Sstevel@tonic-gate __nis_hash_item_mt *it; 672*7c478bd9Sstevel@tonic-gate 673*7c478bd9Sstevel@tonic-gate for (it = table->keys[slot]; it != 0; it = it->next) { 674*7c478bd9Sstevel@tonic-gate if (TRUE == (*func)(it, funcarg)) { 675*7c478bd9Sstevel@tonic-gate break; 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate } 678*7c478bd9Sstevel@tonic-gate } 679*7c478bd9Sstevel@tonic-gate if (__nis_ulock_hash_table(table, 1, "nstmt") == 0) 680*7c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "__nis_scan_table_mt: mutex unlock failed "); 681*7c478bd9Sstevel@tonic-gate } 682