Page MenuHomeFreeBSD

D7042.id18124.diff
No OneTemporary

D7042.id18124.diff

Index: share/man/man9/timeout.9
===================================================================
--- share/man/man9/timeout.9
+++ share/man/man9/timeout.9
@@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 14, 2015
+.Dd July 4, 2016
.Dt TIMEOUT 9
.Os
.Sh NAME
@@ -247,6 +247,10 @@
negative one is returned.
If the callout is currently being serviced and cannot be stopped,
then zero will be returned.
+If the callout is currently being serviced and cannot be stopped, and at the
+same time a next invocation of the same callout is also scheduled, then
+.Fn callout_stop
+unschedules the next run and returns zero.
If the callout has an associated lock,
then that lock must be held when this function is called.
.Pp
@@ -814,7 +818,7 @@
.Fn callout_drain
functions return a value of one if the callout was still pending when it was
called, a zero if the callout could not be stopped and a negative one is it
-was either not running or haas already completed.
+was either not running or has already completed.
The
.Fn timeout
function returns a
Index: sys/kern/kern_timeout.c
===================================================================
--- sys/kern/kern_timeout.c
+++ sys/kern/kern_timeout.c
@@ -681,7 +681,7 @@
if (c->c_iflags & CALLOUT_LOCAL_ALLOC)
c->c_iflags = CALLOUT_LOCAL_ALLOC;
else
- c->c_iflags &= ~CALLOUT_PENDING;
+ c->c_iflags &= ~(CALLOUT_PENDING | CALLOUT_PROCESSED);
cc_exec_curr(cc, direct) = c;
cc_exec_cancel(cc, direct) = false;
@@ -1088,6 +1088,7 @@
LIST_REMOVE(c, c_links.le);
} else {
TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe);
+ c->c_iflags &= ~CALLOUT_PROCESSED;
}
cancelled = 1;
c->c_iflags &= ~ CALLOUT_PENDING;
@@ -1166,7 +1167,7 @@
struct callout_cpu *cc, *old_cc;
struct lock_class *class;
int direct, sq_locked, use_lock;
- int not_on_a_list;
+ int cancelled, not_on_a_list;
if ((flags & CS_DRAIN) != 0)
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, c->c_lock,
@@ -1236,28 +1237,14 @@
}
/*
- * If the callout isn't pending, it's not on the queue, so
- * don't attempt to remove it from the queue. We can try to
- * stop it by other means however.
+ * If the callout is running, try to stop it or drain it.
*/
- if (!(c->c_iflags & CALLOUT_PENDING)) {
+ if (cc_exec_curr(cc, direct) == c) {
/*
- * If it wasn't on the queue and it isn't the current
- * callout, then we can't stop it, so just bail.
- * It probably has already been run (if locking
- * is properly done). You could get here if the caller
- * calls stop twice in a row for example. The second
- * call would fall here without CALLOUT_ACTIVE set.
+ * Succeed we to stop it or not, we must clear the
+ * active flag - this is what API users expect.
*/
c->c_flags &= ~CALLOUT_ACTIVE;
- if (cc_exec_curr(cc, direct) != c) {
- CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p",
- c, c->c_func, c->c_arg);
- CC_UNLOCK(cc);
- if (sq_locked)
- sleepq_release(&cc_exec_waiting(cc, direct));
- return (-1);
- }
if ((flags & CS_DRAIN) != 0) {
/*
@@ -1383,13 +1370,21 @@
if (drain) {
cc_exec_drain(cc, direct) = drain;
}
- CC_UNLOCK(cc);
KASSERT(!sq_locked, ("sleepqueue chain still locked"));
- return (0);
- }
+ cancelled = 0;
+ } else
+ cancelled = 1;
+
if (sq_locked)
sleepq_release(&cc_exec_waiting(cc, direct));
+ if ((c->c_iflags & CALLOUT_PENDING) == 0) {
+ CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p",
+ c, c->c_func, c->c_arg);
+ CC_UNLOCK(cc);
+ return (cancelled);
+ }
+
c->c_iflags &= ~CALLOUT_PENDING;
c->c_flags &= ~CALLOUT_ACTIVE;
@@ -1402,11 +1397,12 @@
LIST_REMOVE(c, c_links.le);
} else {
TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe);
+ c->c_iflags &= ~CALLOUT_PROCESSED;
}
}
callout_cc_del(c, cc);
CC_UNLOCK(cc);
- return (1);
+ return (cancelled);
}
void

File Metadata

Mime Type
text/plain
Expires
Thu, Jan 15, 11:45 AM (7 h, 26 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
27648685
Default Alt Text
D7042.id18124.diff (3 KB)

Event Timeline