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*10629SRoger.Faulkner@Sun.COM * Copyright 2009 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 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 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 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); 810Sstevel@tonic-gate (void) __lwp_sigmask(SIG_UNBLOCK, &sigmask, NULL); 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 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 1182248Sraf thr_panic(const char *why) 1192248Sraf { 1202248Sraf common_panic("*** libc thread failure: ", why); 1212248Sraf } 1222248Sraf 1232248Sraf void 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 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 1600Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg) 1610Sstevel@tonic-gate { 162*10629SRoger.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 169*10629SRoger.Faulkner@Sun.COM /* 170*10629SRoger.Faulkner@Sun.COM * Take a snapshot of the mutex before it changes (we hope!). 171*10629SRoger.Faulkner@Sun.COM * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned. 172*10629SRoger.Faulkner@Sun.COM */ 173*10629SRoger.Faulkner@Sun.COM (void) memcpy(&mcopy, mp, sizeof (mcopy)); 174*10629SRoger.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 2500Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg) 2510Sstevel@tonic-gate { 252*10629SRoger.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 261*10629SRoger.Faulkner@Sun.COM /* 262*10629SRoger.Faulkner@Sun.COM * Take a snapshot of the rwlock before it changes (we hope!). 263*10629SRoger.Faulkner@Sun.COM * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned. 264*10629SRoger.Faulkner@Sun.COM */ 265*10629SRoger.Faulkner@Sun.COM (void) memcpy(&rcopy, rp, sizeof (rcopy)); 266*10629SRoger.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 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 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 4412248Sraf assfail(const char *assertion, const char *filename, int line_num) 4422248Sraf { 4432248Sraf __assfail(assertion, filename, line_num); 4442248Sraf } 445