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