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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 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) _private_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) _private_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) _private_sigemptyset(&sigmask); 82 (void) _private_sigaddset(&sigmask, SIGABRT); 83 (void) __lwp_sigmask(SIG_UNBLOCK, &sigmask, NULL); 84 85 (void) __lwp_kill(lwpid, SIGABRT); /* never returns */ 86 (void) _kill(_private_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 void 95 thr_panic(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) _private_lwp_mutex_lock(&assert_lock); 104 105 (void) _private_memset(msg, 0, sizeof (msg)); 106 (void) strcpy(msg, "*** libc thread failure: "); 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 /* 120 * Utility function for converting a long integer to a string, avoiding stdio. 121 * 'base' must be one of 10 or 16 122 */ 123 void 124 ultos(uint64_t n, int base, char *s) 125 { 126 char lbuf[24]; /* 64 bits fits in 16 hex digits, 20 decimal */ 127 char *cp = lbuf; 128 129 do { 130 *cp++ = "0123456789abcdef"[n%base]; 131 n /= base; 132 } while (n); 133 if (base == 16) { 134 *s++ = '0'; 135 *s++ = 'x'; 136 } 137 do { 138 *s++ = *--cp; 139 } while (cp > lbuf); 140 *s = '\0'; 141 } 142 143 /* 144 * Report application lock usage error for mutexes and condvars. 145 * Not called if _THREAD_ERROR_DETECTION=0. 146 * Continue execution if _THREAD_ERROR_DETECTION=1. 147 * Dump core if _THREAD_ERROR_DETECTION=2. 148 */ 149 void 150 lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg) 151 { 152 /* take a snapshot of the mutex before it changes (we hope!) */ 153 mutex_t mcopy = *mp; 154 char buf[800]; 155 uberdata_t *udp; 156 ulwp_t *self; 157 lwpid_t lwpid; 158 pid_t pid; 159 160 /* avoid recursion deadlock */ 161 if ((self = __curthread()) != NULL) { 162 if (assert_thread == self) 163 _exit(127); 164 enter_critical(self); 165 (void) _private_lwp_mutex_lock(&assert_lock); 166 assert_thread = self; 167 lwpid = self->ul_lwpid; 168 udp = self->ul_uberdata; 169 pid = udp->pid; 170 } else { 171 self = NULL; 172 (void) _private_lwp_mutex_lock(&assert_lock); 173 lwpid = __lwp_self(); 174 udp = &__uberdata; 175 pid = _private_getpid(); 176 } 177 178 (void) strcpy(buf, 179 "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); 180 (void) strcat(buf, who); 181 (void) strcat(buf, "("); 182 if (cv != NULL) { 183 ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf)); 184 (void) strcat(buf, ", "); 185 } 186 ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf)); 187 (void) strcat(buf, ")"); 188 if (msg != NULL) { 189 (void) strcat(buf, ": "); 190 (void) strcat(buf, msg); 191 } else if (!mutex_is_held(&mcopy)) { 192 (void) strcat(buf, ": calling thread does not own the lock"); 193 } else if (mcopy.mutex_rcount) { 194 (void) strcat(buf, ": mutex rcount = "); 195 ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf)); 196 } else { 197 (void) strcat(buf, ": calling thread already owns the lock"); 198 } 199 (void) strcat(buf, "\ncalling thread is "); 200 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 201 (void) strcat(buf, " thread-id "); 202 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 203 if (msg != NULL || mutex_is_held(&mcopy)) 204 /* EMPTY */; 205 else if (mcopy.mutex_lockw == 0) 206 (void) strcat(buf, "\nthe lock is unowned"); 207 else if (!(mcopy.mutex_type & (USYNC_PROCESS|USYNC_PROCESS_ROBUST))) { 208 (void) strcat(buf, "\nthe lock owner is "); 209 ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); 210 } else { 211 (void) strcat(buf, " in process "); 212 ultos((uint64_t)pid, 10, buf + strlen(buf)); 213 (void) strcat(buf, "\nthe lock owner is "); 214 ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf)); 215 (void) strcat(buf, " in process "); 216 ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf)); 217 } 218 (void) strcat(buf, "\n\n"); 219 (void) _write(2, buf, strlen(buf)); 220 if (udp->uberflags.uf_thread_error_detection >= 2) 221 Abort(buf); 222 assert_thread = NULL; 223 (void) _private_lwp_mutex_unlock(&assert_lock); 224 if (self != NULL) 225 exit_critical(self); 226 } 227 228 /* 229 * Report application lock usage error for rwlocks. 230 * Not called if _THREAD_ERROR_DETECTION=0. 231 * Continue execution if _THREAD_ERROR_DETECTION=1. 232 * Dump core if _THREAD_ERROR_DETECTION=2. 233 */ 234 void 235 rwlock_error(const rwlock_t *rp, const char *who, const char *msg) 236 { 237 /* take a snapshot of the rwlock before it changes (we hope) */ 238 rwlock_t rcopy = *rp; 239 char buf[800]; 240 uberdata_t *udp; 241 ulwp_t *self; 242 lwpid_t lwpid; 243 pid_t pid; 244 245 /* avoid recursion deadlock */ 246 if ((self = __curthread()) != NULL) { 247 if (assert_thread == self) 248 _exit(127); 249 enter_critical(self); 250 (void) _private_lwp_mutex_lock(&assert_lock); 251 assert_thread = self; 252 lwpid = self->ul_lwpid; 253 udp = self->ul_uberdata; 254 pid = udp->pid; 255 } else { 256 self = NULL; 257 (void) _private_lwp_mutex_lock(&assert_lock); 258 lwpid = __lwp_self(); 259 udp = &__uberdata; 260 pid = _private_getpid(); 261 } 262 263 (void) strcpy(buf, 264 "\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n"); 265 (void) strcat(buf, who); 266 (void) strcat(buf, "("); 267 ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf)); 268 (void) strcat(buf, "): "); 269 (void) strcat(buf, msg); 270 (void) strcat(buf, "\ncalling thread is "); 271 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 272 (void) strcat(buf, " thread-id "); 273 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 274 if (rcopy.rwlock_type & USYNC_PROCESS) { 275 uint32_t *rwstate = (uint32_t *)&rcopy.rwlock_readers; 276 277 (void) strcat(buf, " in process "); 278 ultos((uint64_t)pid, 10, buf + strlen(buf)); 279 280 if (*rwstate & URW_WRITE_LOCKED) { 281 (void) strcat(buf, "\nthe lock writer owner is "); 282 ultos((uint64_t)rcopy.rwlock_owner, 16, 283 buf + strlen(buf)); 284 (void) strcat(buf, " in process "); 285 ultos((uint64_t)rcopy.rwlock_ownerpid, 10, 286 buf + strlen(buf)); 287 } else if (*rwstate & URW_READERS_MASK) { 288 (void) strcat(buf, "\nthe lock is owned by "); 289 ultos((uint64_t)(*rwstate & URW_READERS_MASK), 10, 290 buf + strlen(buf)); 291 (void) strcat(buf, " readers"); 292 } else 293 (void) strcat(buf, "\nthe lock is unowned"); 294 295 if (*rwstate & URW_HAS_WAITERS) { 296 (void) strcat(buf, "\nand appears to have waiters"); 297 if (*rwstate & URW_WRITE_WANTED) 298 (void) strcat(buf, 299 " (including at least one writer)"); 300 } 301 } else if (rcopy.rwlock_readers < 0) { 302 (void) strcat(buf, "\nthe lock writer owner is "); 303 ultos((uint64_t)rcopy.rwlock_mowner, 16, buf + strlen(buf)); 304 } else if (rcopy.rwlock_readers > 0) { 305 (void) strcat(buf, "\nthe lock is owned by "); 306 ultos((uint64_t)rcopy.rwlock_readers, 10, buf + strlen(buf)); 307 (void) strcat(buf, "readers"); 308 } else { 309 (void) strcat(buf, "\nthe lock is unowned"); 310 } 311 (void) strcat(buf, "\n\n"); 312 (void) _write(2, buf, strlen(buf)); 313 if (udp->uberflags.uf_thread_error_detection >= 2) 314 Abort(buf); 315 assert_thread = NULL; 316 (void) _private_lwp_mutex_unlock(&assert_lock); 317 if (self != NULL) 318 exit_critical(self); 319 } 320 321 /* 322 * Report a thread usage error. 323 * Not called if _THREAD_ERROR_DETECTION=0. 324 * Writes message and continues execution if _THREAD_ERROR_DETECTION=1. 325 * Writes message and dumps core if _THREAD_ERROR_DETECTION=2. 326 */ 327 void 328 thread_error(const char *msg) 329 { 330 char buf[800]; 331 uberdata_t *udp; 332 ulwp_t *self; 333 lwpid_t lwpid; 334 335 /* avoid recursion deadlock */ 336 if ((self = __curthread()) != NULL) { 337 if (assert_thread == self) 338 _exit(127); 339 enter_critical(self); 340 (void) _private_lwp_mutex_lock(&assert_lock); 341 assert_thread = self; 342 lwpid = self->ul_lwpid; 343 udp = self->ul_uberdata; 344 } else { 345 self = NULL; 346 (void) _private_lwp_mutex_lock(&assert_lock); 347 lwpid = __lwp_self(); 348 udp = &__uberdata; 349 } 350 351 (void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: " 352 "thread usage error detected ***\n*** "); 353 (void) strcat(buf, msg); 354 355 (void) strcat(buf, "\n*** calling thread is "); 356 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 357 (void) strcat(buf, " thread-id "); 358 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 359 (void) strcat(buf, "\n\n"); 360 (void) _write(2, buf, strlen(buf)); 361 if (udp->uberflags.uf_thread_error_detection >= 2) 362 Abort(buf); 363 assert_thread = NULL; 364 (void) _private_lwp_mutex_unlock(&assert_lock); 365 if (self != NULL) 366 exit_critical(self); 367 } 368 369 /* 370 * We use __assfail() because the libc __assert() calls 371 * gettext() which calls malloc() which grabs a mutex. 372 * We do everything without calling standard i/o. 373 * _assfail() is an exported function, __assfail() is private to libc. 374 */ 375 #pragma weak _assfail = __assfail 376 void 377 __assfail(const char *assertion, const char *filename, int line_num) 378 { 379 char buf[800]; /* no assert() message in the library is this long */ 380 ulwp_t *self; 381 lwpid_t lwpid; 382 383 /* avoid recursion deadlock */ 384 if ((self = __curthread()) != NULL) { 385 if (assert_thread == self) 386 _exit(127); 387 enter_critical(self); 388 (void) _private_lwp_mutex_lock(&assert_lock); 389 assert_thread = self; 390 lwpid = self->ul_lwpid; 391 } else { 392 self = NULL; 393 (void) _private_lwp_mutex_lock(&assert_lock); 394 lwpid = __lwp_self(); 395 } 396 397 (void) strcpy(buf, "assertion failed for thread "); 398 ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf)); 399 (void) strcat(buf, ", thread-id "); 400 ultos((uint64_t)lwpid, 10, buf + strlen(buf)); 401 (void) strcat(buf, ": "); 402 (void) strcat(buf, assertion); 403 (void) strcat(buf, ", file "); 404 (void) strcat(buf, filename); 405 (void) strcat(buf, ", line "); 406 ultos((uint64_t)line_num, 10, buf + strlen(buf)); 407 (void) strcat(buf, "\n"); 408 (void) _write(2, buf, strlen(buf)); 409 /* 410 * We could replace the call to Abort() with the following code 411 * if we want just to issue a warning message and not die. 412 * assert_thread = NULL; 413 * _private_lwp_mutex_unlock(&assert_lock); 414 * if (self != NULL) 415 * exit_critical(self); 416 */ 417 Abort(buf); 418 } 419