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