xref: /onnv-gate/usr/src/lib/libc/port/threads/tdb_agent.c (revision 6812:febeba71273d)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53864Sraf  * Common Development and Distribution License (the "License").
63864Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213864Sraf 
220Sstevel@tonic-gate /*
236515Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This file contains most of the functionality
310Sstevel@tonic-gate  * required to support the threads portion of libc_db.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate #include "lint.h"
350Sstevel@tonic-gate #include "thr_uberdata.h"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate static void
tdb_event_ready(void)380Sstevel@tonic-gate tdb_event_ready(void) {}
390Sstevel@tonic-gate 
400Sstevel@tonic-gate static void
tdb_event_sleep(void)410Sstevel@tonic-gate tdb_event_sleep(void) {}
420Sstevel@tonic-gate 
430Sstevel@tonic-gate static void
tdb_event_switchto(void)440Sstevel@tonic-gate tdb_event_switchto(void) {}
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static void
tdb_event_switchfrom(void)470Sstevel@tonic-gate tdb_event_switchfrom(void) {}
480Sstevel@tonic-gate 
490Sstevel@tonic-gate static void
tdb_event_lock_try(void)500Sstevel@tonic-gate tdb_event_lock_try(void) {}
510Sstevel@tonic-gate 
520Sstevel@tonic-gate static void
tdb_event_catchsig(void)530Sstevel@tonic-gate tdb_event_catchsig(void) {}
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static void
tdb_event_idle(void)560Sstevel@tonic-gate tdb_event_idle(void) {}
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static void
tdb_event_create(void)590Sstevel@tonic-gate tdb_event_create(void) {}
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static void
tdb_event_death(void)620Sstevel@tonic-gate tdb_event_death(void) {}
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static void
tdb_event_preempt(void)650Sstevel@tonic-gate tdb_event_preempt(void) {}
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static void
tdb_event_pri_inherit(void)680Sstevel@tonic-gate tdb_event_pri_inherit(void) {}
690Sstevel@tonic-gate 
700Sstevel@tonic-gate static void
tdb_event_reap(void)710Sstevel@tonic-gate tdb_event_reap(void) {}
720Sstevel@tonic-gate 
730Sstevel@tonic-gate static void
tdb_event_concurrency(void)740Sstevel@tonic-gate tdb_event_concurrency(void) {}
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static void
tdb_event_timeout(void)770Sstevel@tonic-gate tdb_event_timeout(void) {}
780Sstevel@tonic-gate 
790Sstevel@tonic-gate /*
800Sstevel@tonic-gate  * uberflags.uf_tdb_register_sync is set to REGISTER_SYNC_ENABLE by a debugger
810Sstevel@tonic-gate  * to empty the table and then enable synchronization object registration.
820Sstevel@tonic-gate  *
830Sstevel@tonic-gate  * uberflags.uf_tdb_register_sync is set to REGISTER_SYNC_DISABLE by a debugger
840Sstevel@tonic-gate  * to empty the table and then disable synchronization object registration.
850Sstevel@tonic-gate  */
860Sstevel@tonic-gate 
870Sstevel@tonic-gate const tdb_ev_func_t tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1] = {
880Sstevel@tonic-gate 	tdb_event_ready,
890Sstevel@tonic-gate 	tdb_event_sleep,
900Sstevel@tonic-gate 	tdb_event_switchto,
910Sstevel@tonic-gate 	tdb_event_switchfrom,
920Sstevel@tonic-gate 	tdb_event_lock_try,
930Sstevel@tonic-gate 	tdb_event_catchsig,
940Sstevel@tonic-gate 	tdb_event_idle,
950Sstevel@tonic-gate 	tdb_event_create,
960Sstevel@tonic-gate 	tdb_event_death,
970Sstevel@tonic-gate 	tdb_event_preempt,
980Sstevel@tonic-gate 	tdb_event_pri_inherit,
990Sstevel@tonic-gate 	tdb_event_reap,
1000Sstevel@tonic-gate 	tdb_event_concurrency,
1010Sstevel@tonic-gate 	tdb_event_timeout
1020Sstevel@tonic-gate };
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate #if TDB_HASH_SHIFT != 15
1050Sstevel@tonic-gate #error "this is all broken because TDB_HASH_SHIFT is not 15"
1060Sstevel@tonic-gate #endif
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate static uint_t
tdb_addr_hash(void * addr)1090Sstevel@tonic-gate tdb_addr_hash(void *addr)
1100Sstevel@tonic-gate {
1110Sstevel@tonic-gate 	/*
1120Sstevel@tonic-gate 	 * This knows for a fact that the hash table has
1130Sstevel@tonic-gate 	 * 32K entries; that is, that TDB_HASH_SHIFT is 15.
1140Sstevel@tonic-gate 	 */
1150Sstevel@tonic-gate #ifdef	_LP64
1160Sstevel@tonic-gate 	uint64_t value60 = ((uintptr_t)addr >> 4);	/* 60 bits */
1170Sstevel@tonic-gate 	uint32_t value30 = (value60 >> 30) ^ (value60 & 0x3fffffff);
1180Sstevel@tonic-gate #else
1190Sstevel@tonic-gate 	uint32_t value30 = ((uintptr_t)addr >> 2);	/* 30 bits */
1200Sstevel@tonic-gate #endif
1210Sstevel@tonic-gate 	return ((value30 >> 15) ^ (value30 & 0x7fff));
1220Sstevel@tonic-gate }
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate static tdb_sync_stats_t *
alloc_sync_addr(void * addr)1250Sstevel@tonic-gate alloc_sync_addr(void *addr)
1260Sstevel@tonic-gate {
1270Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1280Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
1290Sstevel@tonic-gate 	tdb_sync_stats_t *sap;
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate 	ASSERT(MUTEX_OWNED(&udp->tdb_hash_lock, curthread));
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate 	if ((sap = tdbp->tdb_sync_addr_free) == NULL) {
1340Sstevel@tonic-gate 		void *vaddr;
1350Sstevel@tonic-gate 		int i;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 		/*
1380Sstevel@tonic-gate 		 * Don't keep trying after mmap() has already failed.
1390Sstevel@tonic-gate 		 */
1400Sstevel@tonic-gate 		if (tdbp->tdb_hash_alloc_failed)
1410Sstevel@tonic-gate 			return (NULL);
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate 		/* double the allocation each time */
1440Sstevel@tonic-gate 		tdbp->tdb_sync_alloc *= 2;
1456515Sraf 		if ((vaddr = mmap(NULL,
1460Sstevel@tonic-gate 		    tdbp->tdb_sync_alloc * sizeof (tdb_sync_stats_t),
1470Sstevel@tonic-gate 		    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,
1480Sstevel@tonic-gate 		    -1, (off_t)0)) == MAP_FAILED) {
1490Sstevel@tonic-gate 			tdbp->tdb_hash_alloc_failed = 1;
1500Sstevel@tonic-gate 			return (NULL);
1510Sstevel@tonic-gate 		}
1520Sstevel@tonic-gate 		sap = tdbp->tdb_sync_addr_free = vaddr;
1530Sstevel@tonic-gate 		for (i = 1; i < tdbp->tdb_sync_alloc; sap++, i++)
1540Sstevel@tonic-gate 			sap->next = (uintptr_t)(sap + 1);
1550Sstevel@tonic-gate 		sap->next = (uintptr_t)0;
1560Sstevel@tonic-gate 		tdbp->tdb_sync_addr_last = sap;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 		sap = tdbp->tdb_sync_addr_free;
1590Sstevel@tonic-gate 	}
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	tdbp->tdb_sync_addr_free = (tdb_sync_stats_t *)(uintptr_t)sap->next;
1620Sstevel@tonic-gate 	sap->next = (uintptr_t)0;
1630Sstevel@tonic-gate 	sap->sync_addr = (uintptr_t)addr;
1646515Sraf 	(void) memset(&sap->un, 0, sizeof (sap->un));
1650Sstevel@tonic-gate 	return (sap);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate static void
initialize_sync_hash()1690Sstevel@tonic-gate initialize_sync_hash()
1700Sstevel@tonic-gate {
1710Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1720Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
1730Sstevel@tonic-gate 	uint64_t *addr_hash;
1740Sstevel@tonic-gate 	tdb_sync_stats_t *sap;
1750Sstevel@tonic-gate 	void *vaddr;
1760Sstevel@tonic-gate 	int i;
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 	if (tdbp->tdb_hash_alloc_failed)
1790Sstevel@tonic-gate 		return;
1800Sstevel@tonic-gate 	lmutex_lock(&udp->tdb_hash_lock);
1810Sstevel@tonic-gate 	if (udp->uberflags.uf_tdb_register_sync == REGISTER_SYNC_DISABLE) {
1820Sstevel@tonic-gate 		/*
1830Sstevel@tonic-gate 		 * There is no point allocating the hash table
1840Sstevel@tonic-gate 		 * if we are disabling registration.
1850Sstevel@tonic-gate 		 */
1860Sstevel@tonic-gate 		udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_OFF;
1870Sstevel@tonic-gate 		lmutex_unlock(&udp->tdb_hash_lock);
1880Sstevel@tonic-gate 		return;
1890Sstevel@tonic-gate 	}
1900Sstevel@tonic-gate 	if (tdbp->tdb_sync_addr_hash != NULL || tdbp->tdb_hash_alloc_failed) {
1910Sstevel@tonic-gate 		lmutex_unlock(&udp->tdb_hash_lock);
1920Sstevel@tonic-gate 		return;
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 	/* start with a free list of 2k elements */
1950Sstevel@tonic-gate 	tdbp->tdb_sync_alloc = 2*1024;
1966515Sraf 	if ((vaddr = mmap(NULL, TDB_HASH_SIZE * sizeof (uint64_t) +
1970Sstevel@tonic-gate 	    tdbp->tdb_sync_alloc * sizeof (tdb_sync_stats_t),
1980Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,
1990Sstevel@tonic-gate 	    -1, (off_t)0)) == MAP_FAILED) {
2000Sstevel@tonic-gate 		tdbp->tdb_hash_alloc_failed = 1;
2010Sstevel@tonic-gate 		return;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 	addr_hash = vaddr;
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate 	/* initialize the free list */
2060Sstevel@tonic-gate 	tdbp->tdb_sync_addr_free = sap =
2076515Sraf 	    (tdb_sync_stats_t *)&addr_hash[TDB_HASH_SIZE];
2080Sstevel@tonic-gate 	for (i = 1; i < tdbp->tdb_sync_alloc; sap++, i++)
2090Sstevel@tonic-gate 		sap->next = (uintptr_t)(sap + 1);
2100Sstevel@tonic-gate 	sap->next = (uintptr_t)0;
2110Sstevel@tonic-gate 	tdbp->tdb_sync_addr_last = sap;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/* insert &udp->tdb_hash_lock itself into the new (empty) table */
2140Sstevel@tonic-gate 	udp->tdb_hash_lock_stats.next = (uintptr_t)0;
2150Sstevel@tonic-gate 	udp->tdb_hash_lock_stats.sync_addr = (uintptr_t)&udp->tdb_hash_lock;
2160Sstevel@tonic-gate 	addr_hash[tdb_addr_hash(&udp->tdb_hash_lock)] =
2176515Sraf 	    (uintptr_t)&udp->tdb_hash_lock_stats;
2180Sstevel@tonic-gate 
2193864Sraf 	tdbp->tdb_register_count = 1;
2200Sstevel@tonic-gate 	/* assign to tdb_sync_addr_hash only after fully initialized */
221*6812Sraf 	membar_producer();
2220Sstevel@tonic-gate 	tdbp->tdb_sync_addr_hash = addr_hash;
2230Sstevel@tonic-gate 	lmutex_unlock(&udp->tdb_hash_lock);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate tdb_sync_stats_t *
tdb_sync_obj_register(void * addr,int * new)2270Sstevel@tonic-gate tdb_sync_obj_register(void *addr, int *new)
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	ulwp_t *self = curthread;
2300Sstevel@tonic-gate 	uberdata_t *udp = self->ul_uberdata;
2310Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
2320Sstevel@tonic-gate 	uint64_t *sapp;
2330Sstevel@tonic-gate 	tdb_sync_stats_t *sap = NULL;
2340Sstevel@tonic-gate 	int locked = 0;
2350Sstevel@tonic-gate 	int i;
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	/*
2380Sstevel@tonic-gate 	 * Don't start statistics collection until
2390Sstevel@tonic-gate 	 * we have initialized the primary link map.
2400Sstevel@tonic-gate 	 */
2410Sstevel@tonic-gate 	if (!self->ul_primarymap)
2420Sstevel@tonic-gate 		return (NULL);
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	if (new)
2450Sstevel@tonic-gate 		*new = 0;
2460Sstevel@tonic-gate 	/*
2470Sstevel@tonic-gate 	 * To avoid recursion problems, we must do two things:
2480Sstevel@tonic-gate 	 * 1. Make a special case for tdb_hash_lock (we use it internally).
2490Sstevel@tonic-gate 	 * 2. Deal with the dynamic linker's lock interface:
2500Sstevel@tonic-gate 	 *    When calling any external function, we may invoke the
2510Sstevel@tonic-gate 	 *    dynamic linker.  It grabs a lock, which calls back here.
2520Sstevel@tonic-gate 	 *    This only happens on the first call to the external
2530Sstevel@tonic-gate 	 *    function, so we can just return NULL if we are called
2540Sstevel@tonic-gate 	 *    recursively (and miss the first count).
2550Sstevel@tonic-gate 	 */
2560Sstevel@tonic-gate 	if (addr == (void *)&udp->tdb_hash_lock)
2570Sstevel@tonic-gate 		return (&udp->tdb_hash_lock_stats);
2580Sstevel@tonic-gate 	if (self->ul_sync_obj_reg)		/* recursive call */
2590Sstevel@tonic-gate 		return (NULL);
2600Sstevel@tonic-gate 	self->ul_sync_obj_reg = 1;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * On the first time through, initialize the hash table and free list.
2640Sstevel@tonic-gate 	 */
2650Sstevel@tonic-gate 	if (tdbp->tdb_sync_addr_hash == NULL) {
2660Sstevel@tonic-gate 		initialize_sync_hash();
2670Sstevel@tonic-gate 		if (tdbp->tdb_sync_addr_hash == NULL) {	/* utter failure */
2680Sstevel@tonic-gate 			udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_OFF;
2690Sstevel@tonic-gate 			goto out;
2700Sstevel@tonic-gate 		}
2710Sstevel@tonic-gate 	}
272*6812Sraf 	membar_consumer();
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	sapp = &tdbp->tdb_sync_addr_hash[tdb_addr_hash(addr)];
2750Sstevel@tonic-gate 	if (udp->uberflags.uf_tdb_register_sync == REGISTER_SYNC_ON) {
2760Sstevel@tonic-gate 		/*
2770Sstevel@tonic-gate 		 * Look up an address in the synchronization object hash table.
2780Sstevel@tonic-gate 		 * No lock is required since it can only deliver a false
2790Sstevel@tonic-gate 		 * negative, in which case we fall into the locked case below.
2800Sstevel@tonic-gate 		 */
2810Sstevel@tonic-gate 		for (sap = (tdb_sync_stats_t *)(uintptr_t)*sapp; sap != NULL;
2820Sstevel@tonic-gate 		    sap = (tdb_sync_stats_t *)(uintptr_t)sap->next) {
2830Sstevel@tonic-gate 			if (sap->sync_addr == (uintptr_t)addr)
2840Sstevel@tonic-gate 				goto out;
2850Sstevel@tonic-gate 		}
2860Sstevel@tonic-gate 	}
2870Sstevel@tonic-gate 
2880Sstevel@tonic-gate 	/*
2890Sstevel@tonic-gate 	 * The search with no lock held failed or a special action is required.
2900Sstevel@tonic-gate 	 * Grab tdb_hash_lock to do special actions and/or get a precise result.
2910Sstevel@tonic-gate 	 */
2920Sstevel@tonic-gate 	lmutex_lock(&udp->tdb_hash_lock);
2930Sstevel@tonic-gate 	locked = 1;
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate 	switch (udp->uberflags.uf_tdb_register_sync) {
2960Sstevel@tonic-gate 	case REGISTER_SYNC_ON:
2970Sstevel@tonic-gate 		break;
2980Sstevel@tonic-gate 	case REGISTER_SYNC_OFF:
2990Sstevel@tonic-gate 		goto out;
3000Sstevel@tonic-gate 	default:
3010Sstevel@tonic-gate 		/*
3020Sstevel@tonic-gate 		 * For all debugger actions, first zero out the
3030Sstevel@tonic-gate 		 * statistics block of every element in the hash table.
3040Sstevel@tonic-gate 		 */
3050Sstevel@tonic-gate 		for (i = 0; i < TDB_HASH_SIZE; i++)
3060Sstevel@tonic-gate 			for (sap = (tdb_sync_stats_t *)
3070Sstevel@tonic-gate 			    (uintptr_t)tdbp->tdb_sync_addr_hash[i];
3080Sstevel@tonic-gate 			    sap != NULL;
3090Sstevel@tonic-gate 			    sap = (tdb_sync_stats_t *)(uintptr_t)sap->next)
3106515Sraf 				(void) memset(&sap->un, 0, sizeof (sap->un));
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 		switch (udp->uberflags.uf_tdb_register_sync) {
3130Sstevel@tonic-gate 		case REGISTER_SYNC_ENABLE:
3140Sstevel@tonic-gate 			udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_ON;
3150Sstevel@tonic-gate 			break;
3160Sstevel@tonic-gate 		case REGISTER_SYNC_DISABLE:
3170Sstevel@tonic-gate 		default:
3180Sstevel@tonic-gate 			udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_OFF;
3190Sstevel@tonic-gate 			goto out;
3200Sstevel@tonic-gate 		}
3210Sstevel@tonic-gate 		break;
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/*
3250Sstevel@tonic-gate 	 * Perform the search while holding tdb_hash_lock.
3260Sstevel@tonic-gate 	 * Keep track of the insertion point.
3270Sstevel@tonic-gate 	 */
3280Sstevel@tonic-gate 	while ((sap = (tdb_sync_stats_t *)(uintptr_t)*sapp) != NULL) {
3290Sstevel@tonic-gate 		if (sap->sync_addr == (uintptr_t)addr)
3300Sstevel@tonic-gate 			break;
3310Sstevel@tonic-gate 		sapp = &sap->next;
3320Sstevel@tonic-gate 	}
3330Sstevel@tonic-gate 
3340Sstevel@tonic-gate 	/*
3350Sstevel@tonic-gate 	 * Insert a new element if necessary.
3360Sstevel@tonic-gate 	 */
3370Sstevel@tonic-gate 	if (sap == NULL && (sap = alloc_sync_addr(addr)) != NULL) {
3380Sstevel@tonic-gate 		*sapp = (uintptr_t)sap;
3390Sstevel@tonic-gate 		tdbp->tdb_register_count++;
3400Sstevel@tonic-gate 		if (new)
3410Sstevel@tonic-gate 			*new = 1;
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate out:
3450Sstevel@tonic-gate 	if (locked)
3460Sstevel@tonic-gate 		lmutex_unlock(&udp->tdb_hash_lock);
3470Sstevel@tonic-gate 	self->ul_sync_obj_reg = 0;
3480Sstevel@tonic-gate 	return (sap);
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate void
tdb_sync_obj_deregister(void * addr)3520Sstevel@tonic-gate tdb_sync_obj_deregister(void *addr)
3530Sstevel@tonic-gate {
3540Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
3550Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
3560Sstevel@tonic-gate 	uint64_t *sapp;
3570Sstevel@tonic-gate 	tdb_sync_stats_t *sap;
3580Sstevel@tonic-gate 	uint_t hash;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/*
3610Sstevel@tonic-gate 	 * tdb_hash_lock is never destroyed.
3620Sstevel@tonic-gate 	 */
3630Sstevel@tonic-gate 	ASSERT(addr != &udp->tdb_hash_lock);
3640Sstevel@tonic-gate 
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * Avoid acquiring tdb_hash_lock if lock statistics gathering has
3670Sstevel@tonic-gate 	 * never been initiated or there is nothing in the hash bucket.
3680Sstevel@tonic-gate 	 * (Once the hash table is allocated, it is never deallocated.)
3690Sstevel@tonic-gate 	 */
3700Sstevel@tonic-gate 	if (tdbp->tdb_sync_addr_hash == NULL ||
3710Sstevel@tonic-gate 	    tdbp->tdb_sync_addr_hash[hash = tdb_addr_hash(addr)] == NULL)
3720Sstevel@tonic-gate 		return;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	lmutex_lock(&udp->tdb_hash_lock);
3750Sstevel@tonic-gate 	sapp = &tdbp->tdb_sync_addr_hash[hash];
3760Sstevel@tonic-gate 	while ((sap = (tdb_sync_stats_t *)(uintptr_t)*sapp) != NULL) {
3770Sstevel@tonic-gate 		if (sap->sync_addr == (uintptr_t)addr) {
3780Sstevel@tonic-gate 			/* remove it from the hash table */
3790Sstevel@tonic-gate 			*sapp = sap->next;
3800Sstevel@tonic-gate 			tdbp->tdb_register_count--;
3810Sstevel@tonic-gate 			/* clear it */
3820Sstevel@tonic-gate 			sap->next = (uintptr_t)0;
3830Sstevel@tonic-gate 			sap->sync_addr = (uintptr_t)0;
3840Sstevel@tonic-gate 			/* insert it on the tail of the free list */
3850Sstevel@tonic-gate 			if (tdbp->tdb_sync_addr_free == NULL) {
3860Sstevel@tonic-gate 				tdbp->tdb_sync_addr_free = sap;
3870Sstevel@tonic-gate 				tdbp->tdb_sync_addr_last = sap;
3880Sstevel@tonic-gate 			} else {
3890Sstevel@tonic-gate 				tdbp->tdb_sync_addr_last->next = (uintptr_t)sap;
3900Sstevel@tonic-gate 				tdbp->tdb_sync_addr_last = sap;
3910Sstevel@tonic-gate 			}
3920Sstevel@tonic-gate 			break;
3930Sstevel@tonic-gate 		}
3940Sstevel@tonic-gate 		sapp = &sap->next;
3950Sstevel@tonic-gate 	}
3960Sstevel@tonic-gate 	lmutex_unlock(&udp->tdb_hash_lock);
3970Sstevel@tonic-gate }
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate /*
4000Sstevel@tonic-gate  * Return a mutex statistics block for the given mutex.
4010Sstevel@tonic-gate  */
4020Sstevel@tonic-gate tdb_mutex_stats_t *
tdb_mutex_stats(mutex_t * mp)4030Sstevel@tonic-gate tdb_mutex_stats(mutex_t *mp)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4080Sstevel@tonic-gate 	if (mp->mutex_magic != MUTEX_MAGIC)
4090Sstevel@tonic-gate 		mp->mutex_magic = MUTEX_MAGIC;
4100Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(mp, NULL)) == NULL)
4110Sstevel@tonic-gate 		return (NULL);
4120Sstevel@tonic-gate 	tssp->un.type = TDB_MUTEX;
4130Sstevel@tonic-gate 	return (&tssp->un.mutex);
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate /*
4170Sstevel@tonic-gate  * Return a condvar statistics block for the given condvar.
4180Sstevel@tonic-gate  */
4190Sstevel@tonic-gate tdb_cond_stats_t *
tdb_cond_stats(cond_t * cvp)4200Sstevel@tonic-gate tdb_cond_stats(cond_t *cvp)
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4250Sstevel@tonic-gate 	if (cvp->cond_magic != COND_MAGIC)
4260Sstevel@tonic-gate 		cvp->cond_magic = COND_MAGIC;
4270Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(cvp, NULL)) == NULL)
4280Sstevel@tonic-gate 		return (NULL);
4290Sstevel@tonic-gate 	tssp->un.type = TDB_COND;
4300Sstevel@tonic-gate 	return (&tssp->un.cond);
4310Sstevel@tonic-gate }
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate /*
4340Sstevel@tonic-gate  * Return an rwlock statistics block for the given rwlock.
4350Sstevel@tonic-gate  */
4360Sstevel@tonic-gate tdb_rwlock_stats_t *
tdb_rwlock_stats(rwlock_t * rwlp)4370Sstevel@tonic-gate tdb_rwlock_stats(rwlock_t *rwlp)
4380Sstevel@tonic-gate {
4390Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4420Sstevel@tonic-gate 	if (rwlp->magic != RWL_MAGIC)
4430Sstevel@tonic-gate 		rwlp->magic = RWL_MAGIC;
4440Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(rwlp, NULL)) == NULL)
4450Sstevel@tonic-gate 		return (NULL);
4460Sstevel@tonic-gate 	tssp->un.type = TDB_RWLOCK;
4470Sstevel@tonic-gate 	return (&tssp->un.rwlock);
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * Return a semaphore statistics block for the given semaphore.
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate tdb_sema_stats_t *
tdb_sema_stats(sema_t * sp)4540Sstevel@tonic-gate tdb_sema_stats(sema_t *sp)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4570Sstevel@tonic-gate 	int new;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4600Sstevel@tonic-gate 	if (sp->magic != SEMA_MAGIC)
4610Sstevel@tonic-gate 		sp->magic = SEMA_MAGIC;
4620Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(sp, &new)) == NULL)
4630Sstevel@tonic-gate 		return (NULL);
4640Sstevel@tonic-gate 	tssp->un.type = TDB_SEMA;
4650Sstevel@tonic-gate 	if (new) {
4660Sstevel@tonic-gate 		tssp->un.sema.sema_max_count = sp->count;
4670Sstevel@tonic-gate 		tssp->un.sema.sema_min_count = sp->count;
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 	return (&tssp->un.sema);
4700Sstevel@tonic-gate }
471