xref: /illumos-gate/usr/src/lib/libc/port/threads/tdb_agent.c (revision e86c3f00315e5838c0ec0b14f34b94c292085956)
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
5cb620785Sraf  * Common Development and Distribution License (the "License").
6cb620785Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21cb620785Sraf 
227c478bd9Sstevel@tonic-gate /*
238cd45542Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * This file contains most of the functionality
297c478bd9Sstevel@tonic-gate  * required to support the threads portion of libc_db.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "lint.h"
337c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate static void
tdb_event_ready(void)367c478bd9Sstevel@tonic-gate tdb_event_ready(void) {}
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate static void
tdb_event_sleep(void)397c478bd9Sstevel@tonic-gate tdb_event_sleep(void) {}
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate static void
tdb_event_switchto(void)427c478bd9Sstevel@tonic-gate tdb_event_switchto(void) {}
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate static void
tdb_event_switchfrom(void)457c478bd9Sstevel@tonic-gate tdb_event_switchfrom(void) {}
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate static void
tdb_event_lock_try(void)487c478bd9Sstevel@tonic-gate tdb_event_lock_try(void) {}
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate static void
tdb_event_catchsig(void)517c478bd9Sstevel@tonic-gate tdb_event_catchsig(void) {}
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static void
tdb_event_idle(void)547c478bd9Sstevel@tonic-gate tdb_event_idle(void) {}
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate static void
tdb_event_create(void)577c478bd9Sstevel@tonic-gate tdb_event_create(void) {}
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate static void
tdb_event_death(void)607c478bd9Sstevel@tonic-gate tdb_event_death(void) {}
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static void
tdb_event_preempt(void)637c478bd9Sstevel@tonic-gate tdb_event_preempt(void) {}
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static void
tdb_event_pri_inherit(void)667c478bd9Sstevel@tonic-gate tdb_event_pri_inherit(void) {}
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static void
tdb_event_reap(void)697c478bd9Sstevel@tonic-gate tdb_event_reap(void) {}
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static void
tdb_event_concurrency(void)727c478bd9Sstevel@tonic-gate tdb_event_concurrency(void) {}
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static void
tdb_event_timeout(void)757c478bd9Sstevel@tonic-gate tdb_event_timeout(void) {}
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate /*
787c478bd9Sstevel@tonic-gate  * uberflags.uf_tdb_register_sync is set to REGISTER_SYNC_ENABLE by a debugger
797c478bd9Sstevel@tonic-gate  * to empty the table and then enable synchronization object registration.
807c478bd9Sstevel@tonic-gate  *
817c478bd9Sstevel@tonic-gate  * uberflags.uf_tdb_register_sync is set to REGISTER_SYNC_DISABLE by a debugger
827c478bd9Sstevel@tonic-gate  * to empty the table and then disable synchronization object registration.
837c478bd9Sstevel@tonic-gate  */
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate const tdb_ev_func_t tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1] = {
867c478bd9Sstevel@tonic-gate 	tdb_event_ready,
877c478bd9Sstevel@tonic-gate 	tdb_event_sleep,
887c478bd9Sstevel@tonic-gate 	tdb_event_switchto,
897c478bd9Sstevel@tonic-gate 	tdb_event_switchfrom,
907c478bd9Sstevel@tonic-gate 	tdb_event_lock_try,
917c478bd9Sstevel@tonic-gate 	tdb_event_catchsig,
927c478bd9Sstevel@tonic-gate 	tdb_event_idle,
937c478bd9Sstevel@tonic-gate 	tdb_event_create,
947c478bd9Sstevel@tonic-gate 	tdb_event_death,
957c478bd9Sstevel@tonic-gate 	tdb_event_preempt,
967c478bd9Sstevel@tonic-gate 	tdb_event_pri_inherit,
977c478bd9Sstevel@tonic-gate 	tdb_event_reap,
987c478bd9Sstevel@tonic-gate 	tdb_event_concurrency,
997c478bd9Sstevel@tonic-gate 	tdb_event_timeout
1007c478bd9Sstevel@tonic-gate };
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate #if TDB_HASH_SHIFT != 15
1037c478bd9Sstevel@tonic-gate #error "this is all broken because TDB_HASH_SHIFT is not 15"
1047c478bd9Sstevel@tonic-gate #endif
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate static uint_t
tdb_addr_hash(void * addr)1077c478bd9Sstevel@tonic-gate tdb_addr_hash(void *addr)
1087c478bd9Sstevel@tonic-gate {
1097c478bd9Sstevel@tonic-gate 	/*
1107c478bd9Sstevel@tonic-gate 	 * This knows for a fact that the hash table has
1117c478bd9Sstevel@tonic-gate 	 * 32K entries; that is, that TDB_HASH_SHIFT is 15.
1127c478bd9Sstevel@tonic-gate 	 */
1137c478bd9Sstevel@tonic-gate #ifdef	_LP64
1147c478bd9Sstevel@tonic-gate 	uint64_t value60 = ((uintptr_t)addr >> 4);	/* 60 bits */
1157c478bd9Sstevel@tonic-gate 	uint32_t value30 = (value60 >> 30) ^ (value60 & 0x3fffffff);
1167c478bd9Sstevel@tonic-gate #else
1177c478bd9Sstevel@tonic-gate 	uint32_t value30 = ((uintptr_t)addr >> 2);	/* 30 bits */
1187c478bd9Sstevel@tonic-gate #endif
1197c478bd9Sstevel@tonic-gate 	return ((value30 >> 15) ^ (value30 & 0x7fff));
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate static tdb_sync_stats_t *
alloc_sync_addr(void * addr)1237c478bd9Sstevel@tonic-gate alloc_sync_addr(void *addr)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1267c478bd9Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
1277c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *sap;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_OWNED(&udp->tdb_hash_lock, curthread));
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	if ((sap = tdbp->tdb_sync_addr_free) == NULL) {
1327c478bd9Sstevel@tonic-gate 		void *vaddr;
1337c478bd9Sstevel@tonic-gate 		int i;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 		/*
1367c478bd9Sstevel@tonic-gate 		 * Don't keep trying after mmap() has already failed.
1377c478bd9Sstevel@tonic-gate 		 */
1387c478bd9Sstevel@tonic-gate 		if (tdbp->tdb_hash_alloc_failed)
1397c478bd9Sstevel@tonic-gate 			return (NULL);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 		/* double the allocation each time */
1427c478bd9Sstevel@tonic-gate 		tdbp->tdb_sync_alloc *= 2;
1438cd45542Sraf 		if ((vaddr = mmap(NULL,
1447c478bd9Sstevel@tonic-gate 		    tdbp->tdb_sync_alloc * sizeof (tdb_sync_stats_t),
1457c478bd9Sstevel@tonic-gate 		    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,
1467c478bd9Sstevel@tonic-gate 		    -1, (off_t)0)) == MAP_FAILED) {
1477c478bd9Sstevel@tonic-gate 			tdbp->tdb_hash_alloc_failed = 1;
1487c478bd9Sstevel@tonic-gate 			return (NULL);
1497c478bd9Sstevel@tonic-gate 		}
1507c478bd9Sstevel@tonic-gate 		sap = tdbp->tdb_sync_addr_free = vaddr;
1517c478bd9Sstevel@tonic-gate 		for (i = 1; i < tdbp->tdb_sync_alloc; sap++, i++)
1527c478bd9Sstevel@tonic-gate 			sap->next = (uintptr_t)(sap + 1);
1537c478bd9Sstevel@tonic-gate 		sap->next = (uintptr_t)0;
1547c478bd9Sstevel@tonic-gate 		tdbp->tdb_sync_addr_last = sap;
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 		sap = tdbp->tdb_sync_addr_free;
1577c478bd9Sstevel@tonic-gate 	}
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate 	tdbp->tdb_sync_addr_free = (tdb_sync_stats_t *)(uintptr_t)sap->next;
1607c478bd9Sstevel@tonic-gate 	sap->next = (uintptr_t)0;
1617c478bd9Sstevel@tonic-gate 	sap->sync_addr = (uintptr_t)addr;
1628cd45542Sraf 	(void) memset(&sap->un, 0, sizeof (sap->un));
1637c478bd9Sstevel@tonic-gate 	return (sap);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static void
initialize_sync_hash()1677c478bd9Sstevel@tonic-gate initialize_sync_hash()
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1707c478bd9Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
1717c478bd9Sstevel@tonic-gate 	uint64_t *addr_hash;
1727c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *sap;
1737c478bd9Sstevel@tonic-gate 	void *vaddr;
1747c478bd9Sstevel@tonic-gate 	int i;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	if (tdbp->tdb_hash_alloc_failed)
1777c478bd9Sstevel@tonic-gate 		return;
1787c478bd9Sstevel@tonic-gate 	lmutex_lock(&udp->tdb_hash_lock);
1797c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_tdb_register_sync == REGISTER_SYNC_DISABLE) {
1807c478bd9Sstevel@tonic-gate 		/*
1817c478bd9Sstevel@tonic-gate 		 * There is no point allocating the hash table
1827c478bd9Sstevel@tonic-gate 		 * if we are disabling registration.
1837c478bd9Sstevel@tonic-gate 		 */
1847c478bd9Sstevel@tonic-gate 		udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_OFF;
1857c478bd9Sstevel@tonic-gate 		lmutex_unlock(&udp->tdb_hash_lock);
1867c478bd9Sstevel@tonic-gate 		return;
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 	if (tdbp->tdb_sync_addr_hash != NULL || tdbp->tdb_hash_alloc_failed) {
1897c478bd9Sstevel@tonic-gate 		lmutex_unlock(&udp->tdb_hash_lock);
1907c478bd9Sstevel@tonic-gate 		return;
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 	/* start with a free list of 2k elements */
1937c478bd9Sstevel@tonic-gate 	tdbp->tdb_sync_alloc = 2*1024;
1948cd45542Sraf 	if ((vaddr = mmap(NULL, TDB_HASH_SIZE * sizeof (uint64_t) +
1957c478bd9Sstevel@tonic-gate 	    tdbp->tdb_sync_alloc * sizeof (tdb_sync_stats_t),
1967c478bd9Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON,
1977c478bd9Sstevel@tonic-gate 	    -1, (off_t)0)) == MAP_FAILED) {
1987c478bd9Sstevel@tonic-gate 		tdbp->tdb_hash_alloc_failed = 1;
1997c478bd9Sstevel@tonic-gate 		return;
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 	addr_hash = vaddr;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	/* initialize the free list */
2047c478bd9Sstevel@tonic-gate 	tdbp->tdb_sync_addr_free = sap =
2057c478bd9Sstevel@tonic-gate 	    (tdb_sync_stats_t *)&addr_hash[TDB_HASH_SIZE];
2067c478bd9Sstevel@tonic-gate 	for (i = 1; i < tdbp->tdb_sync_alloc; sap++, i++)
2077c478bd9Sstevel@tonic-gate 		sap->next = (uintptr_t)(sap + 1);
2087c478bd9Sstevel@tonic-gate 	sap->next = (uintptr_t)0;
2097c478bd9Sstevel@tonic-gate 	tdbp->tdb_sync_addr_last = sap;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	/* insert &udp->tdb_hash_lock itself into the new (empty) table */
2127c478bd9Sstevel@tonic-gate 	udp->tdb_hash_lock_stats.next = (uintptr_t)0;
2137c478bd9Sstevel@tonic-gate 	udp->tdb_hash_lock_stats.sync_addr = (uintptr_t)&udp->tdb_hash_lock;
2147c478bd9Sstevel@tonic-gate 	addr_hash[tdb_addr_hash(&udp->tdb_hash_lock)] =
2157c478bd9Sstevel@tonic-gate 	    (uintptr_t)&udp->tdb_hash_lock_stats;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	tdbp->tdb_register_count = 1;
218cb620785Sraf 	/* assign to tdb_sync_addr_hash only after fully initialized */
2197257d1b4Sraf 	membar_producer();
220cb620785Sraf 	tdbp->tdb_sync_addr_hash = addr_hash;
2217c478bd9Sstevel@tonic-gate 	lmutex_unlock(&udp->tdb_hash_lock);
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate tdb_sync_stats_t *
tdb_sync_obj_register(void * addr,int * new)2257c478bd9Sstevel@tonic-gate tdb_sync_obj_register(void *addr, int *new)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	ulwp_t *self = curthread;
2287c478bd9Sstevel@tonic-gate 	uberdata_t *udp = self->ul_uberdata;
2297c478bd9Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
2307c478bd9Sstevel@tonic-gate 	uint64_t *sapp;
2317c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *sap = NULL;
2327c478bd9Sstevel@tonic-gate 	int locked = 0;
2337c478bd9Sstevel@tonic-gate 	int i;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * Don't start statistics collection until
2377c478bd9Sstevel@tonic-gate 	 * we have initialized the primary link map.
2387c478bd9Sstevel@tonic-gate 	 */
2397c478bd9Sstevel@tonic-gate 	if (!self->ul_primarymap)
2407c478bd9Sstevel@tonic-gate 		return (NULL);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	if (new)
2437c478bd9Sstevel@tonic-gate 		*new = 0;
2447c478bd9Sstevel@tonic-gate 	/*
2457c478bd9Sstevel@tonic-gate 	 * To avoid recursion problems, we must do two things:
2467c478bd9Sstevel@tonic-gate 	 * 1. Make a special case for tdb_hash_lock (we use it internally).
2477c478bd9Sstevel@tonic-gate 	 * 2. Deal with the dynamic linker's lock interface:
2487c478bd9Sstevel@tonic-gate 	 *    When calling any external function, we may invoke the
2497c478bd9Sstevel@tonic-gate 	 *    dynamic linker.  It grabs a lock, which calls back here.
2507c478bd9Sstevel@tonic-gate 	 *    This only happens on the first call to the external
2517c478bd9Sstevel@tonic-gate 	 *    function, so we can just return NULL if we are called
2527c478bd9Sstevel@tonic-gate 	 *    recursively (and miss the first count).
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	if (addr == (void *)&udp->tdb_hash_lock)
2557c478bd9Sstevel@tonic-gate 		return (&udp->tdb_hash_lock_stats);
2567c478bd9Sstevel@tonic-gate 	if (self->ul_sync_obj_reg)		/* recursive call */
2577c478bd9Sstevel@tonic-gate 		return (NULL);
2587c478bd9Sstevel@tonic-gate 	self->ul_sync_obj_reg = 1;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	/*
2617c478bd9Sstevel@tonic-gate 	 * On the first time through, initialize the hash table and free list.
2627c478bd9Sstevel@tonic-gate 	 */
2637c478bd9Sstevel@tonic-gate 	if (tdbp->tdb_sync_addr_hash == NULL) {
2647c478bd9Sstevel@tonic-gate 		initialize_sync_hash();
2657c478bd9Sstevel@tonic-gate 		if (tdbp->tdb_sync_addr_hash == NULL) {	/* utter failure */
2667c478bd9Sstevel@tonic-gate 			udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_OFF;
2677c478bd9Sstevel@tonic-gate 			goto out;
2687c478bd9Sstevel@tonic-gate 		}
2697c478bd9Sstevel@tonic-gate 	}
2707257d1b4Sraf 	membar_consumer();
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	sapp = &tdbp->tdb_sync_addr_hash[tdb_addr_hash(addr)];
2737c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_tdb_register_sync == REGISTER_SYNC_ON) {
2747c478bd9Sstevel@tonic-gate 		/*
2757c478bd9Sstevel@tonic-gate 		 * Look up an address in the synchronization object hash table.
2767c478bd9Sstevel@tonic-gate 		 * No lock is required since it can only deliver a false
2777c478bd9Sstevel@tonic-gate 		 * negative, in which case we fall into the locked case below.
2787c478bd9Sstevel@tonic-gate 		 */
2797c478bd9Sstevel@tonic-gate 		for (sap = (tdb_sync_stats_t *)(uintptr_t)*sapp; sap != NULL;
2807c478bd9Sstevel@tonic-gate 		    sap = (tdb_sync_stats_t *)(uintptr_t)sap->next) {
2817c478bd9Sstevel@tonic-gate 			if (sap->sync_addr == (uintptr_t)addr)
2827c478bd9Sstevel@tonic-gate 				goto out;
2837c478bd9Sstevel@tonic-gate 		}
2847c478bd9Sstevel@tonic-gate 	}
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/*
2877c478bd9Sstevel@tonic-gate 	 * The search with no lock held failed or a special action is required.
2887c478bd9Sstevel@tonic-gate 	 * Grab tdb_hash_lock to do special actions and/or get a precise result.
2897c478bd9Sstevel@tonic-gate 	 */
2907c478bd9Sstevel@tonic-gate 	lmutex_lock(&udp->tdb_hash_lock);
2917c478bd9Sstevel@tonic-gate 	locked = 1;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	switch (udp->uberflags.uf_tdb_register_sync) {
2947c478bd9Sstevel@tonic-gate 	case REGISTER_SYNC_ON:
2957c478bd9Sstevel@tonic-gate 		break;
2967c478bd9Sstevel@tonic-gate 	case REGISTER_SYNC_OFF:
2977c478bd9Sstevel@tonic-gate 		goto out;
2987c478bd9Sstevel@tonic-gate 	default:
2997c478bd9Sstevel@tonic-gate 		/*
3007c478bd9Sstevel@tonic-gate 		 * For all debugger actions, first zero out the
3017c478bd9Sstevel@tonic-gate 		 * statistics block of every element in the hash table.
3027c478bd9Sstevel@tonic-gate 		 */
3037c478bd9Sstevel@tonic-gate 		for (i = 0; i < TDB_HASH_SIZE; i++)
3047c478bd9Sstevel@tonic-gate 			for (sap = (tdb_sync_stats_t *)
3057c478bd9Sstevel@tonic-gate 			    (uintptr_t)tdbp->tdb_sync_addr_hash[i];
3067c478bd9Sstevel@tonic-gate 			    sap != NULL;
3077c478bd9Sstevel@tonic-gate 			    sap = (tdb_sync_stats_t *)(uintptr_t)sap->next)
3088cd45542Sraf 				(void) memset(&sap->un, 0, sizeof (sap->un));
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 		switch (udp->uberflags.uf_tdb_register_sync) {
3117c478bd9Sstevel@tonic-gate 		case REGISTER_SYNC_ENABLE:
3127c478bd9Sstevel@tonic-gate 			udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_ON;
3137c478bd9Sstevel@tonic-gate 			break;
3147c478bd9Sstevel@tonic-gate 		case REGISTER_SYNC_DISABLE:
3157c478bd9Sstevel@tonic-gate 		default:
3167c478bd9Sstevel@tonic-gate 			udp->uberflags.uf_tdb_register_sync = REGISTER_SYNC_OFF;
3177c478bd9Sstevel@tonic-gate 			goto out;
3187c478bd9Sstevel@tonic-gate 		}
3197c478bd9Sstevel@tonic-gate 		break;
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	/*
3237c478bd9Sstevel@tonic-gate 	 * Perform the search while holding tdb_hash_lock.
3247c478bd9Sstevel@tonic-gate 	 * Keep track of the insertion point.
3257c478bd9Sstevel@tonic-gate 	 */
3267c478bd9Sstevel@tonic-gate 	while ((sap = (tdb_sync_stats_t *)(uintptr_t)*sapp) != NULL) {
3277c478bd9Sstevel@tonic-gate 		if (sap->sync_addr == (uintptr_t)addr)
3287c478bd9Sstevel@tonic-gate 			break;
3297c478bd9Sstevel@tonic-gate 		sapp = &sap->next;
3307c478bd9Sstevel@tonic-gate 	}
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	/*
3337c478bd9Sstevel@tonic-gate 	 * Insert a new element if necessary.
3347c478bd9Sstevel@tonic-gate 	 */
3357c478bd9Sstevel@tonic-gate 	if (sap == NULL && (sap = alloc_sync_addr(addr)) != NULL) {
3367c478bd9Sstevel@tonic-gate 		*sapp = (uintptr_t)sap;
3377c478bd9Sstevel@tonic-gate 		tdbp->tdb_register_count++;
3387c478bd9Sstevel@tonic-gate 		if (new)
3397c478bd9Sstevel@tonic-gate 			*new = 1;
3407c478bd9Sstevel@tonic-gate 	}
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate out:
3437c478bd9Sstevel@tonic-gate 	if (locked)
3447c478bd9Sstevel@tonic-gate 		lmutex_unlock(&udp->tdb_hash_lock);
3457c478bd9Sstevel@tonic-gate 	self->ul_sync_obj_reg = 0;
3467c478bd9Sstevel@tonic-gate 	return (sap);
3477c478bd9Sstevel@tonic-gate }
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate void
tdb_sync_obj_deregister(void * addr)3507c478bd9Sstevel@tonic-gate tdb_sync_obj_deregister(void *addr)
3517c478bd9Sstevel@tonic-gate {
3527c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
3537c478bd9Sstevel@tonic-gate 	tdb_t *tdbp = &udp->tdb;
3547c478bd9Sstevel@tonic-gate 	uint64_t *sapp;
3557c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *sap;
3567c478bd9Sstevel@tonic-gate 	uint_t hash;
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/*
3597c478bd9Sstevel@tonic-gate 	 * tdb_hash_lock is never destroyed.
3607c478bd9Sstevel@tonic-gate 	 */
3617c478bd9Sstevel@tonic-gate 	ASSERT(addr != &udp->tdb_hash_lock);
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	/*
3647c478bd9Sstevel@tonic-gate 	 * Avoid acquiring tdb_hash_lock if lock statistics gathering has
3657c478bd9Sstevel@tonic-gate 	 * never been initiated or there is nothing in the hash bucket.
3667c478bd9Sstevel@tonic-gate 	 * (Once the hash table is allocated, it is never deallocated.)
3677c478bd9Sstevel@tonic-gate 	 */
3687c478bd9Sstevel@tonic-gate 	if (tdbp->tdb_sync_addr_hash == NULL ||
369*e86c3f00SToomas Soome 	    tdbp->tdb_sync_addr_hash[hash = tdb_addr_hash(addr)] == 0)
3707c478bd9Sstevel@tonic-gate 		return;
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	lmutex_lock(&udp->tdb_hash_lock);
3737c478bd9Sstevel@tonic-gate 	sapp = &tdbp->tdb_sync_addr_hash[hash];
3747c478bd9Sstevel@tonic-gate 	while ((sap = (tdb_sync_stats_t *)(uintptr_t)*sapp) != NULL) {
3757c478bd9Sstevel@tonic-gate 		if (sap->sync_addr == (uintptr_t)addr) {
3767c478bd9Sstevel@tonic-gate 			/* remove it from the hash table */
3777c478bd9Sstevel@tonic-gate 			*sapp = sap->next;
3787c478bd9Sstevel@tonic-gate 			tdbp->tdb_register_count--;
3797c478bd9Sstevel@tonic-gate 			/* clear it */
3807c478bd9Sstevel@tonic-gate 			sap->next = (uintptr_t)0;
3817c478bd9Sstevel@tonic-gate 			sap->sync_addr = (uintptr_t)0;
3827c478bd9Sstevel@tonic-gate 			/* insert it on the tail of the free list */
3837c478bd9Sstevel@tonic-gate 			if (tdbp->tdb_sync_addr_free == NULL) {
3847c478bd9Sstevel@tonic-gate 				tdbp->tdb_sync_addr_free = sap;
3857c478bd9Sstevel@tonic-gate 				tdbp->tdb_sync_addr_last = sap;
3867c478bd9Sstevel@tonic-gate 			} else {
3877c478bd9Sstevel@tonic-gate 				tdbp->tdb_sync_addr_last->next = (uintptr_t)sap;
3887c478bd9Sstevel@tonic-gate 				tdbp->tdb_sync_addr_last = sap;
3897c478bd9Sstevel@tonic-gate 			}
3907c478bd9Sstevel@tonic-gate 			break;
3917c478bd9Sstevel@tonic-gate 		}
3927c478bd9Sstevel@tonic-gate 		sapp = &sap->next;
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	lmutex_unlock(&udp->tdb_hash_lock);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate  * Return a mutex statistics block for the given mutex.
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate tdb_mutex_stats_t *
tdb_mutex_stats(mutex_t * mp)4017c478bd9Sstevel@tonic-gate tdb_mutex_stats(mutex_t *mp)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4067c478bd9Sstevel@tonic-gate 	if (mp->mutex_magic != MUTEX_MAGIC)
4077c478bd9Sstevel@tonic-gate 		mp->mutex_magic = MUTEX_MAGIC;
4087c478bd9Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(mp, NULL)) == NULL)
4097c478bd9Sstevel@tonic-gate 		return (NULL);
4107c478bd9Sstevel@tonic-gate 	tssp->un.type = TDB_MUTEX;
4117c478bd9Sstevel@tonic-gate 	return (&tssp->un.mutex);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * Return a condvar statistics block for the given condvar.
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate tdb_cond_stats_t *
tdb_cond_stats(cond_t * cvp)4187c478bd9Sstevel@tonic-gate tdb_cond_stats(cond_t *cvp)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4237c478bd9Sstevel@tonic-gate 	if (cvp->cond_magic != COND_MAGIC)
4247c478bd9Sstevel@tonic-gate 		cvp->cond_magic = COND_MAGIC;
4257c478bd9Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(cvp, NULL)) == NULL)
4267c478bd9Sstevel@tonic-gate 		return (NULL);
4277c478bd9Sstevel@tonic-gate 	tssp->un.type = TDB_COND;
4287c478bd9Sstevel@tonic-gate 	return (&tssp->un.cond);
4297c478bd9Sstevel@tonic-gate }
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate  * Return an rwlock statistics block for the given rwlock.
4337c478bd9Sstevel@tonic-gate  */
4347c478bd9Sstevel@tonic-gate tdb_rwlock_stats_t *
tdb_rwlock_stats(rwlock_t * rwlp)4357c478bd9Sstevel@tonic-gate tdb_rwlock_stats(rwlock_t *rwlp)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4407c478bd9Sstevel@tonic-gate 	if (rwlp->magic != RWL_MAGIC)
4417c478bd9Sstevel@tonic-gate 		rwlp->magic = RWL_MAGIC;
4427c478bd9Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(rwlp, NULL)) == NULL)
4437c478bd9Sstevel@tonic-gate 		return (NULL);
4447c478bd9Sstevel@tonic-gate 	tssp->un.type = TDB_RWLOCK;
4457c478bd9Sstevel@tonic-gate 	return (&tssp->un.rwlock);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Return a semaphore statistics block for the given semaphore.
4507c478bd9Sstevel@tonic-gate  */
4517c478bd9Sstevel@tonic-gate tdb_sema_stats_t *
tdb_sema_stats(sema_t * sp)4527c478bd9Sstevel@tonic-gate tdb_sema_stats(sema_t *sp)
4537c478bd9Sstevel@tonic-gate {
4547c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t *tssp;
4557c478bd9Sstevel@tonic-gate 	int new;
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/* avoid stealing the cache line unnecessarily */
4587c478bd9Sstevel@tonic-gate 	if (sp->magic != SEMA_MAGIC)
4597c478bd9Sstevel@tonic-gate 		sp->magic = SEMA_MAGIC;
4607c478bd9Sstevel@tonic-gate 	if ((tssp = tdb_sync_obj_register(sp, &new)) == NULL)
4617c478bd9Sstevel@tonic-gate 		return (NULL);
4627c478bd9Sstevel@tonic-gate 	tssp->un.type = TDB_SEMA;
4637c478bd9Sstevel@tonic-gate 	if (new) {
4647c478bd9Sstevel@tonic-gate 		tssp->un.sema.sema_max_count = sp->count;
4657c478bd9Sstevel@tonic-gate 		tssp->un.sema.sema_min_count = sp->count;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate 	return (&tssp->un.sema);
4687c478bd9Sstevel@tonic-gate }
469