Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157326132
D29106.id85551.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D29106.id85551.diff
View Options
diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c
--- a/sys/kern/init_main.c
+++ b/sys/kern/init_main.c
@@ -524,6 +524,7 @@
callout_init_mtx(&p->p_itcallout, &p->p_mtx, 0);
callout_init_mtx(&p->p_limco, &p->p_mtx, 0);
callout_init(&td->td_slpcallout, 1);
+ TAILQ_INIT(&p->p_kqtim_stop);
/* Create credentials. */
newcred = crget();
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -676,28 +676,81 @@
struct kq_timer_cb_data {
struct callout c;
+ struct proc *p;
+ struct knote *kn;
+ int cpuid;
+ TAILQ_ENTRY(kq_timer_cb_data) link;
sbintime_t next; /* next timer event fires at */
sbintime_t to; /* precalculated timer period, 0 for abs */
};
+static void
+kqtimer_sched_callout(struct kq_timer_cb_data *kc)
+{
+ callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kc->kn,
+ kc->cpuid, C_ABSOLUTE);
+}
+
+void
+kqtimer_proc_continue(struct proc *p)
+{
+ struct kq_timer_cb_data *kc, *kc1;
+ struct bintime bt;
+ sbintime_t now;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ getboottimebin(&bt);
+ now = bttosbt(bt);
+
+ TAILQ_FOREACH_SAFE(kc, &p->p_kqtim_stop, link, kc1) {
+ TAILQ_REMOVE(&p->p_kqtim_stop, kc, link);
+ if (kc->next <= now)
+ filt_timerexpire(kc->kn);
+ else
+ kqtimer_sched_callout(kc);
+ }
+}
+
static void
filt_timerexpire(void *knx)
{
struct knote *kn;
struct kq_timer_cb_data *kc;
+ struct proc *p;
+ sbintime_t now;
kn = knx;
- kn->kn_data++;
- KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */
-
- if ((kn->kn_flags & EV_ONESHOT) != 0)
- return;
kc = kn->kn_ptr.p_v;
- if (kc->to == 0)
+
+ if ((kn->kn_flags & EV_ONESHOT) != 0 || kc->to == 0) {
+ kn->kn_data++;
+ KNOTE_ACTIVATE(kn, 0);
return;
- kc->next += kc->to;
- callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
- PCPU_GET(cpuid), C_ABSOLUTE);
+ }
+
+ for (now = sbinuptime(); kc->next <= now; kc->next += kc->to)
+ kn->kn_data++;
+ KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */
+
+ /*
+ * Initial check for stopped kc->p is racy. It is fine to
+ * miss the set of the stop flags, at worst we would schedule
+ * one more callout. On the other hand, it is not fine to not
+ * schedule when we we missed clearing of the flags, we
+ * recheck them under the lock and observe consistent state.
+ */
+ p = kc->p;
+ if (P_SHOULDSTOP(p) || P_KILLED(p)) {
+ PROC_LOCK(p);
+ if (P_SHOULDSTOP(p) || P_KILLED(p)) {
+ TAILQ_INSERT_TAIL(&p->p_kqtim_stop, kc, link);
+ PROC_UNLOCK(p);
+ return;
+ }
+ PROC_UNLOCK(p);
+ }
+ kqtimer_sched_callout(kc);
}
/*
@@ -753,6 +806,9 @@
kn->kn_flags |= EV_CLEAR; /* automatically set */
kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */
kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK);
+ kc->kn = kn;
+ kc->p = curproc;
+ kc->cpuid = PCPU_GET(cpuid);
callout_init(&kc->c, 1);
filt_timerstart(kn, to);
@@ -772,8 +828,7 @@
kc->next = to + sbinuptime();
kc->to = to;
}
- callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn,
- PCPU_GET(cpuid), C_ABSOLUTE);
+ kqtimer_sched_callout(kc);
}
static void
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -598,6 +598,7 @@
LIST_INIT(&p2->p_orphans);
callout_init_mtx(&p2->p_itcallout, &p2->p_mtx, 0);
+ TAILQ_INIT(&p2->p_kqtim_stop);
/*
* This begins the section where we must prevent the parent
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -2316,7 +2316,7 @@
thread_unsuspend(p);
PROC_SUNLOCK(p);
sigqueue_delete(sigqueue, sig);
- goto out;
+ goto out_cont;
}
if (action == SIG_CATCH) {
/*
@@ -2331,7 +2331,7 @@
*/
thread_unsuspend(p);
PROC_SUNLOCK(p);
- goto out;
+ goto out_cont;
}
if (prop & SIGPROP_STOP) {
@@ -2416,6 +2416,9 @@
PROC_SLOCK(p);
thread_unsuspend(p);
PROC_SUNLOCK(p);
+out_cont:
+ itimer_proc_continue(p);
+ kqtimer_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
--- a/sys/kern/kern_time.c
+++ b/sys/kern/kern_time.c
@@ -881,6 +881,50 @@
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;
+ struct itimer *it;
+ int id;
+
+ 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);
+ }
+
+ for (id = 3; id < TIMER_MAX; id++) {
+ it = p->p_itimers->its_timers[id];
+ if (it == NULL)
+ continue;
+ if ((it->it_flags & ITF_PSTOPPED) != 0) {
+ ITIMER_LOCK(it);
+ if ((it->it_flags & ITF_PSTOPPED) != 0) {
+ it->it_flags &= ~ITF_PSTOPPED;
+ if ((it->it_flags & ITF_DELETING) == 0)
+ realtimer_expire(it);
+ }
+ ITIMER_UNLOCK(it);
+ }
+ }
+}
+
/*
* Real interval timer expired:
* send process whose timer expired an alarm signal.
@@ -908,6 +952,7 @@
wakeup(&p->p_itcallout);
return;
}
+
isbt = tvtosbt(p->p_realtimer.it_interval);
if (isbt >= sbt_timethreshold)
getmicrouptime(&ctv);
@@ -917,8 +962,14 @@
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);
}
/*
@@ -1617,6 +1668,7 @@
struct timespec cts, ts;
struct timeval tv;
struct itimer *it;
+ struct proc *p;
uint64_t interval, now, overruns, value;
it = (struct itimer *)arg;
@@ -1655,10 +1707,15 @@
timespecclear(&it->it_time.it_value);
}
if (timespecisset(&it->it_time.it_value)) {
- timespecsub(&it->it_time.it_value, &cts, &ts);
- TIMESPEC_TO_TIMEVAL(&tv, &ts);
- callout_reset(&it->it_callout, tvtohz(&tv),
- realtimer_expire, it);
+ p = it->it_proc;
+ if (P_SHOULDSTOP(p) || P_KILLED(p)) {
+ it->it_flags |= ITF_PSTOPPED;
+ } else {
+ timespecsub(&it->it_time.it_value, &cts, &ts);
+ TIMESPEC_TO_TIMEVAL(&tv, &ts);
+ callout_reset(&it->it_callout, tvtohz(&tv),
+ realtimer_expire, it);
+ }
}
itimer_enter(it);
ITIMER_UNLOCK(it);
@@ -1666,11 +1723,16 @@
ITIMER_LOCK(it);
itimer_leave(it);
} else if (timespecisset(&it->it_time.it_value)) {
- ts = it->it_time.it_value;
- timespecsub(&ts, &cts, &ts);
- TIMESPEC_TO_TIMEVAL(&tv, &ts);
- callout_reset(&it->it_callout, tvtohz(&tv), realtimer_expire,
- it);
+ p = it->it_proc;
+ if (P_SHOULDSTOP(p) || P_KILLED(p)) {
+ it->it_flags |= ITF_PSTOPPED;
+ } else {
+ ts = it->it_time.it_value;
+ timespecsub(&ts, &cts, &ts);
+ TIMESPEC_TO_TIMEVAL(&tv, &ts);
+ callout_reset(&it->it_callout, tvtohz(&tv),
+ realtimer_expire, it);
+ }
}
}
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1094,6 +1094,8 @@
p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED);
thread_unsuspend(p);
PROC_SUNLOCK(p);
+ itimer_proc_continue(p);
+ kqtimer_proc_continue(p);
break;
case PT_WRITE_I:
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -183,6 +183,7 @@
struct kcov_info;
struct kdtrace_proc;
struct kdtrace_thread;
+struct kq_timer_cb_data;
struct mqueue_notifier;
struct p_sched;
struct proc;
@@ -727,6 +728,8 @@
*/
LIST_ENTRY(proc) p_orphan; /* (e) List of orphan processes. */
LIST_HEAD(, proc) p_orphans; /* (e) Pointer to list of orphans. */
+
+ TAILQ_HEAD(, kq_timer_cb_data) p_kqtim_stop; /* (c) */
};
#define p_session p_pgrp->pg_session
@@ -825,6 +828,7 @@
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 */
@@ -1090,6 +1094,8 @@
struct trapframe *);
void fork_return(struct thread *, struct trapframe *);
int inferior(struct proc *p);
+void itimer_proc_continue(struct proc *p);
+void kqtimer_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);
diff --git a/sys/sys/timers.h b/sys/sys/timers.h
--- a/sys/sys/timers.h
+++ b/sys/sys/timers.h
@@ -82,6 +82,7 @@
#define ITF_DELETING 0x01
#define ITF_WANTED 0x02
+#define ITF_PSTOPPED 0x04
#define ITCF_ONWORKLIST 0x01
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, May 21, 8:49 AM (15 h, 22 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33367159
Default Alt Text
D29106.id85551.diff (8 KB)
Attached To
Mode
D29106: Stop posix realtime timer and kqueue EVFILT_TIMER timers around process stop and kill
Attached
Detach File
Event Timeline
Log In to Comment