summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authorRoger A. Faulkner <Roger.Faulkner@Sun.COM>2009-06-15 13:26:03 -0700
committerRoger A. Faulkner <Roger.Faulkner@Sun.COM>2009-06-15 13:26:03 -0700
commite0cf54a5673ecf2b9054101898211427b97772f7 (patch)
treefd0f69130bffb55710c42fc60b29dc9f9c3d306d /usr/src/uts/common
parent62224350e5355e6834f7deb9d8a7d062a50cb7c2 (diff)
downloadillumos-joyent-e0cf54a5673ecf2b9054101898211427b97772f7.tar.gz
6719215 profile timer survives exec; handler does not; process crashes with Profile Timer Expired
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/os/exec.c7
-rw-r--r--usr/src/uts/common/os/lwp.c3
-rw-r--r--usr/src/uts/common/os/sig.c46
-rw-r--r--usr/src/uts/common/os/timers.c61
-rw-r--r--usr/src/uts/common/sys/proc.h1
-rw-r--r--usr/src/uts/common/sys/timer.h5
6 files changed, 117 insertions, 6 deletions
diff --git a/usr/src/uts/common/os/exec.c b/usr/src/uts/common/os/exec.c
index 2ca011f17b..7bd4273c1d 100644
--- a/usr/src/uts/common/os/exec.c
+++ b/usr/src/uts/common/os/exec.c
@@ -1801,6 +1801,13 @@ exec_args(execa_t *uap, uarg_t *args, intpdata_t *intp, void **auxvpp)
if (p->p_itimer != NULL)
timer_exit();
+ /*
+ * Delete the ITIMER_REALPROF interval timer.
+ * The other ITIMER_* interval timers are specified
+ * to be inherited across exec().
+ */
+ delete_itimer_realprof();
+
if (audit_active)
audit_exec(args->stk_base, args->stk_base + args->arglen,
args->na - args->ne, args->ne);
diff --git a/usr/src/uts/common/os/lwp.c b/usr/src/uts/common/os/lwp.c
index a4bc1bffd2..bf827dd106 100644
--- a/usr/src/uts/common/os/lwp.c
+++ b/usr/src/uts/common/os/lwp.c
@@ -57,6 +57,7 @@
#include <sys/sdt.h>
#include <sys/cmn_err.h>
#include <sys/brand.h>
+#include <sys/cyclic.h>
/* hash function for the lwpid hash table, p->p_tidhash[] */
#define TIDHASH(tid, hash_sz) ((tid) & ((hash_sz) - 1))
@@ -205,7 +206,7 @@ lwp_create(void (*proc)(), caddr_t arg, size_t len, proc_t *p,
/*
* Allocate the SIGPROF buffer if ITIMER_REALPROF is in effect.
*/
- if (timerisset(&p->p_rprof_timer.it_value))
+ if (p->p_rprof_cyclic != CYCLIC_NONE)
t->t_rprof = kmem_zalloc(sizeof (struct rprof), KM_SLEEP);
if (cid != NOCLASS)
diff --git a/usr/src/uts/common/os/sig.c b/usr/src/uts/common/os/sig.c
index 454b9e600f..481d6575af 100644
--- a/usr/src/uts/common/os/sig.c
+++ b/usr/src/uts/common/os/sig.c
@@ -56,6 +56,7 @@
#include <sys/core.h>
#include <sys/schedctl.h>
#include <sys/contract/process_impl.h>
+#include <sys/cyclic.h>
#include <sys/dtrace.h>
#include <sys/sdt.h>
@@ -2550,6 +2551,51 @@ trapsig(k_siginfo_t *ip, int restartable)
mutex_exit(&p->p_lock);
}
+/*
+ * Arrange for the real time profiling signal to be dispatched.
+ */
+void
+realsigprof(int sysnum, int nsysarg, int error)
+{
+ proc_t *p;
+ klwp_t *lwp;
+
+ 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));
+ mutex_exit(&p->p_lock);
+ return;
+ }
+ if (sigismember(&p->p_ignore, SIGPROF) ||
+ signal_is_blocked(curthread, 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;
+ lwp->lwp_lastfault = 0;
+ lwp->lwp_lastfaddr = NULL;
+ sigtoproc(p, curthread, 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);
+}
+
#ifdef _SYSCALL32_IMPL
/*
diff --git a/usr/src/uts/common/os/timers.c b/usr/src/uts/common/os/timers.c
index fbc204e526..2fc7b7bff2 100644
--- a/usr/src/uts/common/os/timers.c
+++ b/usr/src/uts/common/os/timers.c
@@ -18,8 +18,9 @@
*
* CDDL HEADER END
*/
+
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -519,6 +520,61 @@ xsetitimer(uint_t which, struct itimerval *itv, int iskaddr)
}
/*
+ * Delete the ITIMER_REALPROF interval timer.
+ * Called only from exec_args() when exec occurs.
+ * The other ITIMER_* interval timers are specified
+ * to be inherited across exec(), so leave them alone.
+ */
+void
+delete_itimer_realprof(void)
+{
+ kthread_t *t = curthread;
+ struct proc *p = ttoproc(t);
+ klwp_t *lwp = ttolwp(t);
+ cyclic_id_t cyclic;
+
+ mutex_enter(&p->p_lock);
+
+ /* we are performing execve(); assert we are single-threaded */
+ ASSERT(t == p->p_tlist && t == t->t_forw);
+
+ if ((cyclic = p->p_rprof_cyclic) == CYCLIC_NONE) {
+ mutex_exit(&p->p_lock);
+ } else {
+ p->p_rprof_cyclic = CYCLIC_NONE;
+ /*
+ * Delete any current instance of SIGPROF.
+ */
+ if (lwp->lwp_cursig == SIGPROF) {
+ lwp->lwp_cursig = 0;
+ lwp->lwp_extsig = 0;
+ if (lwp->lwp_curinfo) {
+ siginfofree(lwp->lwp_curinfo);
+ lwp->lwp_curinfo = NULL;
+ }
+ }
+ /*
+ * Delete any pending instances of SIGPROF.
+ */
+ sigdelset(&p->p_sig, SIGPROF);
+ sigdelset(&p->p_extsig, SIGPROF);
+ sigdelq(p, NULL, SIGPROF);
+ sigdelset(&t->t_sig, SIGPROF);
+ sigdelset(&t->t_extsig, SIGPROF);
+ sigdelq(p, t, SIGPROF);
+
+ mutex_exit(&p->p_lock);
+
+ /*
+ * Remove the ITIMER_REALPROF cyclic.
+ */
+ mutex_enter(&cpu_lock);
+ cyclic_remove(cyclic);
+ mutex_exit(&cpu_lock);
+ }
+}
+
+/*
* Real interval timer expired:
* send process whose timer expired an alarm signal.
* If time is not set up to reload, then just return.
@@ -578,7 +634,8 @@ realprofexpire(void *arg)
kthread_t *t;
mutex_enter(&p->p_lock);
- if ((t = p->p_tlist) == NULL) {
+ if (p->p_rprof_cyclic == CYCLIC_NONE ||
+ (t = p->p_tlist) == NULL) {
mutex_exit(&p->p_lock);
return;
}
diff --git a/usr/src/uts/common/sys/proc.h b/usr/src/uts/common/sys/proc.h
index 43407bab38..daacb058f7 100644
--- a/usr/src/uts/common/sys/proc.h
+++ b/usr/src/uts/common/sys/proc.h
@@ -613,6 +613,7 @@ extern void psignal(proc_t *, int);
extern void tsignal(kthread_t *, int);
extern void sigtoproc(proc_t *, kthread_t *, int);
extern void trapsig(k_siginfo_t *, int);
+extern void realsigprof(int, int, int);
extern int eat_signal(kthread_t *, int);
extern int signal_is_blocked(kthread_t *, int);
extern int sigcheck(proc_t *, kthread_t *);
diff --git a/usr/src/uts/common/sys/timer.h b/usr/src/uts/common/sys/timer.h
index 05d08bb489..604ddf5d83 100644
--- a/usr/src/uts/common/sys/timer.h
+++ b/usr/src/uts/common/sys/timer.h
@@ -20,15 +20,13 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#ifndef _SYS_TIMER_H
#define _SYS_TIMER_H
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#include <sys/proc.h>
#include <sys/thread.h>
@@ -106,6 +104,7 @@ extern void timespecsub(timespec_t *, timespec_t *);
extern void timespecfix(timespec_t *);
extern int xgetitimer(uint_t, struct itimerval *, int);
extern int xsetitimer(uint_t, struct itimerval *, int);
+extern void delete_itimer_realprof(void);
#define timerspecisset(tvp) ((tvp)->tv_sec || (tvp)->tv_nsec)
#define timerspeccmp(tvp, uvp) (((tvp)->tv_sec - (uvp)->tv_sec) ? \