xref: /trueos/share/man/man9/timeout.9 (revision 96cd89f2c91d7612e3edf9b5e20a45ac80b364f5)
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.\" $FreeBSD$
31.\"
32.Dd October 8, 2014
33.Dt TIMEOUT 9
34.Os
35.Sh NAME
36.Nm callout_active ,
37.Nm callout_deactivate ,
38.Nm callout_drain ,
39.Nm callout_handle_init ,
40.Nm callout_init ,
41.Nm callout_init_mtx ,
42.Nm callout_init_rm ,
43.Nm callout_init_rw ,
44.Nm callout_pending ,
45.Nm callout_reset ,
46.Nm callout_reset_curcpu ,
47.Nm callout_reset_on ,
48.Nm callout_reset_sbt ,
49.Nm callout_reset_sbt_curcpu ,
50.Nm callout_reset_sbt_on ,
51.Nm callout_schedule ,
52.Nm callout_schedule_curcpu ,
53.Nm callout_schedule_on ,
54.Nm callout_schedule_sbt ,
55.Nm callout_schedule_sbt_curcpu ,
56.Nm callout_schedule_sbt_on ,
57.Nm callout_stop ,
58.Nm timeout ,
59.Nm untimeout
60.Nd execute a function after a specified length of time
61.Sh SYNOPSIS
62.In sys/types.h
63.In sys/systm.h
64.Bd -literal
65typedef void timeout_t (void *);
66.Ed
67.Ft int
68.Fn callout_active "struct callout *c"
69.Ft void
70.Fn callout_deactivate "struct callout *c"
71.Ft int
72.Fn callout_drain "struct callout *c"
73.Ft void
74.Fn callout_handle_init "struct callout_handle *handle"
75.Bd -literal
76struct callout_handle handle = CALLOUT_HANDLE_INITIALIZER(&handle);
77.Ed
78.Ft void
79.Fn callout_init "struct callout *c" "int mpsafe"
80.Ft void
81.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags"
82.Ft void
83.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags"
84.Ft void
85.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags"
86.Ft int
87.Fn callout_pending "struct callout *c"
88.Ft int
89.Fn callout_reset "struct callout *c" "int ticks" "timeout_t *func" "void *arg"
90.Ft int
91.Fn callout_reset_curcpu "struct callout *c" "int ticks" "timeout_t *func" \
92"void *arg"
93.Ft int
94.Fn callout_reset_on "struct callout *c" "int ticks" "timeout_t *func" \
95"void *arg" "int cpu"
96.Ft int
97.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \
98"sbintime_t pr" "timeout_t *func" "void *arg" "int flags"
99.Ft int
100.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
101"sbintime_t pr" "timeout_t *func" "void *arg" "int flags"
102.Ft int
103.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \
104"sbintime_t pr" "timeout_t *func" "void *arg" "int cpu" "int flags"
105.Ft int
106.Fn callout_schedule "struct callout *c" "int ticks"
107.Ft int
108.Fn callout_schedule_curcpu "struct callout *c" "int ticks"
109.Ft int
110.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu"
111.Ft int
112.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \
113"sbintime_t pr" "int flags"
114.Ft int
115.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
116"sbintime_t pr" "int flags"
117.Ft int
118.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \
119"sbintime_t pr" "int cpu" "int flags"
120.Ft int
121.Fn callout_stop "struct callout *c"
122.Ft struct callout_handle
123.Fn timeout "timeout_t *func" "void *arg" "int ticks"
124.Ft void
125.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle"
126.Sh DESCRIPTION
127The
128.Nm callout
129API is used to schedule a call to an arbitrary function at a specific
130time in the future.
131Consumers of this API are required to allocate a callout structure
132.Pq struct callout
133for each pending function invocation.
134This structure stores state about the pending function invocation including
135the function to be called and the time at which the function should be invoked.
136Pending function calls can be cancelled or rescheduled to a different time.
137In addition,
138a callout structure may be reused to schedule a new function call after a
139scheduled call is completed.
140.Pp
141Callouts only provide a single-shot mode.
142If a consumer requires a periodic timer,
143it must explicitly reschedule each function call.
144This is normally done by rescheduling the subsequent call within the called
145function.
146.Pp
147Callout functions must not sleep.
148They may not acquire sleepable locks,
149wait on condition variables,
150perform blocking allocation requests,
151or invoke any other action that might sleep.
152.Pp
153Each callout structure must be initialized by
154.Fn callout_init ,
155.Fn callout_init_mtx ,
156.Fn callout_init_rm ,
157or
158.Fn callout_init_rw
159before it is passed to any of the other callout functions.
160The
161.Fn callout_init
162function initializes a callout structure in
163.Fa c
164that is not associated with a specific lock.
165If the
166.Fa mpsafe
167argument is zero,
168the callout structure is not considered to be
169.Dq multi-processor safe ;
170and the Giant lock will be acquired before calling the callout function
171and released when the callout function returns.
172.Pp
173The
174.Fn callout_init_mtx ,
175.Fn callout_init_rm ,
176and
177.Fn callout_init_rw
178functions initialize a callout structure in
179.Fa c
180that is associated with a specific lock.
181The lock is specified by the
182.Fa mtx ,
183.Fa rm ,
184or
185.Fa rw
186parameter.
187The associated lock must be held while stopping or rescheduling the
188callout.
189The callout subsystem acquires the associated lock before calling the
190callout function and releases it after the function returns.
191If the callout was cancelled while the callout subsystem waited for the
192associated lock,
193the callout function is not called,
194and the associated lock is released.
195This ensures that stopping or rescheduling the callout will abort any
196previously scheduled invocation.
197.Pp
198Only regular mutexes may be used with
199.Fn callout_init_mtx ;
200spin mutexes are not supported.
201A sleepable read-mostly lock
202.Po
203one initialized with the
204.Dv RM_SLEEPABLE
205flag
206.Pc
207may not be used with
208.Fn callout_init_rm .
209Similarly, other sleepable lock types such as
210.Xr sx 9
211and
212.Xr lockmgr 9
213cannot be used with callouts because sleeping is not permitted in
214the callout subsystem.
215.Pp
216These
217.Fa flags
218may be specified for
219.Fn callout_init_mtx ,
220.Fn callout_init_rm ,
221or
222.Fn callout_init_rw :
223.Bl -tag -width ".Dv CALLOUT_RETURNUNLOCKED"
224.It Dv CALLOUT_RETURNUNLOCKED
225The callout function will release the associated lock itself,
226so the callout subsystem should not attempt to unlock it
227after the callout function returns.
228.It Dv CALLOUT_SHAREDLOCK
229The lock is only acquired in read mode when running the callout handler.
230This flag is ignored by
231.Fn callout_init_mtx .
232.El
233.Pp
234The function
235.Fn callout_stop
236cancels a callout
237.Fa c
238if it is currently pending.
239If the callout is pending, then
240.Fn callout_stop
241returns a non-zero value.
242If the callout is not set,
243has already been serviced,
244or is currently being serviced,
245then zero will be returned.
246If the callout has an associated lock,
247then that lock must be held when this function is called.
248.Pp
249The function
250.Fn callout_drain
251is identical to
252.Fn callout_stop
253except that it will wait for the callout
254.Fa c
255to complete if it is already in progress.
256This function MUST NOT be called while holding any
257locks on which the callout might block, or deadlock will result.
258Note that if the callout subsystem has already begun processing this
259callout, then the callout function may be invoked before
260.Fn callout_drain
261returns.
262However, the callout subsystem does guarantee that the callout will be
263fully stopped before
264.Fn callout_drain
265returns.
266.Pp
267The
268.Fn callout_reset
269and
270.Fn callout_schedule
271function families schedule a future function invocation for callout
272.Fa c .
273If
274.Fa c
275already has a pending callout,
276it is cancelled before the new invocation is scheduled.
277These functions return a non-zero value if a pending callout was cancelled
278and zero if there was no pending callout.
279If the callout has an associated lock,
280then that lock must be held when any of these functions are called.
281.Pp
282The time at which the callout function will be invoked is determined by
283either the
284.Fa ticks
285argument or the
286.Fa sbt ,
287.Fa pr ,
288and
289.Fa flags
290arguments.
291When
292.Fa ticks
293is used,
294the callout is scheduled to execute after
295.Fa ticks Ns No /hz
296seconds.
297Non-positive values of
298.Fa ticks
299are silently converted to the value
300.Sq 1 .
301.Pp
302The
303.Fa sbt ,
304.Fa pr ,
305and
306.Fa flags
307arguments provide more control over the scheduled time including
308support for higher resolution times,
309specifying the precision of the scheduled time,
310and setting an absolute deadline instead of a relative timeout.
311The callout is scheduled to execute in a time window which begins at
312the time specified in
313.Fa sbt
314and extends for the amount of time specified in
315.Fa pr .
316If
317.Fa sbt
318specifies a time in the past,
319the window is adjusted to start at the current time.
320A non-zero value for
321.Fa pr
322allows the callout subsystem to coalesce callouts scheduled close to each
323other into fewer timer interrupts,
324reducing processing overhead and power consumption.
325These
326.Fa flags
327may be specified to adjust the interpretation of
328.Fa sbt
329and
330.Fa pr :
331.Bl -tag -width ".Dv C_DIRECT_EXEC"
332.It Dv C_ABSOLUTE
333Handle the
334.Fa sbt
335argument as an absolute time since boot.
336By default,
337.Fa sbt
338is treated as a relative amount of time,
339similar to
340.Fa ticks .
341.It Dv C_DIRECT_EXEC
342Run the handler directly from hardware interrupt context instead of from the
343softclock thread.
344This reduces latency and overhead, but puts more constraints on the callout
345function.
346Callout functions run in this context may use only spin mutexes for locking
347and should be as small as possible because they run with absolute priority.
348.It Fn C_PREL
349Specifies relative event time precision as binary logarithm of time interval
350divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4, etc.
351Note that the larger of
352.Fa pr
353or this value is used as the length of the time window.
354Smaller values
355.Pq which result in larger time intervals
356allow the callout subsystem to aggregate more events in one timer interrupt.
357.It Dv C_HARDCLOCK
358Align the timeouts to
359.Fn hardclock
360calls if possible.
361.El
362.Pp
363The
364.Fn callout_reset
365functions accept a
366.Fa func
367argument which identifies the function to be called when the time expires.
368It must be a pointer to a function that takes a single
369.Fa void *
370argument.
371Upon invocation,
372.Fa func
373will receive
374.Fa arg
375as its only argument.
376The
377.Fn callout_schedule
378functions reuse the
379.Fa func
380and
381.Fa arg
382arguments from the previous callout.
383Note that one of the
384.Fn callout_reset
385functions must always be called to initialize
386.Fa func
387and
388.Fa arg
389before one of the
390.Fn callout_schedule
391functions can be used.
392.Pp
393The callout subsystem provides a softclock thread for each CPU in the system.
394Callouts are assigned to a single CPU and are executed by the softclock thread
395for that CPU.
396Initially,
397callouts are assigned to CPU 0.
398The
399.Fn callout_reset_on ,
400.Fn callout_reset_sbt_on ,
401.Fn callout_schedule_on
402and
403.Fn callout_schedule_sbt_on
404functions assign the callout to CPU
405.Fa cpu .
406The
407.Fn callout_reset_curcpu ,
408.Fn callout_reset_sbt_curpu ,
409.Fn callout_schedule_curcpu
410and
411.Fn callout_schedule_sbt_curcpu
412functions assign the callout to the current CPU.
413The
414.Fn callout_reset ,
415.Fn callout_reset_sbt ,
416.Fn callout_schedule
417and
418.Fn callout_schedule_sbt
419functions schedule the callout to execute in the softclock thread of the CPU
420to which it is currently assigned.
421.Pp
422Softclock threads are not pinned to their respective CPUs by default.
423The softclock thread for CPU 0 can be pinned to CPU 0 by setting the
424.Va kern.pin_default_swi
425loader tunable to a non-zero value.
426Softclock threads for CPUs other than zero can be pinned to their
427respective CPUs by setting the
428.Va kern.pin_pcpu_swi
429loader tunable to a non-zero value.
430.Pp
431The macros
432.Fn callout_pending ,
433.Fn callout_active
434and
435.Fn callout_deactivate
436provide access to the current state of the callout.
437The
438.Fn callout_pending
439macro checks whether a callout is
440.Em pending ;
441a callout is considered
442.Em pending
443when a timeout has been set but the time has not yet arrived.
444Note that once the timeout time arrives and the callout subsystem
445starts to process this callout,
446.Fn callout_pending
447will return
448.Dv FALSE
449even though the callout function may not have finished
450.Pq or even begun
451executing.
452The
453.Fn callout_active
454macro checks whether a callout is marked as
455.Em active ,
456and the
457.Fn callout_deactivate
458macro clears the callout's
459.Em active
460flag.
461The callout subsystem marks a callout as
462.Em active
463when a timeout is set and it clears the
464.Em active
465flag in
466.Fn callout_stop
467and
468.Fn callout_drain ,
469but it
470.Em does not
471clear it when a callout expires normally via the execution of the
472callout function.
473.Ss "Avoiding Race Conditions"
474The callout subsystem invokes callout functions from its own thread
475context.
476Without some kind of synchronization,
477it is possible that a callout
478function will be invoked concurrently with an attempt to stop or reset
479the callout by another thread.
480In particular, since callout functions typically acquire a lock as
481their first action, the callout function may have already been invoked,
482but is blocked waiting for that lock at the time that another thread
483tries to reset or stop the callout.
484.Pp
485There are three main techniques for addressing these
486synchronization concerns.
487The first approach is preferred as it is the simplest:
488.Bl -enum -offset indent
489.It
490Callouts can be associated with a specific lock when they are initialized
491by
492.Fn callout_init_mtx ,
493.Fn callout_init_rm ,
494or
495.Fn callout_init_rw .
496When a callout is associated with a lock,
497the callout subsystem acquires the lock before the callout function is
498invoked.
499This allows the callout subsystem to transparently handle races between
500callout cancellation,
501scheduling,
502and execution.
503Note that the associated lock must be acquired before calling
504.Fn callout_stop
505or one of the
506.Fn callout_reset
507or
508.Fn callout_schedule
509functions to provide this safety.
510.Pp
511A callout initialized via
512.Fn callout_init
513with
514.Fa mpsafe
515set to zero is implicitly associated with the
516.Va Giant
517mutex.
518If
519.Va Giant
520is held when cancelling or rescheduling the callout,
521then its use will prevent races with the callout function.
522.It
523The return value from
524.Fn callout_stop
525.Po
526or the
527.Fn callout_reset
528and
529.Fn callout_schedule
530function families
531.Pc
532indicates whether or not the callout was removed.
533If it is known that the callout was set and the callout function has
534not yet executed, then a return value of
535.Dv FALSE
536indicates that the callout function is about to be called.
537For example:
538.Bd -literal -offset indent
539if (sc->sc_flags & SCFLG_CALLOUT_RUNNING) {
540	if (callout_stop(&sc->sc_callout)) {
541		sc->sc_flags &= ~SCFLG_CALLOUT_RUNNING;
542		/* successfully stopped */
543	} else {
544		/*
545		 * callout has expired and callout
546		 * function is about to be executed
547		 */
548	}
549}
550.Ed
551.It
552The
553.Fn callout_pending ,
554.Fn callout_active
555and
556.Fn callout_deactivate
557macros can be used together to work around the race conditions.
558When a callout's timeout is set, the callout subsystem marks the
559callout as both
560.Em active
561and
562.Em pending .
563When the timeout time arrives, the callout subsystem begins processing
564the callout by first clearing the
565.Em pending
566flag.
567It then invokes the callout function without changing the
568.Em active
569flag, and does not clear the
570.Em active
571flag even after the callout function returns.
572The mechanism described here requires the callout function itself to
573clear the
574.Em active
575flag using the
576.Fn callout_deactivate
577macro.
578The
579.Fn callout_stop
580and
581.Fn callout_drain
582functions always clear both the
583.Em active
584and
585.Em pending
586flags before returning.
587.Pp
588The callout function should first check the
589.Em pending
590flag and return without action if
591.Fn callout_pending
592returns
593.Dv TRUE .
594This indicates that the callout was rescheduled using
595.Fn callout_reset
596just before the callout function was invoked.
597If
598.Fn callout_active
599returns
600.Dv FALSE
601then the callout function should also return without action.
602This indicates that the callout has been stopped.
603Finally, the callout function should call
604.Fn callout_deactivate
605to clear the
606.Em active
607flag.
608For example:
609.Bd -literal -offset indent
610mtx_lock(&sc->sc_mtx);
611if (callout_pending(&sc->sc_callout)) {
612	/* callout was reset */
613	mtx_unlock(&sc->sc_mtx);
614	return;
615}
616if (!callout_active(&sc->sc_callout)) {
617	/* callout was stopped */
618	mtx_unlock(&sc->sc_mtx);
619	return;
620}
621callout_deactivate(&sc->sc_callout);
622/* rest of callout function */
623.Ed
624.Pp
625Together with appropriate synchronization, such as the mutex used above,
626this approach permits the
627.Fn callout_stop
628and
629.Fn callout_reset
630functions to be used at any time without races.
631For example:
632.Bd -literal -offset indent
633mtx_lock(&sc->sc_mtx);
634callout_stop(&sc->sc_callout);
635/* The callout is effectively stopped now. */
636.Ed
637.Pp
638If the callout is still pending then these functions operate normally,
639but if processing of the callout has already begun then the tests in
640the callout function cause it to return without further action.
641Synchronization between the callout function and other code ensures that
642stopping or resetting the callout will never be attempted while the
643callout function is past the
644.Fn callout_deactivate
645call.
646.Pp
647The above technique additionally ensures that the
648.Em active
649flag always reflects whether the callout is effectively enabled or
650disabled.
651If
652.Fn callout_active
653returns false, then the callout is effectively disabled, since even if
654the callout subsystem is actually just about to invoke the callout
655function, the callout function will return without action.
656.El
657.Pp
658There is one final race condition that must be considered when a
659callout is being stopped for the last time.
660In this case it may not be safe to let the callout function itself
661detect that the callout was stopped, since it may need to access
662data objects that have already been destroyed or recycled.
663To ensure that the callout is completely finished, a call to
664.Fn callout_drain
665should be used.
666In particular,
667a callout should always be drained prior to destroying its associated lock
668or releasing the storage for the callout structure.
669.Sh LEGACY API
670.Bf Sy
671The functions below are a legacy API that will be removed in a future release.
672New code should not use these routines.
673.Ef
674.Pp
675The function
676.Fn timeout
677schedules a call to the function given by the argument
678.Fa func
679to take place after
680.Fa ticks Ns No /hz
681seconds.
682Non-positive values of
683.Fa ticks
684are silently converted to the value
685.Sq 1 .
686.Fa func
687should be a pointer to a function that takes a
688.Fa void *
689argument.
690Upon invocation,
691.Fa func
692will receive
693.Fa arg
694as its only argument.
695The return value from
696.Fn timeout
697is a
698.Ft struct callout_handle
699which can be used in conjunction with the
700.Fn untimeout
701function to request that a scheduled timeout be canceled.
702.Pp
703The function
704.Fn callout_handle_init
705can be used to initialize a handle to a state which will cause
706any calls to
707.Fn untimeout
708with that handle to return with no side
709effects.
710.Pp
711Assigning a callout handle the value of
712.Fn CALLOUT_HANDLE_INITIALIZER
713performs the same function as
714.Fn callout_handle_init
715and is provided for use on statically declared or global callout handles.
716.Pp
717The function
718.Fn untimeout
719cancels the timeout associated with
720.Fa handle
721using the
722.Fa func
723and
724.Fa arg
725arguments to validate the handle.
726If the handle does not correspond to a timeout with
727the function
728.Fa func
729taking the argument
730.Fa arg
731no action is taken.
732.Fa handle
733must be initialized by a previous call to
734.Fn timeout ,
735.Fn callout_handle_init ,
736or assigned the value of
737.Fn CALLOUT_HANDLE_INITIALIZER "&handle"
738before being passed to
739.Fn untimeout .
740The behavior of calling
741.Fn untimeout
742with an uninitialized handle
743is undefined.
744.Pp
745As handles are recycled by the system, it is possible (although unlikely)
746that a handle from one invocation of
747.Fn timeout
748may match the handle of another invocation of
749.Fn timeout
750if both calls used the same function pointer and argument, and the first
751timeout is expired or canceled before the second call.
752The timeout facility offers O(1) running time for
753.Fn timeout
754and
755.Fn untimeout .
756Timeouts are executed from
757.Fn softclock
758with the
759.Va Giant
760lock held.
761Thus they are protected from re-entrancy.
762.Sh RETURN VALUES
763The
764.Fn callout_active
765macro returns the state of a callout's
766.Em active
767flag.
768.Pp
769The
770.Fn callout_pending
771macro returns the state of a callout's
772.Em pending
773flag.
774.Pp
775The
776.Fn callout_reset
777and
778.Fn callout_schedule
779function families return non-zero if the callout was pending before the new
780function invocation was scheduled.
781.Pp
782The
783.Fn callout_stop
784and
785.Fn callout_drain
786functions return non-zero if the callout was still pending when it was
787called or zero otherwise.
788The
789.Fn timeout
790function returns a
791.Ft struct callout_handle
792that can be passed to
793.Fn untimeout .
794.Sh HISTORY
795The current timeout and untimeout routines are based on the work of
796.An Adam M. Costello
797and
798.An George Varghese ,
799published in a technical report entitled
800.%T "Redesigning the BSD Callout and Timer Facilities"
801and modified slightly for inclusion in
802.Fx
803by
804.An Justin T. Gibbs .
805The original work on the data structures used in this implementation
806was published by
807.An G. Varghese
808and
809.An A. Lauck
810in the paper
811.%T "Hashed and Hierarchical Timing Wheels: Data Structures for the Efficient Implementation of a Timer Facility"
812in the
813.%B "Proceedings of the 11th ACM Annual Symposium on Operating Systems Principles" .
814The current implementation replaces the long standing
815.Bx
816linked list
817callout mechanism which offered O(n) insertion and removal running time
818but did not generate or require handles for untimeout operations.
819