Extract the calculation of the callout fire time into the new function
callout_when(9). See the man page update for the description of the intended use. Tested by: pho Reviewed by: jhb, bjk (man page updates) Sponsored by: The FreeBSD Foundation MFC after: 1 month X-Differential revision: https://reviews.freebsd.org/D7137
This commit is contained in:
parent
a6ce0a6cb5
commit
2b85baaf40
@ -1766,6 +1766,7 @@ MLINKS+=timeout.9 callout.9 \
|
||||
timeout.9 callout_schedule_sbt_curcpu.9 \
|
||||
timeout.9 callout_schedule_sbt_on.9 \
|
||||
timeout.9 callout_stop.9 \
|
||||
timeout.9 callout_when.9 \
|
||||
timeout.9 untimeout.9
|
||||
MLINKS+=ucred.9 cred_update_thread.9 \
|
||||
ucred.9 crcopy.9 \
|
||||
|
@ -29,7 +29,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 4, 2016
|
||||
.Dd July 27, 2016
|
||||
.Dt TIMEOUT 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -56,6 +56,7 @@
|
||||
.Nm callout_schedule_sbt_curcpu ,
|
||||
.Nm callout_schedule_sbt_on ,
|
||||
.Nm callout_stop ,
|
||||
.Nm callout_when ,
|
||||
.Nm timeout ,
|
||||
.Nm untimeout
|
||||
.Nd execute a function after a specified length of time
|
||||
@ -91,20 +92,48 @@ struct callout_handle handle = CALLOUT_HANDLE_INITIALIZER(&handle);
|
||||
.Ft int
|
||||
.Fn callout_reset "struct callout *c" "int ticks" "timeout_t *func" "void *arg"
|
||||
.Ft int
|
||||
.Fn callout_reset_curcpu "struct callout *c" "int ticks" "timeout_t *func" \
|
||||
"void *arg"
|
||||
.Fo callout_reset_curcpu
|
||||
.Fa "struct callout *c"
|
||||
.Fa "int ticks"
|
||||
.Fa "timeout_t *func"
|
||||
.Fa "void *arg"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_reset_on "struct callout *c" "int ticks" "timeout_t *func" \
|
||||
"void *arg" "int cpu"
|
||||
.Fo callout_reset_on
|
||||
.Fa "struct callout *c"
|
||||
.Fa "int ticks"
|
||||
.Fa "timeout_t *func"
|
||||
.Fa "void *arg"
|
||||
.Fa "int cpu"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \
|
||||
"sbintime_t pr" "timeout_t *func" "void *arg" "int flags"
|
||||
.Fo callout_reset_sbt
|
||||
.Fa "struct callout *c"
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t pr"
|
||||
.Fa "timeout_t *func"
|
||||
.Fa "void *arg"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
|
||||
"sbintime_t pr" "timeout_t *func" "void *arg" "int flags"
|
||||
.Fo callout_reset_sbt_curcpu
|
||||
.Fa "struct callout *c"
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t pr"
|
||||
.Fa "timeout_t *func"
|
||||
.Fa "void *arg"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \
|
||||
"sbintime_t pr" "timeout_t *func" "void *arg" "int cpu" "int flags"
|
||||
.Fo callout_reset_sbt_on
|
||||
.Fa "struct callout *c"
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t pr"
|
||||
.Fa "timeout_t *func"
|
||||
.Fa "void *arg"
|
||||
.Fa "int cpu"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_schedule "struct callout *c" "int ticks"
|
||||
.Ft int
|
||||
@ -112,16 +141,37 @@ struct callout_handle handle = CALLOUT_HANDLE_INITIALIZER(&handle);
|
||||
.Ft int
|
||||
.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu"
|
||||
.Ft int
|
||||
.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \
|
||||
"sbintime_t pr" "int flags"
|
||||
.Fo callout_schedule_sbt
|
||||
.Fa "struct callout *c"
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t pr"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
|
||||
"sbintime_t pr" "int flags"
|
||||
.Fo callout_schedule_sbt_curcpu
|
||||
.Fa "struct callout *c"
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t pr"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \
|
||||
"sbintime_t pr" "int cpu" "int flags"
|
||||
.Fo callout_schedule_sbt_on
|
||||
.Fa "struct callout *c"
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t pr"
|
||||
.Fa "int cpu"
|
||||
.Fa "int flags"
|
||||
.Fc
|
||||
.Ft int
|
||||
.Fn callout_stop "struct callout *c"
|
||||
.Ft sbintime_t
|
||||
.Fo callout_when
|
||||
.Fa "sbintime_t sbt"
|
||||
.Fa "sbintime_t precision"
|
||||
.Fa "int flags"
|
||||
.Fa "sbintime_t *sbt_res"
|
||||
.Fa "sbintime_t *precision_res"
|
||||
.Fc
|
||||
.Ft struct callout_handle
|
||||
.Fn timeout "timeout_t *func" "void *arg" "int ticks"
|
||||
.Ft void
|
||||
@ -387,6 +437,26 @@ or this value is used as the length of the time window.
|
||||
Smaller values
|
||||
.Pq which result in larger time intervals
|
||||
allow the callout subsystem to aggregate more events in one timer interrupt.
|
||||
.It Dv C_PRECALC
|
||||
The
|
||||
.Fa sbt
|
||||
argument specifies the absolute time at which the callout should be run,
|
||||
and the
|
||||
.Fa pr
|
||||
argument specifies the requested precision, which will not be
|
||||
adjusted during the scheduling process.
|
||||
The
|
||||
.Fa sbt
|
||||
and
|
||||
.Fa pr
|
||||
values should be calculated by an earlier call to
|
||||
.Fn callout_when
|
||||
which uses the user-supplied
|
||||
.Fa sbt ,
|
||||
.Fa pr ,
|
||||
and
|
||||
.Fa flags
|
||||
values.
|
||||
.It Dv C_HARDCLOCK
|
||||
Align the timeouts to
|
||||
.Fn hardclock
|
||||
@ -503,6 +573,39 @@ but it
|
||||
.Em does not
|
||||
clear it when a callout expires normally via the execution of the
|
||||
callout function.
|
||||
.Pp
|
||||
The
|
||||
.Fn callout_when
|
||||
function may be used to pre-calculate the absolute time at which the
|
||||
timeout should be run and the precision of the scheduled run time
|
||||
according to the required time
|
||||
.Fa sbt ,
|
||||
precision
|
||||
.Fa precision ,
|
||||
and additional adjustments requested by the
|
||||
.Fa flags
|
||||
argument.
|
||||
Flags accepted by the
|
||||
.Fn callout_when
|
||||
function are the same as flags for the
|
||||
.Fn callout_reset
|
||||
function.
|
||||
The resulting time is assigned to the variable pointed to by the
|
||||
.Fa sbt_res
|
||||
argument, and the resulting precision is assigned to
|
||||
.Fa *precision_res .
|
||||
When passing the results to
|
||||
.Fa callout_reset ,
|
||||
add the
|
||||
.Va C_PRECALC
|
||||
flag to
|
||||
.Fa flags ,
|
||||
to avoid incorrect re-adjustment.
|
||||
The function is intended for situations where precise time of the callout
|
||||
run should be known in advance, since
|
||||
trying to read this time from the callout structure itself after a
|
||||
.Fn callout_reset
|
||||
call is racy.
|
||||
.Ss "Avoiding Race Conditions"
|
||||
The callout subsystem invokes callout functions from its own thread
|
||||
context.
|
||||
|
@ -945,6 +945,56 @@ callout_handle_init(struct callout_handle *handle)
|
||||
handle->callout = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
callout_when(sbintime_t sbt, sbintime_t precision, int flags,
|
||||
sbintime_t *res, sbintime_t *prec_res)
|
||||
{
|
||||
sbintime_t to_sbt, to_pr;
|
||||
|
||||
if ((flags & (C_ABSOLUTE | C_PRECALC)) != 0) {
|
||||
*res = sbt;
|
||||
*prec_res = precision;
|
||||
return;
|
||||
}
|
||||
if ((flags & C_HARDCLOCK) != 0 && sbt < tick_sbt)
|
||||
sbt = tick_sbt;
|
||||
if ((flags & C_HARDCLOCK) != 0 ||
|
||||
#ifdef NO_EVENTTIMERS
|
||||
sbt >= sbt_timethreshold) {
|
||||
to_sbt = getsbinuptime();
|
||||
|
||||
/* Add safety belt for the case of hz > 1000. */
|
||||
to_sbt += tc_tick_sbt - tick_sbt;
|
||||
#else
|
||||
sbt >= sbt_tickthreshold) {
|
||||
/*
|
||||
* Obtain the time of the last hardclock() call on
|
||||
* this CPU directly from the kern_clocksource.c.
|
||||
* This value is per-CPU, but it is equal for all
|
||||
* active ones.
|
||||
*/
|
||||
#ifdef __LP64__
|
||||
to_sbt = DPCPU_GET(hardclocktime);
|
||||
#else
|
||||
spinlock_enter();
|
||||
to_sbt = DPCPU_GET(hardclocktime);
|
||||
spinlock_exit();
|
||||
#endif
|
||||
#endif
|
||||
if ((flags & C_HARDCLOCK) == 0)
|
||||
to_sbt += tick_sbt;
|
||||
} else
|
||||
to_sbt = sbinuptime();
|
||||
if (SBT_MAX - to_sbt < sbt)
|
||||
to_sbt = SBT_MAX;
|
||||
else
|
||||
to_sbt += sbt;
|
||||
*res = to_sbt;
|
||||
to_pr = ((C_PRELGET(flags) < 0) ? sbt >> tc_precexp :
|
||||
sbt >> C_PRELGET(flags));
|
||||
*prec_res = to_pr > precision ? to_pr : precision;
|
||||
}
|
||||
|
||||
/*
|
||||
* New interface; clients allocate their own callout structures.
|
||||
*
|
||||
@ -962,10 +1012,10 @@ callout_handle_init(struct callout_handle *handle)
|
||||
* callout_deactivate() - marks the callout as having been serviced
|
||||
*/
|
||||
int
|
||||
callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision,
|
||||
callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t prec,
|
||||
void (*ftn)(void *), void *arg, int cpu, int flags)
|
||||
{
|
||||
sbintime_t to_sbt, pr;
|
||||
sbintime_t to_sbt, precision;
|
||||
struct callout_cpu *cc;
|
||||
int cancelled, direct;
|
||||
int ignore_cpu=0;
|
||||
@ -978,47 +1028,8 @@ callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision,
|
||||
/* Invalid CPU spec */
|
||||
panic("Invalid CPU in callout %d", cpu);
|
||||
}
|
||||
if (flags & C_ABSOLUTE) {
|
||||
to_sbt = sbt;
|
||||
} else {
|
||||
if ((flags & C_HARDCLOCK) && (sbt < tick_sbt))
|
||||
sbt = tick_sbt;
|
||||
if ((flags & C_HARDCLOCK) ||
|
||||
#ifdef NO_EVENTTIMERS
|
||||
sbt >= sbt_timethreshold) {
|
||||
to_sbt = getsbinuptime();
|
||||
callout_when(sbt, prec, flags, &to_sbt, &precision);
|
||||
|
||||
/* Add safety belt for the case of hz > 1000. */
|
||||
to_sbt += tc_tick_sbt - tick_sbt;
|
||||
#else
|
||||
sbt >= sbt_tickthreshold) {
|
||||
/*
|
||||
* Obtain the time of the last hardclock() call on
|
||||
* this CPU directly from the kern_clocksource.c.
|
||||
* This value is per-CPU, but it is equal for all
|
||||
* active ones.
|
||||
*/
|
||||
#ifdef __LP64__
|
||||
to_sbt = DPCPU_GET(hardclocktime);
|
||||
#else
|
||||
spinlock_enter();
|
||||
to_sbt = DPCPU_GET(hardclocktime);
|
||||
spinlock_exit();
|
||||
#endif
|
||||
#endif
|
||||
if ((flags & C_HARDCLOCK) == 0)
|
||||
to_sbt += tick_sbt;
|
||||
} else
|
||||
to_sbt = sbinuptime();
|
||||
if (SBT_MAX - to_sbt < sbt)
|
||||
to_sbt = SBT_MAX;
|
||||
else
|
||||
to_sbt += sbt;
|
||||
pr = ((C_PRELGET(flags) < 0) ? sbt >> tc_precexp :
|
||||
sbt >> C_PRELGET(flags));
|
||||
if (pr > precision)
|
||||
precision = pr;
|
||||
}
|
||||
/*
|
||||
* This flag used to be added by callout_cc_add, but the
|
||||
* first time you call this we could end up with the
|
||||
|
@ -57,6 +57,7 @@
|
||||
#define C_PRELGET(x) (int)((((x) >> 1) & C_PRELRANGE) - 1)
|
||||
#define C_HARDCLOCK 0x0100 /* align to hardclock() calls */
|
||||
#define C_ABSOLUTE 0x0200 /* event time is absolute. */
|
||||
#define C_PRECALC 0x0400 /* event time is pre-calculated. */
|
||||
|
||||
struct callout_handle {
|
||||
struct callout *callout;
|
||||
@ -129,6 +130,8 @@ int _callout_stop_safe(struct callout *, int, void (*)(void *));
|
||||
void callout_process(sbintime_t now);
|
||||
#define callout_async_drain(c, d) \
|
||||
_callout_stop_safe(c, 0, d)
|
||||
void callout_when(sbintime_t sbt, sbintime_t precision, int flags,
|
||||
sbintime_t *sbt_res, sbintime_t *prec_res);
|
||||
#endif
|
||||
|
||||
#endif /* _SYS_CALLOUT_H_ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user