xref: /illumos-gate/usr/src/lib/libc/port/threads/assfail.c (revision 7f9dc0eec05dc1280e3a494124572c5814e7aef9)
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.
280d045c0dSRobert Mustacchi  * Copyright 2015 Joyent, Inc.
29350ffdd5SRobert Mustacchi  * Copyright 2020 Oxide Computer Company
30ad135b5dSChristopher Siden  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "lint.h"
33*7f9dc0eeSBill Sommerfeld #include "libc.h"
347c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
35350ffdd5SRobert Mustacchi #include <upanic.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate const char *panicstr;
387c478bd9Sstevel@tonic-gate ulwp_t *panic_thread;
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate static mutex_t assert_lock = DEFAULTMUTEX;
417c478bd9Sstevel@tonic-gate static ulwp_t *assert_thread = NULL;
427c478bd9Sstevel@tonic-gate 
430d045c0dSRobert Mustacchi mutex_t *panic_mutex = NULL;
440d045c0dSRobert Mustacchi 
45*7f9dc0eeSBill Sommerfeld static void Abort(const char *, size_t) __NORETURN;
46*7f9dc0eeSBill Sommerfeld 
477c478bd9Sstevel@tonic-gate /*
487c478bd9Sstevel@tonic-gate  * Called from __assert() to set panicstr and panic_thread.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate void
__set_panicstr(const char * msg)517c478bd9Sstevel@tonic-gate __set_panicstr(const char *msg)
527c478bd9Sstevel@tonic-gate {
537c478bd9Sstevel@tonic-gate 	panicstr = msg;
547c478bd9Sstevel@tonic-gate 	panic_thread = __curthread();
557c478bd9Sstevel@tonic-gate }
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate /*
587c478bd9Sstevel@tonic-gate  * Called from exit() (atexit function) to give precedence
597c478bd9Sstevel@tonic-gate  * to assertion failures and a core dump over _exit().
607c478bd9Sstevel@tonic-gate  */
617c478bd9Sstevel@tonic-gate void
grab_assert_lock()627c478bd9Sstevel@tonic-gate grab_assert_lock()
637c478bd9Sstevel@tonic-gate {
648cd45542Sraf 	(void) _lwp_mutex_lock(&assert_lock);
657c478bd9Sstevel@tonic-gate }
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate static void
Abort(const char * msg,size_t buflen)68350ffdd5SRobert Mustacchi Abort(const char *msg, size_t buflen)
697c478bd9Sstevel@tonic-gate {
707c478bd9Sstevel@tonic-gate 	ulwp_t *self;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/* to help with core file debugging */
737c478bd9Sstevel@tonic-gate 	panicstr = msg;
747c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
757c478bd9Sstevel@tonic-gate 		panic_thread = self;
767c478bd9Sstevel@tonic-gate 	}
777c478bd9Sstevel@tonic-gate 
78350ffdd5SRobert Mustacchi 	upanic(msg, buflen);
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /*
827c478bd9Sstevel@tonic-gate  * Write a panic message w/o grabbing any locks other than assert_lock.
837c478bd9Sstevel@tonic-gate  * We have no idea what locks are held at this point.
847c478bd9Sstevel@tonic-gate  */
8500efb5e1SYuri Pankov void
common_panic(const char * head,const char * why)86f841f6adSraf common_panic(const char *head, const char *why)
877c478bd9Sstevel@tonic-gate {
887c478bd9Sstevel@tonic-gate 	char msg[400];	/* no panic() message in the library is this long */
897c478bd9Sstevel@tonic-gate 	ulwp_t *self;
907c478bd9Sstevel@tonic-gate 	size_t len1, len2;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL)
937c478bd9Sstevel@tonic-gate 		enter_critical(self);
948cd45542Sraf 	(void) _lwp_mutex_lock(&assert_lock);
957c478bd9Sstevel@tonic-gate 
968cd45542Sraf 	(void) memset(msg, 0, sizeof (msg));
97f841f6adSraf 	(void) strcpy(msg, head);
987c478bd9Sstevel@tonic-gate 	len1 = strlen(msg);
997c478bd9Sstevel@tonic-gate 	len2 = strlen(why);
1007c478bd9Sstevel@tonic-gate 	if (len1 + len2 >= sizeof (msg))
1017c478bd9Sstevel@tonic-gate 		len2 = sizeof (msg) - len1 - 1;
1027c478bd9Sstevel@tonic-gate 	(void) strncat(msg, why, len2);
1037c478bd9Sstevel@tonic-gate 	len1 = strlen(msg);
1047c478bd9Sstevel@tonic-gate 	if (msg[len1 - 1] != '\n')
1057c478bd9Sstevel@tonic-gate 		msg[len1++] = '\n';
106a574db85Sraf 	(void) __write(2, msg, len1);
107350ffdd5SRobert Mustacchi 	Abort(msg, sizeof (msg));
1087c478bd9Sstevel@tonic-gate }
1097c478bd9Sstevel@tonic-gate 
110f841f6adSraf void
thr_panic(const char * why)111f841f6adSraf thr_panic(const char *why)
112f841f6adSraf {
113f841f6adSraf 	common_panic("*** libc thread failure: ", why);
114f841f6adSraf }
115f841f6adSraf 
116f841f6adSraf void
aio_panic(const char * why)117f841f6adSraf aio_panic(const char *why)
118f841f6adSraf {
119f841f6adSraf 	common_panic("*** libc aio system failure: ", why);
120f841f6adSraf }
121f841f6adSraf 
1220d045c0dSRobert Mustacchi void
mutex_panic(mutex_t * mp,const char * why)1230d045c0dSRobert Mustacchi mutex_panic(mutex_t *mp, const char *why)
1240d045c0dSRobert Mustacchi {
1250d045c0dSRobert Mustacchi 	panic_mutex = mp;
1260d045c0dSRobert Mustacchi 	common_panic("*** libc mutex system failure: ", why);
1270d045c0dSRobert Mustacchi }
1280d045c0dSRobert Mustacchi 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * Utility function for converting a long integer to a string, avoiding stdio.
1317c478bd9Sstevel@tonic-gate  * 'base' must be one of 10 or 16
1327c478bd9Sstevel@tonic-gate  */
1337c478bd9Sstevel@tonic-gate void
ultos(uint64_t n,int base,char * s)1347c478bd9Sstevel@tonic-gate ultos(uint64_t n, int base, char *s)
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
1377c478bd9Sstevel@tonic-gate 	char *cp = lbuf;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	do {
1407c478bd9Sstevel@tonic-gate 		*cp++ = "0123456789abcdef"[n%base];
1417c478bd9Sstevel@tonic-gate 		n /= base;
1427c478bd9Sstevel@tonic-gate 	} while (n);
1437c478bd9Sstevel@tonic-gate 	if (base == 16) {
1447c478bd9Sstevel@tonic-gate 		*s++ = '0';
1457c478bd9Sstevel@tonic-gate 		*s++ = 'x';
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 	do {
1487c478bd9Sstevel@tonic-gate 		*s++ = *--cp;
1497c478bd9Sstevel@tonic-gate 	} while (cp > lbuf);
1507c478bd9Sstevel@tonic-gate 	*s = '\0';
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * Report application lock usage error for mutexes and condvars.
1557c478bd9Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
1567c478bd9Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
1577c478bd9Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
1587c478bd9Sstevel@tonic-gate  */
1597c478bd9Sstevel@tonic-gate void
lock_error(const mutex_t * mp,const char * who,void * cv,const char * msg)1607c478bd9Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
1617c478bd9Sstevel@tonic-gate {
16235e6f27aSRoger A. Faulkner 	mutex_t mcopy;
1637c478bd9Sstevel@tonic-gate 	char buf[800];
1647c478bd9Sstevel@tonic-gate 	uberdata_t *udp;
1657c478bd9Sstevel@tonic-gate 	ulwp_t *self;
1667c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
1677c478bd9Sstevel@tonic-gate 	pid_t pid;
1687c478bd9Sstevel@tonic-gate 
16935e6f27aSRoger A. Faulkner 	/*
17035e6f27aSRoger A. Faulkner 	 * Take a snapshot of the mutex before it changes (we hope!).
17135e6f27aSRoger A. Faulkner 	 * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned.
17235e6f27aSRoger A. Faulkner 	 */
17335e6f27aSRoger A. Faulkner 	(void) memcpy(&mcopy, mp, sizeof (mcopy));
17435e6f27aSRoger A. Faulkner 
1757c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
1767c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
1777c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
1787c478bd9Sstevel@tonic-gate 			_exit(127);
1797c478bd9Sstevel@tonic-gate 		enter_critical(self);
1808cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
1817c478bd9Sstevel@tonic-gate 		assert_thread = self;
1827c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
1837c478bd9Sstevel@tonic-gate 		udp = self->ul_uberdata;
1847c478bd9Sstevel@tonic-gate 		pid = udp->pid;
1857c478bd9Sstevel@tonic-gate 	} else {
1867c478bd9Sstevel@tonic-gate 		self = NULL;
1878cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
1887257d1b4Sraf 		lwpid = _lwp_self();
1897c478bd9Sstevel@tonic-gate 		udp = &__uberdata;
1908cd45542Sraf 		pid = getpid();
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	(void) strcpy(buf,
1947c478bd9Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
1957c478bd9Sstevel@tonic-gate 	(void) strcat(buf, who);
1967c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "(");
1977c478bd9Sstevel@tonic-gate 	if (cv != NULL) {
1987c478bd9Sstevel@tonic-gate 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
1997c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ", ");
2007c478bd9Sstevel@tonic-gate 	}
2017c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
2027c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ")");
2037c478bd9Sstevel@tonic-gate 	if (msg != NULL) {
2047c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": ");
2057c478bd9Sstevel@tonic-gate 		(void) strcat(buf, msg);
2067257d1b4Sraf 	} else if (!mutex_held(&mcopy)) {
2077c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread does not own the lock");
2087c478bd9Sstevel@tonic-gate 	} else if (mcopy.mutex_rcount) {
2097c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": mutex rcount = ");
2107c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
2117c478bd9Sstevel@tonic-gate 	} else {
2127c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread already owns the lock");
2137c478bd9Sstevel@tonic-gate 	}
2147c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2157c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2167c478bd9Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2177c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2187257d1b4Sraf 	if (msg != NULL || mutex_held(&mcopy))
2197c478bd9Sstevel@tonic-gate 		/* EMPTY */;
2207c478bd9Sstevel@tonic-gate 	else if (mcopy.mutex_lockw == 0)
2217c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
222883492d5Sraf 	else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
2237c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2247c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2257c478bd9Sstevel@tonic-gate 	} else {
2267c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2277c478bd9Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
2287c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2297c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2307c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2317c478bd9Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
234a574db85Sraf 	(void) __write(2, buf, strlen(buf));
2357c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
236350ffdd5SRobert Mustacchi 		Abort(buf, sizeof (buf));
2377c478bd9Sstevel@tonic-gate 	assert_thread = NULL;
2388cd45542Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
2397c478bd9Sstevel@tonic-gate 	if (self != NULL)
2407c478bd9Sstevel@tonic-gate 		exit_critical(self);
2417c478bd9Sstevel@tonic-gate }
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate /*
2447c478bd9Sstevel@tonic-gate  * Report application lock usage error for rwlocks.
2457c478bd9Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
2467c478bd9Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
2477c478bd9Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
2487c478bd9Sstevel@tonic-gate  */
2497c478bd9Sstevel@tonic-gate void
rwlock_error(const rwlock_t * rp,const char * who,const char * msg)2507c478bd9Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
2517c478bd9Sstevel@tonic-gate {
25235e6f27aSRoger A. Faulkner 	rwlock_t rcopy;
25341efec22Sraf 	uint32_t rwstate;
2547c478bd9Sstevel@tonic-gate 	char buf[800];
2557c478bd9Sstevel@tonic-gate 	uberdata_t *udp;
2567c478bd9Sstevel@tonic-gate 	ulwp_t *self;
2577c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
2587c478bd9Sstevel@tonic-gate 	pid_t pid;
25941efec22Sraf 	int process;
2607c478bd9Sstevel@tonic-gate 
26135e6f27aSRoger A. Faulkner 	/*
26235e6f27aSRoger A. Faulkner 	 * Take a snapshot of the rwlock before it changes (we hope!).
26335e6f27aSRoger A. Faulkner 	 * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned.
26435e6f27aSRoger A. Faulkner 	 */
26535e6f27aSRoger A. Faulkner 	(void) memcpy(&rcopy, rp, sizeof (rcopy));
26635e6f27aSRoger A. Faulkner 
2677c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
2687c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
2697c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
2707c478bd9Sstevel@tonic-gate 			_exit(127);
2717c478bd9Sstevel@tonic-gate 		enter_critical(self);
2728cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2737c478bd9Sstevel@tonic-gate 		assert_thread = self;
2747c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
2757c478bd9Sstevel@tonic-gate 		udp = self->ul_uberdata;
2767c478bd9Sstevel@tonic-gate 		pid = udp->pid;
2777c478bd9Sstevel@tonic-gate 	} else {
2787c478bd9Sstevel@tonic-gate 		self = NULL;
2798cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2807257d1b4Sraf 		lwpid = _lwp_self();
2817c478bd9Sstevel@tonic-gate 		udp = &__uberdata;
2828cd45542Sraf 		pid = getpid();
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
28541efec22Sraf 	rwstate = (uint32_t)rcopy.rwlock_readers;
28641efec22Sraf 	process = (rcopy.rwlock_type & USYNC_PROCESS);
28741efec22Sraf 
2887c478bd9Sstevel@tonic-gate 	(void) strcpy(buf,
2897c478bd9Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
2907c478bd9Sstevel@tonic-gate 	(void) strcat(buf, who);
2917c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "(");
2927c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
2937c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "): ");
2947c478bd9Sstevel@tonic-gate 	(void) strcat(buf, msg);
2957c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2967c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2977c478bd9Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2987c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
29941efec22Sraf 	if (process) {
3007c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
3017c478bd9Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
30241efec22Sraf 	}
30341efec22Sraf 	if (rwstate & URW_WRITE_LOCKED) {
30441efec22Sraf 		(void) strcat(buf, "\nthe writer lock owner is ");
3057c478bd9Sstevel@tonic-gate 		ultos((uint64_t)rcopy.rwlock_owner, 16,
3067c478bd9Sstevel@tonic-gate 		    buf + strlen(buf));
30741efec22Sraf 		if (process) {
3087c478bd9Sstevel@tonic-gate 			(void) strcat(buf, " in process ");
3097c478bd9Sstevel@tonic-gate 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
3107c478bd9Sstevel@tonic-gate 			    buf + strlen(buf));
3117c478bd9Sstevel@tonic-gate 		}
31241efec22Sraf 	} else if (rwstate & URW_READERS_MASK) {
31341efec22Sraf 		(void) strcat(buf, "\nthe reader lock is held by ");
31441efec22Sraf 		ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
31541efec22Sraf 		    buf + strlen(buf));
3167c478bd9Sstevel@tonic-gate 		(void) strcat(buf, " readers");
3177c478bd9Sstevel@tonic-gate 	} else {
3187c478bd9Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
3197c478bd9Sstevel@tonic-gate 	}
32041efec22Sraf 	if (rwstate & URW_HAS_WAITERS)
32141efec22Sraf 		(void) strcat(buf, "\nand the lock appears to have waiters");
3227c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
323a574db85Sraf 	(void) __write(2, buf, strlen(buf));
3247c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
325350ffdd5SRobert Mustacchi 		Abort(buf, sizeof (buf));
3267c478bd9Sstevel@tonic-gate 	assert_thread = NULL;
3278cd45542Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
3287c478bd9Sstevel@tonic-gate 	if (self != NULL)
3297c478bd9Sstevel@tonic-gate 		exit_critical(self);
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate /*
3337c478bd9Sstevel@tonic-gate  * Report a thread usage error.
3347c478bd9Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
3357c478bd9Sstevel@tonic-gate  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
3367c478bd9Sstevel@tonic-gate  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate void
thread_error(const char * msg)3397c478bd9Sstevel@tonic-gate thread_error(const char *msg)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	char buf[800];
3427c478bd9Sstevel@tonic-gate 	uberdata_t *udp;
3437c478bd9Sstevel@tonic-gate 	ulwp_t *self;
3447c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
3477c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3487c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
3497c478bd9Sstevel@tonic-gate 			_exit(127);
3507c478bd9Sstevel@tonic-gate 		enter_critical(self);
3518cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
3527c478bd9Sstevel@tonic-gate 		assert_thread = self;
3537c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
3547c478bd9Sstevel@tonic-gate 		udp = self->ul_uberdata;
3557c478bd9Sstevel@tonic-gate 	} else {
3567c478bd9Sstevel@tonic-gate 		self = NULL;
3578cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
3587257d1b4Sraf 		lwpid = _lwp_self();
3597c478bd9Sstevel@tonic-gate 		udp = &__uberdata;
3607c478bd9Sstevel@tonic-gate 	}
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
3637c478bd9Sstevel@tonic-gate 	    "thread usage error detected ***\n*** ");
3647c478bd9Sstevel@tonic-gate 	(void) strcat(buf, msg);
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n*** calling thread is ");
3677c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3687c478bd9Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
3697c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
3707c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
371a574db85Sraf 	(void) __write(2, buf, strlen(buf));
3727c478bd9Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
373350ffdd5SRobert Mustacchi 		Abort(buf, sizeof (buf));
3747c478bd9Sstevel@tonic-gate 	assert_thread = NULL;
3758cd45542Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
3767c478bd9Sstevel@tonic-gate 	if (self != NULL)
3777c478bd9Sstevel@tonic-gate 		exit_critical(self);
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate  * We use __assfail() because the libc __assert() calls
3827c478bd9Sstevel@tonic-gate  * gettext() which calls malloc() which grabs a mutex.
3837c478bd9Sstevel@tonic-gate  * We do everything without calling standard i/o.
384f841f6adSraf  * assfail() and _assfail() are exported functions;
385f841f6adSraf  * __assfail() is private to libc.
3867c478bd9Sstevel@tonic-gate  */
3877c478bd9Sstevel@tonic-gate #pragma weak _assfail = __assfail
3887c478bd9Sstevel@tonic-gate void
__assfail(const char * assertion,const char * filename,int line_num)3897c478bd9Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	char buf[800];	/* no assert() message in the library is this long */
3927c478bd9Sstevel@tonic-gate 	ulwp_t *self;
3937c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	/* avoid recursion deadlock */
3967c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3977c478bd9Sstevel@tonic-gate 		if (assert_thread == self)
3987c478bd9Sstevel@tonic-gate 			_exit(127);
3997c478bd9Sstevel@tonic-gate 		enter_critical(self);
4008cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
4017c478bd9Sstevel@tonic-gate 		assert_thread = self;
4027c478bd9Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
4037c478bd9Sstevel@tonic-gate 	} else {
4047c478bd9Sstevel@tonic-gate 		self = NULL;
4058cd45542Sraf 		(void) _lwp_mutex_lock(&assert_lock);
4067257d1b4Sraf 		lwpid = _lwp_self();
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 
409fae63477SPrakash Surya 	/*
410fae63477SPrakash Surya 	 * This is a hack, but since the Abort function isn't exported
411fae63477SPrakash Surya 	 * to outside consumers, libzpool's vpanic() function calls
412fae63477SPrakash Surya 	 * assfail() with a filename set to NULL. In that case, it'd be
413fae63477SPrakash Surya 	 * best not to print "assertion failed" since it was a panic and
414fae63477SPrakash Surya 	 * not an assertion failure.
415fae63477SPrakash Surya 	 */
416fae63477SPrakash Surya 	if (filename == NULL) {
417fae63477SPrakash Surya 		(void) strcpy(buf, "failure for thread ");
418fae63477SPrakash Surya 	} else {
4197c478bd9Sstevel@tonic-gate 		(void) strcpy(buf, "assertion failed for thread ");
420fae63477SPrakash Surya 	}
421fae63477SPrakash Surya 
4227c478bd9Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
4237c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ", thread-id ");
4247c478bd9Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
4257c478bd9Sstevel@tonic-gate 	(void) strcat(buf, ": ");
4267c478bd9Sstevel@tonic-gate 	(void) strcat(buf, assertion);
427fae63477SPrakash Surya 
428fae63477SPrakash Surya 	if (filename != NULL) {
4297c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ", file ");
4307c478bd9Sstevel@tonic-gate 		(void) strcat(buf, filename);
4317c478bd9Sstevel@tonic-gate 		(void) strcat(buf, ", line ");
4327c478bd9Sstevel@tonic-gate 		ultos((uint64_t)line_num, 10, buf + strlen(buf));
433fae63477SPrakash Surya 	}
434fae63477SPrakash Surya 
4357c478bd9Sstevel@tonic-gate 	(void) strcat(buf, "\n");
436a574db85Sraf 	(void) __write(2, buf, strlen(buf));
4377c478bd9Sstevel@tonic-gate 	/*
4387c478bd9Sstevel@tonic-gate 	 * We could replace the call to Abort() with the following code
4397c478bd9Sstevel@tonic-gate 	 * if we want just to issue a warning message and not die.
4407c478bd9Sstevel@tonic-gate 	 *	assert_thread = NULL;
4418cd45542Sraf 	 *	_lwp_mutex_unlock(&assert_lock);
4427c478bd9Sstevel@tonic-gate 	 *	if (self != NULL)
4437c478bd9Sstevel@tonic-gate 	 *		exit_critical(self);
4447c478bd9Sstevel@tonic-gate 	 */
445350ffdd5SRobert Mustacchi 	Abort(buf, sizeof (buf));
4467c478bd9Sstevel@tonic-gate }
447f841f6adSraf 
448f841f6adSraf /*
449f841f6adSraf  * We define and export this version of assfail() just because libaio
450f841f6adSraf  * used to define and export it, needlessly.  Now that libaio is folded
451f841f6adSraf  * into libc, we need to continue this for ABI/version reasons.
452f841f6adSraf  * We don't use "#pragma weak assfail __assfail" in order to avoid
453f841f6adSraf  * warnings from the check_fnames utility at build time for libraries
454f841f6adSraf  * that define their own version of assfail().
455*7f9dc0eeSBill Sommerfeld  *
456*7f9dc0eeSBill Sommerfeld  * Additionally, ASSERT() and VERIFY() in <sys/debug.h> can invoke assfail().
457*7f9dc0eeSBill Sommerfeld  *
458*7f9dc0eeSBill Sommerfeld  * We would like this to be declared _NORETURN, but some caution is in order
459*7f9dc0eeSBill Sommerfeld  * as alternate implementations of assfail() exist -- notably the one in
460*7f9dc0eeSBill Sommerfeld  * libfakekernel -- which can return under some circumstances.
461f841f6adSraf  */
462f841f6adSraf void
assfail(const char * assertion,const char * filename,int line_num)463f841f6adSraf assfail(const char *assertion, const char *filename, int line_num)
464f841f6adSraf {
465f841f6adSraf 	__assfail(assertion, filename, line_num);
466*7f9dc0eeSBill Sommerfeld 	/* NOTREACHED */
467f841f6adSraf }
468ad135b5dSChristopher Siden 
469ad135b5dSChristopher Siden void
assfail3(const char * assertion,uintmax_t lv,const char * op,uintmax_t rv,const char * filename,int line_num)470ad135b5dSChristopher Siden assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv,
471ad135b5dSChristopher Siden     const char *filename, int line_num)
472ad135b5dSChristopher Siden {
473ad135b5dSChristopher Siden 	char buf[1000];
474ad135b5dSChristopher Siden 	(void) strcpy(buf, assertion);
475fb09f5aaSMadhav Suresh 	(void) strcat(buf, " (");
476ad135b5dSChristopher Siden 	ultos((uint64_t)lv, 16, buf + strlen(buf));
477ad135b5dSChristopher Siden 	(void) strcat(buf, " ");
478ad135b5dSChristopher Siden 	(void) strcat(buf, op);
479fb09f5aaSMadhav Suresh 	(void) strcat(buf, " ");
480ad135b5dSChristopher Siden 	ultos((uint64_t)rv, 16, buf + strlen(buf));
481ad135b5dSChristopher Siden 	(void) strcat(buf, ")");
482ad135b5dSChristopher Siden 	__assfail(buf, filename, line_num);
483ad135b5dSChristopher Siden }
484