On Thu, Jun 24, 2021 at 05:39:56PM -0500, Scott Cheloha wrote: > On Thu, Jun 24, 2021 at 06:51:07AM +0100, Jason McIntyre wrote: > > On Wed, Jun 23, 2021 at 06:57:00PM -0500, Scott Cheloha wrote: > > > Hi, > > > > > > I want to document kclock timeouts so others can use them. > > > > morning. reads fine, except one issue: > > > > [...] > > > > > +.Bl -tag -width kclock > > > +.It Fa kclock > > > +The timeout is scheduled against the given > > > +.Fa kclock, > > > > you need a space between kclock and the comma > > Huh, I'm a little surprised -Tlint doesn't flag that. >
it did! you must have just missed it somehow. > Fixed. > > Are there any other mdoc(7)-type stylistic anachronisms we can fix up? > everything else looked ok. jmc > Index: share/man/man9/timeout.9 > =================================================================== > RCS file: /cvs/src/share/man/man9/timeout.9,v > retrieving revision 1.53 > diff -u -p -r1.53 timeout.9 > --- share/man/man9/timeout.9 11 May 2021 13:29:25 -0000 1.53 > +++ share/man/man9/timeout.9 24 Jun 2021 22:37:38 -0000 > @@ -44,7 +44,7 @@ > .Nm timeout_triggered , > .Nm TIMEOUT_INITIALIZER , > .Nm TIMEOUT_INITIALIZER_FLAGS > -.Nd execute a function after a specified period of time > +.Nd execute a function in the future > .Sh SYNOPSIS > .In sys/types.h > .In sys/timeout.h > @@ -55,12 +55,13 @@ > .Fa "struct timeout *to" > .Fa "void (*fn)(void *)" > .Fa "void *arg" > +.Fa "int kclock" > .Fa "int flags" > .Fc > .Ft void > .Fn timeout_set_proc "struct timeout *to" "void (*fn)(void *)" "void *arg" > .Ft int > -.Fn timeout_add "struct timeout *to" "int ticks" > +.Fn timeout_add "struct timeout *to" "int nticks" > .Ft int > .Fn timeout_del "struct timeout *to" > .Ft int > @@ -83,174 +84,218 @@ > .Fn timeout_add_usec "struct timeout *to" "int usec" > .Ft int > .Fn timeout_add_nsec "struct timeout *to" "int nsec" > -.Fn TIMEOUT_INITIALIZER "void (*fn)(void *)" "void *arg" > -.Fn TIMEOUT_INITIALIZER_FLAGS "void (*fn)(void *)" "void *arg" "int flags" > +.Ft int > +.Fn timeout_in_nsec "struct timeout *to" "uint64_t nsecs" > +.Ft int > +.Fn timeout_at_ts "struct timeout *to" "const struct timespec *abs" > +.Fo TIMEOUT_INITIALIZER > +.Fa "void (*fn)(void *)" > +.Fa "void *arg" > +.Fc > +.Fo TIMEOUT_INITIALIZER_FLAGS > +.Fa "void (*fn)(void *)" > +.Fa "void *arg" > +.Fa "int kclock" > +.Fa "int flags" > +.Fc > .Sh DESCRIPTION > The > .Nm timeout > -API provides a mechanism to execute a function at a given time. > -The granularity of the time is limited by the granularity of the > -.Xr hardclock 9 > -timer which executes > -.Xr hz 9 > -times a second. > +API provides a mechanism to schedule a function for asynchronous > +execution in the future. > .Pp > -It is the responsibility of the caller to provide these functions with > -pre-allocated timeout structures. > +All state is encapsulated in a caller-allocated timeout structure > +.Pq hereafter, a Qo timeout Qc . > +A timeout must be initialized before it may be used as input to other > +functions in the API. > .Pp > The > .Fn timeout_set > -function prepares the timeout structure > -.Fa to > -to be used in future calls to > -.Fn timeout_add > -and > -.Fn timeout_del . > -The timeout will be prepared to call the function specified by the > +function initializes the timeout > +.Fa to . > +When executed, > +the timeout will call the function > .Fa fn > -argument with a > -.Fa void * > -argument given in the > +with > .Fa arg > -argument. > -Once initialized, the > -.Fa to > -structure can be used repeatedly in > -.Fn timeout_add > -and > -.Fn timeout_del > -and does not need to be reinitialized unless > -the function called and/or its argument must change. > +as its first parameter. > +The timeout is implicitly scheduled against the > +.Dv KCLOCK_NONE > +clock and is not configured with any additional flags. > .Pp > The > .Fn timeout_set_flags > function is similar to > -.Fn timeout_set > -but it additionally accepts the bitwise OR of zero or more of the > -following > +.Fn timeout_set , > +except that it takes two additional parameters: > +.Bl -tag -width kclock > +.It Fa kclock > +The timeout is scheduled against the given > +.Fa kclock , > +which must be one of the following: > +.Bl -tag -width KCLOCK_UPTIME > +.It Dv KCLOCK_NONE > +Low resolution tick-based clock. > +The granularity of this clock is limited by the > +.Xr hardclock 9 , > +which executes roughly > +.Xr hz 9 > +times per second. > +.It Dv KCLOCK_UPTIME > +The uptime clock. > +Counts the time elapsed since the system booted. > +.El > +.It Fa flags > +The timeout's behavior may be configured with the bitwise OR of > +zero or more of the following > .Fa flags : > -.Bl -tag -width TIMEOUT_PROC -offset indent > +.Bl -tag -width TIMEOUT_PROC > .It Dv TIMEOUT_PROC > -Runs the timeout in a process context instead of the default > +Execute the timeout in a process context instead of the default > .Dv IPL_SOFTCLOCK > interrupt context. > .El > +.El > .Pp > The > .Fn timeout_set_proc > -function is similar to > +function is equivalent to > +.Fn timeout_set , > +except that the given timeout is configured with the > +.Dv TIMEOUT_PROC > +flag. > +.Pp > +A timeout may also be initialized statically. > +The > +.Fn TIMEOUT_INITIALIZER > +macro is equivalent to the > .Fn timeout_set > -but it runs the timeout in a process context instead of the default > -.Dv IPL_SOFTCLOCK > -interrupt context. > +function and the > +.Fn TIMEOUT_INITIALIZER_FLAGS > +macro is equivalent to the > +.Fn timeout_set_flags > +function. > .Pp > -The function > -.Fn timeout_add > -schedules the execution of the > +The interfaces available for scheduling a timeout vary with the timeout's > +.Fa kclock . > +.Pp > +.Dv KCLOCK_NONE > +timeouts may be scheduled with the function > +.Fn timeout_add , > +which arms > .Fa to > -timeout in at least > -.Fa ticks Ns /hz > +for execution after > +.Fa nticks > +.Xr hardclock 9 > +ticks have elapsed > +.Pq see Xr hz 9 for details . > +In practice, > +.Fa nticks > +ticks will usually elapse in slightly less than > +.Fa nticks Ns /hz > seconds. > Negative values of > -.Fa ticks > +.Fa nticks > are illegal. > -If the value is > -.Sq 0 > -it will, in the current implementation, be treated as > -.Sq 1 , > -but in the future it might cause an immediate timeout. > -The timeout in the > +If > +.Fa nticks > +is zero it will be silently rounded up to one. > +.Pp > +For convenience, > +.Dv KCLOCK_NONE > +timeouts may also be scheduled with > +.Fn timeout_add_sec , > +.Fn timeout_add_msec , > +.Fn timeout_add_usec , > +.Fn timeout_add_nsec , > +or > +.Fn timeout_add_tv . > +These wrapper functions convert their inputs to a count of ticks before > +calling > +.Fn timeout_add > +to schedule the given timeout. > +.Pp > +.Dv KCLOCK_UPTIME > +timeouts may be scheduled with > +.Fn timeout_in_nsec , > +which arms > .Fa to > -argument must be already initialized by > -.Fn timeout_set , > -.Fn timeout_set_flags , > +to execute after at least > +.Fa nsecs > +nanoseconds have elapsed, > +or with > +.Fn timeout_at_ts , > +which arms > +.Fa to > +to execute at or after the absolute time > +.Fa abs > +has elapsed on the system uptime clock. > +.Pp > +Once scheduled, > +a timeout may not be reinitialized with > +.Fn timeout_set > or > -.Fn timeout_set_proc > -and may not be used in calls to > -.Fn timeout_set , > -.Fn timeout_set_flags , > +.Fn timeout_set_flags > +until it has executed or been cancelled with > +.Fn timeout_del > or > -.Fn timeout_set_proc > -until it has timed out or been removed with > -.Fn timeout_del . > -If the timeout in the > -.Fa to > -argument is already scheduled, the old execution time will be > -replaced by the new one. > +.Fn timeout_del_barrier . > +.Pp > +A pending timeout may be rescheduled without first cancelling it with > +.Fn timeout_del > +or > +.Fn timeout_del_barrier . > +The new expiration time will quietly supersede the original. > .Pp > The function > .Fn timeout_del > -will cancel the timeout in the argument > +cancels any pending execution of > .Fa to . > -If the timeout has already executed or has never been added > +If the timeout has already executed or was never scheduled > the call will have no effect. > .Pp > +The > .Fn timeout_del_barrier > -is like > -.Fn timeout_del > -but it will wait until any current execution of the timeout has completed. > +function is similar to > +.Fn timeout_del , > +except that it may block until any current execution of the timeout > +.Fa to > +has completed. > .Pp > +The > .Fn timeout_barrier > -ensures that any current execution of the timeout in the argument > +function blocks until any current execution of the timeout > .Fa to > -has completed before returning. > +has completed. > .Pp > The > .Fn timeout_pending > -macro can be used to check if a timeout is scheduled to run. > +macro indicates whether the given timeout is scheduled for execution. > +A timeout's pending status is cleared when it is executed or cancelled. > .Pp > The > .Fn timeout_initialized > -macro can be used to check if a timeout has been initialized. > +macro indicates whether the given timeout has been initialized with > +.Fn timeout_set > +or > +.Fn timeout_set_flags . > +This macro must not be used unless the memory underlying > +.Fa to > +has been zeroed. > .Pp > The > .Fn timeout_triggered > -macro can be used to check if a timeout is running or has been run. > -The > -.Fn timeout_add > -and > -.Fn timeout_del > -functions clear the triggered state for that timeout. > -.Pp > -When possible, use the > -.Fn timeout_add_tv , > -.Fn timeout_add_sec , > -.Fn timeout_add_msec , > -.Fn timeout_add_usec , > -and > -.Fn timeout_add_nsec > -functions instead of > -.Fn timeout_add . > -Those functions add a timeout whilst converting the time specified > -by the respective types. > -They also defer the timeout handler for at least one tick if called > -with a positive value. > -.Pp > -A timeout declaration can be initialised with the > -.Fn TIMEOUT_INITIALIZER > -macro. > -The timeout will be prepared to call the function specified by the > -.Fa fn > -argument with the > -.Fa void * > -argument given in > -.Fa arg . > -.Pp > -The > -.Fn TIMEOUT_INITIALIZER_FLAGS > -macro is similar to > -.Fn TIMEOUT_INITIALIZER , > -but it accepts additional flags. > -See the > -.Fn timeout_set_flags > -function for details. > +macro indicates whether the given timeout is executing or has finished > +executing. > +Rescheduling or cancelling a timeout clears its triggered status. > .Sh CONTEXT > .Fn timeout_set , > .Fn timeout_set_flags , > and > .Fn timeout_set_proc > -can be called during autoconf, from process context, or from interrupt > -context. > +can be called during autoconf, > +from process context, > +or from interrupt context. > .Pp > .Fn timeout_add , > .Fn timeout_add_sec , > @@ -258,54 +303,53 @@ context. > .Fn timeout_add_nsec , > .Fn timeout_add_usec , > .Fn timeout_add_tv , > +.Fn timeout_in_nsec , > +.Fn timeout_at_ts , > .Fn timeout_del , > .Fn timeout_pending , > .Fn timeout_initialized , > +and > .Fn timeout_triggered > -can be called during autoconf, from process context, or from any > -interrupt context at or below > +can be called during autoconf, > +from process context, > +or from any interrupt context at or below > .Dv IPL_CLOCK . > .Pp > +The > .Fn timeout_barrier > and > .Fn timeout_del_barrier > -can be called from process context. > +functions may only be called from a process context. > .Pp > -When the timeout runs, the > +When a timeout is executed, > +the function > .Fa fn > -argument to > -.Fn timeout_set > -or > -.Fn timeout_set_flags > -will be called in an interrupt context at > +given at initialization will be called from the > .Dv IPL_SOFTCLOCK > -or a process context if the > +interrupt context, > +or a process context if the timeout was configured with the > .Dv TIMEOUT_PROC > -flag was given at initialization. > -The > -.Fa fn > -argument to > -.Fn timeout_set_proc > -will be called in a process context. > +flag. > .Sh RETURN VALUES > .Fn timeout_add , > .Fn timeout_add_sec , > .Fn timeout_add_msec , > .Fn timeout_add_nsec , > .Fn timeout_add_usec , > -and > .Fn timeout_add_tv > +.Fn timeout_in_nsec , > +and > +.Fn timeout_at_ts > will return 1 if the timeout > .Fa to > -was added to the timeout schedule or 0 if it was already queued. > +was newly scheduled or 0 if the timeout was already pending. > .Pp > .Fn timeout_del > and > .Fn timeout_del_barrier > will return 1 if the timeout > .Fa to > -was removed from the pending timeout schedule or 0 if it was not > -currently queued. > +was pending or 0 otherwise. > .Sh CODE REFERENCES > These functions are implemented in the file > .Pa sys/kern/kern_timeout.c . > Index: sys/kern/kern_timeout.c > =================================================================== > RCS file: /cvs/src/sys/kern/kern_timeout.c,v > retrieving revision 1.85 > diff -u -p -r1.85 kern_timeout.c > --- sys/kern/kern_timeout.c 19 Jun 2021 02:05:33 -0000 1.85 > +++ sys/kern/kern_timeout.c 24 Jun 2021 22:37:39 -0000 > @@ -252,7 +252,7 @@ timeout_proc_init(void) > kthread_create_deferred(softclock_create_thread, NULL); > } > > -static inline void > +void > _timeout_set(struct timeout *to, void (*fn)(void *), void *arg, int kclock, > int flags) > { > @@ -269,9 +269,10 @@ timeout_set(struct timeout *new, void (* > } > > void > -timeout_set_flags(struct timeout *to, void (*fn)(void *), void *arg, int > flags) > +timeout_set_flags(struct timeout *to, void (*fn)(void *), void *arg, int > kclock, > + int flags) > { > - _timeout_set(to, fn, arg, KCLOCK_NONE, flags); > + _timeout_set(to, fn, arg, kclock, flags); > } > > void > @@ -280,13 +281,6 @@ timeout_set_proc(struct timeout *new, vo > _timeout_set(new, fn, arg, KCLOCK_NONE, TIMEOUT_PROC); > } > > -void > -timeout_set_kclock(struct timeout *to, void (*fn)(void *), void *arg, > - int kclock, int flags) > -{ > - _timeout_set(to, fn, arg, kclock, flags | TIMEOUT_KCLOCK); > -} > - > int > timeout_add(struct timeout *new, int to_ticks) > { > @@ -294,7 +288,6 @@ timeout_add(struct timeout *new, int to_ > int ret = 1; > > KASSERT(ISSET(new->to_flags, TIMEOUT_INITIALIZED)); > - KASSERT(!ISSET(new->to_flags, TIMEOUT_KCLOCK)); > KASSERT(new->to_kclock == KCLOCK_NONE); > KASSERT(to_ticks >= 0); > > @@ -402,8 +395,8 @@ timeout_at_ts(struct timeout *to, const > > mtx_enter(&timeout_mutex); > > - KASSERT(ISSET(to->to_flags, TIMEOUT_INITIALIZED | TIMEOUT_KCLOCK)); > - KASSERT(to->to_kclock != KCLOCK_NONE); > + KASSERT(ISSET(to->to_flags, TIMEOUT_INITIALIZED)); > + KASSERT(to->to_kclock == KCLOCK_UPTIME); > > old_abstime = to->to_abstime; > to->to_abstime = *abstime; > @@ -497,7 +490,8 @@ timeout_barrier(struct timeout *to) > procflag = (to->to_flags & TIMEOUT_PROC); > timeout_sync_order(procflag); > > - timeout_set_flags(&barrier, timeout_barrier_timeout, &c, procflag); > + timeout_set_flags(&barrier, timeout_barrier_timeout, &c, KCLOCK_NONE, > + procflag); > barrier.to_process = curproc->p_p; > cond_init(&c); > > @@ -535,7 +529,7 @@ timeout_bucket(const struct timeout *to) > struct timespec diff, shifted_abstime; > uint32_t level; > > - KASSERT(ISSET(to->to_flags, TIMEOUT_KCLOCK)); > + KASSERT(to->to_kclock == KCLOCK_UPTIME); > KASSERT(timespeccmp(&kc->kc_lastscan, &to->to_abstime, <)); > > timespecsub(&to->to_abstime, &kc->kc_lastscan, &diff); > @@ -750,7 +744,7 @@ softclock(void *arg) > CIRCQ_REMOVE(&to->to_list); > if (to == first_new) > new = 1; > - if (ISSET(to->to_flags, TIMEOUT_KCLOCK)) > + if (to->to_kclock != KCLOCK_NONE) > softclock_process_kclock_timeout(to, new); > else > softclock_process_tick_timeout(to, new); > @@ -915,7 +909,7 @@ db_show_timeout(struct timeout *to, stru > else if (bucket == &timeout_proc) > where = "thread"; > else { > - if (ISSET(to->to_flags, TIMEOUT_KCLOCK)) > + if (to->to_kclock != KCLOCK_NONE) > wheel = timeout_wheel_kc; > else > wheel = timeout_wheel; > @@ -924,7 +918,7 @@ db_show_timeout(struct timeout *to, stru > (bucket - wheel) / WHEELSIZE); > where = buf; > } > - if (ISSET(to->to_flags, TIMEOUT_KCLOCK)) { > + if (to->to_kclock != KCLOCK_NONE) { > kc = &timeout_kclock[to->to_kclock]; > timespecsub(&to->to_abstime, &kc->kc_lastscan, &remaining); > db_printf("%20s %8s %7s 0x%0*lx %s\n", > Index: sys/kern/kern_fork.c > =================================================================== > RCS file: /cvs/src/sys/kern/kern_fork.c,v > retrieving revision 1.236 > diff -u -p -r1.236 kern_fork.c > --- sys/kern/kern_fork.c 19 Jun 2021 02:05:33 -0000 1.236 > +++ sys/kern/kern_fork.c 24 Jun 2021 22:37:39 -0000 > @@ -201,7 +201,7 @@ process_initialize(struct process *pr, s > rw_init(&pr->ps_lock, "pslock"); > mtx_init(&pr->ps_mtx, IPL_MPFLOOR); > > - timeout_set_kclock(&pr->ps_realit_to, realitexpire, pr, > + timeout_set_flags(&pr->ps_realit_to, realitexpire, pr, > KCLOCK_UPTIME, 0); > timeout_set(&pr->ps_rucheck_to, rucheck, pr); > } > Index: sys/sys/timeout.h > =================================================================== > RCS file: /cvs/src/sys/sys/timeout.h,v > retrieving revision 1.42 > diff -u -p -r1.42 timeout.h > --- sys/sys/timeout.h 19 Jun 2021 02:05:33 -0000 1.42 > +++ sys/sys/timeout.h 24 Jun 2021 22:37:39 -0000 > @@ -54,7 +54,6 @@ struct timeout { > #define TIMEOUT_ONQUEUE 0x02 /* on any timeout queue */ > #define TIMEOUT_INITIALIZED 0x04 /* initialized */ > #define TIMEOUT_TRIGGERED 0x08 /* running or ran */ > -#define TIMEOUT_KCLOCK 0x10 /* clock-based timeout */ > > struct timeoutstat { > uint64_t tos_added; /* timeout_add*(9) calls */ > @@ -98,18 +97,14 @@ int timeout_sysctl(void *, size_t *, voi > .to_kclock = (_kclock) \ > } > > -#define TIMEOUT_INITIALIZER_KCLOCK(_fn, _arg, _kclock, _flags) > \ > - __TIMEOUT_INITIALIZER((_fn), (_args), (_kclock), (_flags) | > TIMEOUT_KCLOCK) > - > -#define TIMEOUT_INITIALIZER_FLAGS(_fn, _arg, _flags) \ > - __TIMEOUT_INITIALIZER((_fn), (_args), KCLOCK_NONE, (_flags)) > +#define TIMEOUT_INITIALIZER_FLAGS(_fn, _arg, _kclock, _flags) > \ > + __TIMEOUT_INITIALIZER((_fn), (_args), (_kclock), (_flags)) > > #define TIMEOUT_INITIALIZER(_f, _a) \ > __TIMEOUT_INITIALIZER((_f), (_a), KCLOCK_NONE, 0) > > void timeout_set(struct timeout *, void (*)(void *), void *); > -void timeout_set_flags(struct timeout *, void (*)(void *), void *, int); > -void timeout_set_kclock(struct timeout *, void (*)(void *), void *, int, > int); > +void timeout_set_flags(struct timeout *, void (*)(void *), void *, int, int); > void timeout_set_proc(struct timeout *, void (*)(void *), void *); > > int timeout_add(struct timeout *, int); >