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