xref: /titanic_52/usr/src/lib/libc/port/threads/assfail.c (revision 0d045c0d0cb001d79480ee33be28514e847f8612)
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
5f841f6adSraf  * Common Development and Distribution License (the "License").
6f841f6adSraf  * 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  */
21f841f6adSraf 
227c478bd9Sstevel@tonic-gate /*
23bdf0047cSRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
26ad135b5dSChristopher Siden /*
27fae63477SPrakash Surya  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
28*0d045c0dSRobert Mustacchi  * Copyright 2015 Joyent, Inc.
29ad135b5dSChristopher Siden  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include "lint.h"
327c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate const char *panicstr;
357c478bd9Sstevel@tonic-gate ulwp_t *panic_thread;
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate static mutex_t assert_lock = DEFAULTMUTEX;
387c478bd9Sstevel@tonic-gate static ulwp_t *assert_thread = NULL;
397c478bd9Sstevel@tonic-gate 
40*0d045c0dSRobert Mustacchi mutex_t *panic_mutex = NULL;
41*0d045c0dSRobert Mustacchi 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * Called from __assert() to set panicstr and panic_thread.
447c478bd9Sstevel@tonic-gate  */
457c478bd9Sstevel@tonic-gate void
467c478bd9Sstevel@tonic-gate __set_panicstr(const char *msg)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate 	panicstr = msg;
497c478bd9Sstevel@tonic-gate 	panic_thread = __curthread();
507c478bd9Sstevel@tonic-gate }
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Called from exit() (atexit function) to give precedence
547c478bd9Sstevel@tonic-gate  * to assertion failures and a core dump over _exit().
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate void
577c478bd9Sstevel@tonic-gate grab_assert_lock()
587c478bd9Sstevel@tonic-gate {
598cd45542Sraf 	(void) _lwp_mutex_lock(&assert_lock);
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate static void
637c478bd9Sstevel@tonic-gate Abort(const char *msg)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	ulwp_t *self;
667c478bd9Sstevel@tonic-gate 	struct sigaction act;
677c478bd9Sstevel@tonic-gate 	sigset_t sigmask;
687c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate 	/* to help with core file debugging */
717c478bd9Sstevel@tonic-gate 	panicstr = msg;
727c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
737c478bd9Sstevel@tonic-gate 		panic_thread = self;
747c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
757c478bd9Sstevel@tonic-gate 	} else {
767257d1b4Sraf 		lwpid = _lwp_self();
777c478bd9Sstevel@tonic-gate 	}
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 	/* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */
808cd45542Sraf 	(void) memset(&act, 0, sizeof (act));
817c478bd9Sstevel@tonic-gate 	act.sa_sigaction = SIG_DFL;
827c478bd9Sstevel@tonic-gate 	(void) __sigaction(SIGABRT, &act, NULL);
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/* delete SIGABRT from the signal mask */
858cd45542Sraf 	(void) sigemptyset(&sigmask);
868cd45542Sraf 	(void) sigaddset(&sigmask, SIGABRT);
87bdf0047cSRoger A. Faulkner 	(void) __lwp_sigmask(SIG_UNBLOCK, &sigmask);
887c478bd9Sstevel@tonic-gate 
897257d1b4Sraf 	(void) _lwp_kill(lwpid, SIGABRT);	/* never returns */
907257d1b4Sraf 	(void) kill(getpid(), SIGABRT);	/* if it does, try harder */
917c478bd9Sstevel@tonic-gate 	_exit(127);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Write a panic message w/o grabbing any locks other than assert_lock.
967c478bd9Sstevel@tonic-gate  * We have no idea what locks are held at this point.
977c478bd9Sstevel@tonic-gate  */
98f841f6adSraf static void
99f841f6adSraf common_panic(const char *head, const char *why)
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	char msg[400];	/* no panic() message in the library is this long */
1027c478bd9Sstevel@tonic-gate 	ulwp_t *self;
1037c478bd9Sstevel@tonic-gate 	size_t len1, len2;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL)
1067c478bd9Sstevel@tonic-gate 		enter_critical(self);
1078cd45542Sraf 	(void) _lwp_mutex_lock(&assert_lock);
1087c478bd9Sstevel@tonic-gate 
1098cd45542Sraf 	(void) memset(msg, 0, sizeof (msg));
110f841f6adSraf 	(void) strcpy(msg, head);
1117c478bd9Sstevel@tonic-gate 	len1 = strlen(msg);
1127c478bd9Sstevel@tonic-gate 	len2 = strlen(why);
1137c478bd9Sstevel@tonic-gate 	if (len1 + len2 >= sizeof (msg))
1147c478bd9Sstevel@tonic-gate 		len2 = sizeof (msg) - len1 - 1;
1157c478bd9Sstevel@tonic-gate 	(void) strncat(msg, why, len2);
1167c478bd9Sstevel@tonic-gate 	len1 = strlen(msg);
1177c478bd9Sstevel@tonic-gate 	if (msg[len1 - 1] != '\n')
1187c478bd9Sstevel@tonic-gate 		msg[len1++] = '\n';
119a574db85Sraf 	(void) __write(2, msg, len1);
1207c478bd9Sstevel@tonic-gate 	Abort(msg);
1217c478bd9Sstevel@tonic-gate }
1227c478bd9Sstevel@tonic-gate 
123f841f6adSraf void
124f841f6adSraf thr_panic(const char *why)
125f841f6adSraf {
126f841f6adSraf 	common_panic("*** libc thread failure: ", why);
127f841f6adSraf }
128f841f6adSraf 
129f841f6adSraf void
130f841f6adSraf aio_panic(const char *why)
131f841f6adSraf {
132f841f6adSraf 	common_panic("*** libc aio system failure: ", why);
133f841f6adSraf }
134f841f6adSraf 
135*0d045c0dSRobert Mustacchi void
136*0d045c0dSRobert Mustacchi mutex_panic(mutex_t *mp, const char *why)
137*0d045c0dSRobert Mustacchi {
138*0d045c0dSRobert Mustacchi 	panic_mutex = mp;
139*0d045c0dSRobert Mustacchi 	common_panic("*** libc mutex system failure: ", why);
140*0d045c0dSRobert Mustacchi }
141*0d045c0dSRobert Mustacchi 
1427c478bd9Sstevel@tonic-gate /*
1437c478bd9Sstevel@tonic-gate  * Utility function for converting a long integer to a string, avoiding stdio.
1447c478bd9Sstevel@tonic-gate  * 'base' must be one of 10 or 16
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate void
1477c478bd9Sstevel@tonic-gate ultos(uint64_t n, int base, char *s)
1487c478bd9Sstevel@tonic-gate {
1497c478bd9Sstevel@tonic-gate 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
1507c478bd9Sstevel@tonic-gate 	char *cp = lbuf;
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	do {
1537c478bd9Sstevel@tonic-gate 		*cp++ = "0123456789abcdef"[n%base];
1547c478bd9Sstevel@tonic-gate 		n /= base;
1557c478bd9Sstevel@tonic-gate 	} while (n);
1567c478bd9Sstevel@tonic-gate 	if (base == 16) {
1577c478bd9Sstevel@tonic-gate 		*s++ = '0';
1587c478bd9Sstevel@tonic-gate 		*s++ = 'x';
1597c478bd9Sstevel@tonic-gate 	}
1607c478bd9Sstevel@tonic-gate 	do {
1617c478bd9Sstevel@tonic-gate 		*s++ = *--cp;
1627c478bd9Sstevel@tonic-gate 	} while (cp > lbuf);
1637c478bd9Sstevel@tonic-gate 	*s = '\0';
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * Report application lock usage error for mutexes and condvars.
1687c478bd9Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
1697c478bd9Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
1707c478bd9Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate void
1737c478bd9Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
1747c478bd9Sstevel@tonic-gate {
17535e6f27aSRoger A. Faulkner 	mutex_t mcopy;
1767c478bd9Sstevel@tonic-gate 	char buf[800];
1777c478bd9Sstevel@tonic-gate 	uberdata_t *udp;
1787c478bd9Sstevel@tonic-gate 	ulwp_t *self;
1797c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
1807c478bd9Sstevel@tonic-gate 	pid_t pid;
1817c478bd9Sstevel@tonic-gate 
18235e6f27aSRoger A. Faulkner 	/*
18335e6f27aSRoger A. Faulkner 	 * Take a snapshot of the mutex before it changes (we hope!).
18435e6f27aSRoger A. Faulkner 	 * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned.
18535e6f27aSRoger A. Faulkner 	 */
18635e6f27aSRoger A. Faulkner 	(void) memcpy(&mcopy, mp, sizeof (mcopy));
18735e6f27aSRoger A. Faulkner 
1887c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
1897c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
1907c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
1917c478bd9Sstevel@tonic-gate 			_exit(127);
1927c478bd9Sstevel@tonic-gate 		enter_critical(self);
1938cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
1947c478bd9Sstevel@tonic-gate 		assert_thread = self;
1957c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
1967c478bd9Sstevel@tonic-gate 		udp = self->ul_uberdata;
1977c478bd9Sstevel@tonic-gate 		pid = udp->pid;
1987c478bd9Sstevel@tonic-gate 	} else {
1997c478bd9Sstevel@tonic-gate 		self = NULL;
2008cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2017257d1b4Sraf 		lwpid = _lwp_self();
2027c478bd9Sstevel@tonic-gate 		udp = &__uberdata;
2038cd45542Sraf 		pid = getpid();
2047c478bd9Sstevel@tonic-gate 	}
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	(void) strcpy(buf,
2077c478bd9Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
2087c478bd9Sstevel@tonic-gate 	(void) strcat(buf, who);
2097c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "(");
2107c478bd9Sstevel@tonic-gate 	if (cv != NULL) {
2117c478bd9Sstevel@tonic-gate 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
2127c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ", ");
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
2157c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ")");
2167c478bd9Sstevel@tonic-gate 	if (msg != NULL) {
2177c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": ");
2187c478bd9Sstevel@tonic-gate 		(void) strcat(buf, msg);
2197257d1b4Sraf 	} else if (!mutex_held(&mcopy)) {
2207c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread does not own the lock");
2217c478bd9Sstevel@tonic-gate 	} else if (mcopy.mutex_rcount) {
2227c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": mutex rcount = ");
2237c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
2247c478bd9Sstevel@tonic-gate 	} else {
2257c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread already owns the lock");
2267c478bd9Sstevel@tonic-gate 	}
2277c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2287c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2297c478bd9Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2307c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2317257d1b4Sraf 	if (msg != NULL || mutex_held(&mcopy))
2327c478bd9Sstevel@tonic-gate 		/* EMPTY */;
2337c478bd9Sstevel@tonic-gate 	else if (mcopy.mutex_lockw == 0)
2347c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
235883492d5Sraf 	else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
2367c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2377c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2387c478bd9Sstevel@tonic-gate 	} else {
2397c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2407c478bd9Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
2417c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2427c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2437c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2447c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
247a574db85Sraf 	(void) __write(2, buf, strlen(buf));
2487c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
2497c478bd9Sstevel@tonic-gate 		Abort(buf);
2507c478bd9Sstevel@tonic-gate 	assert_thread = NULL;
2518cd45542Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
2527c478bd9Sstevel@tonic-gate 	if (self != NULL)
2537c478bd9Sstevel@tonic-gate 		exit_critical(self);
2547c478bd9Sstevel@tonic-gate }
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*
2577c478bd9Sstevel@tonic-gate  * Report application lock usage error for rwlocks.
2587c478bd9Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
2597c478bd9Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
2607c478bd9Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
2617c478bd9Sstevel@tonic-gate  */
2627c478bd9Sstevel@tonic-gate void
2637c478bd9Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
2647c478bd9Sstevel@tonic-gate {
26535e6f27aSRoger A. Faulkner 	rwlock_t rcopy;
26641efec22Sraf 	uint32_t rwstate;
2677c478bd9Sstevel@tonic-gate 	char buf[800];
2687c478bd9Sstevel@tonic-gate 	uberdata_t *udp;
2697c478bd9Sstevel@tonic-gate 	ulwp_t *self;
2707c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
2717c478bd9Sstevel@tonic-gate 	pid_t pid;
27241efec22Sraf 	int process;
2737c478bd9Sstevel@tonic-gate 
27435e6f27aSRoger A. Faulkner 	/*
27535e6f27aSRoger A. Faulkner 	 * Take a snapshot of the rwlock before it changes (we hope!).
27635e6f27aSRoger A. Faulkner 	 * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned.
27735e6f27aSRoger A. Faulkner 	 */
27835e6f27aSRoger A. Faulkner 	(void) memcpy(&rcopy, rp, sizeof (rcopy));
27935e6f27aSRoger A. Faulkner 
2807c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
2817c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
2827c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
2837c478bd9Sstevel@tonic-gate 			_exit(127);
2847c478bd9Sstevel@tonic-gate 		enter_critical(self);
2858cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2867c478bd9Sstevel@tonic-gate 		assert_thread = self;
2877c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
2887c478bd9Sstevel@tonic-gate 		udp = self->ul_uberdata;
2897c478bd9Sstevel@tonic-gate 		pid = udp->pid;
2907c478bd9Sstevel@tonic-gate 	} else {
2917c478bd9Sstevel@tonic-gate 		self = NULL;
2928cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2937257d1b4Sraf 		lwpid = _lwp_self();
2947c478bd9Sstevel@tonic-gate 		udp = &__uberdata;
2958cd45542Sraf 		pid = getpid();
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
29841efec22Sraf 	rwstate = (uint32_t)rcopy.rwlock_readers;
29941efec22Sraf 	process = (rcopy.rwlock_type & USYNC_PROCESS);
30041efec22Sraf 
3017c478bd9Sstevel@tonic-gate 	(void) strcpy(buf,
3027c478bd9Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
3037c478bd9Sstevel@tonic-gate 	(void) strcat(buf, who);
3047c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "(");
3057c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
3067c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "): ");
3077c478bd9Sstevel@tonic-gate 	(void) strcat(buf, msg);
3087c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
3097c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3107c478bd9Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
3117c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
31241efec22Sraf 	if (process) {
3137c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
3147c478bd9Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
31541efec22Sraf 	}
31641efec22Sraf 	if (rwstate & URW_WRITE_LOCKED) {
31741efec22Sraf 		(void) strcat(buf, "\nthe writer lock owner is ");
3187c478bd9Sstevel@tonic-gate 		ultos((uint64_t)rcopy.rwlock_owner, 16,
3197c478bd9Sstevel@tonic-gate 		    buf + strlen(buf));
32041efec22Sraf 		if (process) {
3217c478bd9Sstevel@tonic-gate 			(void) strcat(buf, " in process ");
3227c478bd9Sstevel@tonic-gate 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
3237c478bd9Sstevel@tonic-gate 			    buf + strlen(buf));
3247c478bd9Sstevel@tonic-gate 		}
32541efec22Sraf 	} else if (rwstate & URW_READERS_MASK) {
32641efec22Sraf 		(void) strcat(buf, "\nthe reader lock is held by ");
32741efec22Sraf 		ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
32841efec22Sraf 		    buf + strlen(buf));
3297c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " readers");
3307c478bd9Sstevel@tonic-gate 	} else {
3317c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
3327c478bd9Sstevel@tonic-gate 	}
33341efec22Sraf 	if (rwstate & URW_HAS_WAITERS)
33441efec22Sraf 		(void) strcat(buf, "\nand the lock appears to have waiters");
3357c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
336a574db85Sraf 	(void) __write(2, buf, strlen(buf));
3377c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3387c478bd9Sstevel@tonic-gate 		Abort(buf);
3397c478bd9Sstevel@tonic-gate 	assert_thread = NULL;
3408cd45542Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
3417c478bd9Sstevel@tonic-gate 	if (self != NULL)
3427c478bd9Sstevel@tonic-gate 		exit_critical(self);
3437c478bd9Sstevel@tonic-gate }
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * Report a thread usage error.
3477c478bd9Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
3487c478bd9Sstevel@tonic-gate  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
3497c478bd9Sstevel@tonic-gate  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
3507c478bd9Sstevel@tonic-gate  */
3517c478bd9Sstevel@tonic-gate void
3527c478bd9Sstevel@tonic-gate thread_error(const char *msg)
3537c478bd9Sstevel@tonic-gate {
3547c478bd9Sstevel@tonic-gate 	char buf[800];
3557c478bd9Sstevel@tonic-gate 	uberdata_t *udp;
3567c478bd9Sstevel@tonic-gate 	ulwp_t *self;
3577c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
3607c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3617c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
3627c478bd9Sstevel@tonic-gate 			_exit(127);
3637c478bd9Sstevel@tonic-gate 		enter_critical(self);
3648cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
3657c478bd9Sstevel@tonic-gate 		assert_thread = self;
3667c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
3677c478bd9Sstevel@tonic-gate 		udp = self->ul_uberdata;
3687c478bd9Sstevel@tonic-gate 	} else {
3697c478bd9Sstevel@tonic-gate 		self = NULL;
3708cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
3717257d1b4Sraf 		lwpid = _lwp_self();
3727c478bd9Sstevel@tonic-gate 		udp = &__uberdata;
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
3767c478bd9Sstevel@tonic-gate 	    "thread usage error detected ***\n*** ");
3777c478bd9Sstevel@tonic-gate 	(void) strcat(buf, msg);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n*** calling thread is ");
3807c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3817c478bd9Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
3827c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
3837c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
384a574db85Sraf 	(void) __write(2, buf, strlen(buf));
3857c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3867c478bd9Sstevel@tonic-gate 		Abort(buf);
3877c478bd9Sstevel@tonic-gate 	assert_thread = NULL;
3888cd45542Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
3897c478bd9Sstevel@tonic-gate 	if (self != NULL)
3907c478bd9Sstevel@tonic-gate 		exit_critical(self);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate  * We use __assfail() because the libc __assert() calls
3957c478bd9Sstevel@tonic-gate  * gettext() which calls malloc() which grabs a mutex.
3967c478bd9Sstevel@tonic-gate  * We do everything without calling standard i/o.
397f841f6adSraf  * assfail() and _assfail() are exported functions;
398f841f6adSraf  * __assfail() is private to libc.
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate #pragma weak _assfail = __assfail
4017c478bd9Sstevel@tonic-gate void
4027c478bd9Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	char buf[800];	/* no assert() message in the library is this long */
4057c478bd9Sstevel@tonic-gate 	ulwp_t *self;
4067c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
4097c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
4107c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
4117c478bd9Sstevel@tonic-gate 			_exit(127);
4127c478bd9Sstevel@tonic-gate 		enter_critical(self);
4138cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
4147c478bd9Sstevel@tonic-gate 		assert_thread = self;
4157c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
4167c478bd9Sstevel@tonic-gate 	} else {
4177c478bd9Sstevel@tonic-gate 		self = NULL;
4188cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
4197257d1b4Sraf 		lwpid = _lwp_self();
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
422fae63477SPrakash Surya 	/*
423fae63477SPrakash Surya 	 * This is a hack, but since the Abort function isn't exported
424fae63477SPrakash Surya 	 * to outside consumers, libzpool's vpanic() function calls
425fae63477SPrakash Surya 	 * assfail() with a filename set to NULL. In that case, it'd be
426fae63477SPrakash Surya 	 * best not to print "assertion failed" since it was a panic and
427fae63477SPrakash Surya 	 * not an assertion failure.
428fae63477SPrakash Surya 	 */
429fae63477SPrakash Surya 	if (filename == NULL) {
430fae63477SPrakash Surya 		(void) strcpy(buf, "failure for thread ");
431fae63477SPrakash Surya 	} else {
4327c478bd9Sstevel@tonic-gate 		(void) strcpy(buf, "assertion failed for thread ");
433fae63477SPrakash Surya 	}
434fae63477SPrakash Surya 
4357c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
4367c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ", thread-id ");
4377c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
4387c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ": ");
4397c478bd9Sstevel@tonic-gate 	(void) strcat(buf, assertion);
440fae63477SPrakash Surya 
441fae63477SPrakash Surya 	if (filename != NULL) {
4427c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ", file ");
4437c478bd9Sstevel@tonic-gate 		(void) strcat(buf, filename);
4447c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ", line ");
4457c478bd9Sstevel@tonic-gate 		ultos((uint64_t)line_num, 10, buf + strlen(buf));
446fae63477SPrakash Surya 	}
447fae63477SPrakash Surya 
4487c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n");
449a574db85Sraf 	(void) __write(2, buf, strlen(buf));
4507c478bd9Sstevel@tonic-gate 	/*
4517c478bd9Sstevel@tonic-gate 	 * We could replace the call to Abort() with the following code
4527c478bd9Sstevel@tonic-gate 	 * if we want just to issue a warning message and not die.
4537c478bd9Sstevel@tonic-gate 	 *	assert_thread = NULL;
4548cd45542Sraf 	 *	_lwp_mutex_unlock(&assert_lock);
4557c478bd9Sstevel@tonic-gate 	 *	if (self != NULL)
4567c478bd9Sstevel@tonic-gate 	 *		exit_critical(self);
4577c478bd9Sstevel@tonic-gate 	 */
4587c478bd9Sstevel@tonic-gate 	Abort(buf);
4597c478bd9Sstevel@tonic-gate }
460f841f6adSraf 
461f841f6adSraf /*
462f841f6adSraf  * We define and export this version of assfail() just because libaio
463f841f6adSraf  * used to define and export it, needlessly.  Now that libaio is folded
464f841f6adSraf  * into libc, we need to continue this for ABI/version reasons.
465f841f6adSraf  * We don't use "#pragma weak assfail __assfail" in order to avoid
466f841f6adSraf  * warnings from the check_fnames utility at build time for libraries
467f841f6adSraf  * that define their own version of assfail().
468f841f6adSraf  */
469f841f6adSraf void
470f841f6adSraf assfail(const char *assertion, const char *filename, int line_num)
471f841f6adSraf {
472f841f6adSraf 	__assfail(assertion, filename, line_num);
473f841f6adSraf }
474ad135b5dSChristopher Siden 
475ad135b5dSChristopher Siden void
476ad135b5dSChristopher Siden assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv,
477ad135b5dSChristopher Siden     const char *filename, int line_num)
478ad135b5dSChristopher Siden {
479ad135b5dSChristopher Siden 	char buf[1000];
480ad135b5dSChristopher Siden 	(void) strcpy(buf, assertion);
481fb09f5aaSMadhav Suresh 	(void) strcat(buf, " (");
482ad135b5dSChristopher Siden 	ultos((uint64_t)lv, 16, buf + strlen(buf));
483ad135b5dSChristopher Siden 	(void) strcat(buf, " ");
484ad135b5dSChristopher Siden 	(void) strcat(buf, op);
485fb09f5aaSMadhav Suresh 	(void) strcat(buf, " ");
486ad135b5dSChristopher Siden 	ultos((uint64_t)rv, 16, buf + strlen(buf));
487ad135b5dSChristopher Siden 	(void) strcat(buf, ")");
488ad135b5dSChristopher Siden 	__assfail(buf, filename, line_num);
489ad135b5dSChristopher Siden }
490