Page MenuHomeFreeBSD

D29106.id85551.diff
No OneTemporary

D29106.id85551.diff

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

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)

Event Timeline