1
0
mirror of https://github.com/openbsd/src.git synced 2025-01-10 06:47:55 -08:00

Fix delivery of SIGPROF and SIGVTALRM to threaded processes by having

hardclock() set a flag on the running thread and force AST processing,
and then have the thread signal itself from userret().

idea and flag names from FreeBSD
ok jsing@
This commit is contained in:
guenther 2013-10-08 03:50:06 +00:00
parent 2e5c7789a6
commit a554f8d9c2
8 changed files with 40 additions and 59 deletions

View File

@ -1,4 +1,4 @@
.\" $OpenBSD: ps.1,v 1.84 2013/09/22 17:28:34 guenther Exp $
.\" $OpenBSD: ps.1,v 1.85 2013/10/08 03:50:08 guenther Exp $
.\" $NetBSD: ps.1,v 1.16 1996/03/21 01:36:28 jtc Exp $
.\"
.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
@ -30,7 +30,7 @@
.\"
.\" @(#)ps.1 8.3 (Berkeley) 4/18/94
.\"
.Dd $Mdocdate: September 22 2013 $
.Dd $Mdocdate: October 8 2013 $
.Dt PS 1
.Os
.Sh NAME
@ -222,6 +222,8 @@ The thread flags (in hexadecimal), as defined in the include file
.Aq Pa sys/proc.h :
.Bd -literal
P_INKTR 0x1 writing ktrace(2) record
P_PROFPEND 0x2 this thread needs SIGPROF
P_ALRMPEND 0x4 this thread needs SIGVTALRM
P_SIGSUSPEND 0x8 need to restore before-suspend mask
P_SELECT 0x40 selecting; wakeup/waiting danger
P_SINTR 0x80 sleep is interruptible

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kern_clock.c,v 1.82 2013/08/13 05:52:23 guenther Exp $ */
/* $OpenBSD: kern_clock.c,v 1.83 2013/10/08 03:50:07 guenther Exp $ */
/* $NetBSD: kern_clock.c,v 1.34 1996/06/09 04:51:03 briggs Exp $ */
/*-
@ -144,40 +144,11 @@ initclocks(void)
/*
* hardclock does the accounting needed for ITIMER_PROF and ITIMER_VIRTUAL.
* We don't want to send signals with psignal from hardclock because it makes
* MULTIPROCESSOR locking very complicated. Instead we use a small trick
* to send the signals safely and without blocking too many interrupts
* while doing that (signal handling can be heavy).
*
* hardclock detects that the itimer has expired, and schedules a timeout
* to deliver the signal. This works because of the following reasons:
* - The timeout can be scheduled with a 1 tick time because we're
* doing it before the timeout processing in hardclock. So it will
* be scheduled to run as soon as possible.
* - The timeout will be run in softclock which will run before we
* return to userland and process pending signals.
* - If the system is so busy that several VIRTUAL/PROF ticks are
* sent before softclock processing, we'll send only one signal.
* But if we'd send the signal from hardclock only one signal would
* be delivered to the user process. So userland will only see one
* signal anyway.
* MULTIPROCESSOR locking very complicated. Instead, to use an idea from
* FreeBSD, we set a flag on the thread and when it goes to return to
* userspace it signals itself.
*/
void
virttimer_trampoline(void *v)
{
struct process *pr = v;
psignal(pr->ps_mainproc, SIGVTALRM);
}
void
proftimer_trampoline(void *v)
{
struct process *pr = v;
psignal(pr->ps_mainproc, SIGPROF);
}
/*
* The real-time timer, interrupting hz times per second.
*/
@ -196,11 +167,15 @@ hardclock(struct clockframe *frame)
*/
if (CLKF_USERMODE(frame) &&
timerisset(&pr->ps_timer[ITIMER_VIRTUAL].it_value) &&
itimerdecr(&pr->ps_timer[ITIMER_VIRTUAL], tick) == 0)
timeout_add(&pr->ps_virt_to, 1);
itimerdecr(&pr->ps_timer[ITIMER_VIRTUAL], tick) == 0) {
atomic_setbits_int(&p->p_flag, P_ALRMPEND);
need_proftick(p);
}
if (timerisset(&pr->ps_timer[ITIMER_PROF].it_value) &&
itimerdecr(&pr->ps_timer[ITIMER_PROF], tick) == 0)
timeout_add(&pr->ps_prof_to, 1);
itimerdecr(&pr->ps_timer[ITIMER_PROF], tick) == 0) {
atomic_setbits_int(&p->p_flag, P_PROFPEND);
need_proftick(p);
}
}
/*

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kern_exit.c,v 1.127 2013/09/14 01:35:00 guenther Exp $ */
/* $OpenBSD: kern_exit.c,v 1.128 2013/10/08 03:50:07 guenther Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@ -185,8 +185,6 @@ exit1(struct proc *p, int rv, int flags)
if ((p->p_flag & P_THREAD) == 0) {
timeout_del(&pr->ps_realit_to);
timeout_del(&pr->ps_virt_to);
timeout_del(&pr->ps_prof_to);
#ifdef SYSVSEM
semexit(pr);
#endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kern_fork.c,v 1.153 2013/08/14 05:26:14 guenther Exp $ */
/* $OpenBSD: kern_fork.c,v 1.154 2013/10/08 03:50:07 guenther Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@ -183,8 +183,6 @@ process_new(struct proc *p, struct process *parent)
pr->ps_limit->p_refcnt++;
timeout_set(&pr->ps_realit_to, realitexpire, pr);
timeout_set(&pr->ps_virt_to, virttimer_trampoline, pr);
timeout_set(&pr->ps_prof_to, proftimer_trampoline, pr);
pr->ps_flags = parent->ps_flags & (PS_SUGID | PS_SUGIDEXEC);
if (parent->ps_session->s_ttyvp != NULL &&

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kern_sig.c,v 1.154 2013/10/08 03:36:48 guenther Exp $ */
/* $OpenBSD: kern_sig.c,v 1.155 2013/10/08 03:50:07 guenther Exp $ */
/* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */
/*
@ -1748,6 +1748,20 @@ userret(struct proc *p)
{
int sig;
/* send SIGPROF or SIGVTALRM if their timers interrupted this thread */
if (p->p_flag & P_PROFPEND) {
atomic_clearbits_int(&p->p_flag, P_PROFPEND);
KERNEL_LOCK();
psignal(p, SIGPROF);
KERNEL_UNLOCK();
}
if (p->p_flag & P_ALRMPEND) {
atomic_clearbits_int(&p->p_flag, P_ALRMPEND);
KERNEL_LOCK();
psignal(p, SIGVTALRM);
KERNEL_UNLOCK();
}
while ((sig = CURSIG(p)) != 0)
postsig(sig);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: kern_time.c,v 1.83 2013/10/06 01:27:50 guenther Exp $ */
/* $OpenBSD: kern_time.c,v 1.84 2013/10/08 03:50:08 guenther Exp $ */
/* $NetBSD: kern_time.c,v 1.20 1996/02/18 11:57:06 fvdl Exp $ */
/*
@ -571,10 +571,6 @@ sys_setitimer(struct proc *p, void *v, register_t *retval)
itimerround(&aitv.it_interval);
s = splclock();
pr->ps_timer[which] = aitv;
if (which == ITIMER_VIRTUAL)
timeout_del(&pr->ps_virt_to);
if (which == ITIMER_PROF)
timeout_del(&pr->ps_prof_to);
splx(s);
}

View File

@ -1,4 +1,4 @@
/* $OpenBSD: proc.h,v 1.170 2013/09/22 17:28:33 guenther Exp $ */
/* $OpenBSD: proc.h,v 1.171 2013/10/08 03:50:06 guenther Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@ -209,8 +209,6 @@ struct process {
struct timespec ps_start; /* starting time. */
struct timeout ps_realit_to; /* real-time itimer trampoline. */
struct timeout ps_virt_to; /* virtual itimer trampoline. */
struct timeout ps_prof_to; /* prof itimer trampoline. */
int ps_refcnt; /* Number of references. */
};
@ -362,6 +360,8 @@ struct proc {
* These flags are per-thread and kept in p_flag
*/
#define P_INKTR 0x000001 /* In a ktrace op, don't recurse */
#define P_PROFPEND 0x000002 /* SIGPROF needs to be posted */
#define P_ALRMPEND 0x000004 /* SIGVTALRM needs to be posted */
#define P_SIGSUSPEND 0x000008 /* Need to restore before-suspend mask*/
#define P_SELECT 0x000040 /* Selecting; wakeup/waiting danger. */
#define P_SINTR 0x000080 /* Sleep is interruptible. */
@ -380,7 +380,8 @@ struct proc {
#define P_CPUPEG 0x40000000 /* Do not move to another cpu. */
#define P_BITS \
("\20\01INKTR\04SIGSUSPEND\07SELECT\010SINTR\012SYSTEM" \
("\20\01INKTR\02PROFPEND\03ALRMPEND\04SIGSUSPEND\07SELECT" \
"\010SINTR\012SYSTEM" \
"\013TIMEOUT\016WEXIT\020OWEUPC\024SUSPSINGLE" \
"\025NOZOMBIE\027SYSTRACE\030CONTINUED\033THREAD" \
"\034SUSPSIG\035SOFTDEP\036STOPPED\037CPUPEG")

View File

@ -1,4 +1,4 @@
/* $OpenBSD: resourcevar.h,v 1.16 2013/06/03 16:55:22 guenther Exp $ */
/* $OpenBSD: resourcevar.h,v 1.17 2013/10/08 03:50:07 guenther Exp $ */
/* $NetBSD: resourcevar.h,v 1.12 1995/11/22 23:01:53 cgd Exp $ */
/*
@ -68,8 +68,5 @@ struct plimit *limcopy(struct plimit *);
void limfree(struct plimit *);
void ruadd(struct rusage *, struct rusage *);
void virttimer_trampoline(void *);
void proftimer_trampoline(void *);
#endif
#endif /* !_SYS_RESOURCEVAR_H_ */