xref: /titanic_53/usr/src/lib/libnisdb/nis_hashitem.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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