summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/man/man9/Makefile1
-rw-r--r--share/man/man9/timeout.921
-rw-r--r--sys/kern/kern_timeout.c39
-rw-r--r--sys/sys/_callout.h2
-rw-r--r--sys/sys/callout.h1
5 files changed, 64 insertions, 0 deletions
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index 2a10157..268361a 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1641,6 +1641,7 @@ MLINKS+=timeout.9 callout.9 \
timeout.9 callout_active.9 \
timeout.9 callout_deactivate.9 \
timeout.9 callout_drain.9 \
+ timeout.9 callout_drain_async.9 \
timeout.9 callout_handle_init.9 \
timeout.9 callout_init.9 \
timeout.9 callout_init_mtx.9 \
diff --git a/share/man/man9/timeout.9 b/share/man/man9/timeout.9
index 7202815..c859440 100644
--- a/share/man/man9/timeout.9
+++ b/share/man/man9/timeout.9
@@ -36,6 +36,7 @@
.Nm callout_active ,
.Nm callout_deactivate ,
.Nm callout_drain ,
+.Nm callout_drain_async ,
.Nm callout_handle_init ,
.Nm callout_init ,
.Nm callout_init_mtx ,
@@ -70,6 +71,8 @@ typedef void timeout_t (void *);
.Fn callout_deactivate "struct callout *c"
.Ft int
.Fn callout_drain "struct callout *c"
+.Ft int
+.Fn callout_drain_async "struct callout *c" "callout_func_t *fn" "void *arg"
.Ft void
.Fn callout_handle_init "struct callout_handle *handle"
.Bd -literal
@@ -264,6 +267,24 @@ fully stopped before
.Fn callout_drain
returns.
.Pp
+The function
+.Fn callout_drain_async
+is non-blocking and works the same as the
+.Fn callout_stop
+function.
+When this function returns non-zero, do not call it again until the callback function given by
+.Fa fn
+has been called with argument
+.Fa arg .
+Only one of
+.Fn callout_drain
+or
+.Fn callout_drain_async
+should be called at a time to drain a callout.
+If this function returns zero, it is safe to free the callout structure pointed to by the
+.Fa c
+argument immediately.
+.Pp
The
.Fn callout_reset
and
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c
index 71c88e0..950cb0e 100644
--- a/sys/kern/kern_timeout.c
+++ b/sys/kern/kern_timeout.c
@@ -1145,6 +1145,45 @@ callout_schedule(struct callout *c, int to_ticks)
}
int
+callout_drain_async(struct callout *c, callout_func_t *func, void *arg)
+{
+ struct callout_cpu *cc;
+ struct lock_class *class;
+ int retval;
+ int direct;
+
+ /* stop callout */
+ callout_stop(c);
+
+ /* check if callback is being called */
+ cc = callout_lock(c);
+ if (c->c_iflags & CALLOUT_DIRECT) {
+ direct = 1;
+ } else {
+ direct = 0;
+ }
+ retval = (cc_exec_curr(cc, direct) == c);
+
+ /* drop locks, if any */
+ if (retval && c->c_lock != NULL &&
+ c->c_lock != &Giant.lock_object) {
+ /* ensure we are properly locked */
+ class = LOCK_CLASS(c->c_lock);
+ class->lc_assert(c->c_lock, LA_XLOCKED);
+ /* the final callback should not be called locked */
+ c->c_lock = NULL;
+ c->c_iflags |= CALLOUT_RETURNUNLOCKED;
+ }
+ CC_UNLOCK(cc);
+
+ /* check if we should queue final callback */
+ if (retval)
+ callout_reset(c, 1, func, arg);
+
+ return (retval);
+}
+
+int
_callout_stop_safe(struct callout *c, int safe)
{
struct callout_cpu *cc, *old_cc;
diff --git a/sys/sys/_callout.h b/sys/sys/_callout.h
index a9134c8..80fef2a 100644
--- a/sys/sys/_callout.h
+++ b/sys/sys/_callout.h
@@ -46,6 +46,8 @@ LIST_HEAD(callout_list, callout);
SLIST_HEAD(callout_slist, callout);
TAILQ_HEAD(callout_tailq, callout);
+typedef void callout_func_t(void *);
+
struct callout {
union {
LIST_ENTRY(callout) le;
diff --git a/sys/sys/callout.h b/sys/sys/callout.h
index 5e21164..f2841e8 100644
--- a/sys/sys/callout.h
+++ b/sys/sys/callout.h
@@ -82,6 +82,7 @@ struct callout_handle {
#define callout_active(c) ((c)->c_flags & CALLOUT_ACTIVE)
#define callout_deactivate(c) ((c)->c_flags &= ~CALLOUT_ACTIVE)
#define callout_drain(c) _callout_stop_safe(c, 1)
+int callout_drain_async(struct callout *, callout_func_t *, void *);
void callout_init(struct callout *, int);
void _callout_init_lock(struct callout *, struct lock_object *, int);
#define callout_init_mtx(c, mtx, flags) \
OpenPOWER on IntegriCloud