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 /*
27*fae63477SPrakash Surya * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
28ad135b5dSChristopher Siden */
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include "lint.h"
317c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate const char *panicstr;
347c478bd9Sstevel@tonic-gate ulwp_t *panic_thread;
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate static mutex_t assert_lock = DEFAULTMUTEX;
377c478bd9Sstevel@tonic-gate static ulwp_t *assert_thread = NULL;
387c478bd9Sstevel@tonic-gate
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate * Called from __assert() to set panicstr and panic_thread.
417c478bd9Sstevel@tonic-gate */
427c478bd9Sstevel@tonic-gate void
__set_panicstr(const char * msg)437c478bd9Sstevel@tonic-gate __set_panicstr(const char *msg)
447c478bd9Sstevel@tonic-gate {
457c478bd9Sstevel@tonic-gate panicstr = msg;
467c478bd9Sstevel@tonic-gate panic_thread = __curthread();
477c478bd9Sstevel@tonic-gate }
487c478bd9Sstevel@tonic-gate
497c478bd9Sstevel@tonic-gate /*
507c478bd9Sstevel@tonic-gate * Called from exit() (atexit function) to give precedence
517c478bd9Sstevel@tonic-gate * to assertion failures and a core dump over _exit().
527c478bd9Sstevel@tonic-gate */
537c478bd9Sstevel@tonic-gate void
grab_assert_lock()547c478bd9Sstevel@tonic-gate grab_assert_lock()
557c478bd9Sstevel@tonic-gate {
568cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
577c478bd9Sstevel@tonic-gate }
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate static void
Abort(const char * msg)607c478bd9Sstevel@tonic-gate Abort(const char *msg)
617c478bd9Sstevel@tonic-gate {
627c478bd9Sstevel@tonic-gate ulwp_t *self;
637c478bd9Sstevel@tonic-gate struct sigaction act;
647c478bd9Sstevel@tonic-gate sigset_t sigmask;
657c478bd9Sstevel@tonic-gate lwpid_t lwpid;
667c478bd9Sstevel@tonic-gate
677c478bd9Sstevel@tonic-gate /* to help with core file debugging */
687c478bd9Sstevel@tonic-gate panicstr = msg;
697c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) {
707c478bd9Sstevel@tonic-gate panic_thread = self;
717c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid;
727c478bd9Sstevel@tonic-gate } else {
737257d1b4Sraf lwpid = _lwp_self();
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate
767c478bd9Sstevel@tonic-gate /* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */
778cd45542Sraf (void) memset(&act, 0, sizeof (act));
787c478bd9Sstevel@tonic-gate act.sa_sigaction = SIG_DFL;
797c478bd9Sstevel@tonic-gate (void) __sigaction(SIGABRT, &act, NULL);
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate /* delete SIGABRT from the signal mask */
828cd45542Sraf (void) sigemptyset(&sigmask);
838cd45542Sraf (void) sigaddset(&sigmask, SIGABRT);
84bdf0047cSRoger A. Faulkner (void) __lwp_sigmask(SIG_UNBLOCK, &sigmask);
857c478bd9Sstevel@tonic-gate
867257d1b4Sraf (void) _lwp_kill(lwpid, SIGABRT); /* never returns */
877257d1b4Sraf (void) kill(getpid(), SIGABRT); /* if it does, try harder */
887c478bd9Sstevel@tonic-gate _exit(127);
897c478bd9Sstevel@tonic-gate }
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate /*
927c478bd9Sstevel@tonic-gate * Write a panic message w/o grabbing any locks other than assert_lock.
937c478bd9Sstevel@tonic-gate * We have no idea what locks are held at this point.
947c478bd9Sstevel@tonic-gate */
95f841f6adSraf static void
common_panic(const char * head,const char * why)96f841f6adSraf common_panic(const char *head, const char *why)
977c478bd9Sstevel@tonic-gate {
987c478bd9Sstevel@tonic-gate char msg[400]; /* no panic() message in the library is this long */
997c478bd9Sstevel@tonic-gate ulwp_t *self;
1007c478bd9Sstevel@tonic-gate size_t len1, len2;
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL)
1037c478bd9Sstevel@tonic-gate enter_critical(self);
1048cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
1057c478bd9Sstevel@tonic-gate
1068cd45542Sraf (void) memset(msg, 0, sizeof (msg));
107f841f6adSraf (void) strcpy(msg, head);
1087c478bd9Sstevel@tonic-gate len1 = strlen(msg);
1097c478bd9Sstevel@tonic-gate len2 = strlen(why);
1107c478bd9Sstevel@tonic-gate if (len1 + len2 >= sizeof (msg))
1117c478bd9Sstevel@tonic-gate len2 = sizeof (msg) - len1 - 1;
1127c478bd9Sstevel@tonic-gate (void) strncat(msg, why, len2);
1137c478bd9Sstevel@tonic-gate len1 = strlen(msg);
1147c478bd9Sstevel@tonic-gate if (msg[len1 - 1] != '\n')
1157c478bd9Sstevel@tonic-gate msg[len1++] = '\n';
116a574db85Sraf (void) __write(2, msg, len1);
1177c478bd9Sstevel@tonic-gate Abort(msg);
1187c478bd9Sstevel@tonic-gate }
1197c478bd9Sstevel@tonic-gate
120f841f6adSraf void
thr_panic(const char * why)121f841f6adSraf thr_panic(const char *why)
122f841f6adSraf {
123f841f6adSraf common_panic("*** libc thread failure: ", why);
124f841f6adSraf }
125f841f6adSraf
126f841f6adSraf void
aio_panic(const char * why)127f841f6adSraf aio_panic(const char *why)
128f841f6adSraf {
129f841f6adSraf common_panic("*** libc aio system failure: ", why);
130f841f6adSraf }
131f841f6adSraf
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate * Utility function for converting a long integer to a string, avoiding stdio.
1347c478bd9Sstevel@tonic-gate * 'base' must be one of 10 or 16
1357c478bd9Sstevel@tonic-gate */
1367c478bd9Sstevel@tonic-gate void
ultos(uint64_t n,int base,char * s)1377c478bd9Sstevel@tonic-gate ultos(uint64_t n, int base, char *s)
1387c478bd9Sstevel@tonic-gate {
1397c478bd9Sstevel@tonic-gate char lbuf[24]; /* 64 bits fits in 16 hex digits, 20 decimal */
1407c478bd9Sstevel@tonic-gate char *cp = lbuf;
1417c478bd9Sstevel@tonic-gate
1427c478bd9Sstevel@tonic-gate do {
1437c478bd9Sstevel@tonic-gate *cp++ = "0123456789abcdef"[n%base];
1447c478bd9Sstevel@tonic-gate n /= base;
1457c478bd9Sstevel@tonic-gate } while (n);
1467c478bd9Sstevel@tonic-gate if (base == 16) {
1477c478bd9Sstevel@tonic-gate *s++ = '0';
1487c478bd9Sstevel@tonic-gate *s++ = 'x';
1497c478bd9Sstevel@tonic-gate }
1507c478bd9Sstevel@tonic-gate do {
1517c478bd9Sstevel@tonic-gate *s++ = *--cp;
1527c478bd9Sstevel@tonic-gate } while (cp > lbuf);
1537c478bd9Sstevel@tonic-gate *s = '\0';
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate /*
1577c478bd9Sstevel@tonic-gate * Report application lock usage error for mutexes and condvars.
1587c478bd9Sstevel@tonic-gate * Not called if _THREAD_ERROR_DETECTION=0.
1597c478bd9Sstevel@tonic-gate * Continue execution if _THREAD_ERROR_DETECTION=1.
1607c478bd9Sstevel@tonic-gate * Dump core if _THREAD_ERROR_DETECTION=2.
1617c478bd9Sstevel@tonic-gate */
1627c478bd9Sstevel@tonic-gate void
lock_error(const mutex_t * mp,const char * who,void * cv,const char * msg)1637c478bd9Sstevel@tonic-gate lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
1647c478bd9Sstevel@tonic-gate {
16535e6f27aSRoger A. Faulkner mutex_t mcopy;
1667c478bd9Sstevel@tonic-gate char buf[800];
1677c478bd9Sstevel@tonic-gate uberdata_t *udp;
1687c478bd9Sstevel@tonic-gate ulwp_t *self;
1697c478bd9Sstevel@tonic-gate lwpid_t lwpid;
1707c478bd9Sstevel@tonic-gate pid_t pid;
1717c478bd9Sstevel@tonic-gate
17235e6f27aSRoger A. Faulkner /*
17335e6f27aSRoger A. Faulkner * Take a snapshot of the mutex before it changes (we hope!).
17435e6f27aSRoger A. Faulkner * Use memcpy() rather than 'mcopy = *mp' in case mp is unaligned.
17535e6f27aSRoger A. Faulkner */
17635e6f27aSRoger A. Faulkner (void) memcpy(&mcopy, mp, sizeof (mcopy));
17735e6f27aSRoger A. Faulkner
1787c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */
1797c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) {
1807c478bd9Sstevel@tonic-gate if (assert_thread == self)
1817c478bd9Sstevel@tonic-gate _exit(127);
1827c478bd9Sstevel@tonic-gate enter_critical(self);
1838cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
1847c478bd9Sstevel@tonic-gate assert_thread = self;
1857c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid;
1867c478bd9Sstevel@tonic-gate udp = self->ul_uberdata;
1877c478bd9Sstevel@tonic-gate pid = udp->pid;
1887c478bd9Sstevel@tonic-gate } else {
1897c478bd9Sstevel@tonic-gate self = NULL;
1908cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
1917257d1b4Sraf lwpid = _lwp_self();
1927c478bd9Sstevel@tonic-gate udp = &__uberdata;
1938cd45542Sraf pid = getpid();
1947c478bd9Sstevel@tonic-gate }
1957c478bd9Sstevel@tonic-gate
1967c478bd9Sstevel@tonic-gate (void) strcpy(buf,
1977c478bd9Sstevel@tonic-gate "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
1987c478bd9Sstevel@tonic-gate (void) strcat(buf, who);
1997c478bd9Sstevel@tonic-gate (void) strcat(buf, "(");
2007c478bd9Sstevel@tonic-gate if (cv != NULL) {
2017c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
2027c478bd9Sstevel@tonic-gate (void) strcat(buf, ", ");
2037c478bd9Sstevel@tonic-gate }
2047c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
2057c478bd9Sstevel@tonic-gate (void) strcat(buf, ")");
2067c478bd9Sstevel@tonic-gate if (msg != NULL) {
2077c478bd9Sstevel@tonic-gate (void) strcat(buf, ": ");
2087c478bd9Sstevel@tonic-gate (void) strcat(buf, msg);
2097257d1b4Sraf } else if (!mutex_held(&mcopy)) {
2107c478bd9Sstevel@tonic-gate (void) strcat(buf, ": calling thread does not own the lock");
2117c478bd9Sstevel@tonic-gate } else if (mcopy.mutex_rcount) {
2127c478bd9Sstevel@tonic-gate (void) strcat(buf, ": mutex rcount = ");
2137c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
2147c478bd9Sstevel@tonic-gate } else {
2157c478bd9Sstevel@tonic-gate (void) strcat(buf, ": calling thread already owns the lock");
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate (void) strcat(buf, "\ncalling thread is ");
2187c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
2197c478bd9Sstevel@tonic-gate (void) strcat(buf, " thread-id ");
2207c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf));
2217257d1b4Sraf if (msg != NULL || mutex_held(&mcopy))
2227c478bd9Sstevel@tonic-gate /* EMPTY */;
2237c478bd9Sstevel@tonic-gate else if (mcopy.mutex_lockw == 0)
2247c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock is unowned");
225883492d5Sraf else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
2267c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock owner is ");
2277c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2287c478bd9Sstevel@tonic-gate } else {
2297c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process ");
2307c478bd9Sstevel@tonic-gate ultos((uint64_t)pid, 10, buf + strlen(buf));
2317c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock owner is ");
2327c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
2337c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process ");
2347c478bd9Sstevel@tonic-gate ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n\n");
237a574db85Sraf (void) __write(2, buf, strlen(buf));
2387c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_thread_error_detection >= 2)
2397c478bd9Sstevel@tonic-gate Abort(buf);
2407c478bd9Sstevel@tonic-gate assert_thread = NULL;
2418cd45542Sraf (void) _lwp_mutex_unlock(&assert_lock);
2427c478bd9Sstevel@tonic-gate if (self != NULL)
2437c478bd9Sstevel@tonic-gate exit_critical(self);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate * Report application lock usage error for rwlocks.
2487c478bd9Sstevel@tonic-gate * Not called if _THREAD_ERROR_DETECTION=0.
2497c478bd9Sstevel@tonic-gate * Continue execution if _THREAD_ERROR_DETECTION=1.
2507c478bd9Sstevel@tonic-gate * Dump core if _THREAD_ERROR_DETECTION=2.
2517c478bd9Sstevel@tonic-gate */
2527c478bd9Sstevel@tonic-gate void
rwlock_error(const rwlock_t * rp,const char * who,const char * msg)2537c478bd9Sstevel@tonic-gate rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
2547c478bd9Sstevel@tonic-gate {
25535e6f27aSRoger A. Faulkner rwlock_t rcopy;
25641efec22Sraf uint32_t rwstate;
2577c478bd9Sstevel@tonic-gate char buf[800];
2587c478bd9Sstevel@tonic-gate uberdata_t *udp;
2597c478bd9Sstevel@tonic-gate ulwp_t *self;
2607c478bd9Sstevel@tonic-gate lwpid_t lwpid;
2617c478bd9Sstevel@tonic-gate pid_t pid;
26241efec22Sraf int process;
2637c478bd9Sstevel@tonic-gate
26435e6f27aSRoger A. Faulkner /*
26535e6f27aSRoger A. Faulkner * Take a snapshot of the rwlock before it changes (we hope!).
26635e6f27aSRoger A. Faulkner * Use memcpy() rather than 'rcopy = *rp' in case rp is unaligned.
26735e6f27aSRoger A. Faulkner */
26835e6f27aSRoger A. Faulkner (void) memcpy(&rcopy, rp, sizeof (rcopy));
26935e6f27aSRoger A. Faulkner
2707c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */
2717c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) {
2727c478bd9Sstevel@tonic-gate if (assert_thread == self)
2737c478bd9Sstevel@tonic-gate _exit(127);
2747c478bd9Sstevel@tonic-gate enter_critical(self);
2758cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
2767c478bd9Sstevel@tonic-gate assert_thread = self;
2777c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid;
2787c478bd9Sstevel@tonic-gate udp = self->ul_uberdata;
2797c478bd9Sstevel@tonic-gate pid = udp->pid;
2807c478bd9Sstevel@tonic-gate } else {
2817c478bd9Sstevel@tonic-gate self = NULL;
2828cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
2837257d1b4Sraf lwpid = _lwp_self();
2847c478bd9Sstevel@tonic-gate udp = &__uberdata;
2858cd45542Sraf pid = getpid();
2867c478bd9Sstevel@tonic-gate }
2877c478bd9Sstevel@tonic-gate
28841efec22Sraf rwstate = (uint32_t)rcopy.rwlock_readers;
28941efec22Sraf process = (rcopy.rwlock_type & USYNC_PROCESS);
29041efec22Sraf
2917c478bd9Sstevel@tonic-gate (void) strcpy(buf,
2927c478bd9Sstevel@tonic-gate "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
2937c478bd9Sstevel@tonic-gate (void) strcat(buf, who);
2947c478bd9Sstevel@tonic-gate (void) strcat(buf, "(");
2957c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
2967c478bd9Sstevel@tonic-gate (void) strcat(buf, "): ");
2977c478bd9Sstevel@tonic-gate (void) strcat(buf, msg);
2987c478bd9Sstevel@tonic-gate (void) strcat(buf, "\ncalling thread is ");
2997c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3007c478bd9Sstevel@tonic-gate (void) strcat(buf, " thread-id ");
3017c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf));
30241efec22Sraf if (process) {
3037c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process ");
3047c478bd9Sstevel@tonic-gate ultos((uint64_t)pid, 10, buf + strlen(buf));
30541efec22Sraf }
30641efec22Sraf if (rwstate & URW_WRITE_LOCKED) {
30741efec22Sraf (void) strcat(buf, "\nthe writer lock owner is ");
3087c478bd9Sstevel@tonic-gate ultos((uint64_t)rcopy.rwlock_owner, 16,
3097c478bd9Sstevel@tonic-gate buf + strlen(buf));
31041efec22Sraf if (process) {
3117c478bd9Sstevel@tonic-gate (void) strcat(buf, " in process ");
3127c478bd9Sstevel@tonic-gate ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
3137c478bd9Sstevel@tonic-gate buf + strlen(buf));
3147c478bd9Sstevel@tonic-gate }
31541efec22Sraf } else if (rwstate & URW_READERS_MASK) {
31641efec22Sraf (void) strcat(buf, "\nthe reader lock is held by ");
31741efec22Sraf ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
31841efec22Sraf buf + strlen(buf));
3197c478bd9Sstevel@tonic-gate (void) strcat(buf, " readers");
3207c478bd9Sstevel@tonic-gate } else {
3217c478bd9Sstevel@tonic-gate (void) strcat(buf, "\nthe lock is unowned");
3227c478bd9Sstevel@tonic-gate }
32341efec22Sraf if (rwstate & URW_HAS_WAITERS)
32441efec22Sraf (void) strcat(buf, "\nand the lock appears to have waiters");
3257c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n\n");
326a574db85Sraf (void) __write(2, buf, strlen(buf));
3277c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_thread_error_detection >= 2)
3287c478bd9Sstevel@tonic-gate Abort(buf);
3297c478bd9Sstevel@tonic-gate assert_thread = NULL;
3308cd45542Sraf (void) _lwp_mutex_unlock(&assert_lock);
3317c478bd9Sstevel@tonic-gate if (self != NULL)
3327c478bd9Sstevel@tonic-gate exit_critical(self);
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate * Report a thread usage error.
3377c478bd9Sstevel@tonic-gate * Not called if _THREAD_ERROR_DETECTION=0.
3387c478bd9Sstevel@tonic-gate * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
3397c478bd9Sstevel@tonic-gate * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
3407c478bd9Sstevel@tonic-gate */
3417c478bd9Sstevel@tonic-gate void
thread_error(const char * msg)3427c478bd9Sstevel@tonic-gate thread_error(const char *msg)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate char buf[800];
3457c478bd9Sstevel@tonic-gate uberdata_t *udp;
3467c478bd9Sstevel@tonic-gate ulwp_t *self;
3477c478bd9Sstevel@tonic-gate lwpid_t lwpid;
3487c478bd9Sstevel@tonic-gate
3497c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */
3507c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) {
3517c478bd9Sstevel@tonic-gate if (assert_thread == self)
3527c478bd9Sstevel@tonic-gate _exit(127);
3537c478bd9Sstevel@tonic-gate enter_critical(self);
3548cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
3557c478bd9Sstevel@tonic-gate assert_thread = self;
3567c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid;
3577c478bd9Sstevel@tonic-gate udp = self->ul_uberdata;
3587c478bd9Sstevel@tonic-gate } else {
3597c478bd9Sstevel@tonic-gate self = NULL;
3608cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
3617257d1b4Sraf lwpid = _lwp_self();
3627c478bd9Sstevel@tonic-gate udp = &__uberdata;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate
3657c478bd9Sstevel@tonic-gate (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
3667c478bd9Sstevel@tonic-gate "thread usage error detected ***\n*** ");
3677c478bd9Sstevel@tonic-gate (void) strcat(buf, msg);
3687c478bd9Sstevel@tonic-gate
3697c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n*** calling thread is ");
3707c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
3717c478bd9Sstevel@tonic-gate (void) strcat(buf, " thread-id ");
3727c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf));
3737c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n\n");
374a574db85Sraf (void) __write(2, buf, strlen(buf));
3757c478bd9Sstevel@tonic-gate if (udp->uberflags.uf_thread_error_detection >= 2)
3767c478bd9Sstevel@tonic-gate Abort(buf);
3777c478bd9Sstevel@tonic-gate assert_thread = NULL;
3788cd45542Sraf (void) _lwp_mutex_unlock(&assert_lock);
3797c478bd9Sstevel@tonic-gate if (self != NULL)
3807c478bd9Sstevel@tonic-gate exit_critical(self);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate * We use __assfail() because the libc __assert() calls
3857c478bd9Sstevel@tonic-gate * gettext() which calls malloc() which grabs a mutex.
3867c478bd9Sstevel@tonic-gate * We do everything without calling standard i/o.
387f841f6adSraf * assfail() and _assfail() are exported functions;
388f841f6adSraf * __assfail() is private to libc.
3897c478bd9Sstevel@tonic-gate */
3907c478bd9Sstevel@tonic-gate #pragma weak _assfail = __assfail
3917c478bd9Sstevel@tonic-gate void
__assfail(const char * assertion,const char * filename,int line_num)3927c478bd9Sstevel@tonic-gate __assfail(const char *assertion, const char *filename, int line_num)
3937c478bd9Sstevel@tonic-gate {
3947c478bd9Sstevel@tonic-gate char buf[800]; /* no assert() message in the library is this long */
3957c478bd9Sstevel@tonic-gate ulwp_t *self;
3967c478bd9Sstevel@tonic-gate lwpid_t lwpid;
3977c478bd9Sstevel@tonic-gate
3987c478bd9Sstevel@tonic-gate /* avoid recursion deadlock */
3997c478bd9Sstevel@tonic-gate if ((self = __curthread()) != NULL) {
4007c478bd9Sstevel@tonic-gate if (assert_thread == self)
4017c478bd9Sstevel@tonic-gate _exit(127);
4027c478bd9Sstevel@tonic-gate enter_critical(self);
4038cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
4047c478bd9Sstevel@tonic-gate assert_thread = self;
4057c478bd9Sstevel@tonic-gate lwpid = self->ul_lwpid;
4067c478bd9Sstevel@tonic-gate } else {
4077c478bd9Sstevel@tonic-gate self = NULL;
4088cd45542Sraf (void) _lwp_mutex_lock(&assert_lock);
4097257d1b4Sraf lwpid = _lwp_self();
4107c478bd9Sstevel@tonic-gate }
4117c478bd9Sstevel@tonic-gate
412*fae63477SPrakash Surya /*
413*fae63477SPrakash Surya * This is a hack, but since the Abort function isn't exported
414*fae63477SPrakash Surya * to outside consumers, libzpool's vpanic() function calls
415*fae63477SPrakash Surya * assfail() with a filename set to NULL. In that case, it'd be
416*fae63477SPrakash Surya * best not to print "assertion failed" since it was a panic and
417*fae63477SPrakash Surya * not an assertion failure.
418*fae63477SPrakash Surya */
419*fae63477SPrakash Surya if (filename == NULL) {
420*fae63477SPrakash Surya (void) strcpy(buf, "failure for thread ");
421*fae63477SPrakash Surya } else {
4227c478bd9Sstevel@tonic-gate (void) strcpy(buf, "assertion failed for thread ");
423*fae63477SPrakash Surya }
424*fae63477SPrakash Surya
4257c478bd9Sstevel@tonic-gate ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
4267c478bd9Sstevel@tonic-gate (void) strcat(buf, ", thread-id ");
4277c478bd9Sstevel@tonic-gate ultos((uint64_t)lwpid, 10, buf + strlen(buf));
4287c478bd9Sstevel@tonic-gate (void) strcat(buf, ": ");
4297c478bd9Sstevel@tonic-gate (void) strcat(buf, assertion);
430*fae63477SPrakash Surya
431*fae63477SPrakash Surya if (filename != NULL) {
4327c478bd9Sstevel@tonic-gate (void) strcat(buf, ", file ");
4337c478bd9Sstevel@tonic-gate (void) strcat(buf, filename);
4347c478bd9Sstevel@tonic-gate (void) strcat(buf, ", line ");
4357c478bd9Sstevel@tonic-gate ultos((uint64_t)line_num, 10, buf + strlen(buf));
436*fae63477SPrakash Surya }
437*fae63477SPrakash Surya
4387c478bd9Sstevel@tonic-gate (void) strcat(buf, "\n");
439a574db85Sraf (void) __write(2, buf, strlen(buf));
4407c478bd9Sstevel@tonic-gate /*
4417c478bd9Sstevel@tonic-gate * We could replace the call to Abort() with the following code
4427c478bd9Sstevel@tonic-gate * if we want just to issue a warning message and not die.
4437c478bd9Sstevel@tonic-gate * assert_thread = NULL;
4448cd45542Sraf * _lwp_mutex_unlock(&assert_lock);
4457c478bd9Sstevel@tonic-gate * if (self != NULL)
4467c478bd9Sstevel@tonic-gate * exit_critical(self);
4477c478bd9Sstevel@tonic-gate */
4487c478bd9Sstevel@tonic-gate Abort(buf);
4497c478bd9Sstevel@tonic-gate }
450f841f6adSraf
451f841f6adSraf /*
452f841f6adSraf * We define and export this version of assfail() just because libaio
453f841f6adSraf * used to define and export it, needlessly. Now that libaio is folded
454f841f6adSraf * into libc, we need to continue this for ABI/version reasons.
455f841f6adSraf * We don't use "#pragma weak assfail __assfail" in order to avoid
456f841f6adSraf * warnings from the check_fnames utility at build time for libraries
457f841f6adSraf * that define their own version of assfail().
458f841f6adSraf */
459f841f6adSraf void
assfail(const char * assertion,const char * filename,int line_num)460f841f6adSraf assfail(const char *assertion, const char *filename, int line_num)
461f841f6adSraf {
462f841f6adSraf __assfail(assertion, filename, line_num);
463f841f6adSraf }
464ad135b5dSChristopher Siden
465ad135b5dSChristopher Siden void
assfail3(const char * assertion,uintmax_t lv,const char * op,uintmax_t rv,const char * filename,int line_num)466ad135b5dSChristopher Siden assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv,
467ad135b5dSChristopher Siden const char *filename, int line_num)
468ad135b5dSChristopher Siden {
469ad135b5dSChristopher Siden char buf[1000];
470ad135b5dSChristopher Siden (void) strcpy(buf, assertion);
471fb09f5aaSMadhav Suresh (void) strcat(buf, " (");
472ad135b5dSChristopher Siden ultos((uint64_t)lv, 16, buf + strlen(buf));
473ad135b5dSChristopher Siden (void) strcat(buf, " ");
474ad135b5dSChristopher Siden (void) strcat(buf, op);
475fb09f5aaSMadhav Suresh (void) strcat(buf, " ");
476ad135b5dSChristopher Siden ultos((uint64_t)rv, 16, buf + strlen(buf));
477ad135b5dSChristopher Siden (void) strcat(buf, ")");
478ad135b5dSChristopher Siden __assfail(buf, filename, line_num);
479ad135b5dSChristopher Siden }
480