17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 23*ecf4100fSsm26363 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 287c478bd9Sstevel@tonic-gate 297c478bd9Sstevel@tonic-gate #include <string.h> 307c478bd9Sstevel@tonic-gate #include <pthread.h> 317c478bd9Sstevel@tonic-gate #include <syslog.h> 327c478bd9Sstevel@tonic-gate #include <rpcsvc/nis.h> 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include "nis_hashitem.h" 357c478bd9Sstevel@tonic-gate 367c478bd9Sstevel@tonic-gate /* We're the magician, so undefine the define-magic */ 377c478bd9Sstevel@tonic-gate #undef NIS_HASH_ITEM 387c478bd9Sstevel@tonic-gate #undef NIS_HASH_TABLE 397c478bd9Sstevel@tonic-gate #undef nis_insert_item 407c478bd9Sstevel@tonic-gate #undef nis_find_item 417c478bd9Sstevel@tonic-gate #undef nis_pop_item 427c478bd9Sstevel@tonic-gate #undef nis_remove_item 437c478bd9Sstevel@tonic-gate 447c478bd9Sstevel@tonic-gate #define set_thread_status(msg, state) 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate /* 477c478bd9Sstevel@tonic-gate * The hash table routines below implement nested (or recursive) 487c478bd9Sstevel@tonic-gate * one-writer-or-many-readers locking. The following restrictions 497c478bd9Sstevel@tonic-gate * exist: 507c478bd9Sstevel@tonic-gate * 517c478bd9Sstevel@tonic-gate * Unless an item destructor has been established, an item 527c478bd9Sstevel@tonic-gate * MUST NOT be removed from a list (__nis_pop_item_mt() or 537c478bd9Sstevel@tonic-gate * (__nis_remove_item_mt()) when the thread performing 547c478bd9Sstevel@tonic-gate * the deletion is holding a read-only lock on the item. 557c478bd9Sstevel@tonic-gate * Doing so will result in the thread blocking in 567c478bd9Sstevel@tonic-gate * pthread_cond_wait() waiting for itself to signal on 577c478bd9Sstevel@tonic-gate * the condition variable. Deletion when the invoking 587c478bd9Sstevel@tonic-gate * thread is holding a write lock (any level of nesting), 597c478bd9Sstevel@tonic-gate * or no lock, is OK. 607c478bd9Sstevel@tonic-gate */ 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate void 637c478bd9Sstevel@tonic-gate __nis_init_hash_table(__nis_hash_table_mt *table, 647c478bd9Sstevel@tonic-gate void (*itemDestructor)(void *)) { 657c478bd9Sstevel@tonic-gate 66*ecf4100fSsm26363 int errorcode; 67*ecf4100fSsm26363 687c478bd9Sstevel@tonic-gate if (table != 0) { 69*ecf4100fSsm26363 errorcode = pthread_mutex_init(&table->lock, 0); 70*ecf4100fSsm26363 if (errorcode != 0) { 71*ecf4100fSsm26363 syslog(LOG_WARNING, "__nis_init_hash_table: " 72*ecf4100fSsm26363 "(table->lock) pthread_mutex_init returned %d (%s)", 73*ecf4100fSsm26363 errorcode, strerror(errorcode)); 74*ecf4100fSsm26363 } 75*ecf4100fSsm26363 76*ecf4100fSsm26363 errorcode = pthread_cond_init(&table->cond, 0); 77*ecf4100fSsm26363 if (errorcode != 0) { 78*ecf4100fSsm26363 syslog(LOG_WARNING, "__nis_init_hash_table: " 79*ecf4100fSsm26363 "(table->cond) pthread_cond_init returned %d (%s)", 80*ecf4100fSsm26363 errorcode, strerror(errorcode)); 81*ecf4100fSsm26363 } 82*ecf4100fSsm26363 83*ecf4100fSsm26363 errorcode = pthread_mutex_init(&table->traverser_id_lock, 0); 84*ecf4100fSsm26363 if (errorcode != 0) { 85*ecf4100fSsm26363 syslog(LOG_WARNING, "__nis_init_hash_table: " 86*ecf4100fSsm26363 "(table->traverser_id_lock) " 87*ecf4100fSsm26363 "pthread_mutex_init returned %d (%s)", 88*ecf4100fSsm26363 errorcode, strerror(errorcode)); 89*ecf4100fSsm26363 } 90*ecf4100fSsm26363 917c478bd9Sstevel@tonic-gate table->traversed = 0; 927c478bd9Sstevel@tonic-gate table->locked_items = 0; 937c478bd9Sstevel@tonic-gate (void) memset(table->keys, 0, sizeof (table->keys)); 947c478bd9Sstevel@tonic-gate table->first = 0; 957c478bd9Sstevel@tonic-gate table->destroyItem = itemDestructor; 967c478bd9Sstevel@tonic-gate } 977c478bd9Sstevel@tonic-gate } 987c478bd9Sstevel@tonic-gate 997c478bd9Sstevel@tonic-gate int 1007c478bd9Sstevel@tonic-gate __nis_lock_hash_table(__nis_hash_table_mt *table, int traverse, char *msg) { 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate pthread_t myself = pthread_self(); 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate if (table != 0) { 1057c478bd9Sstevel@tonic-gate if (traverse) { 1067c478bd9Sstevel@tonic-gate /* 1077c478bd9Sstevel@tonic-gate * We want exclusive access to everything in the 1087c478bd9Sstevel@tonic-gate * table (list). Wait until there are no threads 1097c478bd9Sstevel@tonic-gate * either traversing the list, or with exclusive 1107c478bd9Sstevel@tonic-gate * access to an item. 1117c478bd9Sstevel@tonic-gate */ 1127c478bd9Sstevel@tonic-gate set_thread_status(msg, "table WL"); 1137c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->lock); 1147c478bd9Sstevel@tonic-gate set_thread_status(msg, "table L"); 1157c478bd9Sstevel@tonic-gate while ((table->traversed != 0 && 1167c478bd9Sstevel@tonic-gate table->traverser_id != myself) || 1177c478bd9Sstevel@tonic-gate table->locked_items != 0) { 1187c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverse cond_wait"); 1197c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, 1207c478bd9Sstevel@tonic-gate "%d: lh table 0x%x trav cond wait", 1217c478bd9Sstevel@tonic-gate myself, table)); 1227c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&table->cond, 1237c478bd9Sstevel@tonic-gate &table->lock); 1247c478bd9Sstevel@tonic-gate } 1257c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id WL"); 1267c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->traverser_id_lock); 1277c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 1287c478bd9Sstevel@tonic-gate table->traversed = 1; 1297c478bd9Sstevel@tonic-gate table->traverser_id = myself; 1307c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->traverser_id_lock); 1317c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 1327c478bd9Sstevel@tonic-gate } else { 1337c478bd9Sstevel@tonic-gate /* 1347c478bd9Sstevel@tonic-gate * Called from the nis_*_item() functions. If no one's 1357c478bd9Sstevel@tonic-gate * locked the table, lock it. If the table already is 1367c478bd9Sstevel@tonic-gate * being traversed by us, do nothing. Otherwise, wait 1377c478bd9Sstevel@tonic-gate * for the lock. 1387c478bd9Sstevel@tonic-gate */ 1397c478bd9Sstevel@tonic-gate set_thread_status(msg, "non-traverse TL"); 1407c478bd9Sstevel@tonic-gate if (pthread_mutex_trylock(&table->lock) == EBUSY) { 1417c478bd9Sstevel@tonic-gate int dolock = 1; 1427c478bd9Sstevel@tonic-gate /* Already locked; find out if it's us */ 1437c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 1447c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock( 1457c478bd9Sstevel@tonic-gate &table->traverser_id_lock); 1467c478bd9Sstevel@tonic-gate if (table->traversed != 0 && 1477c478bd9Sstevel@tonic-gate table->traverser_id == myself) { 1487c478bd9Sstevel@tonic-gate /* It's us. No action. */ 1497c478bd9Sstevel@tonic-gate dolock = 0; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock( 1527c478bd9Sstevel@tonic-gate &table->traverser_id_lock); 1537c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 1547c478bd9Sstevel@tonic-gate /* Not us. Wait for the lock */ 1557c478bd9Sstevel@tonic-gate if (dolock) { 1567c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, 1577c478bd9Sstevel@tonic-gate "%d: lh table 0x%x cond wait", 1587c478bd9Sstevel@tonic-gate myself, table)); 1597c478bd9Sstevel@tonic-gate set_thread_status(msg, "table WL"); 1607c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->lock); 1617c478bd9Sstevel@tonic-gate set_thread_status(msg, "table L"); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, "%d: lh table %s lock acquired 0x%x", 1667c478bd9Sstevel@tonic-gate myself, traverse?"traverse":"non-traverse", table)); 1677c478bd9Sstevel@tonic-gate return (1); 1687c478bd9Sstevel@tonic-gate } else { 1697c478bd9Sstevel@tonic-gate return (0); 1707c478bd9Sstevel@tonic-gate } 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate 1737c478bd9Sstevel@tonic-gate int 1747c478bd9Sstevel@tonic-gate __nis_ulock_hash_table(__nis_hash_table_mt *table, int traverse, char *msg) { 1757c478bd9Sstevel@tonic-gate 1767c478bd9Sstevel@tonic-gate int dounlock = 0; 1777c478bd9Sstevel@tonic-gate 1787c478bd9Sstevel@tonic-gate if (table != 0) { 1797c478bd9Sstevel@tonic-gate if (traverse) { 1807c478bd9Sstevel@tonic-gate /* 1817c478bd9Sstevel@tonic-gate * Since we're keeping track of who's traversing the 1827c478bd9Sstevel@tonic-gate * table in order to avoid recursive locking in the 1837c478bd9Sstevel@tonic-gate * nis_*item() functions, we might as well sanity check 1847c478bd9Sstevel@tonic-gate * here. 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id WL"); 1877c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->traverser_id_lock); 1887c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 1897c478bd9Sstevel@tonic-gate if (table->traversed != 0 && 1907c478bd9Sstevel@tonic-gate table->traverser_id == pthread_self()) { 1917c478bd9Sstevel@tonic-gate table->traversed = 0; 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * Leave traverser_id as it is, so that it 1947c478bd9Sstevel@tonic-gate * possible to see which thread last held 1957c478bd9Sstevel@tonic-gate * the traverser lock. 1967c478bd9Sstevel@tonic-gate */ 1977c478bd9Sstevel@tonic-gate dounlock = 1; 1987c478bd9Sstevel@tonic-gate /* Wake up other traversers-to-be */ 1997c478bd9Sstevel@tonic-gate set_thread_status(msg, "table cond_signal"); 2007c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->traverser_id_lock); 2037c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 2047c478bd9Sstevel@tonic-gate } else { 2057c478bd9Sstevel@tonic-gate /* 2067c478bd9Sstevel@tonic-gate * Called from the nis_*_item() functions. If we're 2077c478bd9Sstevel@tonic-gate * traversing the table, leave it locked. 2087c478bd9Sstevel@tonic-gate */ 2097c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id WL"); 2107c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&table->traverser_id_lock); 2117c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id L"); 2127c478bd9Sstevel@tonic-gate if (table->traversed == 0) { 2137c478bd9Sstevel@tonic-gate dounlock = 1; 2147c478bd9Sstevel@tonic-gate } 2157c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->traverser_id_lock); 2167c478bd9Sstevel@tonic-gate set_thread_status(msg, "traverser_id U"); 2177c478bd9Sstevel@tonic-gate } 2187c478bd9Sstevel@tonic-gate if (dounlock) { 2197c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&table->lock); 2207c478bd9Sstevel@tonic-gate set_thread_status(msg, "table U"); 2217c478bd9Sstevel@tonic-gate } 2227c478bd9Sstevel@tonic-gate MT_LOG(1, (LOG_NOTICE, "%d: lh table %s release 0x%x (%s)", 2237c478bd9Sstevel@tonic-gate pthread_self(), traverse?"traverse":"non-traverse", table, 2247c478bd9Sstevel@tonic-gate dounlock?"unlocked":"still held")); 2257c478bd9Sstevel@tonic-gate return (1); 2267c478bd9Sstevel@tonic-gate } else { 2277c478bd9Sstevel@tonic-gate return (0); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate } 2307c478bd9Sstevel@tonic-gate 2317c478bd9Sstevel@tonic-gate static __nis_hash_item_mt ** 2327c478bd9Sstevel@tonic-gate __find_item_mt(nis_name name, __nis_hash_table_mt *table, int *keyp) { 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate int key = 0; 2357c478bd9Sstevel@tonic-gate unsigned char *s; 2367c478bd9Sstevel@tonic-gate __nis_hash_item_mt *it, **pp; 2377c478bd9Sstevel@tonic-gate 2387c478bd9Sstevel@tonic-gate /* Assume table!=0, table lock held */ 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate for (s = (unsigned char *)name; *s != 0; s++) { 2417c478bd9Sstevel@tonic-gate key += *s; 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate key %= (sizeof (table->keys) / sizeof (table->keys[0])); 2447c478bd9Sstevel@tonic-gate 2457c478bd9Sstevel@tonic-gate if (keyp != 0) { 2467c478bd9Sstevel@tonic-gate *keyp = key; 2477c478bd9Sstevel@tonic-gate } 2487c478bd9Sstevel@tonic-gate for (pp = &table->keys[key]; (it = *pp) != 0; pp = &it->next) { 2497c478bd9Sstevel@tonic-gate if (strcmp(name, it->name) == 0) { 2507c478bd9Sstevel@tonic-gate break; 2517c478bd9Sstevel@tonic-gate } 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate return (pp); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate /* 2587c478bd9Sstevel@tonic-gate * The 'readwrite' argument is interpreted as follows on a successful 2597c478bd9Sstevel@tonic-gate * return: 2607c478bd9Sstevel@tonic-gate * 2617c478bd9Sstevel@tonic-gate * < 0 Exclusive access to item 2627c478bd9Sstevel@tonic-gate * 0 Item must not be used or referenced in any way 2637c478bd9Sstevel@tonic-gate * > 0 Non-exclusive access (read-only) to item 2647c478bd9Sstevel@tonic-gate * 2657c478bd9Sstevel@tonic-gate * Except when 'readwrite' == 0, the caller must explicitly release the 2667c478bd9Sstevel@tonic-gate * item (__nis_release_item()). 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate int 2697c478bd9Sstevel@tonic-gate __nis_insert_item_mt(void *arg, __nis_hash_table_mt *table, int readwrite) { 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item = arg; 2727c478bd9Sstevel@tonic-gate int key; 2737c478bd9Sstevel@tonic-gate __nis_hash_item_mt **pp; 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate if (item == 0 || __nis_lock_hash_table(table, 0, "nitmt") == 0) 2767c478bd9Sstevel@tonic-gate return (0); 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate if ((*(pp = __find_item_mt(item->name, table, &key))) != 0) { 2797c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nitmt"); 2807c478bd9Sstevel@tonic-gate return (0); 2817c478bd9Sstevel@tonic-gate } 2827c478bd9Sstevel@tonic-gate 2837c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&item->lock, 0); 2847c478bd9Sstevel@tonic-gate item->readers = item->writer = 0; 2857c478bd9Sstevel@tonic-gate item->last_reader_id = item->writer_id = INV_PTHREAD_ID; 2867c478bd9Sstevel@tonic-gate if (readwrite < 0) { 2877c478bd9Sstevel@tonic-gate item->writer = 1; 2887c478bd9Sstevel@tonic-gate item->writer_id = pthread_self(); 2897c478bd9Sstevel@tonic-gate table->locked_items++; 2907c478bd9Sstevel@tonic-gate } else if (readwrite > 0) { 2917c478bd9Sstevel@tonic-gate item->readers = 1; 2927c478bd9Sstevel@tonic-gate item->last_reader_id = pthread_self(); 2937c478bd9Sstevel@tonic-gate table->locked_items++; 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate item->next = *pp; 2967c478bd9Sstevel@tonic-gate *pp = item; 2977c478bd9Sstevel@tonic-gate item->keychain = key; 2987c478bd9Sstevel@tonic-gate 2997c478bd9Sstevel@tonic-gate if (table->first) 3007c478bd9Sstevel@tonic-gate table->first->prv_item = item; 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate item->nxt_item = table->first; 3037c478bd9Sstevel@tonic-gate item->prv_item = NULL; 3047c478bd9Sstevel@tonic-gate table->first = item; 3057c478bd9Sstevel@tonic-gate 3067c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nitmt"); 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate return (1); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate 3117c478bd9Sstevel@tonic-gate void 3127c478bd9Sstevel@tonic-gate __nis_insert_name_mt(nis_name name, __nis_hash_table_mt *table) { 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item; 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate if (name == 0 || table == 0) 3177c478bd9Sstevel@tonic-gate return; 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if ((item = malloc(sizeof (*item))) == 0) { 3207c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "__nis_insert_name_mt: malloc failed\n"); 3217c478bd9Sstevel@tonic-gate return; 3227c478bd9Sstevel@tonic-gate } 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if ((item->name = strdup(name)) == 0) { 3257c478bd9Sstevel@tonic-gate syslog(LOG_WARNING, "__nis_insert_name_mt: strdup failed\n"); 3267c478bd9Sstevel@tonic-gate free(item); 3277c478bd9Sstevel@tonic-gate return; 3287c478bd9Sstevel@tonic-gate } 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate if (! __nis_insert_item_mt(item, table, 0)) { 3317c478bd9Sstevel@tonic-gate free(item->name); 3327c478bd9Sstevel@tonic-gate free(item); 3337c478bd9Sstevel@tonic-gate } 3347c478bd9Sstevel@tonic-gate } 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate /* 3377c478bd9Sstevel@tonic-gate * readwrite: < 0 Exclusive access 3387c478bd9Sstevel@tonic-gate * 0 No access; must not use returned item in any way, 3397c478bd9Sstevel@tonic-gate * other than to confirm existence indicated by a non-NULL 3407c478bd9Sstevel@tonic-gate * return value. 3417c478bd9Sstevel@tonic-gate * > 0 Non-exclusive (read-only) access 3427c478bd9Sstevel@tonic-gate * 3437c478bd9Sstevel@tonic-gate * If trylock != 0 and *trylock != 0 and the item exists but the requested 3447c478bd9Sstevel@tonic-gate * lock type cannot be acquired, set *trylock = -1 and return 0. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate void * 3477c478bd9Sstevel@tonic-gate __nis_find_item_mt(nis_name name, __nis_hash_table_mt *table, int readwrite, 3487c478bd9Sstevel@tonic-gate int *trylock) { 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item; 3517c478bd9Sstevel@tonic-gate pthread_t me = pthread_self(); 3527c478bd9Sstevel@tonic-gate 3537c478bd9Sstevel@tonic-gate if (name == 0 || __nis_lock_hash_table(table, 0, "nfimt") == 0) 3547c478bd9Sstevel@tonic-gate return (0); 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate /* 3577c478bd9Sstevel@tonic-gate * Block waiting for more favorable conditions unless: 3587c478bd9Sstevel@tonic-gate * 3597c478bd9Sstevel@tonic-gate * The item doesn't exist anymore 3607c478bd9Sstevel@tonic-gate * 3617c478bd9Sstevel@tonic-gate * 'readwrite' == 0 (verify existence only) 3627c478bd9Sstevel@tonic-gate * 3637c478bd9Sstevel@tonic-gate * There's a writer, but it's us 3647c478bd9Sstevel@tonic-gate * 3657c478bd9Sstevel@tonic-gate * There are no writers, and we're satisfied by RO access 3667c478bd9Sstevel@tonic-gate * 3677c478bd9Sstevel@tonic-gate * A trylock was requested 3687c478bd9Sstevel@tonic-gate */ 3697c478bd9Sstevel@tonic-gate while ((item = *__find_item_mt(name, table, 0)) != 0) { 3707c478bd9Sstevel@tonic-gate if (readwrite == 0 || 3717c478bd9Sstevel@tonic-gate (item->writer == 0 && item->readers == 0)) 3727c478bd9Sstevel@tonic-gate break; 3737c478bd9Sstevel@tonic-gate if (item->writer == 0 && readwrite > 0) 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate if ((item->writer != 0 && item->writer_id == me)) 3767c478bd9Sstevel@tonic-gate break; 3777c478bd9Sstevel@tonic-gate if (trylock != 0 && *trylock != 0) { 3787c478bd9Sstevel@tonic-gate *trylock = -1; 3797c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nfimt"); 3807c478bd9Sstevel@tonic-gate return (0); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&item->lock, &table->lock); 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate if (item != 0) { 3867c478bd9Sstevel@tonic-gate if (readwrite < 0) { 3877c478bd9Sstevel@tonic-gate if (item->writer == 0) { 3887c478bd9Sstevel@tonic-gate item->writer_id = me; 3897c478bd9Sstevel@tonic-gate table->locked_items++; 3907c478bd9Sstevel@tonic-gate } 3917c478bd9Sstevel@tonic-gate item->writer++; 3927c478bd9Sstevel@tonic-gate } else if (readwrite > 0) { 3937c478bd9Sstevel@tonic-gate if (item->readers == 0) { 3947c478bd9Sstevel@tonic-gate table->locked_items++; 3957c478bd9Sstevel@tonic-gate } 3967c478bd9Sstevel@tonic-gate item->last_reader_id = me; 3977c478bd9Sstevel@tonic-gate item->readers++; 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nfimt"); 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate return (item); 4047c478bd9Sstevel@tonic-gate } 4057c478bd9Sstevel@tonic-gate 4067c478bd9Sstevel@tonic-gate void * 4077c478bd9Sstevel@tonic-gate __nis_pop_item_mt(__nis_hash_table_mt *table) { 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item, *cur, *prev; 4107c478bd9Sstevel@tonic-gate pthread_t mtid; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate if (__nis_lock_hash_table(table, 0, "npimt") == 0) 4137c478bd9Sstevel@tonic-gate return (0); 4147c478bd9Sstevel@tonic-gate 4157c478bd9Sstevel@tonic-gate /* Wait until the first item isn't in use by another thread */ 4167c478bd9Sstevel@tonic-gate mtid = pthread_self(); 4177c478bd9Sstevel@tonic-gate while ((item = table->first) != 0) { 4187c478bd9Sstevel@tonic-gate if (table->destroyItem != 0) 4197c478bd9Sstevel@tonic-gate break; 4207c478bd9Sstevel@tonic-gate if (item->readers == 0 && item->writer == 0) 4217c478bd9Sstevel@tonic-gate break; 4227c478bd9Sstevel@tonic-gate if (item->writer != 0 && item->writer_id == mtid) 4237c478bd9Sstevel@tonic-gate break; 4247c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&item->lock, &table->lock); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* List might be empty now */ 4287c478bd9Sstevel@tonic-gate if (item == 0) { 4297c478bd9Sstevel@tonic-gate __nis_ulock_hash_table(table, 0, "npimt"); 4307c478bd9Sstevel@tonic-gate return (0); 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate prev = 0; 4347c478bd9Sstevel@tonic-gate for (cur = table->keys[item->keychain]; cur; 4357c478bd9Sstevel@tonic-gate prev = cur, cur = cur->next) { 4367c478bd9Sstevel@tonic-gate if (cur == item) { 4377c478bd9Sstevel@tonic-gate if (prev) 4387c478bd9Sstevel@tonic-gate prev->next = cur->next; 4397c478bd9Sstevel@tonic-gate else 4407c478bd9Sstevel@tonic-gate table->keys[cur->keychain] = cur->next; 4417c478bd9Sstevel@tonic-gate if (cur->prv_item) 4427c478bd9Sstevel@tonic-gate cur->prv_item->nxt_item = cur->nxt_item; 4437c478bd9Sstevel@tonic-gate else 4447c478bd9Sstevel@tonic-gate table->first = cur->nxt_item; 4457c478bd9Sstevel@tonic-gate if (cur->nxt_item) 4467c478bd9Sstevel@tonic-gate cur->nxt_item->prv_item = cur->prv_item; 4477c478bd9Sstevel@tonic-gate break; 4487c478bd9Sstevel@tonic-gate } 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * We use keychain < 0 to indicate that the item isn't linked 4537c478bd9Sstevel@tonic-gate * into the table anymore. 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate item->keychain = -1; 4567c478bd9Sstevel@tonic-gate 4577c478bd9Sstevel@tonic-gate /* Adjust the count of locked items in the table */ 4587c478bd9Sstevel@tonic-gate if (table->locked_items != 0 && 4597c478bd9Sstevel@tonic-gate (item->writer > 0 || item->readers > 0)) { 4607c478bd9Sstevel@tonic-gate table->locked_items--; 4617c478bd9Sstevel@tonic-gate if (table->locked_items == 0) { 4627c478bd9Sstevel@tonic-gate /* Wake up traversers-to-be */ 4637c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 4647c478bd9Sstevel@tonic-gate } 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * Wake up any threads that were waiting for this item. Obviously, 4697c478bd9Sstevel@tonic-gate * such threads must start over scanning the list. 4707c478bd9Sstevel@tonic-gate */ 4717c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&item->lock); 4727c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&item->lock); 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate /* 4757c478bd9Sstevel@tonic-gate * If the item isn't locked, and an item destructor has been 4767c478bd9Sstevel@tonic-gate * established, invoke the destructor. 4777c478bd9Sstevel@tonic-gate */ 4787c478bd9Sstevel@tonic-gate if (item->readers == 0 && item->writer == 0 && 4797c478bd9Sstevel@tonic-gate table->destroyItem != 0) { 4807c478bd9Sstevel@tonic-gate (*table->destroyItem)(item); 4817c478bd9Sstevel@tonic-gate item = 0; 4827c478bd9Sstevel@tonic-gate } else { 4837c478bd9Sstevel@tonic-gate item->next = 0; 4847c478bd9Sstevel@tonic-gate item->prv_item = 0; 4857c478bd9Sstevel@tonic-gate item->nxt_item = 0; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "npimt"); 4897c478bd9Sstevel@tonic-gate 4907c478bd9Sstevel@tonic-gate /* 4917c478bd9Sstevel@tonic-gate * If we get here, and the 'item' is NULL, we've popped the 4927c478bd9Sstevel@tonic-gate * item, but also destroyed it. Returning NULL would make 4937c478bd9Sstevel@tonic-gate * our caller believe the list is empty, so instead, we invoke 4947c478bd9Sstevel@tonic-gate * ourselves to pop the next item. 4957c478bd9Sstevel@tonic-gate */ 4967c478bd9Sstevel@tonic-gate return ((item != 0) ? item : __nis_pop_item_mt(table)); 4977c478bd9Sstevel@tonic-gate } 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate void * 5007c478bd9Sstevel@tonic-gate __nis_remove_item_mt(nis_name name, __nis_hash_table_mt *table) { 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate __nis_hash_item_mt *nl, **pp; 5037c478bd9Sstevel@tonic-gate pthread_t mtid; 5047c478bd9Sstevel@tonic-gate 5057c478bd9Sstevel@tonic-gate if (__nis_lock_hash_table(table, 0, "nrimt") == 0) 5067c478bd9Sstevel@tonic-gate return (0); 5077c478bd9Sstevel@tonic-gate 5087c478bd9Sstevel@tonic-gate /* Find the item, and make sure it's not in use */ 5097c478bd9Sstevel@tonic-gate mtid = pthread_self(); 5107c478bd9Sstevel@tonic-gate while ((nl = *(pp = __find_item_mt(name, table, (int *)0))) != 0) { 5117c478bd9Sstevel@tonic-gate if (table->destroyItem != 0) 5127c478bd9Sstevel@tonic-gate break; 5137c478bd9Sstevel@tonic-gate if (nl->readers == 0 && nl->writer == 0) 5147c478bd9Sstevel@tonic-gate break; 5157c478bd9Sstevel@tonic-gate if (nl->writer != 0 && nl->writer_id == mtid) 5167c478bd9Sstevel@tonic-gate break; 5177c478bd9Sstevel@tonic-gate (void) pthread_cond_wait(&nl->lock, &table->lock); 5187c478bd9Sstevel@tonic-gate } 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if (nl == 0) { 5217c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nrimt"); 5227c478bd9Sstevel@tonic-gate return (0); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate 5257c478bd9Sstevel@tonic-gate /* Remove nl from the hash chain */ 5267c478bd9Sstevel@tonic-gate *pp = nl->next; 5277c478bd9Sstevel@tonic-gate nl->next = 0; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* Remove nl from the linked list of all names */ 5307c478bd9Sstevel@tonic-gate if (nl->prv_item) 5317c478bd9Sstevel@tonic-gate nl->prv_item->nxt_item = nl->nxt_item; 5327c478bd9Sstevel@tonic-gate else 5337c478bd9Sstevel@tonic-gate table->first = nl->nxt_item; 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate if (nl->nxt_item) 5367c478bd9Sstevel@tonic-gate nl->nxt_item->prv_item = nl->prv_item; 5377c478bd9Sstevel@tonic-gate nl->prv_item = 0; 5387c478bd9Sstevel@tonic-gate nl->nxt_item = 0; 5397c478bd9Sstevel@tonic-gate 5407c478bd9Sstevel@tonic-gate /* keychain < 0 means not in table anymore */ 5417c478bd9Sstevel@tonic-gate nl->keychain = -1; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate /* 5447c478bd9Sstevel@tonic-gate * If this item was locked, we can now decrement the count of 5457c478bd9Sstevel@tonic-gate * locked items for the table. 5467c478bd9Sstevel@tonic-gate */ 5477c478bd9Sstevel@tonic-gate if (table->locked_items != 0 && 5487c478bd9Sstevel@tonic-gate (nl->writer > 0 || nl->readers > 0)) { 5497c478bd9Sstevel@tonic-gate table->locked_items--; 5507c478bd9Sstevel@tonic-gate if (table->locked_items == 0) { 5517c478bd9Sstevel@tonic-gate /* Wake up traversers-to-be */ 5527c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate } 5557c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&nl->lock); 5567c478bd9Sstevel@tonic-gate (void) pthread_cond_destroy(&nl->lock); 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate /* 5597c478bd9Sstevel@tonic-gate * If the item isn't locked, and an item destructor has been 5607c478bd9Sstevel@tonic-gate * established, invoke the destructor. In that case, we return 5617c478bd9Sstevel@tonic-gate * NULL, so that our caller doesn't try to reference the 5627c478bd9Sstevel@tonic-gate * deleted item. 5637c478bd9Sstevel@tonic-gate */ 5647c478bd9Sstevel@tonic-gate if (nl->readers == 0 && nl->writer == 0 && table->destroyItem != 0) { 5657c478bd9Sstevel@tonic-gate (*table->destroyItem)(nl); 5667c478bd9Sstevel@tonic-gate nl = 0; 5677c478bd9Sstevel@tonic-gate } 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nrimt"); 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate return (nl); 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate /* 5757c478bd9Sstevel@tonic-gate * Release an item that had been acquired exclusively or non-exclusively. 5767c478bd9Sstevel@tonic-gate * Note that 'readwrite' can assume any integer value, and thus can be 5777c478bd9Sstevel@tonic-gate * used to release any level of recursive locking. It's the responsibility 5787c478bd9Sstevel@tonic-gate * of the caller to make sure that proper nesting is maintained. 5797c478bd9Sstevel@tonic-gate */ 5807c478bd9Sstevel@tonic-gate int 5817c478bd9Sstevel@tonic-gate __nis_release_item(void *arg, __nis_hash_table_mt *table, int readwrite) { 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item = arg; 5847c478bd9Sstevel@tonic-gate int wakeup = 0; 5857c478bd9Sstevel@tonic-gate 5867c478bd9Sstevel@tonic-gate if (item == 0 || __nis_lock_hash_table(table, 0, "nreli") == 0) 5877c478bd9Sstevel@tonic-gate return (0); 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate if ((readwrite < 0 && abs(readwrite) > item->writer) || 5907c478bd9Sstevel@tonic-gate (readwrite < 0 && item->writer > 0 && 5917c478bd9Sstevel@tonic-gate item->writer_id != pthread_self()) || 5927c478bd9Sstevel@tonic-gate (readwrite > 0 && readwrite > item->readers)) { 5937c478bd9Sstevel@tonic-gate /* Caller confused; ignore */ 5947c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nreli"); 5957c478bd9Sstevel@tonic-gate return (0); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate if (readwrite < 0) { 5997c478bd9Sstevel@tonic-gate item->writer += readwrite; 6007c478bd9Sstevel@tonic-gate if (item->writer == 0 && item->keychain >= 0) { 6017c478bd9Sstevel@tonic-gate if (table->locked_items != 0) 6027c478bd9Sstevel@tonic-gate table->locked_items--; 6037c478bd9Sstevel@tonic-gate wakeup = 1; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate } else if (readwrite > 0) { 6067c478bd9Sstevel@tonic-gate item->readers -= readwrite; 6077c478bd9Sstevel@tonic-gate item->last_reader_id = INV_PTHREAD_ID; 6087c478bd9Sstevel@tonic-gate if (item->readers == 0 && item->keychain >= 0) { 6097c478bd9Sstevel@tonic-gate if (table->locked_items != 0) 6107c478bd9Sstevel@tonic-gate table->locked_items--; 6117c478bd9Sstevel@tonic-gate wakeup = 1; 6127c478bd9Sstevel@tonic-gate } 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate if (table->locked_items == 0) { 6167c478bd9Sstevel@tonic-gate /* Wake up traversers-to-be */ 6177c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&table->cond); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate if (wakeup) { 6207c478bd9Sstevel@tonic-gate /* Wake up anyone else who wants this item */ 6217c478bd9Sstevel@tonic-gate (void) pthread_cond_signal(&item->lock); 6227c478bd9Sstevel@tonic-gate } 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * Delete if no references, not linked into list, and destructor 6267c478bd9Sstevel@tonic-gate * established. 6277c478bd9Sstevel@tonic-gate */ 6287c478bd9Sstevel@tonic-gate if (item->keychain < 0 && 6297c478bd9Sstevel@tonic-gate item->readers == 0 && item->writer == 0 && 6307c478bd9Sstevel@tonic-gate item->next == 0 && 6317c478bd9Sstevel@tonic-gate item->prv_item == 0 && item->nxt_item == 0 && 6327c478bd9Sstevel@tonic-gate table->destroyItem != 0) 6337c478bd9Sstevel@tonic-gate (*table->destroyItem)(item); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate (void) __nis_ulock_hash_table(table, 0, "nreli"); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate return (1); 6387c478bd9Sstevel@tonic-gate } 6397c478bd9Sstevel@tonic-gate 6407c478bd9Sstevel@tonic-gate /* 6417c478bd9Sstevel@tonic-gate * Return -1 if item checked out for both reading and writing, 1 if 6427c478bd9Sstevel@tonic-gate * readonly, and 0 otherwise. 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate int 6457c478bd9Sstevel@tonic-gate __nis_item_access(void *arg) { 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate __nis_hash_item_mt *item = arg; 6487c478bd9Sstevel@tonic-gate 6497c478bd9Sstevel@tonic-gate if (item != 0) { 6507c478bd9Sstevel@tonic-gate if (item->writer > 0) { 6517c478bd9Sstevel@tonic-gate if (item->writer_id != pthread_self()) 6527c478bd9Sstevel@tonic-gate abort(); 6537c478bd9Sstevel@tonic-gate return (-1); 6547c478bd9Sstevel@tonic-gate } else if (item->readers > 0) { 6557c478bd9Sstevel@tonic-gate return (1); 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate } 6587c478bd9Sstevel@tonic-gate 6597c478bd9Sstevel@tonic-gate return (0); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate 6627c478bd9Sstevel@tonic-gate /* 6637c478bd9Sstevel@tonic-gate * __nis_scan_table_mt() 6647c478bd9Sstevel@tonic-gate * 6657c478bd9Sstevel@tonic-gate * Iterate over all items in a __nis_hash_table_mt. We ignore 6667c478bd9Sstevel@tonic-gate * first/prv_item/nxt_item and scan in hash-chain order. The iterator 6677c478bd9Sstevel@tonic-gate * function should *not* insert or delete items. If the iterator 6687c478bd9Sstevel@tonic-gate * function returns TRUE the scan terminates. For compatibility with 6697c478bd9Sstevel@tonic-gate * the existing non-MT nis_scan_table() this function has no return 6707c478bd9Sstevel@tonic-gate * value. 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate void 6737c478bd9Sstevel@tonic-gate __nis_scan_table_mt( 6747c478bd9Sstevel@tonic-gate __nis_hash_table_mt *table, 6757c478bd9Sstevel@tonic-gate bool_t (*func)(__nis_hash_item_mt *, void *), 6767c478bd9Sstevel@tonic-gate void *funcarg) 6777c478bd9Sstevel@tonic-gate { 6787c478bd9Sstevel@tonic-gate int slot; 6797c478bd9Sstevel@tonic-gate 6807c478bd9Sstevel@tonic-gate if (table == 0) { 6817c478bd9Sstevel@tonic-gate return; 6827c478bd9Sstevel@tonic-gate } 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (__nis_lock_hash_table(table, 1, "nstmt") == 0) { 6857c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "__nis_scan_table_mt: mutex lock failed "); 6867c478bd9Sstevel@tonic-gate return; 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate 6897c478bd9Sstevel@tonic-gate for (slot = 0; 6907c478bd9Sstevel@tonic-gate slot < sizeof (table->keys) / sizeof (table->keys[0]); 6917c478bd9Sstevel@tonic-gate slot++) { 6927c478bd9Sstevel@tonic-gate __nis_hash_item_mt *it; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate for (it = table->keys[slot]; it != 0; it = it->next) { 6957c478bd9Sstevel@tonic-gate if (TRUE == (*func)(it, funcarg)) { 6967c478bd9Sstevel@tonic-gate break; 6977c478bd9Sstevel@tonic-gate } 6987c478bd9Sstevel@tonic-gate } 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate if (__nis_ulock_hash_table(table, 1, "nstmt") == 0) 7017c478bd9Sstevel@tonic-gate syslog(LOG_DEBUG, "__nis_scan_table_mt: mutex unlock failed "); 7027c478bd9Sstevel@tonic-gate } 703