summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorRoger A. Faulkner <Roger.Faulkner@Sun.COM>2009-08-18 20:06:58 -0700
committerRoger A. Faulkner <Roger.Faulkner@Sun.COM>2009-08-18 20:06:58 -0700
commit7be238fce69ba74b2163fc0ea898dfdc01a4aa22 (patch)
tree7a78a0a39337b5ff0884b006e68b05c4135d7add /usr/src
parent98e8d17584d08c481c8a827f2311c1e3e6aceabb (diff)
downloadillumos-joyent-7be238fce69ba74b2163fc0ea898dfdc01a4aa22.tar.gz
6817506 Lock contention in kernel severely degrades clock-profiling on T5440 in SIGPROF handling
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/uts/common/os/schedctl.c9
-rw-r--r--usr/src/uts/common/os/sig.c156
-rw-r--r--usr/src/uts/common/syscall/signotify.c11
-rw-r--r--usr/src/uts/common/syscall/sigprocmask.c18
-rw-r--r--usr/src/uts/intel/ia32/syscall/getcontext.c32
-rw-r--r--usr/src/uts/sparc/syscall/getcontext.c37
6 files changed, 169 insertions, 94 deletions
diff --git a/usr/src/uts/common/os/schedctl.c b/usr/src/uts/common/os/schedctl.c
index 752c2535c4..ed6e74c558 100644
--- a/usr/src/uts/common/os/schedctl.c
+++ b/usr/src/uts/common/os/schedctl.c
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/systm.h>
#include <sys/schedctl.h>
@@ -333,14 +331,15 @@ schedctl_sigblock(kthread_t *t)
* its signal mask to block all maskable signals, then clear the
* sc_sigblock field. This finishes what user-level code requested
* to be done when it set tdp->sc_shared->sc_sigblock non-zero.
- * Called by signal-related code that holds the process's p_lock.
+ * Called from signal-related code either by the current thread for
+ * itself or by a thread that holds the process's p_lock (/proc code).
*/
void
schedctl_finish_sigblock(kthread_t *t)
{
sc_shared_t *tdp = t->t_schedctl;
- ASSERT(MUTEX_HELD(&ttoproc(t)->p_lock));
+ ASSERT(t == curthread || MUTEX_HELD(&ttoproc(t)->p_lock));
if (tdp != NULL && tdp->sc_sigblock) {
t->t_hold.__sigbits[0] = FILLSET0 & ~CANTMASK0;
diff --git a/usr/src/uts/common/os/sig.c b/usr/src/uts/common/os/sig.c
index 32f69d22da..763214a60d 100644
--- a/usr/src/uts/common/os/sig.c
+++ b/usr/src/uts/common/os/sig.c
@@ -2535,48 +2535,152 @@ trapsig(k_siginfo_t *ip, int restartable)
}
/*
- * Arrange for the real time profiling signal to be dispatched.
+ * Dispatch the real time profiling signal in the traditional way,
+ * honoring all of the /proc tracing mechanism built into issig().
*/
-void
-realsigprof(int sysnum, int nsysarg, int error)
+static void
+realsigprof_slow(int sysnum, int nsysarg, int error)
{
- proc_t *p;
- klwp_t *lwp;
+ kthread_t *t = curthread;
+ proc_t *p = ttoproc(t);
+ klwp_t *lwp = ttolwp(t);
+ k_siginfo_t *sip = &lwp->lwp_siginfo;
+ void (*func)();
- if (curthread->t_rprof->rp_anystate == 0)
- return;
- p = ttoproc(curthread);
- lwp = ttolwp(curthread);
mutex_enter(&p->p_lock);
- if (p->p_rprof_cyclic == CYCLIC_NONE) {
- bzero(curthread->t_rprof, sizeof (*curthread->t_rprof));
+ func = PTOU(p)->u_signal[SIGPROF - 1];
+ if (p->p_rprof_cyclic == CYCLIC_NONE ||
+ func == SIG_DFL || func == SIG_IGN) {
+ bzero(t->t_rprof, sizeof (*t->t_rprof));
mutex_exit(&p->p_lock);
return;
}
- if (sigismember(&p->p_ignore, SIGPROF) ||
- signal_is_blocked(curthread, SIGPROF)) {
+ if (sigismember(&t->t_hold, SIGPROF)) {
mutex_exit(&p->p_lock);
return;
}
- lwp->lwp_siginfo.si_signo = SIGPROF;
- lwp->lwp_siginfo.si_code = PROF_SIG;
- lwp->lwp_siginfo.si_errno = error;
- hrt2ts(gethrtime(), &lwp->lwp_siginfo.si_tstamp);
- lwp->lwp_siginfo.si_syscall = sysnum;
- lwp->lwp_siginfo.si_nsysarg = nsysarg;
- lwp->lwp_siginfo.si_fault = lwp->lwp_lastfault;
- lwp->lwp_siginfo.si_faddr = lwp->lwp_lastfaddr;
+ sip->si_signo = SIGPROF;
+ sip->si_code = PROF_SIG;
+ sip->si_errno = error;
+ hrt2ts(gethrtime(), &sip->si_tstamp);
+ sip->si_syscall = sysnum;
+ sip->si_nsysarg = nsysarg;
+ sip->si_fault = lwp->lwp_lastfault;
+ sip->si_faddr = lwp->lwp_lastfaddr;
lwp->lwp_lastfault = 0;
lwp->lwp_lastfaddr = NULL;
- sigtoproc(p, curthread, SIGPROF);
+ sigtoproc(p, t, SIGPROF);
mutex_exit(&p->p_lock);
ASSERT(lwp->lwp_cursig == 0);
if (issig(FORREAL))
psig();
- mutex_enter(&p->p_lock);
- lwp->lwp_siginfo.si_signo = 0;
- bzero(curthread->t_rprof, sizeof (*curthread->t_rprof));
- mutex_exit(&p->p_lock);
+ sip->si_signo = 0;
+ bzero(t->t_rprof, sizeof (*t->t_rprof));
+}
+
+/*
+ * We are not tracing the SIGPROF signal, or doing any other unnatural
+ * acts, like watchpoints, so dispatch the real time profiling signal
+ * directly, bypassing all of the overhead built into issig().
+ */
+static void
+realsigprof_fast(int sysnum, int nsysarg, int error)
+{
+ kthread_t *t = curthread;
+ proc_t *p = ttoproc(t);
+ klwp_t *lwp = ttolwp(t);
+ k_siginfo_t *sip = &lwp->lwp_siginfo;
+ void (*func)();
+ int rc;
+ int code;
+
+ /*
+ * We don't need to acquire p->p_lock here;
+ * we are manipulating thread-private data.
+ */
+ func = PTOU(p)->u_signal[SIGPROF - 1];
+ if (p->p_rprof_cyclic == CYCLIC_NONE ||
+ func == SIG_DFL || func == SIG_IGN) {
+ bzero(t->t_rprof, sizeof (*t->t_rprof));
+ return;
+ }
+ if (lwp->lwp_cursig != 0 ||
+ lwp->lwp_curinfo != NULL ||
+ sigismember(&t->t_hold, SIGPROF)) {
+ return;
+ }
+ sip->si_signo = SIGPROF;
+ sip->si_code = PROF_SIG;
+ sip->si_errno = error;
+ hrt2ts(gethrtime(), &sip->si_tstamp);
+ sip->si_syscall = sysnum;
+ sip->si_nsysarg = nsysarg;
+ sip->si_fault = lwp->lwp_lastfault;
+ sip->si_faddr = lwp->lwp_lastfaddr;
+ lwp->lwp_lastfault = 0;
+ lwp->lwp_lastfaddr = NULL;
+ if (t->t_flag & T_TOMASK)
+ t->t_flag &= ~T_TOMASK;
+ else
+ lwp->lwp_sigoldmask = t->t_hold;
+ sigorset(&t->t_hold, &PTOU(p)->u_sigmask[SIGPROF - 1]);
+ if (!sigismember(&PTOU(p)->u_signodefer, SIGPROF))
+ sigaddset(&t->t_hold, SIGPROF);
+ lwp->lwp_extsig = 0;
+ lwp->lwp_ru.nsignals++;
+ if (p->p_model == DATAMODEL_NATIVE)
+ rc = sendsig(SIGPROF, sip, func);
+#ifdef _SYSCALL32_IMPL
+ else
+ rc = sendsig32(SIGPROF, sip, func);
+#endif /* _SYSCALL32_IMPL */
+ sip->si_signo = 0;
+ bzero(t->t_rprof, sizeof (*t->t_rprof));
+ if (rc == 0) {
+ /*
+ * sendsig() failed; we must dump core with a SIGSEGV.
+ * See psig(). This code is copied from there.
+ */
+ lwp->lwp_cursig = SIGSEGV;
+ code = CLD_KILLED;
+ proc_is_exiting(p);
+ if (exitlwps(1) != 0) {
+ mutex_enter(&p->p_lock);
+ lwp_exit();
+ }
+ if (audit_active)
+ audit_core_start(SIGSEGV);
+ if (core(SIGSEGV, 0) == 0)
+ code = CLD_DUMPED;
+ if (audit_active)
+ audit_core_finish(code);
+ exit(code, SIGSEGV);
+ }
+}
+
+/*
+ * Arrange for the real time profiling signal to be dispatched.
+ */
+void
+realsigprof(int sysnum, int nsysarg, int error)
+{
+ kthread_t *t = curthread;
+ proc_t *p = ttoproc(t);
+
+ if (t->t_rprof->rp_anystate == 0)
+ return;
+
+ schedctl_finish_sigblock(t);
+
+ /* test for any activity that requires p->p_lock */
+ if (tracing(p, SIGPROF) || pr_watch_active(p) ||
+ sigismember(&PTOU(p)->u_sigresethand, SIGPROF)) {
+ /* do it the classic slow way */
+ realsigprof_slow(sysnum, nsysarg, error);
+ } else {
+ /* do it the cheating-a-little fast way */
+ realsigprof_fast(sysnum, nsysarg, error);
+ }
}
#ifdef _SYSCALL32_IMPL
diff --git a/usr/src/uts/common/syscall/signotify.c b/usr/src/uts/common/syscall/signotify.c
index d851abebba..bf5ed3b45e 100644
--- a/usr/src/uts/common/syscall/signotify.c
+++ b/usr/src/uts/common/syscall/signotify.c
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -229,7 +229,6 @@ int
sigresend(int sig, siginfo_t *siginfo, sigset_t *mask)
{
kthread_t *t = curthread;
- proc_t *p = ttoproc(t);
klwp_t *lwp = ttolwp(t);
sigqueue_t *sqp = kmem_zalloc(sizeof (*sqp), KM_SLEEP);
sigset_t set;
@@ -261,9 +260,11 @@ sigresend(int sig, siginfo_t *siginfo, sigset_t *mask)
}
sigutok(&set, &kset);
- mutex_enter(&p->p_lock);
+ /*
+ * We don't need to acquire p->p_lock here;
+ * we are manipulating thread-private data.
+ */
if (lwp->lwp_cursig || lwp->lwp_curinfo) {
- mutex_exit(&p->p_lock);
t->t_sig_check = 1;
error = EAGAIN;
goto bad;
@@ -272,8 +273,6 @@ sigresend(int sig, siginfo_t *siginfo, sigset_t *mask)
lwp->lwp_curinfo = sqp;
schedctl_finish_sigblock(t);
t->t_hold = kset;
- mutex_exit(&p->p_lock);
-
t->t_sig_check = 1;
return (0);
bad:
diff --git a/usr/src/uts/common/syscall/sigprocmask.c b/usr/src/uts/common/syscall/sigprocmask.c
index 8f7cf6113d..51afc4e643 100644
--- a/usr/src/uts/common/syscall/sigprocmask.c
+++ b/usr/src/uts/common/syscall/sigprocmask.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -19,15 +18,13 @@
*
* CDDL HEADER END
*/
-/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-
/*
- * Copyright 1994-2003 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
#include <sys/param.h>
#include <sys/types.h>
@@ -47,7 +44,11 @@ lwp_sigmask(int how, uint_t bits0, uint_t bits1)
proc_t *p = ttoproc(t);
rval_t rv;
- mutex_enter(&p->p_lock);
+ /*
+ * We don't need to acquire p->p_lock here;
+ * we are manipulating thread-private data.
+ */
+
schedctl_finish_sigblock(t);
bits0 &= (FILLSET0 & ~CANTMASK0);
@@ -75,7 +76,6 @@ lwp_sigmask(int how, uint_t bits0, uint_t bits1)
break;
}
- mutex_exit(&p->p_lock);
return (rv.r_vals);
}
diff --git a/usr/src/uts/intel/ia32/syscall/getcontext.c b/usr/src/uts/intel/ia32/syscall/getcontext.c
index 35be9fc49c..972a90fdf5 100644
--- a/usr/src/uts/intel/ia32/syscall/getcontext.c
+++ b/usr/src/uts/intel/ia32/syscall/getcontext.c
@@ -18,16 +18,14 @@
*
* CDDL HEADER END
*/
-/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
-/* All Rights Reserved */
-
/*
- * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
#include <sys/param.h>
#include <sys/types.h>
@@ -166,14 +164,14 @@ restorecontext(ucontext_t *ucp)
setfpregs(lwp, &ucp->uc_mcontext.fpregs);
if (ucp->uc_flags & UC_SIGMASK) {
- proc_t *p = ttoproc(t);
-
- mutex_enter(&p->p_lock);
+ /*
+ * We don't need to acquire p->p_lock here;
+ * we are manipulating thread-private data.
+ */
schedctl_finish_sigblock(t);
sigutok(&ucp->uc_sigmask, &t->t_hold);
- if (sigcheck(p, t))
+ if (sigcheck(ttoproc(t), t))
t->t_sig_check = 1;
- mutex_exit(&p->p_lock);
}
}
@@ -199,12 +197,7 @@ getsetcontext(int flag, void *arg)
return (set_errno(EINVAL));
case GETCONTEXT:
- if (schedctl_sigblock(curthread)) {
- proc_t *p = ttoproc(curthread);
- mutex_enter(&p->p_lock);
- schedctl_finish_sigblock(curthread);
- mutex_exit(&p->p_lock);
- }
+ schedctl_finish_sigblock(curthread);
savecontext(&uc, curthread->t_hold);
if (copyout(&uc, arg, sizeof (uc)))
return (set_errno(EFAULT));
@@ -331,12 +324,7 @@ getsetcontext32(int flag, void *arg)
return (set_errno(EINVAL));
case GETCONTEXT:
- if (schedctl_sigblock(curthread)) {
- proc_t *p = ttoproc(curthread);
- mutex_enter(&p->p_lock);
- schedctl_finish_sigblock(curthread);
- mutex_exit(&p->p_lock);
- }
+ schedctl_finish_sigblock(curthread);
savecontext32(&uc, curthread->t_hold);
if (copyout(&uc, arg, sizeof (uc)))
return (set_errno(EFAULT));
diff --git a/usr/src/uts/sparc/syscall/getcontext.c b/usr/src/uts/sparc/syscall/getcontext.c
index 1f35c963f2..144971af01 100644
--- a/usr/src/uts/sparc/syscall/getcontext.c
+++ b/usr/src/uts/sparc/syscall/getcontext.c
@@ -2,9 +2,8 @@
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License"). You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
@@ -21,16 +20,13 @@
*/
/*
- * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
-
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <sys/types.h>
#include <sys/vmparam.h>
@@ -163,14 +159,14 @@ restorecontext(ucontext_t *ucp)
}
if (ucp->uc_flags & UC_SIGMASK) {
- proc_t *p = ttoproc(t);
-
- mutex_enter(&p->p_lock);
+ /*
+ * We don't need to acquire p->p_lock here;
+ * we are manipulating thread-private data.
+ */
schedctl_finish_sigblock(t);
sigutok(&ucp->uc_sigmask, &t->t_hold);
- if (sigcheck(p, t))
+ if (sigcheck(ttoproc(t), t))
t->t_sig_check = 1;
- mutex_exit(&p->p_lock);
}
}
@@ -202,12 +198,7 @@ getsetcontext(int flag, void *arg)
return (set_errno(EINVAL));
case GETCONTEXT:
- if (schedctl_sigblock(curthread)) {
- proc_t *p = ttoproc(curthread);
- mutex_enter(&p->p_lock);
- schedctl_finish_sigblock(curthread);
- mutex_exit(&p->p_lock);
- }
+ schedctl_finish_sigblock(curthread);
savecontext(&uc, curthread->t_hold);
/*
* When using floating point it should not be possible to
@@ -453,12 +444,7 @@ getsetcontext32(int flag, void *arg)
return (set_errno(EINVAL));
case GETCONTEXT:
- if (schedctl_sigblock(curthread)) {
- proc_t *p = ttoproc(curthread);
- mutex_enter(&p->p_lock);
- schedctl_finish_sigblock(curthread);
- mutex_exit(&p->p_lock);
- }
+ schedctl_finish_sigblock(curthread);
savecontext32(&uc, curthread->t_hold, NULL);
/*
* When using floating point it should not be possible to
@@ -530,8 +516,7 @@ getsetcontext32(int flag, void *arg)
* bytes to copy out. We just *know* that wbcnt
* is the first element of the structure.
*/
- gwin = kmem_zalloc(sizeof (gwindows32_t),
- KM_SLEEP);
+ gwin = kmem_zalloc(sizeof (gwindows32_t), KM_SLEEP);
if (copyin((void *)(uintptr_t)uc.uc_mcontext.gwins,
&gwin->wbcnt, sizeof (gwin->wbcnt))) {
kmem_free(gwin, sizeof (gwindows32_t));