diff options
author | Roger A. Faulkner <Roger.Faulkner@Sun.COM> | 2009-08-18 20:06:58 -0700 |
---|---|---|
committer | Roger A. Faulkner <Roger.Faulkner@Sun.COM> | 2009-08-18 20:06:58 -0700 |
commit | 7be238fce69ba74b2163fc0ea898dfdc01a4aa22 (patch) | |
tree | 7a78a0a39337b5ff0884b006e68b05c4135d7add /usr/src | |
parent | 98e8d17584d08c481c8a827f2311c1e3e6aceabb (diff) | |
download | illumos-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.c | 9 | ||||
-rw-r--r-- | usr/src/uts/common/os/sig.c | 156 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/signotify.c | 11 | ||||
-rw-r--r-- | usr/src/uts/common/syscall/sigprocmask.c | 18 | ||||
-rw-r--r-- | usr/src/uts/intel/ia32/syscall/getcontext.c | 32 | ||||
-rw-r--r-- | usr/src/uts/sparc/syscall/getcontext.c | 37 |
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)); |