Index: ObsoleteFiles.inc =================================================================== --- ObsoleteFiles.inc +++ ObsoleteFiles.inc @@ -38,6 +38,9 @@ # xargs -n1 | sort | uniq -d; # done +# 2019xxxx: remove timeout(9) +OLD_FILES+=usr/share/man/man9/timeout.9.gz +OLD_FILES+=usr/share/man/man9/untimeout.9.gz # 20191009: new clang import which bumps version from 8.0.1 to 9.0.0. OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/allocator_interface.h OLD_FILES+=usr/lib/clang/8.0.1/include/sanitizer/asan_interface.h Index: share/man/man9/Makefile =================================================================== --- share/man/man9/Makefile +++ share/man/man9/Makefile @@ -55,6 +55,7 @@ BUS_SETUP_INTR.9 \ bus_space.9 \ byteorder.9 \ + callout.9 \ casuword.9 \ cd.9 \ cnv.9 \ @@ -314,7 +315,6 @@ tcp_functions.9 \ thread_exit.9 \ time.9 \ - timeout.9 \ tvtohz.9 \ ucred.9 \ uidinfo.9 \ @@ -765,6 +765,30 @@ byteorder.9 le64dec.9 \ byteorder.9 le64enc.9 \ byteorder.9 le64toh.9 +MLINKS+=callout.9 callout_active.9 \ + callout.9 callout_async_drain.9 \ + callout.9 callout_deactivate.9 \ + callout.9 callout_drain.9 \ + callout.9 callout_handle_init.9 \ + callout.9 callout_init.9 \ + callout.9 callout_init_mtx.9 \ + callout.9 callout_init_rm.9 \ + callout.9 callout_init_rw.9 \ + callout.9 callout_pending.9 \ + callout.9 callout_reset.9 \ + callout.9 callout_reset_curcpu.9 \ + callout.9 callout_reset_on.9 \ + callout.9 callout_reset_sbt.9 \ + callout.9 callout_reset_sbt_curcpu.9 \ + callout.9 callout_reset_sbt_on.9 \ + callout.9 callout_schedule.9 \ + callout.9 callout_schedule_curcpu.9 \ + callout.9 callout_schedule_on.9 \ + callout.9 callout_schedule_sbt.9 \ + callout.9 callout_schedule_sbt_curcpu.9 \ + callout.9 callout_schedule_sbt_on.9 \ + callout.9 callout_stop.9 \ + callout.9 callout_when.9 MLINKS+=cnv.9 cnvlist.9 \ cnv.9 cnvlist_free_binary.9 \ cnv.9 cnvlist_free_bool.9 \ @@ -2096,32 +2120,6 @@ MLINKS+=time.9 boottime.9 \ time.9 time_second.9 \ time.9 time_uptime.9 -MLINKS+=timeout.9 callout.9 \ - timeout.9 callout_active.9 \ - timeout.9 callout_async_drain.9 \ - timeout.9 callout_deactivate.9 \ - timeout.9 callout_drain.9 \ - timeout.9 callout_handle_init.9 \ - timeout.9 callout_init.9 \ - timeout.9 callout_init_mtx.9 \ - timeout.9 callout_init_rm.9 \ - timeout.9 callout_init_rw.9 \ - timeout.9 callout_pending.9 \ - timeout.9 callout_reset.9 \ - timeout.9 callout_reset_curcpu.9 \ - timeout.9 callout_reset_on.9 \ - timeout.9 callout_reset_sbt.9 \ - timeout.9 callout_reset_sbt_curcpu.9 \ - timeout.9 callout_reset_sbt_on.9 \ - timeout.9 callout_schedule.9 \ - timeout.9 callout_schedule_curcpu.9 \ - timeout.9 callout_schedule_on.9 \ - timeout.9 callout_schedule_sbt.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 crcopy.9 \ ucred.9 crcopysafe.9 \ ucred.9 crdup.9 \ Index: share/man/man9/callout.9 =================================================================== --- share/man/man9/callout.9 +++ share/man/man9/callout.9 @@ -30,7 +30,7 @@ .\" $FreeBSD: head/share/man/man9/timeout.9 332043 2018-04-04 20:15:41Z markj $ .\" .Dd July 27, 2016 -.Dt TIMEOUT 9 +.Dt CALLOUT 9 .Os .Sh NAME .Nm callout_active , @@ -56,22 +56,17 @@ .Nm callout_schedule_sbt_curcpu , .Nm callout_schedule_sbt_on , .Nm callout_stop , -.Nm callout_when , -.Nm timeout , -.Nm untimeout +.Nm callout_when .Nd execute a function after a specified length of time .Sh SYNOPSIS .In sys/types.h .In sys/systm.h -.Bd -literal -typedef void timeout_t (void *); -.Ed .Ft int .Fn callout_active "struct callout *c" .Ft void .Fn callout_deactivate "struct callout *c" .Ft int -.Fn callout_async_drain "struct callout *c" "timeout_t *drain" +.Fn callout_async_drain "struct callout *c" "void (*drain)(void *)" .Ft int .Fn callout_drain "struct callout *c" .Ft void @@ -90,19 +85,24 @@ .Ft int .Fn callout_pending "struct callout *c" .Ft int -.Fn callout_reset "struct callout *c" "int ticks" "timeout_t *func" "void *arg" +.Fo callout_reset +.Fa "struct callout *c" +.Fa "int ticks" +.Fa "void (*func)(void *)" +.Fa "void *arg" +.Fc .Ft int .Fo callout_reset_curcpu .Fa "struct callout *c" .Fa "int ticks" -.Fa "timeout_t *func" +.Fa "void (*func)(void *)" .Fa "void *arg" .Fc .Ft int .Fo callout_reset_on .Fa "struct callout *c" .Fa "int ticks" -.Fa "timeout_t *func" +.Fa "void (*func)(void *)" .Fa "void *arg" .Fa "int cpu" .Fc @@ -111,7 +111,7 @@ .Fa "struct callout *c" .Fa "sbintime_t sbt" .Fa "sbintime_t pr" -.Fa "timeout_t *func" +.Fa "void (*func)(void *)" .Fa "void *arg" .Fa "int flags" .Fc @@ -120,7 +120,7 @@ .Fa "struct callout *c" .Fa "sbintime_t sbt" .Fa "sbintime_t pr" -.Fa "timeout_t *func" +.Fa "void (*func)(void *)" .Fa "void *arg" .Fa "int flags" .Fc @@ -129,7 +129,7 @@ .Fa "struct callout *c" .Fa "sbintime_t sbt" .Fa "sbintime_t pr" -.Fa "timeout_t *func" +.Fa "void (*func)(void *)" .Fa "void *arg" .Fa "int cpu" .Fa "int flags" @@ -172,10 +172,6 @@ .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 -.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle" .Sh DESCRIPTION The .Nm callout @@ -801,99 +797,6 @@ In particular, a callout should always be drained prior to destroying its associated lock or releasing the storage for the callout structure. -.Sh LEGACY API -.Bf Sy -The functions below are a legacy API that will be removed in a future release. -New code should not use these routines. -.Ef -.Pp -The function -.Fn timeout -schedules a call to the function given by the argument -.Fa func -to take place after -.Fa ticks Ns No /hz -seconds. -Non-positive values of -.Fa ticks -are silently converted to the value -.Sq 1 . -.Fa func -should be a pointer to a function that takes a -.Fa void * -argument. -Upon invocation, -.Fa func -will receive -.Fa arg -as its only argument. -The return value from -.Fn timeout -is a -.Ft struct callout_handle -which can be used in conjunction with the -.Fn untimeout -function to request that a scheduled timeout be canceled. -.Pp -The function -.Fn callout_handle_init -can be used to initialize a handle to a state which will cause -any calls to -.Fn untimeout -with that handle to return with no side -effects. -.Pp -Assigning a callout handle the value of -.Fn CALLOUT_HANDLE_INITIALIZER -performs the same function as -.Fn callout_handle_init -and is provided for use on statically declared or global callout handles. -.Pp -The function -.Fn untimeout -cancels the timeout associated with -.Fa handle -using the -.Fa func -and -.Fa arg -arguments to validate the handle. -If the handle does not correspond to a timeout with -the function -.Fa func -taking the argument -.Fa arg -no action is taken. -.Fa handle -must be initialized by a previous call to -.Fn timeout , -.Fn callout_handle_init , -or assigned the value of -.Fn CALLOUT_HANDLE_INITIALIZER "&handle" -before being passed to -.Fn untimeout . -The behavior of calling -.Fn untimeout -with an uninitialized handle -is undefined. -.Pp -As handles are recycled by the system, it is possible (although unlikely) -that a handle from one invocation of -.Fn timeout -may match the handle of another invocation of -.Fn timeout -if both calls used the same function pointer and argument, and the first -timeout is expired or canceled before the second call. -The timeout facility offers O(1) running time for -.Fn timeout -and -.Fn untimeout . -Timeouts are executed from -.Fn softclock -with the -.Va Giant -lock held. -Thus they are protected from re-entrancy. .Sh RETURN VALUES The .Fn callout_active @@ -921,20 +824,14 @@ functions return a value of one if the callout was still pending when it was called, a zero if the callout could not be stopped and a negative one is it was either not running or has already completed. -The -.Fn timeout -function returns a -.Ft struct callout_handle -that can be passed to -.Fn untimeout . .Sh HISTORY -The current timeout and untimeout routines are based on the work of +The current callout routines are based on the work of .An Adam M. Costello and .An George Varghese , published in a technical report entitled .%T "Redesigning the BSD Callout and Timer Facilities" -and modified slightly for inclusion in +and modified for inclusion in .Fx by .An Justin T. Gibbs . Index: share/man/man9/timeout.9 =================================================================== --- share/man/man9/timeout.9 +++ share/man/man9/timeout.9 @@ -1,954 +0,0 @@ -.\" $NetBSD: timeout.9,v 1.2 1996/06/23 22:32:34 pk Exp $ -.\" -.\" Copyright (c) 1996 The NetBSD Foundation, Inc. -.\" All rights reserved. -.\" -.\" This code is derived from software contributed to The NetBSD Foundation -.\" by Paul Kranenburg. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS -.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE -.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -.\" POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $FreeBSD$ -.\" -.Dd July 27, 2016 -.Dt TIMEOUT 9 -.Os -.Sh NAME -.Nm callout_active , -.Nm callout_deactivate , -.Nm callout_async_drain , -.Nm callout_drain , -.Nm callout_handle_init , -.Nm callout_init , -.Nm callout_init_mtx , -.Nm callout_init_rm , -.Nm callout_init_rw , -.Nm callout_pending , -.Nm callout_reset , -.Nm callout_reset_curcpu , -.Nm callout_reset_on , -.Nm callout_reset_sbt , -.Nm callout_reset_sbt_curcpu , -.Nm callout_reset_sbt_on , -.Nm callout_schedule , -.Nm callout_schedule_curcpu , -.Nm callout_schedule_on , -.Nm callout_schedule_sbt , -.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 -.Sh SYNOPSIS -.In sys/types.h -.In sys/systm.h -.Bd -literal -typedef void timeout_t (void *); -.Ed -.Ft int -.Fn callout_active "struct callout *c" -.Ft void -.Fn callout_deactivate "struct callout *c" -.Ft int -.Fn callout_async_drain "struct callout *c" "timeout_t *drain" -.Ft int -.Fn callout_drain "struct callout *c" -.Ft void -.Fn callout_handle_init "struct callout_handle *handle" -.Bd -literal -struct callout_handle handle = CALLOUT_HANDLE_INITIALIZER(&handle); -.Ed -.Ft void -.Fn callout_init "struct callout *c" "int mpsafe" -.Ft void -.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags" -.Ft void -.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags" -.Ft void -.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags" -.Ft int -.Fn callout_pending "struct callout *c" -.Ft int -.Fn callout_reset "struct callout *c" "int ticks" "timeout_t *func" "void *arg" -.Ft int -.Fo callout_reset_curcpu -.Fa "struct callout *c" -.Fa "int ticks" -.Fa "timeout_t *func" -.Fa "void *arg" -.Fc -.Ft int -.Fo callout_reset_on -.Fa "struct callout *c" -.Fa "int ticks" -.Fa "timeout_t *func" -.Fa "void *arg" -.Fa "int cpu" -.Fc -.Ft int -.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 -.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 -.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 -.Fn callout_schedule_curcpu "struct callout *c" "int ticks" -.Ft int -.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu" -.Ft int -.Fo callout_schedule_sbt -.Fa "struct callout *c" -.Fa "sbintime_t sbt" -.Fa "sbintime_t pr" -.Fa "int flags" -.Fc -.Ft int -.Fo callout_schedule_sbt_curcpu -.Fa "struct callout *c" -.Fa "sbintime_t sbt" -.Fa "sbintime_t pr" -.Fa "int flags" -.Fc -.Ft int -.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 -.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle" -.Sh DESCRIPTION -The -.Nm callout -API is used to schedule a call to an arbitrary function at a specific -time in the future. -Consumers of this API are required to allocate a callout structure -.Pq struct callout -for each pending function invocation. -This structure stores state about the pending function invocation including -the function to be called and the time at which the function should be invoked. -Pending function calls can be cancelled or rescheduled to a different time. -In addition, -a callout structure may be reused to schedule a new function call after a -scheduled call is completed. -.Pp -Callouts only provide a single-shot mode. -If a consumer requires a periodic timer, -it must explicitly reschedule each function call. -This is normally done by rescheduling the subsequent call within the called -function. -.Pp -Callout functions must not sleep. -They may not acquire sleepable locks, -wait on condition variables, -perform blocking allocation requests, -or invoke any other action that might sleep. -.Pp -Each callout structure must be initialized by -.Fn callout_init , -.Fn callout_init_mtx , -.Fn callout_init_rm , -or -.Fn callout_init_rw -before it is passed to any of the other callout functions. -The -.Fn callout_init -function initializes a callout structure in -.Fa c -that is not associated with a specific lock. -If the -.Fa mpsafe -argument is zero, -the callout structure is not considered to be -.Dq multi-processor safe ; -and the Giant lock will be acquired before calling the callout function -and released when the callout function returns. -.Pp -The -.Fn callout_init_mtx , -.Fn callout_init_rm , -and -.Fn callout_init_rw -functions initialize a callout structure in -.Fa c -that is associated with a specific lock. -The lock is specified by the -.Fa mtx , -.Fa rm , -or -.Fa rw -parameter. -The associated lock must be held while stopping or rescheduling the -callout. -The callout subsystem acquires the associated lock before calling the -callout function and releases it after the function returns. -If the callout was cancelled while the callout subsystem waited for the -associated lock, -the callout function is not called, -and the associated lock is released. -This ensures that stopping or rescheduling the callout will abort any -previously scheduled invocation. -.Pp -Only regular mutexes may be used with -.Fn callout_init_mtx ; -spin mutexes are not supported. -A sleepable read-mostly lock -.Po -one initialized with the -.Dv RM_SLEEPABLE -flag -.Pc -may not be used with -.Fn callout_init_rm . -Similarly, other sleepable lock types such as -.Xr sx 9 -and -.Xr lockmgr 9 -cannot be used with callouts because sleeping is not permitted in -the callout subsystem. -.Pp -These -.Fa flags -may be specified for -.Fn callout_init_mtx , -.Fn callout_init_rm , -or -.Fn callout_init_rw : -.Bl -tag -width ".Dv CALLOUT_RETURNUNLOCKED" -.It Dv CALLOUT_RETURNUNLOCKED -The callout function will release the associated lock itself, -so the callout subsystem should not attempt to unlock it -after the callout function returns. -.It Dv CALLOUT_SHAREDLOCK -The lock is only acquired in read mode when running the callout handler. -This flag is ignored by -.Fn callout_init_mtx . -.El -.Pp -The function -.Fn callout_stop -cancels a callout -.Fa c -if it is currently pending. -If the callout is pending and successfully stopped, then -.Fn callout_stop -returns a value of one. -If the callout is not set, or -has already been serviced, then -negative one is returned. -If the callout is currently being serviced and cannot be stopped, -then zero will be returned. -If the callout is currently being serviced and cannot be stopped, and at the -same time a next invocation of the same callout is also scheduled, then -.Fn callout_stop -unschedules the next run and returns zero. -If the callout has an associated lock, -then that lock must be held when this function is called. -.Pp -The function -.Fn callout_async_drain -is identical to -.Fn callout_stop -with one difference. -When -.Fn callout_async_drain -returns zero it will arrange for the function -.Fa drain -to be called using the same argument given to the -.Fn callout_reset -function. -.Fn callout_async_drain -If the callout has an associated lock, -then that lock must be held when this function is called. -Note that when stopping multiple callouts that use the same lock it is possible -to get multiple return's of zero and multiple calls to the -.Fa drain -function, depending upon which CPU's the callouts are running. -The -.Fa drain -function itself is called from the context of the completing callout -i.e. softclock or hardclock, just like a callout itself. -.Pp -The function -.Fn callout_drain -is identical to -.Fn callout_stop -except that it will wait for the callout -.Fa c -to complete if it is already in progress. -This function MUST NOT be called while holding any -locks on which the callout might block, or deadlock will result. -Note that if the callout subsystem has already begun processing this -callout, then the callout function may be invoked before -.Fn callout_drain -returns. -However, the callout subsystem does guarantee that the callout will be -fully stopped before -.Fn callout_drain -returns. -.Pp -The -.Fn callout_reset -and -.Fn callout_schedule -function families schedule a future function invocation for callout -.Fa c . -If -.Fa c -already has a pending callout, -it is cancelled before the new invocation is scheduled. -These functions return a value of one if a pending callout was cancelled -and zero if there was no pending callout. -If the callout has an associated lock, -then that lock must be held when any of these functions are called. -.Pp -The time at which the callout function will be invoked is determined by -either the -.Fa ticks -argument or the -.Fa sbt , -.Fa pr , -and -.Fa flags -arguments. -When -.Fa ticks -is used, -the callout is scheduled to execute after -.Fa ticks Ns No /hz -seconds. -Non-positive values of -.Fa ticks -are silently converted to the value -.Sq 1 . -.Pp -The -.Fa sbt , -.Fa pr , -and -.Fa flags -arguments provide more control over the scheduled time including -support for higher resolution times, -specifying the precision of the scheduled time, -and setting an absolute deadline instead of a relative timeout. -The callout is scheduled to execute in a time window which begins at -the time specified in -.Fa sbt -and extends for the amount of time specified in -.Fa pr . -If -.Fa sbt -specifies a time in the past, -the window is adjusted to start at the current time. -A non-zero value for -.Fa pr -allows the callout subsystem to coalesce callouts scheduled close to each -other into fewer timer interrupts, -reducing processing overhead and power consumption. -These -.Fa flags -may be specified to adjust the interpretation of -.Fa sbt -and -.Fa pr : -.Bl -tag -width ".Dv C_DIRECT_EXEC" -.It Dv C_ABSOLUTE -Handle the -.Fa sbt -argument as an absolute time since boot. -By default, -.Fa sbt -is treated as a relative amount of time, -similar to -.Fa ticks . -.It Dv C_DIRECT_EXEC -Run the handler directly from hardware interrupt context instead of from the -softclock thread. -This reduces latency and overhead, but puts more constraints on the callout -function. -Callout functions run in this context may use only spin mutexes for locking -and should be as small as possible because they run with absolute priority. -.It Fn C_PREL -Specifies relative event time precision as binary logarithm of time interval -divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4, etc. -Note that the larger of -.Fa pr -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 -calls if possible. -.El -.Pp -The -.Fn callout_reset -functions accept a -.Fa func -argument which identifies the function to be called when the time expires. -It must be a pointer to a function that takes a single -.Fa void * -argument. -Upon invocation, -.Fa func -will receive -.Fa arg -as its only argument. -The -.Fn callout_schedule -functions reuse the -.Fa func -and -.Fa arg -arguments from the previous callout. -Note that one of the -.Fn callout_reset -functions must always be called to initialize -.Fa func -and -.Fa arg -before one of the -.Fn callout_schedule -functions can be used. -.Pp -The callout subsystem provides a softclock thread for each CPU in the system. -Callouts are assigned to a single CPU and are executed by the softclock thread -for that CPU. -Initially, -callouts are assigned to CPU 0. -The -.Fn callout_reset_on , -.Fn callout_reset_sbt_on , -.Fn callout_schedule_on -and -.Fn callout_schedule_sbt_on -functions assign the callout to CPU -.Fa cpu . -The -.Fn callout_reset_curcpu , -.Fn callout_reset_sbt_curpu , -.Fn callout_schedule_curcpu -and -.Fn callout_schedule_sbt_curcpu -functions assign the callout to the current CPU. -The -.Fn callout_reset , -.Fn callout_reset_sbt , -.Fn callout_schedule -and -.Fn callout_schedule_sbt -functions schedule the callout to execute in the softclock thread of the CPU -to which it is currently assigned. -.Pp -Softclock threads are not pinned to their respective CPUs by default. -The softclock thread for CPU 0 can be pinned to CPU 0 by setting the -.Va kern.pin_default_swi -loader tunable to a non-zero value. -Softclock threads for CPUs other than zero can be pinned to their -respective CPUs by setting the -.Va kern.pin_pcpu_swi -loader tunable to a non-zero value. -.Pp -The macros -.Fn callout_pending , -.Fn callout_active -and -.Fn callout_deactivate -provide access to the current state of the callout. -The -.Fn callout_pending -macro checks whether a callout is -.Em pending ; -a callout is considered -.Em pending -when a timeout has been set but the time has not yet arrived. -Note that once the timeout time arrives and the callout subsystem -starts to process this callout, -.Fn callout_pending -will return -.Dv FALSE -even though the callout function may not have finished -.Pq or even begun -executing. -The -.Fn callout_active -macro checks whether a callout is marked as -.Em active , -and the -.Fn callout_deactivate -macro clears the callout's -.Em active -flag. -The callout subsystem marks a callout as -.Em active -when a timeout is set and it clears the -.Em active -flag in -.Fn callout_stop -and -.Fn callout_drain , -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. -Without some kind of synchronization, -it is possible that a callout -function will be invoked concurrently with an attempt to stop or reset -the callout by another thread. -In particular, since callout functions typically acquire a lock as -their first action, the callout function may have already been invoked, -but is blocked waiting for that lock at the time that another thread -tries to reset or stop the callout. -.Pp -There are three main techniques for addressing these -synchronization concerns. -The first approach is preferred as it is the simplest: -.Bl -enum -offset indent -.It -Callouts can be associated with a specific lock when they are initialized -by -.Fn callout_init_mtx , -.Fn callout_init_rm , -or -.Fn callout_init_rw . -When a callout is associated with a lock, -the callout subsystem acquires the lock before the callout function is -invoked. -This allows the callout subsystem to transparently handle races between -callout cancellation, -scheduling, -and execution. -Note that the associated lock must be acquired before calling -.Fn callout_stop -or one of the -.Fn callout_reset -or -.Fn callout_schedule -functions to provide this safety. -.Pp -A callout initialized via -.Fn callout_init -with -.Fa mpsafe -set to zero is implicitly associated with the -.Va Giant -mutex. -If -.Va Giant -is held when cancelling or rescheduling the callout, -then its use will prevent races with the callout function. -.It -The return value from -.Fn callout_stop -.Po -or the -.Fn callout_reset -and -.Fn callout_schedule -function families -.Pc -indicates whether or not the callout was removed. -If it is known that the callout was set and the callout function has -not yet executed, then a return value of -.Dv FALSE -indicates that the callout function is about to be called. -For example: -.Bd -literal -offset indent -if (sc->sc_flags & SCFLG_CALLOUT_RUNNING) { - if (callout_stop(&sc->sc_callout)) { - sc->sc_flags &= ~SCFLG_CALLOUT_RUNNING; - /* successfully stopped */ - } else { - /* - * callout has expired and callout - * function is about to be executed - */ - } -} -.Ed -.It -The -.Fn callout_pending , -.Fn callout_active -and -.Fn callout_deactivate -macros can be used together to work around the race conditions. -When a callout's timeout is set, the callout subsystem marks the -callout as both -.Em active -and -.Em pending . -When the timeout time arrives, the callout subsystem begins processing -the callout by first clearing the -.Em pending -flag. -It then invokes the callout function without changing the -.Em active -flag, and does not clear the -.Em active -flag even after the callout function returns. -The mechanism described here requires the callout function itself to -clear the -.Em active -flag using the -.Fn callout_deactivate -macro. -The -.Fn callout_stop -and -.Fn callout_drain -functions always clear both the -.Em active -and -.Em pending -flags before returning. -.Pp -The callout function should first check the -.Em pending -flag and return without action if -.Fn callout_pending -returns -.Dv TRUE . -This indicates that the callout was rescheduled using -.Fn callout_reset -just before the callout function was invoked. -If -.Fn callout_active -returns -.Dv FALSE -then the callout function should also return without action. -This indicates that the callout has been stopped. -Finally, the callout function should call -.Fn callout_deactivate -to clear the -.Em active -flag. -For example: -.Bd -literal -offset indent -mtx_lock(&sc->sc_mtx); -if (callout_pending(&sc->sc_callout)) { - /* callout was reset */ - mtx_unlock(&sc->sc_mtx); - return; -} -if (!callout_active(&sc->sc_callout)) { - /* callout was stopped */ - mtx_unlock(&sc->sc_mtx); - return; -} -callout_deactivate(&sc->sc_callout); -/* rest of callout function */ -.Ed -.Pp -Together with appropriate synchronization, such as the mutex used above, -this approach permits the -.Fn callout_stop -and -.Fn callout_reset -functions to be used at any time without races. -For example: -.Bd -literal -offset indent -mtx_lock(&sc->sc_mtx); -callout_stop(&sc->sc_callout); -/* The callout is effectively stopped now. */ -.Ed -.Pp -If the callout is still pending then these functions operate normally, -but if processing of the callout has already begun then the tests in -the callout function cause it to return without further action. -Synchronization between the callout function and other code ensures that -stopping or resetting the callout will never be attempted while the -callout function is past the -.Fn callout_deactivate -call. -.Pp -The above technique additionally ensures that the -.Em active -flag always reflects whether the callout is effectively enabled or -disabled. -If -.Fn callout_active -returns false, then the callout is effectively disabled, since even if -the callout subsystem is actually just about to invoke the callout -function, the callout function will return without action. -.El -.Pp -There is one final race condition that must be considered when a -callout is being stopped for the last time. -In this case it may not be safe to let the callout function itself -detect that the callout was stopped, since it may need to access -data objects that have already been destroyed or recycled. -To ensure that the callout is completely finished, a call to -.Fn callout_drain -should be used. -In particular, -a callout should always be drained prior to destroying its associated lock -or releasing the storage for the callout structure. -.Sh LEGACY API -.Bf Sy -The functions below are a legacy API that will be removed in a future release. -New code should not use these routines. -.Ef -.Pp -The function -.Fn timeout -schedules a call to the function given by the argument -.Fa func -to take place after -.Fa ticks Ns No /hz -seconds. -Non-positive values of -.Fa ticks -are silently converted to the value -.Sq 1 . -.Fa func -should be a pointer to a function that takes a -.Fa void * -argument. -Upon invocation, -.Fa func -will receive -.Fa arg -as its only argument. -The return value from -.Fn timeout -is a -.Ft struct callout_handle -which can be used in conjunction with the -.Fn untimeout -function to request that a scheduled timeout be canceled. -.Pp -The function -.Fn callout_handle_init -can be used to initialize a handle to a state which will cause -any calls to -.Fn untimeout -with that handle to return with no side -effects. -.Pp -Assigning a callout handle the value of -.Fn CALLOUT_HANDLE_INITIALIZER -performs the same function as -.Fn callout_handle_init -and is provided for use on statically declared or global callout handles. -.Pp -The function -.Fn untimeout -cancels the timeout associated with -.Fa handle -using the -.Fa func -and -.Fa arg -arguments to validate the handle. -If the handle does not correspond to a timeout with -the function -.Fa func -taking the argument -.Fa arg -no action is taken. -.Fa handle -must be initialized by a previous call to -.Fn timeout , -.Fn callout_handle_init , -or assigned the value of -.Fn CALLOUT_HANDLE_INITIALIZER "&handle" -before being passed to -.Fn untimeout . -The behavior of calling -.Fn untimeout -with an uninitialized handle -is undefined. -.Pp -As handles are recycled by the system, it is possible (although unlikely) -that a handle from one invocation of -.Fn timeout -may match the handle of another invocation of -.Fn timeout -if both calls used the same function pointer and argument, and the first -timeout is expired or canceled before the second call. -The timeout facility offers O(1) running time for -.Fn timeout -and -.Fn untimeout . -Timeouts are executed from -.Fn softclock -with the -.Va Giant -lock held. -Thus they are protected from re-entrancy. -.Sh RETURN VALUES -The -.Fn callout_active -macro returns the state of a callout's -.Em active -flag. -.Pp -The -.Fn callout_pending -macro returns the state of a callout's -.Em pending -flag. -.Pp -The -.Fn callout_reset -and -.Fn callout_schedule -function families return a value of one if the callout was pending before the new -function invocation was scheduled. -.Pp -The -.Fn callout_stop -and -.Fn callout_drain -functions return a value of one if the callout was still pending when it was -called, a zero if the callout could not be stopped and a negative one is it -was either not running or has already completed. -The -.Fn timeout -function returns a -.Ft struct callout_handle -that can be passed to -.Fn untimeout . -.Sh HISTORY -The current timeout and untimeout routines are based on the work of -.An Adam M. Costello -and -.An George Varghese , -published in a technical report entitled -.%T "Redesigning the BSD Callout and Timer Facilities" -and modified slightly for inclusion in -.Fx -by -.An Justin T. Gibbs . -The original work on the data structures used in this implementation -was published by -.An G. Varghese -and -.An A. Lauck -in the paper -.%T "Hashed and Hierarchical Timing Wheels: Data Structures for the Efficient Implementation of a Timer Facility" -in the -.%B "Proceedings of the 11th ACM Annual Symposium on Operating Systems Principles" . -The current implementation replaces the long standing -.Bx -linked list -callout mechanism which offered O(n) insertion and removal running time -but did not generate or require handles for untimeout operations. Index: sys/kern/kern_intr.c =================================================================== --- sys/kern/kern_intr.c +++ sys/kern/kern_intr.c @@ -84,7 +84,6 @@ uintptr_t event; }; -struct intr_event *clk_intr_event; struct intr_event *tty_intr_event; void *vm_ih; struct proc *intrproc; Index: sys/kern/kern_timeout.c =================================================================== --- sys/kern/kern_timeout.c +++ sys/kern/kern_timeout.c @@ -166,10 +166,8 @@ struct mtx_padalign cc_lock; struct cc_exec cc_exec_entity[2]; struct callout *cc_next; - struct callout *cc_callout; struct callout_list *cc_callwheel; struct callout_tailq cc_expireq; - struct callout_slist cc_callfree; sbintime_t cc_firstevent; sbintime_t cc_lastscan; void *cc_cookie; @@ -207,7 +205,7 @@ #define CC_UNLOCK(cc) mtx_unlock_spin(&(cc)->cc_lock) #define CC_LOCK_ASSERT(cc) mtx_assert(&(cc)->cc_lock, MA_OWNED) -static int timeout_cpu; +static int cc_default_cpu; static void callout_cpu_init(struct callout_cpu *cc, int cpu); static void softclock_call_cc(struct callout *c, struct callout_cpu *cc, @@ -276,6 +274,7 @@ callout_callwheel_init(void *dummy) { struct callout_cpu *cc; + int cpu; /* * Calculate the size of the callout wheel and the preallocated @@ -301,16 +300,14 @@ TUNABLE_INT_FETCH("kern.pin_pcpu_swi", &pin_pcpu_swi); /* - * Only BSP handles timeout(9) and receives a preallocation. - * - * XXX: Once all timeout(9) consumers are converted this can - * be removed. + * Initialize callout wheels. The software interrupt threads + * are created later. */ - timeout_cpu = PCPU_GET(cpuid); - cc = CC_CPU(timeout_cpu); - cc->cc_callout = malloc(ncallout * sizeof(struct callout), - M_CALLOUT, M_WAITOK); - callout_cpu_init(cc, timeout_cpu); + cc_default_cpu = PCPU_GET(cpuid); + CPU_FOREACH(cpu) { + cc = CC_CPU(cpu); + callout_cpu_init(cc, cpu); + } } SYSINIT(callwheel_init, SI_SUB_CPU, SI_ORDER_ANY, callout_callwheel_init, NULL); @@ -320,11 +317,9 @@ static void callout_cpu_init(struct callout_cpu *cc, int cpu) { - struct callout *c; int i; mtx_init(&cc->cc_lock, "callout", NULL, MTX_SPIN | MTX_RECURSE); - SLIST_INIT(&cc->cc_callfree); cc->cc_inited = 1; cc->cc_callwheel = malloc_domainset(sizeof(struct callout_list) * callwheelsize, M_CALLOUT, @@ -337,14 +332,6 @@ cc_cce_cleanup(cc, i); snprintf(cc->cc_ktr_event_name, sizeof(cc->cc_ktr_event_name), "callwheel cpu %d", cpu); - if (cc->cc_callout == NULL) /* Only BSP handles timeout(9) */ - return; - for (i = 0; i < ncallout; i++) { - c = &cc->cc_callout[i]; - callout_init(c, 0); - c->c_iflags = CALLOUT_LOCAL_ALLOC; - SLIST_INSERT_HEAD(&cc->cc_callfree, c, c_links.sle); - } } #ifdef SMP @@ -378,50 +365,35 @@ #endif /* - * Start standard softclock thread. + * Start softclock threads. */ static void start_softclock(void *dummy) { struct callout_cpu *cc; char name[MAXCOMLEN]; -#ifdef SMP int cpu; + bool pin_swi; struct intr_event *ie; -#endif - cc = CC_CPU(timeout_cpu); - snprintf(name, sizeof(name), "clock (%d)", timeout_cpu); - if (swi_add(&clk_intr_event, name, softclock, cc, SWI_CLOCK, - INTR_MPSAFE, &cc->cc_cookie)) - panic("died while creating standard software ithreads"); - if (pin_default_swi && - (intr_event_bind(clk_intr_event, timeout_cpu) != 0)) { - printf("%s: timeout clock couldn't be pinned to cpu %d\n", - __func__, - timeout_cpu); - } - -#ifdef SMP CPU_FOREACH(cpu) { - if (cpu == timeout_cpu) - continue; cc = CC_CPU(cpu); - cc->cc_callout = NULL; /* Only BSP handles timeout(9). */ - callout_cpu_init(cc, cpu); snprintf(name, sizeof(name), "clock (%d)", cpu); ie = NULL; if (swi_add(&ie, name, softclock, cc, SWI_CLOCK, INTR_MPSAFE, &cc->cc_cookie)) panic("died while creating standard software ithreads"); - if (pin_pcpu_swi && (intr_event_bind(ie, cpu) != 0)) { - printf("%s: per-cpu clock couldn't be pinned to " - "cpu %d\n", + if (cpu == cc_default_cpu) + pin_swi = pin_default_swi; + else + pin_swi = pin_pcpu_swi; + if (pin_swi && (intr_event_bind(ie, cpu) != 0)) { + printf("%s: %s clock couldn't be pinned to cpu %d\n", __func__, + cpu == cc_default_cpu ? "default" : "per-cpu", cpu); } } -#endif } SYSINIT(start_softclock, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softclock, NULL); @@ -634,16 +606,6 @@ } static void -callout_cc_del(struct callout *c, struct callout_cpu *cc) -{ - - if ((c->c_iflags & CALLOUT_LOCAL_ALLOC) == 0) - return; - c->c_func = NULL; - SLIST_INSERT_HEAD(&cc->cc_callfree, c, c_links.sle); -} - -static void softclock_call_cc(struct callout *c, struct callout_cpu *cc, #ifdef CALLOUT_PROFILING int *mpcalls, int *lockcalls, int *gcalls, @@ -668,7 +630,7 @@ sbintime_t sbt1, sbt2; struct timespec ts2; static sbintime_t maxdt = 2 * SBT_1MS; /* 2 msec */ - static timeout_t *lastfunc; + static void (*lastfunc)(void *); #endif KASSERT((c->c_iflags & CALLOUT_PENDING) == CALLOUT_PENDING, @@ -687,10 +649,7 @@ c_func = c->c_func; c_arg = c->c_arg; c_iflags = c->c_iflags; - if (c->c_iflags & CALLOUT_LOCAL_ALLOC) - c->c_iflags = CALLOUT_LOCAL_ALLOC; - else - c->c_iflags &= ~CALLOUT_PENDING; + c->c_iflags &= ~CALLOUT_PENDING; cc_exec_curr(cc, direct) = c; cc_exec_last_func(cc, direct) = c_func; @@ -792,8 +751,6 @@ wakeup(&cc_exec_waiting(cc, direct)); CC_LOCK(cc); } else if (cc_cce_migrating(cc, direct)) { - KASSERT((c_iflags & CALLOUT_LOCAL_ALLOC) == 0, - ("Migrating legacy callout %p", c)); #ifdef SMP /* * If the callout was scheduled for @@ -816,7 +773,6 @@ CTR3(KTR_CALLOUT, "deferred cancelled %p func %p arg %p", c, new_func, new_arg); - callout_cc_del(c, cc); return; } c->c_iflags &= ~CALLOUT_DFRMIGRATION; @@ -831,19 +787,6 @@ panic("migration should not happen"); #endif } - /* - * If the current callout is locally allocated (from - * timeout(9)) then put it on the freelist. - * - * Note: we need to check the cached copy of c_iflags because - * if it was not local, then it's not safe to deref the - * callout pointer. - */ - KASSERT((c_iflags & CALLOUT_LOCAL_ALLOC) == 0 || - c->c_iflags == CALLOUT_LOCAL_ALLOC, - ("corrupted callout")); - if (c_iflags & CALLOUT_LOCAL_ALLOC) - callout_cc_del(c, cc); } /* @@ -893,70 +836,7 @@ CC_UNLOCK(cc); } -/* - * timeout -- - * Execute a function after a specified length of time. - * - * untimeout -- - * Cancel previous timeout function call. - * - * callout_handle_init -- - * Initialize a handle so that using it with untimeout is benign. - * - * See AT&T BCI Driver Reference Manual for specification. This - * implementation differs from that one in that although an - * identification value is returned from timeout, the original - * arguments to timeout as well as the identifier are used to - * identify entries for untimeout. - */ -struct callout_handle -timeout(timeout_t *ftn, void *arg, int to_ticks) -{ - struct callout_cpu *cc; - struct callout *new; - struct callout_handle handle; - - cc = CC_CPU(timeout_cpu); - CC_LOCK(cc); - /* Fill in the next free callout structure. */ - new = SLIST_FIRST(&cc->cc_callfree); - if (new == NULL) - /* XXX Attempt to malloc first */ - panic("timeout table full"); - SLIST_REMOVE_HEAD(&cc->cc_callfree, c_links.sle); - callout_reset(new, to_ticks, ftn, arg); - handle.callout = new; - CC_UNLOCK(cc); - - return (handle); -} - void -untimeout(timeout_t *ftn, void *arg, struct callout_handle handle) -{ - struct callout_cpu *cc; - - /* - * Check for a handle that was initialized - * by callout_handle_init, but never used - * for a real timeout. - */ - if (handle.callout == NULL) - return; - - cc = callout_lock(handle.callout); - if (handle.callout->c_func == ftn && handle.callout->c_arg == arg) - callout_stop(handle.callout); - CC_UNLOCK(cc); -} - -void -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) { @@ -1057,12 +937,9 @@ ("%s: direct callout %p has lock", __func__, c)); cc = callout_lock(c); /* - * Don't allow migration of pre-allocated callouts lest they - * become unbalanced or handle the case where the user does - * not care. + * Don't allow migrate if the user does not care. */ - if ((c->c_iflags & CALLOUT_LOCAL_ALLOC) || - ignore_cpu) { + if (ignore_cpu) { cpu = c->c_cpu; } @@ -1432,7 +1309,6 @@ TAILQ_REMOVE(&cc->cc_expireq, c, c_links.tqe); } } - callout_cc_del(c, cc); CC_UNLOCK(cc); return (cancelled); } @@ -1448,7 +1324,7 @@ c->c_lock = &Giant.lock_object; c->c_iflags = 0; } - c->c_cpu = timeout_cpu; + c->c_cpu = cc_default_cpu; /* XXX: PCPU_GET(cpuid)? */ } void @@ -1464,7 +1340,7 @@ (LC_SPINLOCK | LC_SLEEPABLE)), ("%s: invalid lock class", __func__)); c->c_iflags = flags & (CALLOUT_RETURNUNLOCKED | CALLOUT_SHAREDLOCK); - c->c_cpu = timeout_cpu; + c->c_cpu = cc_default_cpu; /* XXX: PCPU_GET(cpuid)? */ } #ifdef APM_FIXUP_CALLTODO @@ -1556,9 +1432,7 @@ sbintime_t maxpr, maxt, medpr, medt, now, spr, st, t; int ct[64], cpr[64], ccpbk[32]; int error, val, i, count, tcum, pcum, maxc, c, medc; -#ifdef SMP int cpu; -#endif val = 0; error = sysctl_handle_int(oidp, &val, 0, req); @@ -1570,12 +1444,8 @@ bzero(ct, sizeof(ct)); bzero(cpr, sizeof(cpr)); now = sbinuptime(); -#ifdef SMP CPU_FOREACH(cpu) { cc = CC_CPU(cpu); -#else - cc = CC_CPU(timeout_cpu); -#endif CC_LOCK(cc); for (i = 0; i < callwheelsize; i++) { sc = &cc->cc_callwheel[i]; @@ -1600,9 +1470,7 @@ count += c; } CC_UNLOCK(cc); -#ifdef SMP } -#endif for (i = 0, tcum = 0; i < 64 && tcum < count / 2; i++) tcum += ct[i]; Index: sys/netgraph/ng_base.c =================================================================== --- sys/netgraph/ng_base.c +++ sys/netgraph/ng_base.c @@ -3801,7 +3801,7 @@ return (0); } -/* A special modified version of untimeout() */ +/* A special modified version of callout_stop() */ int ng_uncallout(struct callout *c, node_p node) { Index: sys/sys/interrupt.h =================================================================== --- sys/sys/interrupt.h +++ sys/sys/interrupt.h @@ -152,7 +152,6 @@ struct proc; extern struct intr_event *tty_intr_event; -extern struct intr_event *clk_intr_event; extern void *vm_ih; /* Counts and names for statistics (defined in MD code). */ Index: sys/sys/systm.h =================================================================== --- sys/sys/systm.h +++ sys/sys/systm.h @@ -440,15 +440,6 @@ void kern_reboot(int) __dead2; void shutdown_nice(int); -/* Timeouts */ -typedef void timeout_t(void *); /* timeout function type */ -#define CALLOUT_HANDLE_INITIALIZER(handle) \ - { NULL } - -void callout_handle_init(struct callout_handle *); -struct callout_handle timeout(timeout_t *, void *, int); -void untimeout(timeout_t *, void *, struct callout_handle); - /* Stubs for obsolete functions that used to be for interrupt management */ static __inline intrmask_t splbio(void) { return 0; } static __inline intrmask_t splcam(void) { return 0; }