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.
Fixed.
Are there any other mdoc(7)-type stylistic anachronisms we can fix up?
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);