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