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
__set_panicstr(const char * msg)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
grab_assert_lock()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
Abort(const char * msg)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
common_panic(const char * head,const char * why)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
thr_panic(const char * why)124f841f6adSraf thr_panic(const char *why)
125f841f6adSraf {
126f841f6adSraf common_panic("*** libc thread failure: ", why);
127f841f6adSraf }
128f841f6adSraf
129f841f6adSraf void
aio_panic(const char * why)130f841f6adSraf aio_panic(const char *why)
131f841f6adSraf {
132f841f6adSraf common_panic("*** libc aio system failure: ", why);
133f841f6adSraf }
134f841f6adSraf
135*0d045c0dSRobert Mustacchi void
mutex_panic(mutex_t * mp,const char * why)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
ultos(uint64_t n,int base,char * s)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
lock_error(const mutex_t * mp,const char * who,void * cv,const char * msg)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
rwlock_error(const rwlock_t * rp,const char * who,const char * msg)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
thread_error(const char * msg)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
__assfail(const char * assertion,const char * filename,int line_num)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
assfail(const char * assertion,const char * filename,int line_num)470f841f6adSraf assfail(const char *assertion, const char *filename, int line_num)
471f841f6adSraf {
472f841f6adSraf __assfail(assertion, filename, line_num);
473f841f6adSraf }
474ad135b5dSChristopher Siden
475ad135b5dSChristopher Siden void
assfail3(const char * assertion,uintmax_t lv,const char * op,uintmax_t rv,const char * filename,int line_num)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