summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_timeout.c
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2016-03-02 18:46:17 +0000
committerkib <kib@FreeBSD.org>2016-03-02 18:46:17 +0000
commit486320aac47a70ba38fa073d099952762d964f7b (patch)
treec0a34461afd95f99062c6c31c7238d7d0e7e763c /sys/kern/kern_timeout.c
parenta45b6b4d9cfa0c7046106013d930f98c3df904d4 (diff)
downloadFreeBSD-src-486320aac47a70ba38fa073d099952762d964f7b.zip
FreeBSD-src-486320aac47a70ba38fa073d099952762d964f7b.tar.gz
If callout_stop_safe() noted that the callout is currently executing,
but next invocation is cancelled while migrating, sleepq_check_timeout() needs to be informed that the callout is stopped. Otherwise the thread switches off CPU and never become runnable, since running callout could have already raced with us, while the migrating and cancelled callout could be one which is expected to set TDP_TIMOFAIL flag for us. This contradicts with the expected behaviour of callout_stop() for other callers, which e.g. decrement references from the callout callbacks. Add a new flag CS_MIGRBLOCK requesting report of the situation as 'successfully stopped'. Reviewed by: jhb (previous version) Tested by: cognet, pho PR: 200992 Sponsored by: The FreeBSD Foundation MFC after: 2 weeks Differential revision: https://reviews.freebsd.org/D5221
Diffstat (limited to 'sys/kern/kern_timeout.c')
-rw-r--r--sys/kern/kern_timeout.c10
1 files changed, 5 insertions, 5 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 9c9d25f..b13a63f 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -1155,14 +1155,14 @@ callout_schedule(struct callout *c, int to_ticks)
}
int
-_callout_stop_safe(struct callout *c, int safe, void (*drain)(void *))
+_callout_stop_safe(struct callout *c, int flags, void (*drain)(void *))
{
struct callout_cpu *cc, *old_cc;
struct lock_class *class;
int direct, sq_locked, use_lock;
int not_on_a_list;
- if (safe)
+ if ((flags & CS_DRAIN) != 0)
WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, c->c_lock,
"calling %s", __func__);
@@ -1170,7 +1170,7 @@ _callout_stop_safe(struct callout *c, int safe, void (*drain)(void *))
* Some old subsystems don't hold Giant while running a callout_stop(),
* so just discard this check for the moment.
*/
- if (!safe && c->c_lock != NULL) {
+ if ((flags & CS_DRAIN) == 0 && c->c_lock != NULL) {
if (c->c_lock == &Giant.lock_object)
use_lock = mtx_owned(&Giant);
else {
@@ -1253,7 +1253,7 @@ again:
return (-1);
}
- if (safe) {
+ if ((flags & CS_DRAIN) != 0) {
/*
* The current callout is running (or just
* about to run) and blocking is allowed, so
@@ -1370,7 +1370,7 @@ again:
cc_exec_drain(cc, direct) = drain;
}
CC_UNLOCK(cc);
- return (0);
+ return ((flags & CS_MIGRBLOCK) != 0);
}
CTR3(KTR_CALLOUT, "failed to stop %p func %p arg %p",
c, c->c_func, c->c_arg);
OpenPOWER on IntegriCloud