17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5f841f6adSraf * Common Development and Distribution License (the "License"). 6f841f6adSraf * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21f841f6adSraf 227c478bd9Sstevel@tonic-gate /* 23bdf0047cSRoger A. Faulkner * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 26ad135b5dSChristopher Siden /* 27fae63477SPrakash Surya * Copyright (c) 2012, 2014 by Delphix. All rights reserved. 28*0d045c0dSRobert Mustacchi * Copyright 2015 Joyent, Inc. 29ad135b5dSChristopher Siden */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include "lint.h" 327c478bd9Sstevel@tonic-gate #include "thr_uberdata.h" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate const char *panicstr; 357c478bd9Sstevel@tonic-gate ulwp_t *panic_thread; 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate static mutex_t assert_lock = DEFAULTMUTEX; 387c478bd9Sstevel@tonic-gate static ulwp_t *assert_thread = NULL; 397c478bd9Sstevel@tonic-gate 40*0d045c0dSRobert Mustacchi mutex_t *panic_mutex = NULL; 41*0d045c0dSRobert Mustacchi 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * Called from __assert() to set panicstr and panic_thread. 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate void 467c478bd9Sstevel@tonic-gate __set_panicstr(const char *msg) 477c478bd9Sstevel@tonic-gate { 487c478bd9Sstevel@tonic-gate panicstr = msg; 497c478bd9Sstevel@tonic-gate panic_thread = __curthread(); 507c478bd9Sstevel@tonic-gate } 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate /* 537c478bd9Sstevel@tonic-gate * Called from exit() (atexit function) to give precedence 547c478bd9Sstevel@tonic-gate * to assertion failures and a core dump over _exit(). 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate void 577c478bd9Sstevel@tonic-gate grab_assert_lock() 587c478bd9Sstevel@tonic-gate { 598cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 607c478bd9Sstevel@tonic-gate } 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate static void 637c478bd9Sstevel@tonic-gate Abort(const char *msg) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate ulwp_t *self; 667c478bd9Sstevel@tonic-gate struct sigaction act; 677c478bd9Sstevel@tonic-gate sigset_t sigmask; 687c478bd9Sstevel@tonic-gate lwpid_t lwpid; 697c478bd9Sstevel@tonic-gate 707c478bd9Sstevel@tonic-gate /* to help with core file debugging */ 717c478bd9Sstevel@tonic-gate panicstr = msg; 727c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) { 737c478bd9Sstevel@tonic-gate panic_thread = self; 747c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid; 757c478bd9Sstevel@tonic-gate } else { 767257d1b4Sraf lwpid = _lwp_self(); 777c478bd9Sstevel@tonic-gate } 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate /* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */ 808cd45542Sraf (void) memset(&act, 0, sizeof (act)); 817c478bd9Sstevel@tonic-gate act.sa_sigaction = SIG_DFL; 827c478bd9Sstevel@tonic-gate (void) __sigaction(SIGABRT, &act, NULL); 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate /* delete SIGABRT from the signal mask */ 858cd45542Sraf (void) sigemptyset(&sigmask); 868cd45542Sraf (void) sigaddset(&sigmask, SIGABRT); 87bdf0047cSRoger A. Faulkner (void) __lwp_sigmask(SIG_UNBLOCK, &sigmask); 887c478bd9Sstevel@tonic-gate 897257d1b4Sraf (void) _lwp_kill(lwpid, SIGABRT); /* never returns */ 907257d1b4Sraf (void) kill(getpid(), SIGABRT); /* if it does, try harder */ 917c478bd9Sstevel@tonic-gate _exit(127); 927c478bd9Sstevel@tonic-gate } 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * Write a panic message w/o grabbing any locks other than assert_lock. 967c478bd9Sstevel@tonic-gate * We have no idea what locks are held at this point. 977c478bd9Sstevel@tonic-gate */ 98f841f6adSraf static void 99f841f6adSraf common_panic(const char *head, const char *why) 1007c478bd9Sstevel@tonic-gate { 1017c478bd9Sstevel@tonic-gate char msg[400]; /* no panic() message in the library is this long */ 1027c478bd9Sstevel@tonic-gate ulwp_t *self; 1037c478bd9Sstevel@tonic-gate size_t len1, len2; 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) 1067c478bd9Sstevel@tonic-gate enter_critical(self); 1078cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 1087c478bd9Sstevel@tonic-gate 1098cd45542Sraf (void) memset(msg, 0, sizeof (msg)); 110f841f6adSraf (void) strcpy(msg, head); 1117c478bd9Sstevel@tonic-gate len1 = strlen(msg); 1127c478bd9Sstevel@tonic-gate len2 = strlen(why); 1137c478bd9Sstevel@tonic-gate if (len1 + len2 >= sizeof (msg)) 1147c478bd9Sstevel@tonic-gate len2 = sizeof (msg) - len1 - 1; 1157c478bd9Sstevel@tonic-gate (void) strncat(msg, why, len2); 1167c478bd9Sstevel@tonic-gate len1 = strlen(msg); 1177c478bd9Sstevel@tonic-gate if (msg[len1 - 1] != '\n') 1187c478bd9Sstevel@tonic-gate msg[len1++] = '\n'; 119a574db85Sraf (void) __write(2, msg, len1); 1207c478bd9Sstevel@tonic-gate Abort(msg); 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate 123f841f6adSraf void 124f841f6adSraf thr_panic(const char *why) 125f841f6adSraf { 126f841f6adSraf common_panic("*** libc thread failure: ", why); 127f841f6adSraf } 128f841f6adSraf 129f841f6adSraf void 130f841f6adSraf aio_panic(const char *why) 131f841f6adSraf { 132f841f6adSraf common_panic("*** libc aio system failure: ", why); 133f841f6adSraf } 134f841f6adSraf 135*0d045c0dSRobert Mustacchi void 136*0d045c0dSRobert Mustacchi mutex_panic(mutex_t *mp, const char *why) 137*0d045c0dSRobert Mustacchi { 138*0d045c0dSRobert Mustacchi panic_mutex = mp; 139*0d045c0dSRobert Mustacchi common_panic("*** libc mutex system failure: ", why); 140*0d045c0dSRobert Mustacchi } 141*0d045c0dSRobert Mustacchi 1427c478bd9Sstevel@tonic-gate /* 1437c478bd9Sstevel@tonic-gate * Utility function for converting a long integer to a string, avoiding stdio. 1447c478bd9Sstevel@tonic-gate * 'base' must be one of 10 or 16 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate void 1477c478bd9Sstevel@tonic-gate ultos(uint64_t n, int base, char *s) 1487c478bd9Sstevel@tonic-gate { 1497c478bd9Sstevel@tonic-gate char lbuf[24]; /* 64 bits fits in 16 hex digits, 20 decimal */ 1507c478bd9Sstevel@tonic-gate char *cp = lbuf; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate do { 1537c478bd9Sstevel@tonic-gate *cp++ = "0123456789abcdef"[n%base]; 1547c478bd9Sstevel@tonic-gate n /= base; 1557c478bd9Sstevel@tonic-gate } while (n); 1567c478bd9Sstevel@tonic-gate if (base == 16) { 1577c478bd9Sstevel@tonic-gate *s++ = '0'; 1587c478bd9Sstevel@tonic-gate *s++ = 'x'; 1597c478bd9Sstevel@tonic-gate } 1607c478bd9Sstevel@tonic-gate do { 1617c478bd9Sstevel@tonic-gate *s++ = *--cp; 1627c478bd9Sstevel@tonic-gate } while (cp > lbuf); 1637c478bd9Sstevel@tonic-gate *s = '\0'; 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* 1677c478bd9Sstevel@tonic-gate * Report application lock usage error for mutexes and condvars. 1687c478bd9Sstevel@tonic-gate * Not called if _THREAD_ERROR_DETECTION=0. 1697c478bd9Sstevel@tonic-gate * Continue execution if _THREAD_ERROR_DETECTION=1. 1707c478bd9Sstevel@tonic-gate * Dump core if _THREAD_ERROR_DETECTION=2. 1717c478bd9Sstevel@tonic-gate */ 1727c478bd9Sstevel@tonic-gate void 1737c478bd9Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg) 1747c478bd9Sstevel@tonic-gate { 17535e6f27aSRoger A. Faulkner mutex_t mcopy; 1767c478bd9Sstevel@tonic-gate char buf[800]; 1777c478bd9Sstevel@tonic-gate uberdata_t *udp; 1787c478bd9Sstevel@tonic-gate ulwp_t *self; 1797c478bd9Sstevel@tonic-gate lwpid_t lwpid; 1807c478bd9Sstevel@tonic-gate pid_t pid; 1817c478bd9Sstevel@tonic-gate 18235e6f27aSRoger A. Faulkner /* 18335e6f27aSRoger A. Faulkner * Take a snapshot of the mutex before it changes (we hope!). 18435e6f27aSRoger A. Faulkner * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned. 18535e6f27aSRoger A. Faulkner */ 18635e6f27aSRoger A. Faulkner (void) memcpy(&mcopy, mp, sizeof (mcopy)); 18735e6f27aSRoger A. Faulkner 1887c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */ 1897c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) { 1907c478bd9Sstevel@tonic-gate if (assert_thread == self) 1917c478bd9Sstevel@tonic-gate _exit(127); 1927c478bd9Sstevel@tonic-gate enter_critical(self); 1938cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 1947c478bd9Sstevel@tonic-gate assert_thread = self; 1957c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid; 1967c478bd9Sstevel@tonic-gate udp = self->ul_uberdata; 1977c478bd9Sstevel@tonic-gate pid = udp->pid; 1987c478bd9Sstevel@tonic-gate } else { 1997c478bd9Sstevel@tonic-gate self = NULL; 2008cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 2017257d1b4Sraf lwpid = _lwp_self(); 2027c478bd9Sstevel@tonic-gate udp = &__uberdata; 2038cd45542Sraf pid = getpid(); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate (void) strcpy(buf, 2077c478bd9Sstevel@tonic-gate "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); 2087c478bd9Sstevel@tonic-gate (void) strcat(buf, who); 2097c478bd9Sstevel@tonic-gate (void) strcat(buf, "("); 2107c478bd9Sstevel@tonic-gate if (cv != NULL) { 2117c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf)); 2127c478bd9Sstevel@tonic-gate (void) strcat(buf, ", "); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf)); 2157c478bd9Sstevel@tonic-gate (void) strcat(buf, ")"); 2167c478bd9Sstevel@tonic-gate if (msg != NULL) { 2177c478bd9Sstevel@tonic-gate (void) strcat(buf, ": "); 2187c478bd9Sstevel@tonic-gate (void) strcat(buf, msg); 2197257d1b4Sraf } else if (!mutex_held(&mcopy)) { 2207c478bd9Sstevel@tonic-gate (void) strcat(buf, ": calling thread does not own the lock"); 2217c478bd9Sstevel@tonic-gate } else if (mcopy.mutex_rcount) { 2227c478bd9Sstevel@tonic-gate (void) strcat(buf, ": mutex rcount = "); 2237c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf)); 2247c478bd9Sstevel@tonic-gate } else { 2257c478bd9Sstevel@tonic-gate (void) strcat(buf, ": calling thread already owns the lock"); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate (void) strcat(buf, "\ncalling thread is "); 2287c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 2297c478bd9Sstevel@tonic-gate (void) strcat(buf, " thread-id "); 2307c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 2317257d1b4Sraf if (msg != NULL || mutex_held(&mcopy)) 2327c478bd9Sstevel@tonic-gate /* EMPTY */; 2337c478bd9Sstevel@tonic-gate else if (mcopy.mutex_lockw == 0) 2347c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock is unowned"); 235883492d5Sraf else if (!(mcopy.mutex_type & USYNC_PROCESS)) { 2367c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock owner is "); 2377c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); 2387c478bd9Sstevel@tonic-gate } else { 2397c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process "); 2407c478bd9Sstevel@tonic-gate ultos((uint64_t)pid, 10, buf + strlen(buf)); 2417c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock owner is "); 2427c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); 2437c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process "); 2447c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf)); 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n\n"); 247a574db85Sraf (void) __write(2, buf, strlen(buf)); 2487c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_thread_error_detection >= 2) 2497c478bd9Sstevel@tonic-gate Abort(buf); 2507c478bd9Sstevel@tonic-gate assert_thread = NULL; 2518cd45542Sraf (void) _lwp_mutex_unlock(&assert_lock); 2527c478bd9Sstevel@tonic-gate if (self != NULL) 2537c478bd9Sstevel@tonic-gate exit_critical(self); 2547c478bd9Sstevel@tonic-gate } 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate /* 2577c478bd9Sstevel@tonic-gate * Report application lock usage error for rwlocks. 2587c478bd9Sstevel@tonic-gate * Not called if _THREAD_ERROR_DETECTION=0. 2597c478bd9Sstevel@tonic-gate * Continue execution if _THREAD_ERROR_DETECTION=1. 2607c478bd9Sstevel@tonic-gate * Dump core if _THREAD_ERROR_DETECTION=2. 2617c478bd9Sstevel@tonic-gate */ 2627c478bd9Sstevel@tonic-gate void 2637c478bd9Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg) 2647c478bd9Sstevel@tonic-gate { 26535e6f27aSRoger A. Faulkner rwlock_t rcopy; 26641efec22Sraf uint32_t rwstate; 2677c478bd9Sstevel@tonic-gate char buf[800]; 2687c478bd9Sstevel@tonic-gate uberdata_t *udp; 2697c478bd9Sstevel@tonic-gate ulwp_t *self; 2707c478bd9Sstevel@tonic-gate lwpid_t lwpid; 2717c478bd9Sstevel@tonic-gate pid_t pid; 27241efec22Sraf int process; 2737c478bd9Sstevel@tonic-gate 27435e6f27aSRoger A. Faulkner /* 27535e6f27aSRoger A. Faulkner * Take a snapshot of the rwlock before it changes (we hope!). 27635e6f27aSRoger A. Faulkner * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned. 27735e6f27aSRoger A. Faulkner */ 27835e6f27aSRoger A. Faulkner (void) memcpy(&rcopy, rp, sizeof (rcopy)); 27935e6f27aSRoger A. Faulkner 2807c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */ 2817c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) { 2827c478bd9Sstevel@tonic-gate if (assert_thread == self) 2837c478bd9Sstevel@tonic-gate _exit(127); 2847c478bd9Sstevel@tonic-gate enter_critical(self); 2858cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 2867c478bd9Sstevel@tonic-gate assert_thread = self; 2877c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid; 2887c478bd9Sstevel@tonic-gate udp = self->ul_uberdata; 2897c478bd9Sstevel@tonic-gate pid = udp->pid; 2907c478bd9Sstevel@tonic-gate } else { 2917c478bd9Sstevel@tonic-gate self = NULL; 2928cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 2937257d1b4Sraf lwpid = _lwp_self(); 2947c478bd9Sstevel@tonic-gate udp = &__uberdata; 2958cd45542Sraf pid = getpid(); 2967c478bd9Sstevel@tonic-gate } 2977c478bd9Sstevel@tonic-gate 29841efec22Sraf rwstate = (uint32_t)rcopy.rwlock_readers; 29941efec22Sraf process = (rcopy.rwlock_type & USYNC_PROCESS); 30041efec22Sraf 3017c478bd9Sstevel@tonic-gate (void) strcpy(buf, 3027c478bd9Sstevel@tonic-gate "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); 3037c478bd9Sstevel@tonic-gate (void) strcat(buf, who); 3047c478bd9Sstevel@tonic-gate (void) strcat(buf, "("); 3057c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf)); 3067c478bd9Sstevel@tonic-gate (void) strcat(buf, "): "); 3077c478bd9Sstevel@tonic-gate (void) strcat(buf, msg); 3087c478bd9Sstevel@tonic-gate (void) strcat(buf, "\ncalling thread is "); 3097c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 3107c478bd9Sstevel@tonic-gate (void) strcat(buf, " thread-id "); 3117c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 31241efec22Sraf if (process) { 3137c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process "); 3147c478bd9Sstevel@tonic-gate ultos((uint64_t)pid, 10, buf + strlen(buf)); 31541efec22Sraf } 31641efec22Sraf if (rwstate & URW_WRITE_LOCKED) { 31741efec22Sraf (void) strcat(buf, "\nthe writer lock owner is "); 3187c478bd9Sstevel@tonic-gate ultos((uint64_t)rcopy.rwlock_owner, 16, 3197c478bd9Sstevel@tonic-gate buf + strlen(buf)); 32041efec22Sraf if (process) { 3217c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process "); 3227c478bd9Sstevel@tonic-gate ultos((uint64_t)rcopy.rwlock_ownerpid, 10, 3237c478bd9Sstevel@tonic-gate buf + strlen(buf)); 3247c478bd9Sstevel@tonic-gate } 32541efec22Sraf } else if (rwstate & URW_READERS_MASK) { 32641efec22Sraf (void) strcat(buf, "\nthe reader lock is held by "); 32741efec22Sraf ultos((uint64_t)(rwstate & URW_READERS_MASK), 10, 32841efec22Sraf buf + strlen(buf)); 3297c478bd9Sstevel@tonic-gate (void) strcat(buf, " readers"); 3307c478bd9Sstevel@tonic-gate } else { 3317c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock is unowned"); 3327c478bd9Sstevel@tonic-gate } 33341efec22Sraf if (rwstate & URW_HAS_WAITERS) 33441efec22Sraf (void) strcat(buf, "\nand the lock appears to have waiters"); 3357c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n\n"); 336a574db85Sraf (void) __write(2, buf, strlen(buf)); 3377c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_thread_error_detection >= 2) 3387c478bd9Sstevel@tonic-gate Abort(buf); 3397c478bd9Sstevel@tonic-gate assert_thread = NULL; 3408cd45542Sraf (void) _lwp_mutex_unlock(&assert_lock); 3417c478bd9Sstevel@tonic-gate if (self != NULL) 3427c478bd9Sstevel@tonic-gate exit_critical(self); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * Report a thread usage error. 3477c478bd9Sstevel@tonic-gate * Not called if _THREAD_ERROR_DETECTION=0. 3487c478bd9Sstevel@tonic-gate * Writes message and continues execution if _THREAD_ERROR_DETECTION=1. 3497c478bd9Sstevel@tonic-gate * Writes message and dumps core if _THREAD_ERROR_DETECTION=2. 3507c478bd9Sstevel@tonic-gate */ 3517c478bd9Sstevel@tonic-gate void 3527c478bd9Sstevel@tonic-gate thread_error(const char *msg) 3537c478bd9Sstevel@tonic-gate { 3547c478bd9Sstevel@tonic-gate char buf[800]; 3557c478bd9Sstevel@tonic-gate uberdata_t *udp; 3567c478bd9Sstevel@tonic-gate ulwp_t *self; 3577c478bd9Sstevel@tonic-gate lwpid_t lwpid; 3587c478bd9Sstevel@tonic-gate 3597c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */ 3607c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) { 3617c478bd9Sstevel@tonic-gate if (assert_thread == self) 3627c478bd9Sstevel@tonic-gate _exit(127); 3637c478bd9Sstevel@tonic-gate enter_critical(self); 3648cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 3657c478bd9Sstevel@tonic-gate assert_thread = self; 3667c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid; 3677c478bd9Sstevel@tonic-gate udp = self->ul_uberdata; 3687c478bd9Sstevel@tonic-gate } else { 3697c478bd9Sstevel@tonic-gate self = NULL; 3708cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 3717257d1b4Sraf lwpid = _lwp_self(); 3727c478bd9Sstevel@tonic-gate udp = &__uberdata; 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: " 3767c478bd9Sstevel@tonic-gate "thread usage error detected ***\n*** "); 3777c478bd9Sstevel@tonic-gate (void) strcat(buf, msg); 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n*** calling thread is "); 3807c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 3817c478bd9Sstevel@tonic-gate (void) strcat(buf, " thread-id "); 3827c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 3837c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n\n"); 384a574db85Sraf (void) __write(2, buf, strlen(buf)); 3857c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_thread_error_detection >= 2) 3867c478bd9Sstevel@tonic-gate Abort(buf); 3877c478bd9Sstevel@tonic-gate assert_thread = NULL; 3888cd45542Sraf (void) _lwp_mutex_unlock(&assert_lock); 3897c478bd9Sstevel@tonic-gate if (self != NULL) 3907c478bd9Sstevel@tonic-gate exit_critical(self); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * We use __assfail() because the libc __assert() calls 3957c478bd9Sstevel@tonic-gate * gettext() which calls malloc() which grabs a mutex. 3967c478bd9Sstevel@tonic-gate * We do everything without calling standard i/o. 397f841f6adSraf * assfail() and _assfail() are exported functions; 398f841f6adSraf * __assfail() is private to libc. 3997c478bd9Sstevel@tonic-gate */ 4007c478bd9Sstevel@tonic-gate #pragma weak _assfail = __assfail 4017c478bd9Sstevel@tonic-gate void 4027c478bd9Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num) 4037c478bd9Sstevel@tonic-gate { 4047c478bd9Sstevel@tonic-gate char buf[800]; /* no assert() message in the library is this long */ 4057c478bd9Sstevel@tonic-gate ulwp_t *self; 4067c478bd9Sstevel@tonic-gate lwpid_t lwpid; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */ 4097c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) { 4107c478bd9Sstevel@tonic-gate if (assert_thread == self) 4117c478bd9Sstevel@tonic-gate _exit(127); 4127c478bd9Sstevel@tonic-gate enter_critical(self); 4138cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 4147c478bd9Sstevel@tonic-gate assert_thread = self; 4157c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid; 4167c478bd9Sstevel@tonic-gate } else { 4177c478bd9Sstevel@tonic-gate self = NULL; 4188cd45542Sraf (void) _lwp_mutex_lock(&assert_lock); 4197257d1b4Sraf lwpid = _lwp_self(); 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate 422fae63477SPrakash Surya /* 423fae63477SPrakash Surya * This is a hack, but since the Abort function isn't exported 424fae63477SPrakash Surya * to outside consumers, libzpool's vpanic() function calls 425fae63477SPrakash Surya * assfail() with a filename set to NULL. In that case, it'd be 426fae63477SPrakash Surya * best not to print "assertion failed" since it was a panic and 427fae63477SPrakash Surya * not an assertion failure. 428fae63477SPrakash Surya */ 429fae63477SPrakash Surya if (filename == NULL) { 430fae63477SPrakash Surya (void) strcpy(buf, "failure for thread "); 431fae63477SPrakash Surya } else { 4327c478bd9Sstevel@tonic-gate (void) strcpy(buf, "assertion failed for thread "); 433fae63477SPrakash Surya } 434fae63477SPrakash Surya 4357c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 4367c478bd9Sstevel@tonic-gate (void) strcat(buf, ", thread-id "); 4377c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 4387c478bd9Sstevel@tonic-gate (void) strcat(buf, ": "); 4397c478bd9Sstevel@tonic-gate (void) strcat(buf, assertion); 440fae63477SPrakash Surya 441fae63477SPrakash Surya if (filename != NULL) { 4427c478bd9Sstevel@tonic-gate (void) strcat(buf, ", file "); 4437c478bd9Sstevel@tonic-gate (void) strcat(buf, filename); 4447c478bd9Sstevel@tonic-gate (void) strcat(buf, ", line "); 4457c478bd9Sstevel@tonic-gate ultos((uint64_t)line_num, 10, buf + strlen(buf)); 446fae63477SPrakash Surya } 447fae63477SPrakash Surya 4487c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n"); 449a574db85Sraf (void) __write(2, buf, strlen(buf)); 4507c478bd9Sstevel@tonic-gate /* 4517c478bd9Sstevel@tonic-gate * We could replace the call to Abort() with the following code 4527c478bd9Sstevel@tonic-gate * if we want just to issue a warning message and not die. 4537c478bd9Sstevel@tonic-gate * assert_thread = NULL; 4548cd45542Sraf * _lwp_mutex_unlock(&assert_lock); 4557c478bd9Sstevel@tonic-gate * if (self != NULL) 4567c478bd9Sstevel@tonic-gate * exit_critical(self); 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate Abort(buf); 4597c478bd9Sstevel@tonic-gate } 460f841f6adSraf 461f841f6adSraf /* 462f841f6adSraf * We define and export this version of assfail() just because libaio 463f841f6adSraf * used to define and export it, needlessly. Now that libaio is folded 464f841f6adSraf * into libc, we need to continue this for ABI/version reasons. 465f841f6adSraf * We don't use "#pragma weak assfail __assfail" in order to avoid 466f841f6adSraf * warnings from the check_fnames utility at build time for libraries 467f841f6adSraf * that define their own version of assfail(). 468f841f6adSraf */ 469f841f6adSraf void 470f841f6adSraf assfail(const char *assertion, const char *filename, int line_num) 471f841f6adSraf { 472f841f6adSraf __assfail(assertion, filename, line_num); 473f841f6adSraf } 474ad135b5dSChristopher Siden 475ad135b5dSChristopher Siden void 476ad135b5dSChristopher Siden assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv, 477ad135b5dSChristopher Siden const char *filename, int line_num) 478ad135b5dSChristopher Siden { 479ad135b5dSChristopher Siden char buf[1000]; 480ad135b5dSChristopher Siden (void) strcpy(buf, assertion); 481fb09f5aaSMadhav Suresh (void) strcat(buf, " ("); 482ad135b5dSChristopher Siden ultos((uint64_t)lv, 16, buf + strlen(buf)); 483ad135b5dSChristopher Siden (void) strcat(buf, " "); 484ad135b5dSChristopher Siden (void) strcat(buf, op); 485fb09f5aaSMadhav Suresh (void) strcat(buf, " "); 486ad135b5dSChristopher Siden ultos((uint64_t)rv, 16, buf + strlen(buf)); 487ad135b5dSChristopher Siden (void) strcat(buf, ")"); 488ad135b5dSChristopher Siden __assfail(buf, filename, line_num); 489ad135b5dSChristopher Siden } 490