diff options
-rw-r--r-- | share/man/man9/Makefile | 1 | ||||
-rw-r--r-- | share/man/man9/timeout.9 | 21 | ||||
-rw-r--r-- | sys/kern/kern_timeout.c | 39 | ||||
-rw-r--r-- | sys/sys/_callout.h | 2 | ||||
-rw-r--r-- | sys/sys/callout.h | 1 |
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) \ |