xref: /onnv-gate/usr/src/lib/libc/port/threads/assfail.c (revision 11913:283e725df792)
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*11913SRoger.Faulkner@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include "lint.h"
280Sstevel@tonic-gate #include "thr_uberdata.h"
290Sstevel@tonic-gate 
300Sstevel@tonic-gate const char *panicstr;
310Sstevel@tonic-gate ulwp_t *panic_thread;
320Sstevel@tonic-gate 
330Sstevel@tonic-gate static mutex_t assert_lock = DEFAULTMUTEX;
340Sstevel@tonic-gate static ulwp_t *assert_thread = NULL;
350Sstevel@tonic-gate 
360Sstevel@tonic-gate /*
370Sstevel@tonic-gate  * Called from __assert() to set panicstr and panic_thread.
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate void
__set_panicstr(const char * msg)400Sstevel@tonic-gate __set_panicstr(const char *msg)
410Sstevel@tonic-gate {
420Sstevel@tonic-gate 	panicstr = msg;
430Sstevel@tonic-gate 	panic_thread = __curthread();
440Sstevel@tonic-gate }
450Sstevel@tonic-gate 
460Sstevel@tonic-gate /*
470Sstevel@tonic-gate  * Called from exit() (atexit function) to give precedence
480Sstevel@tonic-gate  * to assertion failures and a core dump over _exit().
490Sstevel@tonic-gate  */
500Sstevel@tonic-gate void
grab_assert_lock()510Sstevel@tonic-gate grab_assert_lock()
520Sstevel@tonic-gate {
536515Sraf 	(void) _lwp_mutex_lock(&assert_lock);
540Sstevel@tonic-gate }
550Sstevel@tonic-gate 
560Sstevel@tonic-gate static void
Abort(const char * msg)570Sstevel@tonic-gate Abort(const char *msg)
580Sstevel@tonic-gate {
590Sstevel@tonic-gate 	ulwp_t *self;
600Sstevel@tonic-gate 	struct sigaction act;
610Sstevel@tonic-gate 	sigset_t sigmask;
620Sstevel@tonic-gate 	lwpid_t lwpid;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate 	/* to help with core file debugging */
650Sstevel@tonic-gate 	panicstr = msg;
660Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
670Sstevel@tonic-gate 		panic_thread = self;
680Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
690Sstevel@tonic-gate 	} else {
706812Sraf 		lwpid = _lwp_self();
710Sstevel@tonic-gate 	}
720Sstevel@tonic-gate 
730Sstevel@tonic-gate 	/* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */
746515Sraf 	(void) memset(&act, 0, sizeof (act));
750Sstevel@tonic-gate 	act.sa_sigaction = SIG_DFL;
760Sstevel@tonic-gate 	(void) __sigaction(SIGABRT, &act, NULL);
770Sstevel@tonic-gate 
780Sstevel@tonic-gate 	/* delete SIGABRT from the signal mask */
796515Sraf 	(void) sigemptyset(&sigmask);
806515Sraf 	(void) sigaddset(&sigmask, SIGABRT);
81*11913SRoger.Faulkner@Sun.COM 	(void) __lwp_sigmask(SIG_UNBLOCK, &sigmask);
820Sstevel@tonic-gate 
836812Sraf 	(void) _lwp_kill(lwpid, SIGABRT);	/* never returns */
846812Sraf 	(void) kill(getpid(), SIGABRT);	/* if it does, try harder */
850Sstevel@tonic-gate 	_exit(127);
860Sstevel@tonic-gate }
870Sstevel@tonic-gate 
880Sstevel@tonic-gate /*
890Sstevel@tonic-gate  * Write a panic message w/o grabbing any locks other than assert_lock.
900Sstevel@tonic-gate  * We have no idea what locks are held at this point.
910Sstevel@tonic-gate  */
922248Sraf static void
common_panic(const char * head,const char * why)932248Sraf common_panic(const char *head, const char *why)
940Sstevel@tonic-gate {
950Sstevel@tonic-gate 	char msg[400];	/* no panic() message in the library is this long */
960Sstevel@tonic-gate 	ulwp_t *self;
970Sstevel@tonic-gate 	size_t len1, len2;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	if ((self = __curthread()) != NULL)
1000Sstevel@tonic-gate 		enter_critical(self);
1016515Sraf 	(void) _lwp_mutex_lock(&assert_lock);
1020Sstevel@tonic-gate 
1036515Sraf 	(void) memset(msg, 0, sizeof (msg));
1042248Sraf 	(void) strcpy(msg, head);
1050Sstevel@tonic-gate 	len1 = strlen(msg);
1060Sstevel@tonic-gate 	len2 = strlen(why);
1070Sstevel@tonic-gate 	if (len1 + len2 >= sizeof (msg))
1080Sstevel@tonic-gate 		len2 = sizeof (msg) - len1 - 1;
1090Sstevel@tonic-gate 	(void) strncat(msg, why, len2);
1100Sstevel@tonic-gate 	len1 = strlen(msg);
1110Sstevel@tonic-gate 	if (msg[len1 - 1] != '\n')
1120Sstevel@tonic-gate 		msg[len1++] = '\n';
1135891Sraf 	(void) __write(2, msg, len1);
1140Sstevel@tonic-gate 	Abort(msg);
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate 
1172248Sraf void
thr_panic(const char * why)1182248Sraf thr_panic(const char *why)
1192248Sraf {
1202248Sraf 	common_panic("*** libc thread failure: ", why);
1212248Sraf }
1222248Sraf 
1232248Sraf void
aio_panic(const char * why)1242248Sraf aio_panic(const char *why)
1252248Sraf {
1262248Sraf 	common_panic("*** libc aio system failure: ", why);
1272248Sraf }
1282248Sraf 
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate  * Utility function for converting a long integer to a string, avoiding stdio.
1310Sstevel@tonic-gate  * 'base' must be one of 10 or 16
1320Sstevel@tonic-gate  */
1330Sstevel@tonic-gate void
ultos(uint64_t n,int base,char * s)1340Sstevel@tonic-gate ultos(uint64_t n, int base, char *s)
1350Sstevel@tonic-gate {
1360Sstevel@tonic-gate 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
1370Sstevel@tonic-gate 	char *cp = lbuf;
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	do {
1400Sstevel@tonic-gate 		*cp++ = "0123456789abcdef"[n%base];
1410Sstevel@tonic-gate 		n /= base;
1420Sstevel@tonic-gate 	} while (n);
1430Sstevel@tonic-gate 	if (base == 16) {
1440Sstevel@tonic-gate 		*s++ = '0';
1450Sstevel@tonic-gate 		*s++ = 'x';
1460Sstevel@tonic-gate 	}
1470Sstevel@tonic-gate 	do {
1480Sstevel@tonic-gate 		*s++ = *--cp;
1490Sstevel@tonic-gate 	} while (cp > lbuf);
1500Sstevel@tonic-gate 	*s = '\0';
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * Report application lock usage error for mutexes and condvars.
1550Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
1560Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
1570Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate void
lock_error(const mutex_t * mp,const char * who,void * cv,const char * msg)1600Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
1610Sstevel@tonic-gate {
16210629SRoger.Faulkner@Sun.COM 	mutex_t mcopy;
1630Sstevel@tonic-gate 	char buf[800];
1640Sstevel@tonic-gate 	uberdata_t *udp;
1650Sstevel@tonic-gate 	ulwp_t *self;
1660Sstevel@tonic-gate 	lwpid_t lwpid;
1670Sstevel@tonic-gate 	pid_t pid;
1680Sstevel@tonic-gate 
16910629SRoger.Faulkner@Sun.COM 	/*
17010629SRoger.Faulkner@Sun.COM 	 * Take a snapshot of the mutex before it changes (we hope!).
17110629SRoger.Faulkner@Sun.COM 	 * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned.
17210629SRoger.Faulkner@Sun.COM 	 */
17310629SRoger.Faulkner@Sun.COM 	(void) memcpy(&mcopy, mp, sizeof (mcopy));
17410629SRoger.Faulkner@Sun.COM 
1750Sstevel@tonic-gate 	/* avoid recursion deadlock */
1760Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
1770Sstevel@tonic-gate 		if (assert_thread == self)
1780Sstevel@tonic-gate 			_exit(127);
1790Sstevel@tonic-gate 		enter_critical(self);
1806515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
1810Sstevel@tonic-gate 		assert_thread = self;
1820Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
1830Sstevel@tonic-gate 		udp = self->ul_uberdata;
1840Sstevel@tonic-gate 		pid = udp->pid;
1850Sstevel@tonic-gate 	} else {
1860Sstevel@tonic-gate 		self = NULL;
1876515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
1886812Sraf 		lwpid = _lwp_self();
1890Sstevel@tonic-gate 		udp = &__uberdata;
1906515Sraf 		pid = getpid();
1910Sstevel@tonic-gate 	}
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	(void) strcpy(buf,
1940Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
1950Sstevel@tonic-gate 	(void) strcat(buf, who);
1960Sstevel@tonic-gate 	(void) strcat(buf, "(");
1970Sstevel@tonic-gate 	if (cv != NULL) {
1980Sstevel@tonic-gate 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
1990Sstevel@tonic-gate 		(void) strcat(buf, ", ");
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
2020Sstevel@tonic-gate 	(void) strcat(buf, ")");
2030Sstevel@tonic-gate 	if (msg != NULL) {
2040Sstevel@tonic-gate 		(void) strcat(buf, ": ");
2050Sstevel@tonic-gate 		(void) strcat(buf, msg);
2066812Sraf 	} else if (!mutex_held(&mcopy)) {
2070Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread does not own the lock");
2080Sstevel@tonic-gate 	} else if (mcopy.mutex_rcount) {
2090Sstevel@tonic-gate 		(void) strcat(buf, ": mutex rcount = ");
2100Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
2110Sstevel@tonic-gate 	} else {
2120Sstevel@tonic-gate 		(void) strcat(buf, ": calling thread already owns the lock");
2130Sstevel@tonic-gate 	}
2140Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2150Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2160Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2170Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2186812Sraf 	if (msg != NULL || mutex_held(&mcopy))
2190Sstevel@tonic-gate 		/* EMPTY */;
2200Sstevel@tonic-gate 	else if (mcopy.mutex_lockw == 0)
2210Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
2224574Sraf 	else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
2230Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2240Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2250Sstevel@tonic-gate 	} else {
2260Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2270Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
2280Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock owner is ");
2290Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2300Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
2310Sstevel@tonic-gate 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
2345891Sraf 	(void) __write(2, buf, strlen(buf));
2350Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
2360Sstevel@tonic-gate 		Abort(buf);
2370Sstevel@tonic-gate 	assert_thread = NULL;
2386515Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
2390Sstevel@tonic-gate 	if (self != NULL)
2400Sstevel@tonic-gate 		exit_critical(self);
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate /*
2440Sstevel@tonic-gate  * Report application lock usage error for rwlocks.
2450Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
2460Sstevel@tonic-gate  * Continue execution if _THREAD_ERROR_DETECTION=1.
2470Sstevel@tonic-gate  * Dump core if _THREAD_ERROR_DETECTION=2.
2480Sstevel@tonic-gate  */
2490Sstevel@tonic-gate void
rwlock_error(const rwlock_t * rp,const char * who,const char * msg)2500Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
2510Sstevel@tonic-gate {
25210629SRoger.Faulkner@Sun.COM 	rwlock_t rcopy;
2534570Sraf 	uint32_t rwstate;
2540Sstevel@tonic-gate 	char buf[800];
2550Sstevel@tonic-gate 	uberdata_t *udp;
2560Sstevel@tonic-gate 	ulwp_t *self;
2570Sstevel@tonic-gate 	lwpid_t lwpid;
2580Sstevel@tonic-gate 	pid_t pid;
2594570Sraf 	int process;
2600Sstevel@tonic-gate 
26110629SRoger.Faulkner@Sun.COM 	/*
26210629SRoger.Faulkner@Sun.COM 	 * Take a snapshot of the rwlock before it changes (we hope!).
26310629SRoger.Faulkner@Sun.COM 	 * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned.
26410629SRoger.Faulkner@Sun.COM 	 */
26510629SRoger.Faulkner@Sun.COM 	(void) memcpy(&rcopy, rp, sizeof (rcopy));
26610629SRoger.Faulkner@Sun.COM 
2670Sstevel@tonic-gate 	/* avoid recursion deadlock */
2680Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
2690Sstevel@tonic-gate 		if (assert_thread == self)
2700Sstevel@tonic-gate 			_exit(127);
2710Sstevel@tonic-gate 		enter_critical(self);
2726515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2730Sstevel@tonic-gate 		assert_thread = self;
2740Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
2750Sstevel@tonic-gate 		udp = self->ul_uberdata;
2760Sstevel@tonic-gate 		pid = udp->pid;
2770Sstevel@tonic-gate 	} else {
2780Sstevel@tonic-gate 		self = NULL;
2796515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
2806812Sraf 		lwpid = _lwp_self();
2810Sstevel@tonic-gate 		udp = &__uberdata;
2826515Sraf 		pid = getpid();
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 
2854570Sraf 	rwstate = (uint32_t)rcopy.rwlock_readers;
2864570Sraf 	process = (rcopy.rwlock_type & USYNC_PROCESS);
2874570Sraf 
2880Sstevel@tonic-gate 	(void) strcpy(buf,
2890Sstevel@tonic-gate 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
2900Sstevel@tonic-gate 	(void) strcat(buf, who);
2910Sstevel@tonic-gate 	(void) strcat(buf, "(");
2920Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
2930Sstevel@tonic-gate 	(void) strcat(buf, "): ");
2940Sstevel@tonic-gate 	(void) strcat(buf, msg);
2950Sstevel@tonic-gate 	(void) strcat(buf, "\ncalling thread is ");
2960Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2970Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
2980Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2994570Sraf 	if (process) {
3000Sstevel@tonic-gate 		(void) strcat(buf, " in process ");
3010Sstevel@tonic-gate 		ultos((uint64_t)pid, 10, buf + strlen(buf));
3024570Sraf 	}
3034570Sraf 	if (rwstate & URW_WRITE_LOCKED) {
3044570Sraf 		(void) strcat(buf, "\nthe writer lock owner is ");
3054570Sraf 		ultos((uint64_t)rcopy.rwlock_owner, 16,
3064570Sraf 		    buf + strlen(buf));
3074570Sraf 		if (process) {
3080Sstevel@tonic-gate 			(void) strcat(buf, " in process ");
3090Sstevel@tonic-gate 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
3100Sstevel@tonic-gate 			    buf + strlen(buf));
3110Sstevel@tonic-gate 		}
3124570Sraf 	} else if (rwstate & URW_READERS_MASK) {
3134570Sraf 		(void) strcat(buf, "\nthe reader lock is held by ");
3144570Sraf 		ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
3154570Sraf 		    buf + strlen(buf));
3164570Sraf 		(void) strcat(buf, " readers");
3170Sstevel@tonic-gate 	} else {
3180Sstevel@tonic-gate 		(void) strcat(buf, "\nthe lock is unowned");
3190Sstevel@tonic-gate 	}
3204570Sraf 	if (rwstate & URW_HAS_WAITERS)
3214570Sraf 		(void) strcat(buf, "\nand the lock appears to have waiters");
3220Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
3235891Sraf 	(void) __write(2, buf, strlen(buf));
3240Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3250Sstevel@tonic-gate 		Abort(buf);
3260Sstevel@tonic-gate 	assert_thread = NULL;
3276515Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
3280Sstevel@tonic-gate 	if (self != NULL)
3290Sstevel@tonic-gate 		exit_critical(self);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate  * Report a thread usage error.
3340Sstevel@tonic-gate  * Not called if _THREAD_ERROR_DETECTION=0.
3350Sstevel@tonic-gate  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
3360Sstevel@tonic-gate  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
3370Sstevel@tonic-gate  */
3380Sstevel@tonic-gate void
thread_error(const char * msg)3390Sstevel@tonic-gate thread_error(const char *msg)
3400Sstevel@tonic-gate {
3410Sstevel@tonic-gate 	char buf[800];
3420Sstevel@tonic-gate 	uberdata_t *udp;
3430Sstevel@tonic-gate 	ulwp_t *self;
3440Sstevel@tonic-gate 	lwpid_t lwpid;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	/* avoid recursion deadlock */
3470Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3480Sstevel@tonic-gate 		if (assert_thread == self)
3490Sstevel@tonic-gate 			_exit(127);
3500Sstevel@tonic-gate 		enter_critical(self);
3516515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
3520Sstevel@tonic-gate 		assert_thread = self;
3530Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
3540Sstevel@tonic-gate 		udp = self->ul_uberdata;
3550Sstevel@tonic-gate 	} else {
3560Sstevel@tonic-gate 		self = NULL;
3576515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
3586812Sraf 		lwpid = _lwp_self();
3590Sstevel@tonic-gate 		udp = &__uberdata;
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
3635891Sraf 	    "thread usage error detected ***\n*** ");
3640Sstevel@tonic-gate 	(void) strcat(buf, msg);
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	(void) strcat(buf, "\n*** calling thread is ");
3670Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3680Sstevel@tonic-gate 	(void) strcat(buf, " thread-id ");
3690Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
3700Sstevel@tonic-gate 	(void) strcat(buf, "\n\n");
3715891Sraf 	(void) __write(2, buf, strlen(buf));
3720Sstevel@tonic-gate 	if (udp->uberflags.uf_thread_error_detection >= 2)
3730Sstevel@tonic-gate 		Abort(buf);
3740Sstevel@tonic-gate 	assert_thread = NULL;
3756515Sraf 	(void) _lwp_mutex_unlock(&assert_lock);
3760Sstevel@tonic-gate 	if (self != NULL)
3770Sstevel@tonic-gate 		exit_critical(self);
3780Sstevel@tonic-gate }
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate  * We use __assfail() because the libc __assert() calls
3820Sstevel@tonic-gate  * gettext() which calls malloc() which grabs a mutex.
3830Sstevel@tonic-gate  * We do everything without calling standard i/o.
3842248Sraf  * assfail() and _assfail() are exported functions;
3852248Sraf  * __assfail() is private to libc.
3860Sstevel@tonic-gate  */
3870Sstevel@tonic-gate #pragma weak _assfail = __assfail
3880Sstevel@tonic-gate void
__assfail(const char * assertion,const char * filename,int line_num)3890Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	char buf[800];	/* no assert() message in the library is this long */
3920Sstevel@tonic-gate 	ulwp_t *self;
3930Sstevel@tonic-gate 	lwpid_t lwpid;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/* avoid recursion deadlock */
3960Sstevel@tonic-gate 	if ((self = __curthread()) != NULL) {
3970Sstevel@tonic-gate 		if (assert_thread == self)
3980Sstevel@tonic-gate 			_exit(127);
3990Sstevel@tonic-gate 		enter_critical(self);
4006515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
4010Sstevel@tonic-gate 		assert_thread = self;
4020Sstevel@tonic-gate 		lwpid = self->ul_lwpid;
4030Sstevel@tonic-gate 	} else {
4040Sstevel@tonic-gate 		self = NULL;
4056515Sraf 		(void) _lwp_mutex_lock(&assert_lock);
4066812Sraf 		lwpid = _lwp_self();
4070Sstevel@tonic-gate 	}
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate 	(void) strcpy(buf, "assertion failed for thread ");
4100Sstevel@tonic-gate 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
4110Sstevel@tonic-gate 	(void) strcat(buf, ", thread-id ");
4120Sstevel@tonic-gate 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
4130Sstevel@tonic-gate 	(void) strcat(buf, ": ");
4140Sstevel@tonic-gate 	(void) strcat(buf, assertion);
4150Sstevel@tonic-gate 	(void) strcat(buf, ", file ");
4160Sstevel@tonic-gate 	(void) strcat(buf, filename);
4170Sstevel@tonic-gate 	(void) strcat(buf, ", line ");
4180Sstevel@tonic-gate 	ultos((uint64_t)line_num, 10, buf + strlen(buf));
4190Sstevel@tonic-gate 	(void) strcat(buf, "\n");
4205891Sraf 	(void) __write(2, buf, strlen(buf));
4210Sstevel@tonic-gate 	/*
4220Sstevel@tonic-gate 	 * We could replace the call to Abort() with the following code
4230Sstevel@tonic-gate 	 * if we want just to issue a warning message and not die.
4240Sstevel@tonic-gate 	 *	assert_thread = NULL;
4256515Sraf 	 *	_lwp_mutex_unlock(&assert_lock);
4260Sstevel@tonic-gate 	 *	if (self != NULL)
4270Sstevel@tonic-gate 	 *		exit_critical(self);
4280Sstevel@tonic-gate 	 */
4290Sstevel@tonic-gate 	Abort(buf);
4300Sstevel@tonic-gate }
4312248Sraf 
4322248Sraf /*
4332248Sraf  * We define and export this version of assfail() just because libaio
4342248Sraf  * used to define and export it, needlessly.  Now that libaio is folded
4352248Sraf  * into libc, we need to continue this for ABI/version reasons.
4362248Sraf  * We don't use "#pragma weak assfail __assfail" in order to avoid
4372248Sraf  * warnings from the check_fnames utility at build time for libraries
4382248Sraf  * that define their own version of assfail().
4392248Sraf  */
4402248Sraf void
assfail(const char * assertion,const char * filename,int line_num)4412248Sraf assfail(const char *assertion, const char *filename, int line_num)
4422248Sraf {
4432248Sraf 	__assfail(assertion, filename, line_num);
4442248Sraf }
445