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