xref: /onnv-gate/usr/src/lib/libc/port/threads/assfail.c (revision 4570:f93b74ddbdd5)
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
52248Sraf  * Common Development and Distribution License (the "License").
62248Sraf  * 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  */
212248Sraf 
220Sstevel@tonic-gate /*
23*4570Sraf  * Copyright 2007 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  */
942248Sraf static void
952248Sraf 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));
1062248Sraf 	(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 
1192248Sraf void
1202248Sraf thr_panic(const char *why)
1212248Sraf {
1222248Sraf 	common_panic("*** libc thread failure: ", why);
1232248Sraf }
1242248Sraf 
1252248Sraf void
1262248Sraf aio_panic(const char *why)
1272248Sraf {
1282248Sraf 	common_panic("*** libc aio system failure: ", why);
1292248Sraf }
1302248Sraf 
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;
251*4570Sraf 	uint32_t rwstate;
2520Sstevel@tonic-gate 	char buf[800];
2530Sstevel@tonic-gate 	uberdata_t *udp;
2540Sstevel@tonic-gate 	ulwp_t *self;
2550Sstevel@tonic-gate 	lwpid_t lwpid;
2560Sstevel@tonic-gate 	pid_t pid;
257*4570Sraf 	int process;
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	/* avoid recursion deadlock */
2600Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
2610Sstevel@tonic-gate 		if (assert_thread == self)
2620Sstevel@tonic-gate 			_exit(127);
2630Sstevel@tonic-gate 		enter_critical(self);
2640Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
2650Sstevel@tonic-gate 		assert_thread = self;
2660Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
2670Sstevel@tonic-gate 		udp = self->ul_uberdata;
2680Sstevel@tonic-gate 		pid = udp->pid;
2690Sstevel@tonic-gate 	} else {
2700Sstevel@tonic-gate 		self = NULL;
2710Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
2720Sstevel@tonic-gate 		lwpid = __lwp_self();
2730Sstevel@tonic-gate 		udp = &__uberdata;
2740Sstevel@tonic-gate 		pid = _private_getpid();
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
277*4570Sraf 	rwstate = (uint32_t)rcopy.rwlock_readers;
278*4570Sraf 	process = (rcopy.rwlock_type & USYNC_PROCESS);
279*4570Sraf 
2800Sstevel@tonic-gate 	(void) strcpy(buf,
2810Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
2820Sstevel@tonic-gate 	(void) strcat(buf, who);
2830Sstevel@tonic-gate 	(void) strcat(buf, "(");
2840Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
2850Sstevel@tonic-gate 	(void) strcat(buf, "): ");
2860Sstevel@tonic-gate 	(void) strcat(buf, msg);
2870Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2880Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2890Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2900Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
291*4570Sraf 	if (process) {
2920Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2930Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
294*4570Sraf 	}
295*4570Sraf 	if (rwstate & URW_WRITE_LOCKED) {
296*4570Sraf 		(void) strcat(buf, "\nthe writer lock owner is ");
297*4570Sraf 		ultos((uint64_t)rcopy.rwlock_owner, 16,
298*4570Sraf 		    buf + strlen(buf));
299*4570Sraf 		if (process) {
3000Sstevel@tonic-gate 			(void) strcat(buf, " in process ");
3010Sstevel@tonic-gate 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
3020Sstevel@tonic-gate 			    buf + strlen(buf));
3030Sstevel@tonic-gate 		}
304*4570Sraf 	} else if (rwstate & URW_READERS_MASK) {
305*4570Sraf 		(void) strcat(buf, "\nthe reader lock is held by ");
306*4570Sraf 		ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
307*4570Sraf 		    buf + strlen(buf));
308*4570Sraf 		(void) strcat(buf, " readers");
3090Sstevel@tonic-gate 	} else {
3100Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
3110Sstevel@tonic-gate 	}
312*4570Sraf 	if (rwstate & URW_HAS_WAITERS)
313*4570Sraf 		(void) strcat(buf, "\nand the lock appears to have waiters");
3140Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
3150Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
3160Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3170Sstevel@tonic-gate 		Abort(buf);
3180Sstevel@tonic-gate 	assert_thread = NULL;
3190Sstevel@tonic-gate 	(void) _private_lwp_mutex_unlock(&assert_lock);
3200Sstevel@tonic-gate 	if (self != NULL)
3210Sstevel@tonic-gate 		exit_critical(self);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate /*
3250Sstevel@tonic-gate  * Report a thread usage error.
3260Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
3270Sstevel@tonic-gate  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
3280Sstevel@tonic-gate  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
3290Sstevel@tonic-gate  */
3300Sstevel@tonic-gate void
3310Sstevel@tonic-gate thread_error(const char *msg)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	char buf[800];
3340Sstevel@tonic-gate 	uberdata_t *udp;
3350Sstevel@tonic-gate 	ulwp_t *self;
3360Sstevel@tonic-gate 	lwpid_t lwpid;
3370Sstevel@tonic-gate 
3380Sstevel@tonic-gate 	/* avoid recursion deadlock */
3390Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3400Sstevel@tonic-gate 		if (assert_thread == self)
3410Sstevel@tonic-gate 			_exit(127);
3420Sstevel@tonic-gate 		enter_critical(self);
3430Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
3440Sstevel@tonic-gate 		assert_thread = self;
3450Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
3460Sstevel@tonic-gate 		udp = self->ul_uberdata;
3470Sstevel@tonic-gate 	} else {
3480Sstevel@tonic-gate 		self = NULL;
3490Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
3500Sstevel@tonic-gate 		lwpid = __lwp_self();
3510Sstevel@tonic-gate 		udp = &__uberdata;
3520Sstevel@tonic-gate 	}
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
3550Sstevel@tonic-gate 		"thread usage error detected ***\n*** ");
3560Sstevel@tonic-gate 	(void) strcat(buf, msg);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	(void) strcat(buf, "\n*** calling thread is ");
3590Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3600Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
3610Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
3620Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
3630Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
3640Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3650Sstevel@tonic-gate 		Abort(buf);
3660Sstevel@tonic-gate 	assert_thread = NULL;
3670Sstevel@tonic-gate 	(void) _private_lwp_mutex_unlock(&assert_lock);
3680Sstevel@tonic-gate 	if (self != NULL)
3690Sstevel@tonic-gate 		exit_critical(self);
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate /*
3730Sstevel@tonic-gate  * We use __assfail() because the libc __assert() calls
3740Sstevel@tonic-gate  * gettext() which calls malloc() which grabs a mutex.
3750Sstevel@tonic-gate  * We do everything without calling standard i/o.
3762248Sraf  * assfail() and _assfail() are exported functions;
3772248Sraf  * __assfail() is private to libc.
3780Sstevel@tonic-gate  */
3790Sstevel@tonic-gate #pragma weak _assfail = __assfail
3800Sstevel@tonic-gate void
3810Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num)
3820Sstevel@tonic-gate {
3830Sstevel@tonic-gate 	char buf[800];	/* no assert() message in the library is this long */
3840Sstevel@tonic-gate 	ulwp_t *self;
3850Sstevel@tonic-gate 	lwpid_t lwpid;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	/* avoid recursion deadlock */
3880Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3890Sstevel@tonic-gate 		if (assert_thread == self)
3900Sstevel@tonic-gate 			_exit(127);
3910Sstevel@tonic-gate 		enter_critical(self);
3920Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
3930Sstevel@tonic-gate 		assert_thread = self;
3940Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
3950Sstevel@tonic-gate 	} else {
3960Sstevel@tonic-gate 		self = NULL;
3970Sstevel@tonic-gate 		(void) _private_lwp_mutex_lock(&assert_lock);
3980Sstevel@tonic-gate 		lwpid = __lwp_self();
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 
4010Sstevel@tonic-gate 	(void) strcpy(buf, "assertion failed for thread ");
4020Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
4030Sstevel@tonic-gate 	(void) strcat(buf, ", thread-id ");
4040Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
4050Sstevel@tonic-gate 	(void) strcat(buf, ": ");
4060Sstevel@tonic-gate 	(void) strcat(buf, assertion);
4070Sstevel@tonic-gate 	(void) strcat(buf, ", file ");
4080Sstevel@tonic-gate 	(void) strcat(buf, filename);
4090Sstevel@tonic-gate 	(void) strcat(buf, ", line ");
4100Sstevel@tonic-gate 	ultos((uint64_t)line_num, 10, buf + strlen(buf));
4110Sstevel@tonic-gate 	(void) strcat(buf, "\n");
4120Sstevel@tonic-gate 	(void) _write(2, buf, strlen(buf));
4130Sstevel@tonic-gate 	/*
4140Sstevel@tonic-gate 	 * We could replace the call to Abort() with the following code
4150Sstevel@tonic-gate 	 * if we want just to issue a warning message and not die.
4160Sstevel@tonic-gate 	 *	assert_thread = NULL;
4170Sstevel@tonic-gate 	 *	_private_lwp_mutex_unlock(&assert_lock);
4180Sstevel@tonic-gate 	 *	if (self != NULL)
4190Sstevel@tonic-gate 	 *		exit_critical(self);
4200Sstevel@tonic-gate 	 */
4210Sstevel@tonic-gate 	Abort(buf);
4220Sstevel@tonic-gate }
4232248Sraf 
4242248Sraf /*
4252248Sraf  * We define and export this version of assfail() just because libaio
4262248Sraf  * used to define and export it, needlessly.  Now that libaio is folded
4272248Sraf  * into libc, we need to continue this for ABI/version reasons.
4282248Sraf  * We don't use "#pragma weak assfail __assfail" in order to avoid
4292248Sraf  * warnings from the check_fnames utility at build time for libraries
4302248Sraf  * that define their own version of assfail().
4312248Sraf  */
4322248Sraf void
4332248Sraf assfail(const char *assertion, const char *filename, int line_num)
4342248Sraf {
4352248Sraf 	__assfail(assertion, filename, line_num);
4362248Sraf }
437