#include "lint.h"
#include "libc.h"
#include "thr_uberdata.h"
#include <upanic.h>
const char *panicstr;
ulwp_t *panic_thread;
static mutex_t assert_lock = DEFAULTMUTEX;
static ulwp_t *assert_thread = NULL;
mutex_t *panic_mutex = NULL;
static void Abort(const char *, size_t) __NORETURN;
void
__set_panicstr(const char *msg)
{
panicstr = msg;
panic_thread = __curthread();
}
void
grab_assert_lock()
{
(void) _lwp_mutex_lock(&assert_lock);
}
static void
Abort(const char *msg, size_t buflen)
{
ulwp_t *self;
panicstr = msg;
if ((self = __curthread()) != NULL) {
panic_thread = self;
}
upanic(msg, buflen);
}
void
common_panic(const char *head, const char *why)
{
char msg[400];
ulwp_t *self;
size_t len1, len2;
if ((self = __curthread()) != NULL)
enter_critical(self);
(void) _lwp_mutex_lock(&assert_lock);
(void) memset(msg, 0, sizeof (msg));
(void) strcpy(msg, head);
len1 = strlen(msg);
len2 = strlen(why);
if (len1 + len2 >= sizeof (msg))
len2 = sizeof (msg) - len1 - 1;
(void) strncat(msg, why, len2);
len1 = strlen(msg);
if (msg[len1 - 1] != '\n')
msg[len1++] = '\n';
(void) __write(2, msg, len1);
Abort(msg, sizeof (msg));
}
void
thr_panic(const char *why)
{
common_panic("*** libc thread failure: ", why);
}
void
aio_panic(const char *why)
{
common_panic("*** libc aio system failure: ", why);
}
void
mutex_panic(mutex_t *mp, const char *why)
{
panic_mutex = mp;
common_panic("*** libc mutex system failure: ", why);
}
void
ultos(uint64_t n, int base, char *s)
{
char lbuf[24];
char *cp = lbuf;
do {
*cp++ = "0123456789abcdef"[n%base];
n /= base;
} while (n);
if (base == 16) {
*s++ = '0';
*s++ = 'x';
}
do {
*s++ = *--cp;
} while (cp > lbuf);
*s = '\0';
}
void
lock_error(const mutex_t *mp, const char *who, void *cv, const char *msg)
{
mutex_t mcopy;
char buf[800];
uberdata_t *udp;
ulwp_t *self;
lwpid_t lwpid;
pid_t pid;
(void) memcpy(&mcopy, mp, sizeof (mcopy));
if ((self = __curthread()) != NULL) {
if (assert_thread == self)
_exit(127);
enter_critical(self);
(void) _lwp_mutex_lock(&assert_lock);
assert_thread = self;
lwpid = self->ul_lwpid;
udp = self->ul_uberdata;
pid = udp->pid;
} else {
self = NULL;
(void) _lwp_mutex_lock(&assert_lock);
lwpid = _lwp_self();
udp = &__uberdata;
pid = getpid();
}
(void) strcpy(buf,
"\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
(void) strcat(buf, who);
(void) strcat(buf, "(");
if (cv != NULL) {
ultos((uint64_t)(uintptr_t)cv, 16, buf + strlen(buf));
(void) strcat(buf, ", ");
}
ultos((uint64_t)(uintptr_t)mp, 16, buf + strlen(buf));
(void) strcat(buf, ")");
if (msg != NULL) {
(void) strcat(buf, ": ");
(void) strcat(buf, msg);
} else if (!mutex_held(&mcopy)) {
(void) strcat(buf, ": calling thread does not own the lock");
} else if (mcopy.mutex_rcount) {
(void) strcat(buf, ": mutex rcount = ");
ultos((uint64_t)mcopy.mutex_rcount, 10, buf + strlen(buf));
} else {
(void) strcat(buf, ": calling thread already owns the lock");
}
(void) strcat(buf, "\ncalling thread is ");
ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
(void) strcat(buf, " thread-id ");
ultos((uint64_t)lwpid, 10, buf + strlen(buf));
if (msg != NULL || mutex_held(&mcopy))
;
else if (mcopy.mutex_lockw == 0)
(void) strcat(buf, "\nthe lock is unowned");
else if (!(mcopy.mutex_type & USYNC_PROCESS)) {
(void) strcat(buf, "\nthe lock owner is ");
ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
} else {
(void) strcat(buf, " in process ");
ultos((uint64_t)pid, 10, buf + strlen(buf));
(void) strcat(buf, "\nthe lock owner is ");
ultos((uint64_t)mcopy.mutex_owner, 16, buf + strlen(buf));
(void) strcat(buf, " in process ");
ultos((uint64_t)mcopy.mutex_ownerpid, 10, buf + strlen(buf));
}
(void) strcat(buf, "\n\n");
(void) __write(2, buf, strlen(buf));
if (udp->uberflags.uf_thread_error_detection >= 2)
Abort(buf, sizeof (buf));
assert_thread = NULL;
(void) _lwp_mutex_unlock(&assert_lock);
if (self != NULL)
exit_critical(self);
}
void
rwlock_error(const rwlock_t *rp, const char *who, const char *msg)
{
rwlock_t rcopy;
uint32_t rwstate;
char buf[800];
uberdata_t *udp;
ulwp_t *self;
lwpid_t lwpid;
pid_t pid;
int process;
(void) memcpy(&rcopy, rp, sizeof (rcopy));
if ((self = __curthread()) != NULL) {
if (assert_thread == self)
_exit(127);
enter_critical(self);
(void) _lwp_mutex_lock(&assert_lock);
assert_thread = self;
lwpid = self->ul_lwpid;
udp = self->ul_uberdata;
pid = udp->pid;
} else {
self = NULL;
(void) _lwp_mutex_lock(&assert_lock);
lwpid = _lwp_self();
udp = &__uberdata;
pid = getpid();
}
rwstate = (uint32_t)rcopy.rwlock_readers;
process = (rcopy.rwlock_type & USYNC_PROCESS);
(void) strcpy(buf,
"\n*** _THREAD_ERROR_DETECTION: lock usage error detected ***\n");
(void) strcat(buf, who);
(void) strcat(buf, "(");
ultos((uint64_t)(uintptr_t)rp, 16, buf + strlen(buf));
(void) strcat(buf, "): ");
(void) strcat(buf, msg);
(void) strcat(buf, "\ncalling thread is ");
ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
(void) strcat(buf, " thread-id ");
ultos((uint64_t)lwpid, 10, buf + strlen(buf));
if (process) {
(void) strcat(buf, " in process ");
ultos((uint64_t)pid, 10, buf + strlen(buf));
}
if (rwstate & URW_WRITE_LOCKED) {
(void) strcat(buf, "\nthe writer lock owner is ");
ultos((uint64_t)rcopy.rwlock_owner, 16,
buf + strlen(buf));
if (process) {
(void) strcat(buf, " in process ");
ultos((uint64_t)rcopy.rwlock_ownerpid, 10,
buf + strlen(buf));
}
} else if (rwstate & URW_READERS_MASK) {
(void) strcat(buf, "\nthe reader lock is held by ");
ultos((uint64_t)(rwstate & URW_READERS_MASK), 10,
buf + strlen(buf));
(void) strcat(buf, " readers");
} else {
(void) strcat(buf, "\nthe lock is unowned");
}
if (rwstate & URW_HAS_WAITERS)
(void) strcat(buf, "\nand the lock appears to have waiters");
(void) strcat(buf, "\n\n");
(void) __write(2, buf, strlen(buf));
if (udp->uberflags.uf_thread_error_detection >= 2)
Abort(buf, sizeof (buf));
assert_thread = NULL;
(void) _lwp_mutex_unlock(&assert_lock);
if (self != NULL)
exit_critical(self);
}
void
thread_error(const char *msg)
{
char buf[800];
uberdata_t *udp;
ulwp_t *self;
lwpid_t lwpid;
if ((self = __curthread()) != NULL) {
if (assert_thread == self)
_exit(127);
enter_critical(self);
(void) _lwp_mutex_lock(&assert_lock);
assert_thread = self;
lwpid = self->ul_lwpid;
udp = self->ul_uberdata;
} else {
self = NULL;
(void) _lwp_mutex_lock(&assert_lock);
lwpid = _lwp_self();
udp = &__uberdata;
}
(void) strcpy(buf, "\n*** _THREAD_ERROR_DETECTION: "
"thread usage error detected ***\n*** ");
(void) strcat(buf, msg);
(void) strcat(buf, "\n*** calling thread is ");
ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
(void) strcat(buf, " thread-id ");
ultos((uint64_t)lwpid, 10, buf + strlen(buf));
(void) strcat(buf, "\n\n");
(void) __write(2, buf, strlen(buf));
if (udp->uberflags.uf_thread_error_detection >= 2)
Abort(buf, sizeof (buf));
assert_thread = NULL;
(void) _lwp_mutex_unlock(&assert_lock);
if (self != NULL)
exit_critical(self);
}
#pragma weak _assfail = __assfail
void
__assfail(const char *assertion, const char *filename, int line_num)
{
char buf[800];
ulwp_t *self;
lwpid_t lwpid;
if ((self = __curthread()) != NULL) {
if (assert_thread == self)
_exit(127);
enter_critical(self);
(void) _lwp_mutex_lock(&assert_lock);
assert_thread = self;
lwpid = self->ul_lwpid;
} else {
self = NULL;
(void) _lwp_mutex_lock(&assert_lock);
lwpid = _lwp_self();
}
if (filename == NULL) {
(void) strcpy(buf, "failure for thread ");
} else {
(void) strcpy(buf, "assertion failed for thread ");
}
ultos((uint64_t)(uintptr_t)self, 16, buf + strlen(buf));
(void) strcat(buf, ", thread-id ");
ultos((uint64_t)lwpid, 10, buf + strlen(buf));
(void) strcat(buf, ": ");
(void) strcat(buf, assertion);
if (filename != NULL) {
(void) strcat(buf, ", file ");
(void) strcat(buf, filename);
(void) strcat(buf, ", line ");
ultos((uint64_t)line_num, 10, buf + strlen(buf));
}
(void) strcat(buf, "\n");
(void) __write(2, buf, strlen(buf));
Abort(buf, sizeof (buf));
}
void
assfail(const char *assertion, const char *filename, int line_num)
{
__assfail(assertion, filename, line_num);
}
void
assfail3(const char *assertion, uintmax_t lv, const char *op, uintmax_t rv,
const char *filename, int line_num)
{
char buf[1000];
(void) strcpy(buf, assertion);
(void) strcat(buf, " (");
ultos((uint64_t)lv, 16, buf + strlen(buf));
(void) strcat(buf, " ");
(void) strcat(buf, op);
(void) strcat(buf, " ");
ultos((uint64_t)rv, 16, buf + strlen(buf));
(void) strcat(buf, ")");
__assfail(buf, filename, line_num);
}