Page MenuHomeFreeBSD

D29106.id85258.diff
No OneTemporary

D29106.id85258.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,79 @@
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_continued(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;
+ 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.
+ */
+ if (P_SHOULDSTOP(kc->p) || P_KILLED(kc->p)) {
+ PROC_LOCK(kc->p);
+ if (P_SHOULDSTOP(kc->p) || P_KILLED(kc->p)) {
+ TAILQ_INSERT_TAIL(&kc->p->p_kqtim_stop, kc, link);
+ PROC_UNLOCK(kc->p);
+ return;
+ }
+ PROC_UNLOCK(kc->p);
+ }
+ kqtimer_sched_callout(kc);
}
/*
@@ -753,6 +804,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 +826,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_continued(p);
+ kqtimer_proc_continued(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,33 @@
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_continued(struct proc *p)
+{
+ struct timeval ctv;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ if ((p->p_flag2 & P2_ITSTOPPED) == 0)
+ return;
+
+ 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 @@
wakeup(&p->p_itcallout);
return;
}
+
isbt = tvtosbt(p->p_realtimer.it_interval);
if (isbt >= sbt_timethreshold)
getmicrouptime(&ctv);
@@ -917,8 +945,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);
}
/*
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_continued(p);
+ kqtimer_proc_continued(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_continued(struct proc *p);
+void kqtimer_proc_continued(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);

File Metadata

Mime Type
text/plain
Expires
Fri, Oct 24, 11:32 PM (4 h, 7 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24149649
Default Alt Text
D29106.id85258.diff (7 KB)

Event Timeline