summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_timeout.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/kern_timeout.c')
-rw-r--r--sys/kern/kern_timeout.c23
1 files changed, 19 insertions, 4 deletions
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 70d558c..679430f 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -230,11 +230,8 @@ softclock(void *dummy)
c_arg = c->c_arg;
c_flags = c->c_flags;
if (c->c_flags & CALLOUT_LOCAL_ALLOC) {
- c->c_func = NULL;
c->c_flags = CALLOUT_LOCAL_ALLOC;
- SLIST_INSERT_HEAD(&callfree, c,
- c_links.sle);
- curr_callout = NULL;
+ curr_callout = c;
} else {
c->c_flags =
(c->c_flags & ~CALLOUT_PENDING);
@@ -299,6 +296,24 @@ softclock(void *dummy)
class->lc_unlock(c_lock);
skip:
mtx_lock_spin(&callout_lock);
+ /*
+ * If the current callout is locally
+ * allocated (from timeout(9))
+ * then put it on the freelist.
+ *
+ * Note: we need to check the cached
+ * copy of c_flags because if it was not
+ * local, then it's not safe to deref the
+ * callout pointer.
+ */
+ if (c_flags & CALLOUT_LOCAL_ALLOC) {
+ KASSERT(c->c_flags ==
+ CALLOUT_LOCAL_ALLOC,
+ ("corrupted callout"));
+ c->c_func = NULL;
+ SLIST_INSERT_HEAD(&callfree, c,
+ c_links.sle);
+ }
curr_callout = NULL;
if (callout_wait) {
/*
OpenPOWER on IntegriCloud