xref: /freebsd/share/man/man9/callout.9 (revision bdcbfde31e8e9b343f113a1956384bdf30d1ed62)
1.\"	$NetBSD: timeout.9,v 1.2 1996/06/23 22:32:34 pk Exp $
2.\"
3.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
4.\" All rights reserved.
5.\"
6.\" This code is derived from software contributed to The NetBSD Foundation
7.\" by Paul Kranenburg.
8.\"
9.\" Redistribution and use in source and binary forms, with or without
10.\" modification, are permitted provided that the following conditions
11.\" are met:
12.\" 1. Redistributions of source code must retain the above copyright
13.\"    notice, this list of conditions and the following disclaimer.
14.\" 2. Redistributions in binary form must reproduce the above copyright
15.\"    notice, this list of conditions and the following disclaimer in the
16.\"    documentation and/or other materials provided with the distribution.
17.\"
18.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
22.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28.\" POSSIBILITY OF SUCH DAMAGE.
29.\"
30.Dd September 1, 2021
31.Dt CALLOUT 9
32.Os
33.Sh NAME
34.Nm callout_active ,
35.Nm callout_deactivate ,
36.Nm callout_async_drain ,
37.Nm callout_drain ,
38.Nm callout_init ,
39.Nm callout_init_mtx ,
40.Nm callout_init_rm ,
41.Nm callout_init_rw ,
42.Nm callout_pending ,
43.Nm callout_reset ,
44.Nm callout_reset_curcpu ,
45.Nm callout_reset_on ,
46.Nm callout_reset_sbt ,
47.Nm callout_reset_sbt_curcpu ,
48.Nm callout_reset_sbt_on ,
49.Nm callout_schedule ,
50.Nm callout_schedule_curcpu ,
51.Nm callout_schedule_on ,
52.Nm callout_schedule_sbt ,
53.Nm callout_schedule_sbt_curcpu ,
54.Nm callout_schedule_sbt_on ,
55.Nm callout_stop ,
56.Nm callout_when
57.Nd execute a function after a specified length of time
58.Sh SYNOPSIS
59.In sys/types.h
60.In sys/callout.h
61.Bd -literal
62typedef void callout_func_t (void *);
63.Ed
64.Ft int
65.Fn callout_active "struct callout *c"
66.Ft void
67.Fn callout_deactivate "struct callout *c"
68.Ft int
69.Fn callout_async_drain "struct callout *c" "callout_func_t *drain"
70.Ft int
71.Fn callout_drain "struct callout *c"
72.Ft void
73.Fn callout_init "struct callout *c" "int mpsafe"
74.Ft void
75.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags"
76.Ft void
77.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags"
78.Ft void
79.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags"
80.Ft int
81.Fn callout_pending "struct callout *c"
82.Ft int
83.Fo callout_reset
84.Fa "struct callout *c"
85.Fa "int ticks"
86.Fa "callout_func_t *func"
87.Fa "void *arg"
88.Fc
89.Ft int
90.Fo callout_reset_curcpu
91.Fa "struct callout *c"
92.Fa "int ticks"
93.Fa "callout_func_t *func"
94.Fa "void *arg"
95.Fc
96.Ft int
97.Fo callout_reset_on
98.Fa "struct callout *c"
99.Fa "int ticks"
100.Fa "callout_func_t *func"
101.Fa "void *arg"
102.Fa "int cpu"
103.Fc
104.Ft int
105.Fo callout_reset_sbt
106.Fa "struct callout *c"
107.Fa "sbintime_t sbt"
108.Fa "sbintime_t pr"
109.Fa "callout_func_t *func"
110.Fa "void *arg"
111.Fa "int flags"
112.Fc
113.Ft int
114.Fo callout_reset_sbt_curcpu
115.Fa "struct callout *c"
116.Fa "sbintime_t sbt"
117.Fa "sbintime_t pr"
118.Fa "callout_func_t *func"
119.Fa "void *arg"
120.Fa "int flags"
121.Fc
122.Ft int
123.Fo callout_reset_sbt_on
124.Fa "struct callout *c"
125.Fa "sbintime_t sbt"
126.Fa "sbintime_t pr"
127.Fa "callout_func_t *func"
128.Fa "void *arg"
129.Fa "int cpu"
130.Fa "int flags"
131.Fc
132.Ft int
133.Fn callout_schedule "struct callout *c" "int ticks"
134.Ft int
135.Fn callout_schedule_curcpu "struct callout *c" "int ticks"
136.Ft int
137.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu"
138.Ft int
139.Fo callout_schedule_sbt
140.Fa "struct callout *c"
141.Fa "sbintime_t sbt"
142.Fa "sbintime_t pr"
143.Fa "int flags"
144.Fc
145.Ft int
146.Fo callout_schedule_sbt_curcpu
147.Fa "struct callout *c"
148.Fa "sbintime_t sbt"
149.Fa "sbintime_t pr"
150.Fa "int flags"
151.Fc
152.Ft int
153.Fo callout_schedule_sbt_on
154.Fa "struct callout *c"
155.Fa "sbintime_t sbt"
156.Fa "sbintime_t pr"
157.Fa "int cpu"
158.Fa "int flags"
159.Fc
160.Ft int
161.Fn callout_stop "struct callout *c"
162.Ft sbintime_t
163.Fo callout_when
164.Fa "sbintime_t sbt"
165.Fa "sbintime_t precision"
166.Fa "int flags"
167.Fa "sbintime_t *sbt_res"
168.Fa "sbintime_t *precision_res"
169.Fc
170.Sh DESCRIPTION
171The
172.Nm callout
173API is used to schedule a call to an arbitrary function at a specific
174time in the future.
175Consumers of this API are required to allocate a callout structure
176.Pq struct callout
177for each pending function invocation.
178This structure stores state about the pending function invocation including
179the function to be called and the time at which the function should be invoked.
180Pending function calls can be cancelled or rescheduled to a different time.
181In addition,
182a callout structure may be reused to schedule a new function call after a
183scheduled call is completed.
184.Pp
185Callouts only provide a single-shot mode.
186If a consumer requires a periodic timer,
187it must explicitly reschedule each function call.
188This is normally done by rescheduling the subsequent call within the called
189function.
190.Pp
191Callout functions must not sleep.
192They may not acquire sleepable locks,
193wait on condition variables,
194perform blocking allocation requests,
195or invoke any other action that might sleep.
196.Pp
197Each callout structure must be initialized by
198.Fn callout_init ,
199.Fn callout_init_mtx ,
200.Fn callout_init_rm ,
201or
202.Fn callout_init_rw
203before it is passed to any of the other callout functions.
204The
205.Fn callout_init
206function initializes a callout structure in
207.Fa c
208that is not associated with a specific lock.
209If the
210.Fa mpsafe
211argument is zero,
212the callout structure is not considered to be
213.Dq multi-processor safe ;
214and the Giant lock will be acquired before calling the callout function
215and released when the callout function returns.
216.Pp
217The
218.Fn callout_init_mtx ,
219.Fn callout_init_rm ,
220and
221.Fn callout_init_rw
222functions initialize a callout structure in
223.Fa c
224that is associated with a specific lock.
225The lock is specified by the
226.Fa mtx ,
227.Fa rm ,
228or
229.Fa rw
230parameter.
231The associated lock must be held while stopping or rescheduling the
232callout.
233The callout subsystem acquires the associated lock before calling the
234callout function and releases it after the function returns.
235If the callout was cancelled while the callout subsystem waited for the
236associated lock,
237the callout function is not called,
238and the associated lock is released.
239This ensures that stopping or rescheduling the callout will abort any
240previously scheduled invocation.
241.Pp
242A sleepable read-mostly lock
243.Po
244one initialized with the
245.Dv RM_SLEEPABLE
246flag
247.Pc
248may not be used with
249.Fn callout_init_rm .
250Similarly, other sleepable lock types such as
251.Xr sx 9
252and
253.Xr lockmgr 9
254cannot be used with callouts because sleeping is not permitted in
255the callout subsystem.
256.Pp
257These
258.Fa flags
259may be specified for
260.Fn callout_init_mtx ,
261.Fn callout_init_rm ,
262or
263.Fn callout_init_rw :
264.Bl -tag -width ".Dv CALLOUT_RETURNUNLOCKED"
265.It Dv CALLOUT_RETURNUNLOCKED
266The callout function will release the associated lock itself,
267so the callout subsystem should not attempt to unlock it
268after the callout function returns.
269.It Dv CALLOUT_SHAREDLOCK
270The lock is only acquired in read mode when running the callout handler.
271This flag is ignored by
272.Fn callout_init_mtx .
273.El
274.Pp
275The function
276.Fn callout_stop
277cancels a callout
278.Fa c
279if it is currently pending.
280If the callout is pending and successfully stopped, then
281.Fn callout_stop
282returns a value of one.
283If the callout is not set, or
284has already been serviced, then
285negative one is returned.
286If the callout is currently being serviced and cannot be stopped,
287then zero will be returned.
288If the callout is currently being serviced and cannot be stopped, and at the
289same time a next invocation of the same callout is also scheduled, then
290.Fn callout_stop
291unschedules the next run and returns zero.
292If the callout has an associated lock,
293then that lock must be held when this function is called.
294.Pp
295The function
296.Fn callout_async_drain
297is identical to
298.Fn callout_stop
299with one difference.
300When
301.Fn callout_async_drain
302returns zero it will arrange for the function
303.Fa drain
304to be called using the same argument given to the
305.Fn callout_reset
306function.
307.Fn callout_async_drain
308If the callout has an associated lock,
309then that lock must be held when this function is called.
310Note that when stopping multiple callouts that use the same lock it is possible
311to get multiple return's of zero and multiple calls to the
312.Fa drain
313function, depending upon which CPU's the callouts are running.
314The
315.Fa drain
316function itself is called from the context of the completing callout
317i.e. softclock or hardclock, just like a callout itself.
318.Pp
319The function
320.Fn callout_drain
321is identical to
322.Fn callout_stop
323except that it will wait for the callout
324.Fa c
325to complete if it is already in progress.
326This function MUST NOT be called while holding any
327locks on which the callout might block, or deadlock will result.
328Note that if the callout subsystem has already begun processing this
329callout, then the callout function may be invoked before
330.Fn callout_drain
331returns.
332However, the callout subsystem does guarantee that the callout will be
333fully stopped before
334.Fn callout_drain
335returns.
336.Pp
337The
338.Fn callout_reset
339and
340.Fn callout_schedule
341function families schedule a future function invocation for callout
342.Fa c .
343If
344.Fa c
345already has a pending callout,
346it is cancelled before the new invocation is scheduled.
347These functions return a value of one if a pending callout was cancelled
348and zero if there was no pending callout.
349If the callout has an associated lock,
350then that lock must be held when any of these functions are called.
351.Pp
352The time at which the callout function will be invoked is determined by
353either the
354.Fa ticks
355argument or the
356.Fa sbt ,
357.Fa pr ,
358and
359.Fa flags
360arguments.
361When
362.Fa ticks
363is used,
364the callout is scheduled to execute after
365.Fa ticks Ns No /hz
366seconds.
367Non-positive values of
368.Fa ticks
369are silently converted to the value
370.Sq 1 .
371.Pp
372The
373.Fa sbt ,
374.Fa pr ,
375and
376.Fa flags
377arguments provide more control over the scheduled time including
378support for higher resolution times,
379specifying the precision of the scheduled time,
380and setting an absolute deadline instead of a relative timeout.
381The callout is scheduled to execute in a time window which begins at
382the time specified in
383.Fa sbt
384and extends for the amount of time specified in
385.Fa pr .
386If
387.Fa sbt
388specifies a time in the past,
389the window is adjusted to start at the current time.
390A non-zero value for
391.Fa pr
392allows the callout subsystem to coalesce callouts scheduled close to each
393other into fewer timer interrupts,
394reducing processing overhead and power consumption.
395These
396.Fa flags
397may be specified to adjust the interpretation of
398.Fa sbt
399and
400.Fa pr :
401.Bl -tag -width ".Dv C_DIRECT_EXEC"
402.It Dv C_ABSOLUTE
403Handle the
404.Fa sbt
405argument as an absolute time since boot.
406By default,
407.Fa sbt
408is treated as a relative amount of time,
409similar to
410.Fa ticks .
411.It Dv C_DIRECT_EXEC
412Run the handler directly from hardware interrupt context instead of from the
413softclock thread.
414This reduces latency and overhead, but puts more constraints on the callout
415function.
416Callout functions run in this context may use only spin mutexes for locking
417and should be as small as possible because they run with absolute priority.
418.It Fn C_PREL
419Specifies relative event time precision as binary logarithm of time interval
420divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4, etc.
421Note that the larger of
422.Fa pr
423or this value is used as the length of the time window.
424Smaller values
425.Pq which result in larger time intervals
426allow the callout subsystem to aggregate more events in one timer interrupt.
427.It Dv C_PRECALC
428The
429.Fa sbt
430argument specifies the absolute time at which the callout should be run,
431and the
432.Fa pr
433argument specifies the requested precision, which will not be
434adjusted during the scheduling process.
435The
436.Fa sbt
437and
438.Fa pr
439values should be calculated by an earlier call to
440.Fn callout_when
441which uses the user-supplied
442.Fa sbt ,
443.Fa pr ,
444and
445.Fa flags
446values.
447.It Dv C_HARDCLOCK
448Align the timeouts to
449.Fn hardclock
450calls if possible.
451.El
452.Pp
453The
454.Fn callout_reset
455functions accept a
456.Fa func
457argument which identifies the function to be called when the time expires.
458It must be a pointer to a function that takes a single
459.Fa void *
460argument.
461Upon invocation,
462.Fa func
463will receive
464.Fa arg
465as its only argument.
466The
467.Fn callout_schedule
468functions reuse the
469.Fa func
470and
471.Fa arg
472arguments from the previous callout.
473Note that one of the
474.Fn callout_reset
475functions must always be called to initialize
476.Fa func
477and
478.Fa arg
479before one of the
480.Fn callout_schedule
481functions can be used.
482.Pp
483The callout subsystem provides a softclock thread for each CPU in the system.
484Callouts are assigned to a single CPU and are executed by the softclock thread
485for that CPU.
486Initially,
487callouts are assigned to CPU 0.
488The
489.Fn callout_reset_on ,
490.Fn callout_reset_sbt_on ,
491.Fn callout_schedule_on
492and
493.Fn callout_schedule_sbt_on
494functions assign the callout to CPU
495.Fa cpu .
496The
497.Fn callout_reset_curcpu ,
498.Fn callout_reset_sbt_curpu ,
499.Fn callout_schedule_curcpu
500and
501.Fn callout_schedule_sbt_curcpu
502functions assign the callout to the current CPU.
503The
504.Fn callout_reset ,
505.Fn callout_reset_sbt ,
506.Fn callout_schedule
507and
508.Fn callout_schedule_sbt
509functions schedule the callout to execute in the softclock thread of the CPU
510to which it is currently assigned.
511.Pp
512Softclock threads are not pinned to their respective CPUs by default.
513The softclock thread for CPU 0 can be pinned to CPU 0 by setting the
514.Va kern.pin_default_swi
515loader tunable to a non-zero value.
516Softclock threads for CPUs other than zero can be pinned to their
517respective CPUs by setting the
518.Va kern.pin_pcpu_swi
519loader tunable to a non-zero value.
520.Pp
521The macros
522.Fn callout_pending ,
523.Fn callout_active
524and
525.Fn callout_deactivate
526provide access to the current state of the callout.
527The
528.Fn callout_pending
529macro checks whether a callout is
530.Em pending ;
531a callout is considered
532.Em pending
533when a timeout has been set but the time has not yet arrived.
534Note that once the timeout time arrives and the callout subsystem
535starts to process this callout,
536.Fn callout_pending
537will return
538.Dv FALSE
539even though the callout function may not have finished
540.Pq or even begun
541executing.
542The
543.Fn callout_active
544macro checks whether a callout is marked as
545.Em active ,
546and the
547.Fn callout_deactivate
548macro clears the callout's
549.Em active
550flag.
551The callout subsystem marks a callout as
552.Em active
553when a timeout is set and it clears the
554.Em active
555flag in
556.Fn callout_stop
557and
558.Fn callout_drain ,
559but it
560.Em does not
561clear it when a callout expires normally via the execution of the
562callout function.
563.Pp
564The
565.Fn callout_when
566function may be used to pre-calculate the absolute time at which the
567timeout should be run and the precision of the scheduled run time
568according to the required time
569.Fa sbt ,
570precision
571.Fa precision ,
572and additional adjustments requested by the
573.Fa flags
574argument.
575Flags accepted by the
576.Fn callout_when
577function are the same as flags for the
578.Fn callout_reset
579function.
580The resulting time is assigned to the variable pointed to by the
581.Fa sbt_res
582argument, and the resulting precision is assigned to
583.Fa *precision_res .
584When passing the results to
585.Fa callout_reset ,
586add the
587.Va C_PRECALC
588flag to
589.Fa flags ,
590to avoid incorrect re-adjustment.
591The function is intended for situations where precise time of the callout
592run should be known in advance, since
593trying to read this time from the callout structure itself after a
594.Fn callout_reset
595call is racy.
596.Ss "Avoiding Race Conditions"
597The callout subsystem invokes callout functions from its own thread
598context.
599Without some kind of synchronization,
600it is possible that a callout
601function will be invoked concurrently with an attempt to stop or reset
602the callout by another thread.
603In particular, since callout functions typically acquire a lock as
604their first action, the callout function may have already been invoked,
605but is blocked waiting for that lock at the time that another thread
606tries to reset or stop the callout.
607.Pp
608There are three main techniques for addressing these
609synchronization concerns.
610The first approach is preferred as it is the simplest:
611.Bl -enum -offset indent
612.It
613Callouts can be associated with a specific lock when they are initialized
614by
615.Fn callout_init_mtx ,
616.Fn callout_init_rm ,
617or
618.Fn callout_init_rw .
619When a callout is associated with a lock,
620the callout subsystem acquires the lock before the callout function is
621invoked.
622This allows the callout subsystem to transparently handle races between
623callout cancellation,
624scheduling,
625and execution.
626Note that the associated lock must be acquired before calling
627.Fn callout_stop
628or one of the
629.Fn callout_reset
630or
631.Fn callout_schedule
632functions to provide this safety.
633.Pp
634A callout initialized via
635.Fn callout_init
636with
637.Fa mpsafe
638set to zero is implicitly associated with the
639.Va Giant
640mutex.
641If
642.Va Giant
643is held when cancelling or rescheduling the callout,
644then its use will prevent races with the callout function.
645.It
646The return value from
647.Fn callout_stop
648.Po
649or the
650.Fn callout_reset
651and
652.Fn callout_schedule
653function families
654.Pc
655indicates whether or not the callout was removed.
656If it is known that the callout was set and the callout function has
657not yet executed, then a return value of
658.Dv FALSE
659indicates that the callout function is about to be called.
660For example:
661.Bd -literal -offset indent
662if (sc->sc_flags & SCFLG_CALLOUT_RUNNING) {
663	if (callout_stop(&sc->sc_callout)) {
664		sc->sc_flags &= ~SCFLG_CALLOUT_RUNNING;
665		/* successfully stopped */
666	} else {
667		/*
668		 * callout has expired and callout
669		 * function is about to be executed
670		 */
671	}
672}
673.Ed
674.It
675The
676.Fn callout_pending ,
677.Fn callout_active
678and
679.Fn callout_deactivate
680macros can be used together to work around the race conditions.
681When a callout's timeout is set, the callout subsystem marks the
682callout as both
683.Em active
684and
685.Em pending .
686When the timeout time arrives, the callout subsystem begins processing
687the callout by first clearing the
688.Em pending
689flag.
690It then invokes the callout function without changing the
691.Em active
692flag, and does not clear the
693.Em active
694flag even after the callout function returns.
695The mechanism described here requires the callout function itself to
696clear the
697.Em active
698flag using the
699.Fn callout_deactivate
700macro.
701The
702.Fn callout_stop
703and
704.Fn callout_drain
705functions always clear both the
706.Em active
707and
708.Em pending
709flags before returning.
710.Pp
711The callout function should first check the
712.Em pending
713flag and return without action if
714.Fn callout_pending
715returns
716.Dv TRUE .
717This indicates that the callout was rescheduled using
718.Fn callout_reset
719just before the callout function was invoked.
720If
721.Fn callout_active
722returns
723.Dv FALSE
724then the callout function should also return without action.
725This indicates that the callout has been stopped.
726Finally, the callout function should call
727.Fn callout_deactivate
728to clear the
729.Em active
730flag.
731For example:
732.Bd -literal -offset indent
733mtx_lock(&sc->sc_mtx);
734if (callout_pending(&sc->sc_callout)) {
735	/* callout was reset */
736	mtx_unlock(&sc->sc_mtx);
737	return;
738}
739if (!callout_active(&sc->sc_callout)) {
740	/* callout was stopped */
741	mtx_unlock(&sc->sc_mtx);
742	return;
743}
744callout_deactivate(&sc->sc_callout);
745/* rest of callout function */
746.Ed
747.Pp
748Together with appropriate synchronization, such as the mutex used above,
749this approach permits the
750.Fn callout_stop
751and
752.Fn callout_reset
753functions to be used at any time without races.
754For example:
755.Bd -literal -offset indent
756mtx_lock(&sc->sc_mtx);
757callout_stop(&sc->sc_callout);
758/* The callout is effectively stopped now. */
759.Ed
760.Pp
761If the callout is still pending then these functions operate normally,
762but if processing of the callout has already begun then the tests in
763the callout function cause it to return without further action.
764Synchronization between the callout function and other code ensures that
765stopping or resetting the callout will never be attempted while the
766callout function is past the
767.Fn callout_deactivate
768call.
769.Pp
770The above technique additionally ensures that the
771.Em active
772flag always reflects whether the callout is effectively enabled or
773disabled.
774If
775.Fn callout_active
776returns false, then the callout is effectively disabled, since even if
777the callout subsystem is actually just about to invoke the callout
778function, the callout function will return without action.
779.El
780.Pp
781There is one final race condition that must be considered when a
782callout is being stopped for the last time.
783In this case it may not be safe to let the callout function itself
784detect that the callout was stopped, since it may need to access
785data objects that have already been destroyed or recycled.
786To ensure that the callout is completely finished, a call to
787.Fn callout_drain
788should be used.
789In particular,
790a callout should always be drained prior to destroying its associated lock
791or releasing the storage for the callout structure.
792.Sh RETURN VALUES
793The
794.Fn callout_active
795macro returns the state of a callout's
796.Em active
797flag.
798.Pp
799The
800.Fn callout_pending
801macro returns the state of a callout's
802.Em pending
803flag.
804.Pp
805The
806.Fn callout_reset
807and
808.Fn callout_schedule
809function families return a value of one if the callout was pending before the new
810function invocation was scheduled.
811.Pp
812The
813.Fn callout_stop
814and
815.Fn callout_drain
816functions return a value of one if the callout was still pending when it was
817called, a zero if the callout could not be stopped and a negative one is it
818was either not running or has already completed.
819.Sh HISTORY
820.Fx
821initially used the long standing
822.Bx
823linked list
824callout mechanism which offered O(n) insertion and removal running time
825but did not generate or require handles for untimeout operations.
826.Pp
827.Fx 3.0
828introduced a new set of timeout and untimeout routines from
829.Nx
830based on the work of
831.An Adam M. Costello
832and
833.An George Varghese ,
834published in a technical report entitled
835.%T "Redesigning the BSD Callout and Timer Facilities"
836and modified for inclusion in
837.Fx
838by
839.An Justin T. Gibbs .
840The original work on the data structures used in that implementation
841was published by
842.An G. Varghese
843and
844.An A. Lauck
845in the paper
846.%T "Hashed and Hierarchical Timing Wheels: Data Structures for the Efficient Implementation of a Timer Facility"
847in the
848.%B "Proceedings of the 11th ACM Annual Symposium on Operating Systems Principles" .
849.Pp
850.Fx 3.3
851introduced the first implementations of
852.Fn callout_init ,
853.Fn callout_reset ,
854and
855.Fn callout_stop
856which permitted callers to allocate dedicated storage for callouts.
857This ensured that a callout would always fire unlike
858.Fn timeout
859which would silently fail if it was unable to allocate a callout.
860.Pp
861.Fx 5.0
862permitted callout handlers to be tagged as MPSAFE via
863.Fn callout_init .
864.Pp
865.Fx 5.3
866introduced
867.Fn callout_drain .
868.Pp
869.Fx 6.0
870introduced
871.Fn callout_init_mtx .
872.Pp
873.Fx 8.0
874introduced per-CPU callout wheels,
875.Fn callout_init_rw ,
876and
877.Fn callout_schedule .
878.Pp
879.Fx 9.0
880changed the underlying timer interrupts used to drive callouts to prefer
881one-shot event timers instead of a periodic timer interrupt.
882.Pp
883.Fx 10.0
884switched the callout wheel to support tickless operation.
885These changes introduced
886.Vt sbintime_t
887and the
888.Fn callout_reset_sbt*
889family of functions.
890.Fx 10.0 also added
891.Dv C_DIRECT_EXEC
892and
893.Fn callout_init_rm .
894.Pp
895.Fx 10.2
896introduced the
897.Fn callout_schedule_sbt*
898family of functions.
899.Pp
900.Fx 11.0
901introduced
902.Fn callout_async_drain .
903.Fx 11.1
904introduced
905.Fn callout_when .
906.Fx 13.0
907removed
908.Vt timeout_t ,
909.Fn timeout ,
910and
911.Fn untimeout .
912