Home | History | Annotate | Download | only in threads
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     28 
     29 #include "lint.h"
     30 #include "thr_uberdata.h"
     31 
     32 const char *panicstr;
     33 ulwp_t *panic_thread;
     34 
     35 static mutex_t assert_lock = DEFAULTMUTEX;
     36 static ulwp_t *assert_thread = NULL;
     37 
     38 /*
     39  * Called from __assert() to set panicstr and panic_thread.
     40  */
     41 void
     42 __set_panicstr(const char *msg)
     43 {
     44 	panicstr = msg;
     45 	panic_thread = __curthread();
     46 }
     47 
     48 /*
     49  * Called from exit() (atexit function) to give precedence
     50  * to assertion failures and a core dump over _exit().
     51  */
     52 void
     53 grab_assert_lock()
     54 {
     55 	(void) _lwp_mutex_lock(&assert_lock);
     56 }
     57 
     58 static void
     59 Abort(const char *msg)
     60 {
     61 	ulwp_t *self;
     62 	struct sigaction act;
     63 	sigset_t sigmask;
     64 	lwpid_t lwpid;
     65 
     66 	/* to help with core file debugging */
     67 	panicstr = msg;
     68 	if ((self = __curthread()) != NULL) {
     69 		panic_thread = self;
     70 		lwpid = self->ul_lwpid;
     71 	} else {
     72 		lwpid = _lwp_self();
     73 	}
     74 
     75 	/* set SIGABRT signal handler to SIG_DFL w/o grabbing any locks */
     76 	(void) memset(&act, 0, sizeof (act));
     77 	act.sa_sigaction = SIG_DFL;
     78 	(void) __sigaction(SIGABRT, &act, NULL);
     79 
     80 	/* delete SIGABRT from the signal mask */
     81 	(void) sigemptyset(&sigmask);
     82 	(void) sigaddset(&sigmask, SIGABRT);
     83 	(void) __lwp_sigmask(SIG_UNBLOCK, &sigmask, NULL);
     84 
     85 	(void) _lwp_kill(lwpid, SIGABRT);	/* never returns */
     86 	(void) kill(getpid(), SIGABRT);	/* if it does, try harder */
     87 	_exit(127);
     88 }
     89 
     90 /*
     91  * Write a panic message w/o grabbing any locks other than assert_lock.
     92  * We have no idea what locks are held at this point.
     93  */
     94 static void
     95 common_panic(const char *head, const char *why)
     96 {
     97 	char msg[400];	/* no panic() message in the library is this long */
     98 	ulwp_t *self;
     99 	size_t len1, len2;
    100 
    101 	if ((self = __curthread()) != NULL)
    102 		enter_critical(self);
    103 	(void) _lwp_mutex_lock(&assert_lock);
    104 
    105 	(void) memset(msg, 0, sizeof (msg));
    106 	(void) strcpy(msg, head);
    107 	len1 = strlen(msg);
    108 	len2 = strlen(why);
    109 	if (len1 + len2 >= sizeof (msg))
    110 		len2 = sizeof (msg) - len1 - 1;
    111 	(void) strncat(msg, why, len2);
    112 	len1 = strlen(msg);
    113 	if (msg[len1 - 1] != '\n')
    114 		msg[len1++] = '\n';
    115 	(void) __write(2, msg, len1);
    116 	Abort(msg);
    117 }
    118 
    119 void
    120 thr_panic(const char *why)
    121 {
    122 	common_panic("*** libc thread failure: ", why);
    123 }
    124 
    125 void
    126 aio_panic(const char *why)
    127 {
    128 	common_panic("*** libc aio system failure: ", why);
    129 }
    130 
    131 /*
    132  * Utility function for converting a long integer to a string, avoiding stdio.
    133  * 'base' must be one of 10 or 16
    134  */
    135 void
    136 ultos(uint64_t n, int base, char *s)
    137 {
    138 	char lbuf[24];		/* 64 bits fits in 16 hex digits, 20 decimal */
    139 	char *cp = lbuf;
    140 
    141 	do {
    142 		*cp++ = "0123456789abcdef"[n%base];
    143 		n /= base;
    144 	} while (n);
    145 	if (base == 16) {
    146 		*s++ = '0';
    147 		*s++ = 'x';
    148 	}
    149 	do {
    150 		*s++ = *--cp;
    151 	} while (cp > lbuf);
    152 	*s = '\0';
    153 }
    154 
    155 /*
    156  * Report application lock usage error for mutexes and condvars.
    157  * Not called if _THREAD_ERROR_DETECTION=0.
    158  * Continue execution if _THREAD_ERROR_DETECTION=1.
    159  * Dump core if _THREAD_ERROR_DETECTION=2.
    160  */
    161 void
    162 lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
    163 {
    164 	/* take a snapshot of the mutex before it changes (we hope!) */
    165 	mutex_t mcopy = *mp;
    166 	char buf[800];
    167 	uberdata_t *udp;
    168 	ulwp_t *self;
    169 	lwpid_t lwpid;
    170 	pid_t pid;
    171 
    172 	/* avoid recursion deadlock */
    173 	if ((self = __curthread()) != NULL) {
    174 		if (assert_thread == self)
    175 			_exit(127);
    176 		enter_critical(self);
    177 		(void) _lwp_mutex_lock(&assert_lock);
    178 		assert_thread = self;
    179 		lwpid = self->ul_lwpid;
    180 		udp = self->ul_uberdata;
    181 		pid = udp->pid;
    182 	} else {
    183 		self = NULL;
    184 		(void) _lwp_mutex_lock(&assert_lock);
    185 		lwpid = _lwp_self();
    186 		udp = &__uberdata;
    187 		pid = getpid();
    188 	}
    189 
    190 	(void) strcpy(buf,
    191 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
    192 	(void) strcat(buf, who);
    193 	(void) strcat(buf, "(");
    194 	if (cv != NULL) {
    195 		ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
    196 		(void) strcat(buf, ", ");
    197 	}
    198 	ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
    199 	(void) strcat(buf, ")");
    200 	if (msg != NULL) {
    201 		(void) strcat(buf, ": ");
    202 		(void) strcat(buf, msg);
    203 	} else if (!mutex_held(&mcopy)) {
    204 		(void) strcat(buf, ": calling thread does not own the lock");
    205 	} else if (mcopy.mutex_rcount) {
    206 		(void) strcat(buf, ": mutex rcount = ");
    207 		ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
    208 	} else {
    209 		(void) strcat(buf, ": calling thread already owns the lock");
    210 	}
    211 	(void) strcat(buf, "\ncalling thread is ");
    212 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
    213 	(void) strcat(buf, " thread-id ");
    214 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
    215 	if (msg != NULL || mutex_held(&mcopy))
    216 		/* EMPTY */;
    217 	else if (mcopy.mutex_lockw == 0)
    218 		(void) strcat(buf, "\nthe lock is unowned");
    219 	else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
    220 		(void) strcat(buf, "\nthe lock owner is ");
    221 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
    222 	} else {
    223 		(void) strcat(buf, " in process ");
    224 		ultos((uint64_t)pid, 10, buf + strlen(buf));
    225 		(void) strcat(buf, "\nthe lock owner is ");
    226 		ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
    227 		(void) strcat(buf, " in process ");
    228 		ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
    229 	}
    230 	(void) strcat(buf, "\n\n");
    231 	(void) __write(2, buf, strlen(buf));
    232 	if (udp->uberflags.uf_thread_error_detection >= 2)
    233 		Abort(buf);
    234 	assert_thread = NULL;
    235 	(void) _lwp_mutex_unlock(&assert_lock);
    236 	if (self != NULL)
    237 		exit_critical(self);
    238 }
    239 
    240 /*
    241  * Report application lock usage error for rwlocks.
    242  * Not called if _THREAD_ERROR_DETECTION=0.
    243  * Continue execution if _THREAD_ERROR_DETECTION=1.
    244  * Dump core if _THREAD_ERROR_DETECTION=2.
    245  */
    246 void
    247 rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
    248 {
    249 	/* take a snapshot of the rwlock before it changes (we hope) */
    250 	rwlock_t rcopy = *rp;
    251 	uint32_t rwstate;
    252 	char buf[800];
    253 	uberdata_t *udp;
    254 	ulwp_t *self;
    255 	lwpid_t lwpid;
    256 	pid_t pid;
    257 	int process;
    258 
    259 	/* avoid recursion deadlock */
    260 	if ((self = __curthread()) != NULL) {
    261 		if (assert_thread == self)
    262 			_exit(127);
    263 		enter_critical(self);
    264 		(void) _lwp_mutex_lock(&assert_lock);
    265 		assert_thread = self;
    266 		lwpid = self->ul_lwpid;
    267 		udp = self->ul_uberdata;
    268 		pid = udp->pid;
    269 	} else {
    270 		self = NULL;
    271 		(void) _lwp_mutex_lock(&assert_lock);
    272 		lwpid = _lwp_self();
    273 		udp = &__uberdata;
    274 		pid = getpid();
    275 	}
    276 
    277 	rwstate = (uint32_t)rcopy.rwlock_readers;
    278 	process = (rcopy.rwlock_type & USYNC_PROCESS);
    279 
    280 	(void) strcpy(buf,
    281 	    "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
    282 	(void) strcat(buf, who);
    283 	(void) strcat(buf, "(");
    284 	ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
    285 	(void) strcat(buf, "): ");
    286 	(void) strcat(buf, msg);
    287 	(void) strcat(buf, "\ncalling thread is ");
    288 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
    289 	(void) strcat(buf, " thread-id ");
    290 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
    291 	if (process) {
    292 		(void) strcat(buf, " in process ");
    293 		ultos((uint64_t)pid, 10, buf + strlen(buf));
    294 	}
    295 	if (rwstate & URW_WRITE_LOCKED) {
    296 		(void) strcat(buf, "\nthe writer lock owner is ");
    297 		ultos((uint64_t)rcopy.rwlock_owner, 16,
    298 		    buf + strlen(buf));
    299 		if (process) {
    300 			(void) strcat(buf, " in process ");
    301 			ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
    302 			    buf + strlen(buf));
    303 		}
    304 	} else if (rwstate & URW_READERS_MASK) {
    305 		(void) strcat(buf, "\nthe reader lock is held by ");
    306 		ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
    307 		    buf + strlen(buf));
    308 		(void) strcat(buf, " readers");
    309 	} else {
    310 		(void) strcat(buf, "\nthe lock is unowned");
    311 	}
    312 	if (rwstate & URW_HAS_WAITERS)
    313 		(void) strcat(buf, "\nand the lock appears to have waiters");
    314 	(void) strcat(buf, "\n\n");
    315 	(void) __write(2, buf, strlen(buf));
    316 	if (udp->uberflags.uf_thread_error_detection >= 2)
    317 		Abort(buf);
    318 	assert_thread = NULL;
    319 	(void) _lwp_mutex_unlock(&assert_lock);
    320 	if (self != NULL)
    321 		exit_critical(self);
    322 }
    323 
    324 /*
    325  * Report a thread usage error.
    326  * Not called if _THREAD_ERROR_DETECTION=0.
    327  * Writes message and continues execution if _THREAD_ERROR_DETECTION=1.
    328  * Writes message and dumps core if _THREAD_ERROR_DETECTION=2.
    329  */
    330 void
    331 thread_error(const char *msg)
    332 {
    333 	char buf[800];
    334 	uberdata_t *udp;
    335 	ulwp_t *self;
    336 	lwpid_t lwpid;
    337 
    338 	/* avoid recursion deadlock */
    339 	if ((self = __curthread()) != NULL) {
    340 		if (assert_thread == self)
    341 			_exit(127);
    342 		enter_critical(self);
    343 		(void) _lwp_mutex_lock(&assert_lock);
    344 		assert_thread = self;
    345 		lwpid = self->ul_lwpid;
    346 		udp = self->ul_uberdata;
    347 	} else {
    348 		self = NULL;
    349 		(void) _lwp_mutex_lock(&assert_lock);
    350 		lwpid = _lwp_self();
    351 		udp = &__uberdata;
    352 	}
    353 
    354 	(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
    355 	    "thread usage error detected ***\n*** ");
    356 	(void) strcat(buf, msg);
    357 
    358 	(void) strcat(buf, "\n*** calling thread is ");
    359 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
    360 	(void) strcat(buf, " thread-id ");
    361 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
    362 	(void) strcat(buf, "\n\n");
    363 	(void) __write(2, buf, strlen(buf));
    364 	if (udp->uberflags.uf_thread_error_detection >= 2)
    365 		Abort(buf);
    366 	assert_thread = NULL;
    367 	(void) _lwp_mutex_unlock(&assert_lock);
    368 	if (self != NULL)
    369 		exit_critical(self);
    370 }
    371 
    372 /*
    373  * We use __assfail() because the libc __assert() calls
    374  * gettext() which calls malloc() which grabs a mutex.
    375  * We do everything without calling standard i/o.
    376  * assfail() and _assfail() are exported functions;
    377  * __assfail() is private to libc.
    378  */
    379 #pragma weak _assfail = __assfail
    380 void
    381 __assfail(const char *assertion, const char *filename, int line_num)
    382 {
    383 	char buf[800];	/* no assert() message in the library is this long */
    384 	ulwp_t *self;
    385 	lwpid_t lwpid;
    386 
    387 	/* avoid recursion deadlock */
    388 	if ((self = __curthread()) != NULL) {
    389 		if (assert_thread == self)
    390 			_exit(127);
    391 		enter_critical(self);
    392 		(void) _lwp_mutex_lock(&assert_lock);
    393 		assert_thread = self;
    394 		lwpid = self->ul_lwpid;
    395 	} else {
    396 		self = NULL;
    397 		(void) _lwp_mutex_lock(&assert_lock);
    398 		lwpid = _lwp_self();
    399 	}
    400 
    401 	(void) strcpy(buf, "assertion failed for thread ");
    402 	ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
    403 	(void) strcat(buf, ", thread-id ");
    404 	ultos((uint64_t)lwpid, 10, buf + strlen(buf));
    405 	(void) strcat(buf, ": ");
    406 	(void) strcat(buf, assertion);
    407 	(void) strcat(buf, ", file ");
    408 	(void) strcat(buf, filename);
    409 	(void) strcat(buf, ", line ");
    410 	ultos((uint64_t)line_num, 10, buf + strlen(buf));
    411 	(void) strcat(buf, "\n");
    412 	(void) __write(2, buf, strlen(buf));
    413 	/*
    414 	 * We could replace the call to Abort() with the following code
    415 	 * if we want just to issue a warning message and not die.
    416 	 *	assert_thread = NULL;
    417 	 *	_lwp_mutex_unlock(&assert_lock);
    418 	 *	if (self != NULL)
    419 	 *		exit_critical(self);
    420 	 */
    421 	Abort(buf);
    422 }
    423 
    424 /*
    425  * We define and export this version of assfail() just because libaio
    426  * used to define and export it, needlessly.  Now that libaio is folded
    427  * into libc, we need to continue this for ABI/version reasons.
    428  * We don't use "#pragma weak assfail __assfail" in order to avoid
    429  * warnings from the check_fnames utility at build time for libraries
    430  * that define their own version of assfail().
    431  */
    432 void
    433 assfail(const char *assertion, const char *filename, int line_num)
    434 {
    435 	__assfail(assertion, filename, line_num);
    436 }
    437