xref: /onnv-gate/usr/src/lib/libc/port/threads/assfail.c (revision 2248:4609e8bb25ad)
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
5*2248Sraf  * Common Development and Distribution License (the "License").
6*2248Sraf  * 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  */
21*2248Sraf 
220Sstevel@tonic-gate /*
23*2248Sraf  * Copyright 2006 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 #include "lint.h"
300Sstevel@tonic-gate #include "thr_uberdata.h"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate const char *panicstr;
330Sstevel@tonic-gate ulwp_t *panic_thread;
340Sstevel@tonic-gate 
350Sstevel@tonic-gate static mutex_t assert_lock = DEFAULTMUTEX;
360Sstevel@tonic-gate static ulwp_t *assert_thread = NULL;
370Sstevel@tonic-gate 
380Sstevel@tonic-gate /*
390Sstevel@tonic-gate  * Called from __assert() to set panicstr and panic_thread.
400Sstevel@tonic-gate  */
410Sstevel@tonic-gate void
420Sstevel@tonic-gate __set_panicstr(const char *msg)
430Sstevel@tonic-gate {
440Sstevel@tonic-gate 	panicstr = msg;
450Sstevel@tonic-gate 	panic_thread = __curthread();
460Sstevel@tonic-gate }
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * Called from exit() (atexit function) to give precedence
500Sstevel@tonic-gate  * to assertion failures and a core dump over _exit().
510Sstevel@tonic-gate  */
520Sstevel@tonic-gate void
530Sstevel@tonic-gate grab_assert_lock()
540Sstevel@tonic-gate {
550Sstevel@tonic-gate 	(void) _private_lwp_mutex_lock(&assert_lock);
560Sstevel@tonic-gate }
570Sstevel@tonic-gate 
580Sstevel@tonic-gate static void
590Sstevel@tonic-gate Abort(const char *msg)
600Sstevel@tonic-gate {
610Sstevel@tonic-gate 	ulwp_t *self;
620Sstevel@tonic-gate 	struct sigaction act;
630Sstevel@tonic-gate 	sigset_t sigmask;
640Sstevel@tonic-gate 	lwpid_t lwpid;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate 	/* to help with core file debugging */
670Sstevel@tonic-gate 	panicstr = msg;
680Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
690Sstevel@tonic-gate 		panic_thread = self;
700Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
710Sstevel@tonic-gate 	} else {
720Sstevel@tonic-gate 		lwpid = __lwp_self();
730Sstevel@tonic-gate 	}
740Sstevel@tonic-gate 
750Sstevel@tonic-gate 	/* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */
760Sstevel@tonic-gate 	(void) _private_memset(&act, 0, sizeof (act));
770Sstevel@tonic-gate 	act.sa_sigaction = SIG_DFL;
780Sstevel@tonic-gate 	(void) __sigaction(SIGABRT, &act, NULL);
790Sstevel@tonic-gate 
800Sstevel@tonic-gate 	/* delete SIGABRT from the signal mask */
810Sstevel@tonic-gate 	(void) _private_sigemptyset(&sigmask);
820Sstevel@tonic-gate 	(void) _private_sigaddset(&sigmask, SIGABRT);
830Sstevel@tonic-gate 	(void) __lwp_sigmask(SIG_UNBLOCK, &sigmask, NULL);
840Sstevel@tonic-gate 
850Sstevel@tonic-gate 	(void) __lwp_kill(lwpid, SIGABRT);	/* never returns */
860Sstevel@tonic-gate 	(void) _kill(_private_getpid(), SIGABRT); /* if it does, try harder */
870Sstevel@tonic-gate 	_exit(127);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate 
900Sstevel@tonic-gate /*
910Sstevel@tonic-gate  * Write a panic message w/o grabbing any locks other than assert_lock.
920Sstevel@tonic-gate  * We have no idea what locks are held at this point.
930Sstevel@tonic-gate  */
94*2248Sraf static void
95*2248Sraf common_panic(const char *head, const char *why)
960Sstevel@tonic-gate {
970Sstevel@tonic-gate 	char msg[400];	/* no panic() message in the library is this long */
980Sstevel@tonic-gate 	ulwp_t *self;
990Sstevel@tonic-gate 	size_t len1, len2;
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate 	if ((self = __curthread()) != NULL)
1020Sstevel@tonic-gate 		enter_critical(self);
1030Sstevel@tonic-gate 	(void) _private_lwp_mutex_lock(&assert_lock);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	(void) _private_memset(msg, 0, sizeof (msg));
106*2248Sraf 	(void) strcpy(msg, head);
1070Sstevel@tonic-gate 	len1 = strlen(msg);
1080Sstevel@tonic-gate 	len2 = strlen(why);
1090Sstevel@tonic-gate 	if (len1 + len2 >= sizeof (msg))
1100Sstevel@tonic-gate 		len2 = sizeof (msg) - len1 - 1;
1110Sstevel@tonic-gate 	(void) strncat(msg, why, len2);
1120Sstevel@tonic-gate 	len1 = strlen(msg);
1130Sstevel@tonic-gate 	if (msg[len1 - 1] != '\n')
1140Sstevel@tonic-gate 		msg[len1++] = '\n';
1150Sstevel@tonic-gate 	(void) _write(2, msg, len1);
1160Sstevel@tonic-gate 	Abort(msg);
1170Sstevel@tonic-gate }
1180Sstevel@tonic-gate 
119*2248Sraf void
120*2248Sraf thr_panic(const char *why)
121*2248Sraf {
122*2248Sraf 	common_panic("*** libc thread failure: ", why);
123*2248Sraf }
124*2248Sraf 
125*2248Sraf void
126*2248Sraf aio_panic(const char *why)
127*2248Sraf {
128*2248Sraf 	common_panic("*** libc aio system failure: ", why);
129*2248Sraf }
130*2248Sraf 
1310Sstevel@tonic-gate /*
1320Sstevel@tonic-gate  * Utility function for converting a long integer to a string, avoiding stdio.
1330Sstevel@tonic-gate  * 'base' must be one of 10 or 16
1340Sstevel@tonic-gate  */
1350Sstevel@tonic-gate void
1360Sstevel@tonic-gate ultos(uint64_t n, int base, char *s)
1370Sstevel@tonic-gate {
1380Sstevel@tonic-gate 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
1390Sstevel@tonic-gate 	char *cp = lbuf;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 	do {
1420Sstevel@tonic-gate 		*cp++ = "0123456789abcdef"[n%base];
1430Sstevel@tonic-gate 		n /= base;
1440Sstevel@tonic-gate 	} while (n);
1450Sstevel@tonic-gate 	if (base == 16) {
1460Sstevel@tonic-gate 		*s++ = '0';
1470Sstevel@tonic-gate 		*s++ = 'x';
1480Sstevel@tonic-gate 	}
1490Sstevel@tonic-gate 	do {
1500Sstevel@tonic-gate 		*s++ = *--cp;
1510Sstevel@tonic-gate 	} while (cp > lbuf);
1520Sstevel@tonic-gate 	*s = '\0';
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate /*
1560Sstevel@tonic-gate  * Report application lock usage error for mutexes and condvars.
1570Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
1580Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
1590Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
1600Sstevel@tonic-gate  */
1610Sstevel@tonic-gate void
1620Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate 	/* take a snapshot of the mutex before it changes (we hope!) */
1650Sstevel@tonic-gate 	mutex_t mcopy = *mp;
1660Sstevel@tonic-gate 	char buf[800];
1670Sstevel@tonic-gate 	uberdata_t *udp;
1680Sstevel@tonic-gate 	ulwp_t *self;
1690Sstevel@tonic-gate 	lwpid_t lwpid;
1700Sstevel@tonic-gate 	pid_t pid;
1710Sstevel@tonic-gate 
1720Sstevel@tonic-gate 	/* avoid recursion deadlock */
1730Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
1740Sstevel@tonic-gate 		if (assert_thread == self)
1750Sstevel@tonic-gate 			_exit(127);
1760Sstevel@tonic-gate 		enter_critical(self);
1770Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
1780Sstevel@tonic-gate 		assert_thread = self;
1790Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
1800Sstevel@tonic-gate 		udp = self->ul_uberdata;
1810Sstevel@tonic-gate 		pid = udp->pid;
1820Sstevel@tonic-gate 	} else {
1830Sstevel@tonic-gate 		self = NULL;
1840Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
1850Sstevel@tonic-gate 		lwpid = __lwp_self();
1860Sstevel@tonic-gate 		udp = &__uberdata;
1870Sstevel@tonic-gate 		pid = _private_getpid();
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate 
1900Sstevel@tonic-gate 	(void) strcpy(buf,
1910Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
1920Sstevel@tonic-gate 	(void) strcat(buf, who);
1930Sstevel@tonic-gate 	(void) strcat(buf, "(");
1940Sstevel@tonic-gate 	if (cv != NULL) {
1950Sstevel@tonic-gate 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
1960Sstevel@tonic-gate 		(void) strcat(buf, ", ");
1970Sstevel@tonic-gate 	}
1980Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
1990Sstevel@tonic-gate 	(void) strcat(buf, ")");
2000Sstevel@tonic-gate 	if (msg != NULL) {
2010Sstevel@tonic-gate 		(void) strcat(buf, ": ");
2020Sstevel@tonic-gate 		(void) strcat(buf, msg);
2030Sstevel@tonic-gate 	} else if (!mutex_is_held(&mcopy)) {
2040Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread does not own the lock");
2050Sstevel@tonic-gate 	} else if (mcopy.mutex_rcount) {
2060Sstevel@tonic-gate 		(void) strcat(buf, ": mutex rcount = ");
2070Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
2080Sstevel@tonic-gate 	} else {
2090Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread already owns the lock");
2100Sstevel@tonic-gate 	}
2110Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2120Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2130Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2140Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2150Sstevel@tonic-gate 	if (msg != NULL || mutex_is_held(&mcopy))
2160Sstevel@tonic-gate 		/* EMPTY */;
2170Sstevel@tonic-gate 	else if (mcopy.mutex_lockw == 0)
2180Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
2190Sstevel@tonic-gate 	else if (!(mcopy.mutex_type & (USYNC_PROCESS|USYNC_PROCESS_ROBUST))) {
2200Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2210Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2220Sstevel@tonic-gate 	} else {
2230Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2240Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
2250Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2260Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2270Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2280Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
2310Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
2320Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
2330Sstevel@tonic-gate 		Abort(buf);
2340Sstevel@tonic-gate 	assert_thread = NULL;
2350Sstevel@tonic-gate 	(void) _private_lwp_mutex_unlock(&assert_lock);
2360Sstevel@tonic-gate 	if (self != NULL)
2370Sstevel@tonic-gate 		exit_critical(self);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /*
2410Sstevel@tonic-gate  * Report application lock usage error for rwlocks.
2420Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
2430Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
2440Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
2450Sstevel@tonic-gate  */
2460Sstevel@tonic-gate void
2470Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	/* take a snapshot of the rwlock before it changes (we hope) */
2500Sstevel@tonic-gate 	rwlock_t rcopy = *rp;
2510Sstevel@tonic-gate 	char buf[800];
2520Sstevel@tonic-gate 	uberdata_t *udp;
2530Sstevel@tonic-gate 	ulwp_t *self;
2540Sstevel@tonic-gate 	lwpid_t lwpid;
2550Sstevel@tonic-gate 	pid_t pid;
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate 	/* avoid recursion deadlock */
2580Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
2590Sstevel@tonic-gate 		if (assert_thread == self)
2600Sstevel@tonic-gate 			_exit(127);
2610Sstevel@tonic-gate 		enter_critical(self);
2620Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
2630Sstevel@tonic-gate 		assert_thread = self;
2640Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
2650Sstevel@tonic-gate 		udp = self->ul_uberdata;
2660Sstevel@tonic-gate 		pid = udp->pid;
2670Sstevel@tonic-gate 	} else {
2680Sstevel@tonic-gate 		self = NULL;
2690Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
2700Sstevel@tonic-gate 		lwpid = __lwp_self();
2710Sstevel@tonic-gate 		udp = &__uberdata;
2720Sstevel@tonic-gate 		pid = _private_getpid();
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	(void) strcpy(buf,
2760Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
2770Sstevel@tonic-gate 	(void) strcat(buf, who);
2780Sstevel@tonic-gate 	(void) strcat(buf, "(");
2790Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
2800Sstevel@tonic-gate 	(void) strcat(buf, "): ");
2810Sstevel@tonic-gate 	(void) strcat(buf, msg);
2820Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2830Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2840Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2850Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2860Sstevel@tonic-gate 	if (rcopy.rwlock_type & USYNC_PROCESS) {
2870Sstevel@tonic-gate 		uint32_t *rwstate = (uint32_t *)&rcopy.rwlock_readers;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2900Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 		if (*rwstate & URW_WRITE_LOCKED) {
2930Sstevel@tonic-gate 			(void) strcat(buf, "\nthe lock writer owner is ");
2940Sstevel@tonic-gate 			ultos((uint64_t)rcopy.rwlock_owner, 16,
2950Sstevel@tonic-gate 			    buf + strlen(buf));
2960Sstevel@tonic-gate 			(void) strcat(buf, " in process ");
2970Sstevel@tonic-gate 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
2980Sstevel@tonic-gate 			    buf + strlen(buf));
2990Sstevel@tonic-gate 		} else if (*rwstate & URW_READERS_MASK) {
3000Sstevel@tonic-gate 			(void) strcat(buf, "\nthe lock is owned by ");
3010Sstevel@tonic-gate 			ultos((uint64_t)(*rwstate & URW_READERS_MASK), 10,
3020Sstevel@tonic-gate 			    buf + strlen(buf));
3030Sstevel@tonic-gate 			(void) strcat(buf, " readers");
3040Sstevel@tonic-gate 		} else
3050Sstevel@tonic-gate 			(void) strcat(buf, "\nthe lock is unowned");
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 		if (*rwstate & URW_HAS_WAITERS) {
3080Sstevel@tonic-gate 			(void) strcat(buf, "\nand appears to have waiters");
3090Sstevel@tonic-gate 			if (*rwstate & URW_WRITE_WANTED)
3100Sstevel@tonic-gate 				(void) strcat(buf,
3110Sstevel@tonic-gate 				    " (including at least one writer)");
3120Sstevel@tonic-gate 		}
3130Sstevel@tonic-gate 	} else if (rcopy.rwlock_readers < 0) {
3140Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock writer owner is ");
3150Sstevel@tonic-gate 		ultos((uint64_t)rcopy.rwlock_mowner, 16, buf + strlen(buf));
3160Sstevel@tonic-gate 	} else if (rcopy.rwlock_readers > 0) {
3170Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is owned by ");
3180Sstevel@tonic-gate 		ultos((uint64_t)rcopy.rwlock_readers, 10, buf + strlen(buf));
3190Sstevel@tonic-gate 		(void) strcat(buf, "readers");
3200Sstevel@tonic-gate 	} else {
3210Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
3240Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
3250Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3260Sstevel@tonic-gate 		Abort(buf);
3270Sstevel@tonic-gate 	assert_thread = NULL;
3280Sstevel@tonic-gate 	(void) _private_lwp_mutex_unlock(&assert_lock);
3290Sstevel@tonic-gate 	if (self != NULL)
3300Sstevel@tonic-gate 		exit_critical(self);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate /*
3340Sstevel@tonic-gate  * Report a thread usage error.
3350Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
3360Sstevel@tonic-gate  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
3370Sstevel@tonic-gate  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
3380Sstevel@tonic-gate  */
3390Sstevel@tonic-gate void
3400Sstevel@tonic-gate thread_error(const char *msg)
3410Sstevel@tonic-gate {
3420Sstevel@tonic-gate 	char buf[800];
3430Sstevel@tonic-gate 	uberdata_t *udp;
3440Sstevel@tonic-gate 	ulwp_t *self;
3450Sstevel@tonic-gate 	lwpid_t lwpid;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	/* avoid recursion deadlock */
3480Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3490Sstevel@tonic-gate 		if (assert_thread == self)
3500Sstevel@tonic-gate 			_exit(127);
3510Sstevel@tonic-gate 		enter_critical(self);
3520Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
3530Sstevel@tonic-gate 		assert_thread = self;
3540Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
3550Sstevel@tonic-gate 		udp = self->ul_uberdata;
3560Sstevel@tonic-gate 	} else {
3570Sstevel@tonic-gate 		self = NULL;
3580Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
3590Sstevel@tonic-gate 		lwpid = __lwp_self();
3600Sstevel@tonic-gate 		udp = &__uberdata;
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
3640Sstevel@tonic-gate 		"thread usage error detected ***\n*** ");
3650Sstevel@tonic-gate 	(void) strcat(buf, msg);
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate 	(void) strcat(buf, "\n*** calling thread is ");
3680Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3690Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
3700Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
3710Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
3720Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
3730Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3740Sstevel@tonic-gate 		Abort(buf);
3750Sstevel@tonic-gate 	assert_thread = NULL;
3760Sstevel@tonic-gate 	(void) _private_lwp_mutex_unlock(&assert_lock);
3770Sstevel@tonic-gate 	if (self != NULL)
3780Sstevel@tonic-gate 		exit_critical(self);
3790Sstevel@tonic-gate }
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate /*
3820Sstevel@tonic-gate  * We use __assfail() because the libc __assert() calls
3830Sstevel@tonic-gate  * gettext() which calls malloc() which grabs a mutex.
3840Sstevel@tonic-gate  * We do everything without calling standard i/o.
385*2248Sraf  * assfail() and _assfail() are exported functions;
386*2248Sraf  * __assfail() is private to libc.
3870Sstevel@tonic-gate  */
3880Sstevel@tonic-gate #pragma weak _assfail = __assfail
3890Sstevel@tonic-gate void
3900Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num)
3910Sstevel@tonic-gate {
3920Sstevel@tonic-gate 	char buf[800];	/* no assert() message in the library is this long */
3930Sstevel@tonic-gate 	ulwp_t *self;
3940Sstevel@tonic-gate 	lwpid_t lwpid;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/* avoid recursion deadlock */
3970Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3980Sstevel@tonic-gate 		if (assert_thread == self)
3990Sstevel@tonic-gate 			_exit(127);
4000Sstevel@tonic-gate 		enter_critical(self);
4010Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
4020Sstevel@tonic-gate 		assert_thread = self;
4030Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
4040Sstevel@tonic-gate 	} else {
4050Sstevel@tonic-gate 		self = NULL;
4060Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
4070Sstevel@tonic-gate 		lwpid = __lwp_self();
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	(void) strcpy(buf, "assertion failed for thread ");
4110Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
4120Sstevel@tonic-gate 	(void) strcat(buf, ", thread-id ");
4130Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
4140Sstevel@tonic-gate 	(void) strcat(buf, ": ");
4150Sstevel@tonic-gate 	(void) strcat(buf, assertion);
4160Sstevel@tonic-gate 	(void) strcat(buf, ", file ");
4170Sstevel@tonic-gate 	(void) strcat(buf, filename);
4180Sstevel@tonic-gate 	(void) strcat(buf, ", line ");
4190Sstevel@tonic-gate 	ultos((uint64_t)line_num, 10, buf + strlen(buf));
4200Sstevel@tonic-gate 	(void) strcat(buf, "\n");
4210Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
4220Sstevel@tonic-gate 	/*
4230Sstevel@tonic-gate 	 * We could replace the call to Abort() with the following code
4240Sstevel@tonic-gate 	 * if we want just to issue a warning message and not die.
4250Sstevel@tonic-gate 	 *	assert_thread = NULL;
4260Sstevel@tonic-gate 	 *	_private_lwp_mutex_unlock(&assert_lock);
4270Sstevel@tonic-gate 	 *	if (self != NULL)
4280Sstevel@tonic-gate 	 *		exit_critical(self);
4290Sstevel@tonic-gate 	 */
4300Sstevel@tonic-gate 	Abort(buf);
4310Sstevel@tonic-gate }
432*2248Sraf 
433*2248Sraf /*
434*2248Sraf  * We define and export this version of assfail() just because libaio
435*2248Sraf  * used to define and export it, needlessly.  Now that libaio is folded
436*2248Sraf  * into libc, we need to continue this for ABI/version reasons.
437*2248Sraf  * We don't use "#pragma weak assfail __assfail" in order to avoid
438*2248Sraf  * warnings from the check_fnames utility at build time for libraries
439*2248Sraf  * that define their own version of assfail().
440*2248Sraf  */
441*2248Sraf void
442*2248Sraf assfail(const char *assertion, const char *filename, int line_num)
443*2248Sraf {
444*2248Sraf 	__assfail(assertion, filename, line_num);
445*2248Sraf }
446