aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Belousov <kib@FreeBSD.org>2021-03-05 21:19:35 +0000
committerKonstantin Belousov <kib@FreeBSD.org>2021-04-09 20:42:44 +0000
commitdc47fdf1319f18be1aadbcdef17c721a83415d84 (patch)
tree3c4ae1e1290b10e96dcf4f2a7bd467de447f6527
parentee2cf2b3609ee179f39080e0ebe8bf79dcb13461 (diff)
downloadsrc-dc47fdf1319f18be1aadbcdef17c721a83415d84.tar.gz
src-dc47fdf1319f18be1aadbcdef17c721a83415d84.zip
Stop arming periodic process timers on suspend or terminate
Reported and reviewed by: markj Tested by: markj, pho Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D29106
-rw-r--r--sys/kern/kern_sig.c6
-rw-r--r--sys/kern/kern_time.c38
-rw-r--r--sys/kern/sys_process.c1
-rw-r--r--sys/sys/proc.h2
4 files changed, 43 insertions, 4 deletions
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 3d55405d3151..212b4997dd5e 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2322,7 +2322,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
thread_unsuspend(p);
PROC_SUNLOCK(p);
sigqueue_delete(sigqueue, sig);
- goto out;
+ goto out_cont;
}
if (action == SIG_CATCH) {
/*
@@ -2337,7 +2337,7 @@ tdsendsignal(struct proc *p, struct thread *td, int sig, ksiginfo_t *ksi)
*/
thread_unsuspend(p);
PROC_SUNLOCK(p);
- goto out;
+ goto out_cont;
}
if (prop & SIGPROP_STOP) {
@@ -2422,6 +2422,8 @@ runfast:
PROC_SLOCK(p);
thread_unsuspend(p);
PROC_SUNLOCK(p);
+out_cont:
+ itimer_proc_continue(p);
out:
/* If we jump here, proc slock should not be owned. */
PROC_SLOCK_ASSERT(p, MA_NOTOWNED);
diff --git a/sys/kern/kern_time.c b/sys/kern/kern_time.c
index 44f6b4ad07f2..3010ee326105 100644
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -881,6 +881,33 @@ kern_setitimer(struct thread *td, u_int which, struct itimerval *aitv,
return (0);
}
+static void
+realitexpire_reset_callout(struct proc *p, sbintime_t *isbtp)
+{
+ sbintime_t prec;
+
+ prec = isbtp == NULL ? tvtosbt(p->p_realtimer.it_interval) : *isbtp;
+ callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value),
+ prec >> tc_precexp, realitexpire, p, C_ABSOLUTE);
+}
+
+void
+itimer_proc_continue(struct proc *p)
+{
+ struct timeval ctv;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ if ((p->p_flag2 & P2_ITSTOPPED) != 0) {
+ p->p_flag2 &= ~P2_ITSTOPPED;
+ microuptime(&ctv);
+ if (timevalcmp(&p->p_realtimer.it_value, &ctv, >=))
+ realitexpire(p);
+ else
+ realitexpire_reset_callout(p, NULL);
+ }
+}
+
/*
* Real interval timer expired:
* send process whose timer expired an alarm signal.
@@ -908,6 +935,7 @@ realitexpire(void *arg)
wakeup(&p->p_itcallout);
return;
}
+
isbt = tvtosbt(p->p_realtimer.it_interval);
if (isbt >= sbt_timethreshold)
getmicrouptime(&ctv);
@@ -917,8 +945,14 @@ realitexpire(void *arg)
timevaladd(&p->p_realtimer.it_value,
&p->p_realtimer.it_interval);
} while (timevalcmp(&p->p_realtimer.it_value, &ctv, <=));
- callout_reset_sbt(&p->p_itcallout, tvtosbt(p->p_realtimer.it_value),
- isbt >> tc_precexp, realitexpire, p, C_ABSOLUTE);
+
+ if (P_SHOULDSTOP(p) || P_KILLED(p)) {
+ p->p_flag2 |= P2_ITSTOPPED;
+ return;
+ }
+
+ p->p_flag2 &= ~P2_ITSTOPPED;
+ realitexpire_reset_callout(p, &isbt);
}
/*
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 3a184f1d678f..8c0f743aef8a 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1094,6 +1094,7 @@ kern_ptrace(struct thread *td, int req, pid_t pid, void *addr, int data)
p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED);
thread_unsuspend(p);
PROC_SUNLOCK(p);
+ itimer_proc_continue(p);
break;
case PT_WRITE_I:
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index d51ad1093833..8d41b9b20f10 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -825,6 +825,7 @@ struct proc {
MAP_STACK */
#define P2_STKGAP_DISABLE_EXEC 0x00001000 /* Stack gap disabled
after exec */
+#define P2_ITSTOPPED 0x00002000
/* Flags protected by proctree_lock, kept in p_treeflags. */
#define P_TREE_ORPHANED 0x00000001 /* Reparented, on orphan list */
@@ -1091,6 +1092,7 @@ void fork_exit(void (*)(void *, struct trapframe *), void *,
struct trapframe *);
void fork_return(struct thread *, struct trapframe *);
int inferior(struct proc *p);
+void itimer_proc_continue(struct proc *p);
void kern_proc_vmmap_resident(struct vm_map *map, struct vm_map_entry *entry,
int *resident_count, bool *super);
void kern_yield(int);