Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 19 Jan 2015 14:22:33 -0800
From:      Adrian Chadd <adrian@freebsd.org>
To:        Hans Petter Selasky <hselasky@freebsd.org>
Cc:        "svn-src-head@freebsd.org" <svn-src-head@freebsd.org>, "svn-src-all@freebsd.org" <svn-src-all@freebsd.org>, "src-committers@freebsd.org" <src-committers@freebsd.org>
Subject:   Re: svn commit: r277213 - in head: share/man/man9 sys/kern sys/ofed/include/linux sys/sys
Message-ID:  <CAJ-VmomOE6AzbEFw45VOtVbLTtDMbnixkYDVK951pSCkcMrQjQ@mail.gmail.com>
In-Reply-To: <CAJ-Vmok0GXZoojyi=jE=b5D-d338APztaf3Pw0_AAQ-173XSWw@mail.gmail.com>
References:  <201501151532.t0FFWV2Y037455@svn.freebsd.org> <CAJ-Vmok0GXZoojyi=jE=b5D-d338APztaf3Pw0_AAQ-173XSWw@mail.gmail.com>

next in thread | previous in thread | raw e-mail | index | archive | help
Yeah, it looks like you set c_cpu to timeout_cpu in
_callout_init_locked(), but then you only handle the case of the CPU
being changed in certain circumstances. You aren't handling the CPU
being initialised when the callout is first added.

And, callout_restart_async() calls callout_lock(), which calls
CC_LOCK() on the callout CPU, which initially is zero. Then, it never
seems to be 'moved' into the correct CPU, even though it's being
called with a CPU id.

So, if I am reading this all correctly, you aren't really handling
multi CPU callwheels at all. ;)

In my instance, I'm seeing quite a lot of lock contention between the
userland threads, the network RX threads and the clock thread, all
contending on a single callout wheel being used for TCP timers. One of
the early goals for fixing up the RSS stuff in -HEAD was to make
per-CPU (Well, per-RSS-bucket really) TCP timers not contend with the
NIC RX processing path, and now it does. :(



-adrian


On 19 January 2015 at 13:59, Adrian Chadd <adrian@freebsd.org> wrote:
> Hi,
>
> Would you please check what the results of this are with CPU specific
> callwheels?
>
> I'm doing some 10+ gig traffic testing on -HEAD with RSS enabled (on
> ixgbe) and with this setup, the per-CPU TCP callwheel stuff is
> enabled. But all the callwheels are now back on clock(0) and so is the
> lock contention. :(
>
> Thanks,
>
>
>
> -adrian
>
>
> On 15 January 2015 at 07:32, Hans Petter Selasky <hselasky@freebsd.org> wrote:
>> Author: hselasky
>> Date: Thu Jan 15 15:32:30 2015
>> New Revision: 277213
>> URL: https://svnweb.freebsd.org/changeset/base/277213
>>
>> Log:
>>   Major callout subsystem cleanup and rewrite:
>>   - Close a migration race where callout_reset() failed to set the
>>     CALLOUT_ACTIVE flag.
>>   - Callout callback functions are now allowed to be protected by
>>     spinlocks.
>>   - Switching the callout CPU number cannot always be done on a
>>     per-callout basis. See the updated timeout(9) manual page for more
>>     information.
>>   - The timeout(9) manual page has been updated to reflect how all the
>>     functions inside the callout API are working. The manual page has
>>     been made function oriented to make it easier to deduce how each of
>>     the functions making up the callout API are working without having
>>     to first read the whole manual page. Group all functions into a
>>     handful of sections which should give a quick top-level overview
>>     when the different functions should be used.
>>   - The CALLOUT_SHAREDLOCK flag and its functionality has been removed
>>     to reduce the complexity in the callout code and to avoid problems
>>     about atomically stopping callouts via callout_stop(). If someone
>>     needs it, it can be re-added. From my quick grep there are no
>>     CALLOUT_SHAREDLOCK clients in the kernel.
>>   - A new callout API function named "callout_drain_async()" has been
>>     added. See the updated timeout(9) manual page for a complete
>>     description.
>>   - Update the callout clients in the "kern/" folder to use the callout
>>     API properly, like cv_timedwait(). Previously there was some custom
>>     sleepqueue code in the callout subsystem, which has been removed,
>>     because we now allow callouts to be protected by spinlocks. This
>>     allows us to tear down the callout like done with regular mutexes,
>>     and a "td_slpmutex" has been added to "struct thread" to atomically
>>     teardown the "td_slpcallout". Further the "TDF_TIMOFAIL" and
>>     "SWT_SLEEPQTIMO" states can now be completely removed. Currently
>>     they are marked as available and will be cleaned up in a follow up
>>     commit.
>>   - Bump the __FreeBSD_version to indicate kernel modules need
>>     recompilation.
>>   - There has been several reports that this patch "seems to squash a
>>     serious bug leading to a callout timeout and panic".
>>
>>   Kernel build testing: all architectures were built
>>   MFC after:            2 weeks
>>   Differential Revision:        https://reviews.freebsd.org/D1438
>>   Sponsored by:         Mellanox Technologies
>>   Reviewed by:          jhb, adrian, sbruno and emaste
>>
>> Modified:
>>   head/share/man/man9/Makefile
>>   head/share/man/man9/timeout.9
>>   head/sys/kern/init_main.c
>>   head/sys/kern/kern_condvar.c
>>   head/sys/kern/kern_lock.c
>>   head/sys/kern/kern_switch.c
>>   head/sys/kern/kern_synch.c
>>   head/sys/kern/kern_thread.c
>>   head/sys/kern/kern_timeout.c
>>   head/sys/kern/subr_sleepqueue.c
>>   head/sys/ofed/include/linux/completion.h
>>   head/sys/sys/_callout.h
>>   head/sys/sys/callout.h
>>   head/sys/sys/param.h
>>   head/sys/sys/proc.h
>>
>> Modified: head/share/man/man9/Makefile
>> ==============================================================================
>> --- head/share/man/man9/Makefile        Thu Jan 15 14:47:48 2015        (r277212)
>> +++ head/share/man/man9/Makefile        Thu Jan 15 15:32:30 2015        (r277213)
>> @@ -1570,6 +1570,7 @@ MLINKS+=timeout.9 callout.9 \
>>         timeout.9 callout_active.9 \
>>         timeout.9 callout_deactivate.9 \
>>         timeout.9 callout_drain.9 \
>> +       timeout.9 callout_drain_async.9 \
>>         timeout.9 callout_handle_init.9 \
>>         timeout.9 callout_init.9 \
>>         timeout.9 callout_init_mtx.9 \
>>
>> Modified: head/share/man/man9/timeout.9
>> ==============================================================================
>> --- head/share/man/man9/timeout.9       Thu Jan 15 14:47:48 2015        (r277212)
>> +++ head/share/man/man9/timeout.9       Thu Jan 15 15:32:30 2015        (r277213)
>> @@ -29,13 +29,14 @@
>>  .\"
>>  .\" $FreeBSD$
>>  .\"
>> -.Dd October 8, 2014
>> +.Dd January 14, 2015
>>  .Dt TIMEOUT 9
>>  .Os
>>  .Sh NAME
>>  .Nm callout_active ,
>>  .Nm callout_deactivate ,
>>  .Nm callout_drain ,
>> +.Nm callout_drain_async ,
>>  .Nm callout_handle_init ,
>>  .Nm callout_init ,
>>  .Nm callout_init_mtx ,
>> @@ -63,279 +64,232 @@
>>  .In sys/systm.h
>>  .Bd -literal
>>  typedef void timeout_t (void *);
>> +typedef void callout_func_t (void *);
>>  .Ed
>> -.Ft int
>> -.Fn callout_active "struct callout *c"
>> -.Ft void
>> -.Fn callout_deactivate "struct callout *c"
>> -.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
>> -.Fn callout_reset_curcpu "struct callout *c" "int ticks" "timeout_t *func" \
>> -"void *arg"
>> -.Ft int
>> -.Fn callout_reset_on "struct callout *c" "int ticks" "timeout_t *func" \
>> -"void *arg" "int cpu"
>> -.Ft int
>> -.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \
>> -"sbintime_t pr" "timeout_t *func" "void *arg" "int flags"
>> -.Ft int
>> -.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
>> -"sbintime_t pr" "timeout_t *func" "void *arg" "int flags"
>> -.Ft int
>> -.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \
>> -"sbintime_t pr" "timeout_t *func" "void *arg" "int cpu" "int flags"
>> -.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
>> -.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \
>> -"sbintime_t pr" "int flags"
>> -.Ft int
>> -.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
>> -"sbintime_t pr" "int flags"
>> -.Ft int
>> -.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \
>> -"sbintime_t pr" "int cpu" "int flags"
>> -.Ft int
>> -.Fn callout_stop "struct callout *c"
>> -.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
>> +time in the future in a single-shot fashion.
>> +Consumers of this API are required to allocate a
>>  .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.
>> +structure for each pending function invocation.
>> +The
>> +.Pq struct callout
>> +structure stores the full state about any pending function call and
>> +should be drained by a call to
>> +.Fn callout_drain
>> +or
>> +.Fn callout_drain_async
>> +before freeing.
>> +.Sh INITIALISATION
>> +.Ft void
>> +.Fn callout_handle_init "struct callout_handle *handle"
>> +This function is deprecated and is used to prepare a
>> +.Pq struct callout_handle
>> +structure before it can be used the first time.
>> +If this function is called on a pending timeout, the pending timeout
>> +cannot be cancelled and the
>> +.Fn untimeout
>> +function will return as if there was no timeout pending.
>>  .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.
>> +.Fn CALLOUT_HANDLE_INITIALIZER "&handle"
>> +This macro is deprecated and can be used instead of
>> +.Fn callout_handle_init
>> +to assign the default state to the
>> +.Pq struct callout_handle
>> +structure when declaring static timeouts.
>>  .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.
>> +.Ft void
>> +.Fn callout_init "struct callout *c" "int mpsafe"
>> +This function prepares a
>> +.Pq struct callout
>> +structure before it can be used.
>> +This function should not be used when the callout is pending a timeout.
>>  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.
>> +argument is non-zero, the callback function will be running unlocked.
>> +Else the Giant mutex will be locked before calling the callback function.
>>  .Pp
>> +.Ft void
>> +.Fn callout_init_mtx "struct callout *c" "struct mtx *mtx" "int flags"
>> +This function prepares a
>> +.Pq struct callout
>> +structure before it can be used.
>> +This function should not be used when the callout is pending a timeout.
>>  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 mtx
>> +argument should be non-zero and should specify a pointer to a valid
>> +spinlock type of mutex or a valid regular non-sleepable mutex which
>> +the callback subsystem should lock before calling the callback
>> +function.
>> +Valid
>>  .Fa flags
>> -may be specified for
>> -.Fn callout_init_mtx ,
>> -.Fn callout_init_rm ,
>> -or
>> -.Fn callout_init_rw :
>> +are:
>>  .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 .
>> +It is assumed that the callout function has released the specified
>> +mutex before returning.
>> +Else the callout subsystem will release the specified mutex after the
>> +callout function has returned.
>>  .El
>>  .Pp
>> -The function
>> -.Fn callout_stop
>> -cancels a callout
>> -.Fa c
>> -if it is currently pending.
>> -If the callout is pending, then
>> -.Fn callout_stop
>> -returns a non-zero value.
>> -If the callout is not set,
>> -has already been serviced,
>> -or is currently being serviced,
>> -then zero will be returned.
>> -If the callout has an associated lock,
>> -then that lock must be held when this function is called.
>> -.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 non-zero value 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.
>> +.Ft void
>> +.Fn callout_init_rm "struct callout *c" "struct rmlock *rm" "int flags"
>> +This function is the same like the
>> +.Fn callout_init_mtx
>> +function except it accepts a read-mostly type of lock.
>> +The read-mostly lock must not be initialised with the
>> +.Dv RM_SLEEPABLE
>> +flag.
>>  .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
>> +.Ft void
>> +.Fn callout_init_rw "struct callout *c" "struct rwlock *rw" "int flags"
>> +This function is the same like the
>> +.Fn callout_init_mtx
>> +function except it accepts a reader-writer type of lock.
>> +.Sh SCHEDULING CALLOUTS
>> +.Ft struct callout_handle
>> +.Fn timeout "timeout_t *func" "void *arg" "int ticks"
>> +This function is deprecated and 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 .
>> -.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 func
>> +argument should be a valid pointer to a function that takes a single
>> +.Fa void *
>> +argument.
>> +Upon invocation, the
>> +.Fa func
>> +function will receive
>> +.Fa arg
>> +as its only argument.
>> +The Giant lock is locked when the
>> +.Fa arg
>> +function is invoked and should not be unlocked by this function.
>> +The returned value from
>> +.Fn timeout
>> +is a
>> +.Ft struct callout_handle
>> +structure which can be used in conjunction with the
>> +.Fn untimeout
>> +function to request that a scheduled timeout be cancelled.
>> +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.
>> +Please ensure that the function and argument pointers are unique when using this function.
>> +.Pp
>> +.Ft int
>> +.Fn callout_reset "struct callout *c" "int ticks" "callout_func_t *func" "void *arg"
>> +This function is used to schedule or re-schedule a callout.
>> +This function at first stops the callout given by the
>> +.Fa c
>> +argument, if any.
>> +Then it will start the callout given by the
>> +.Fa c
>> +argument.
>> +The relative time until the timeout callback happens is given by the
>> +.Fa ticks
>> +argument.
>> +The number of ticks in a second is defined by
>> +.Dv hz
>> +and can vary from system to system.
>> +This function returns a non-zero value if the given callout was pending and
>> +the callback function was prevented from being called.
>> +Else a value of zero is returned.
>> +If a lock is associated with the callout given by the
>> +.Fa c
>> +argument and it is exclusivly locked when this function is called this
>> +function will always ensure that previous callback function, if any,
>> +is never reached.
>> +In other words the callout will be atomically restarted.
>> +Else there is no such guarantee.
>> +The callback function is given by the
>> +.Fa func
>> +argument and its function argument is given by the
>> +.Fa arg
>> +argument.
>> +.Pp
>> +.Ft int
>> +.Fn callout_reset_curcpu "struct callout *c" "int ticks" "callout_func_t *func" \
>> +"void *arg"
>> +This function works the same like the
>> +.Fn callout_reset
>> +function except the callback function given by the
>> +.Fa func
>> +argument will be executed on the same CPU which called this function.
>> +A change in the CPU selection can happen if the callout has a lock
>> +associated with it and is locked when this function is called.
>> +A change in the CPU selection cannot happen if this function is
>> +re-scheduled inside a callout function.
>> +Else the callback function given by the
>> +.Fa func
>> +argument will be executed on the same CPU like previously done.
>> +.Pp
>> +.Ft int
>> +.Fn callout_reset_on "struct callout *c" "int ticks" "callout_func_t *func" \
>> +"void *arg" "int cpu"
>> +This function works the same like the
>> +.Fn callout_reset
>> +function except the callback function given by the
>> +.Fa func
>> +argument will be executed on the CPU given by the
>> +.Fa cpu
>> +argument.
>> +A change in the CPU selection can happen if the callout has a lock
>> +associated with it and is locked when this function is called.
>> +A change in the CPU selection cannot happen if this function is
>> +re-scheduled inside a callout function.
>> +Else the callback function given by the
>> +.Fa func
>> +argument will be executed on the same CPU like previously done.
>> +.Pp
>> +.Ft int
>> +.Fn callout_reset_sbt "struct callout *c" "sbintime_t sbt" \
>> +"sbintime_t pr" "callout_func_t *func" "void *arg" "int flags"
>> +This function works the same like the
>> +.Fn callout_reset
>> +function except the relative or absolute time after which the timeout
>> +callback should happen is given by the
>>  .Fa sbt
>> -and extends for the amount of time specified in
>> -.Fa pr .
>> -If
>> +argument and extends for the amount of time specified in the
>> +.Fa pr
>> +argument.
>> +This function is used when you need high precision timeouts.
>> +If the
>>  .Fa sbt
>> -specifies a time in the past,
>> +argument 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
>> +The
>>  .Fa flags
>> -may be specified to adjust the interpretation of
>> +argument may be non-zero to adjust the interpretation of the
>>  .Fa sbt
>> -and
>> -.Fa pr :
>> +and the
>> +.Fa pr
>> +arguments:
>>  .Bl -tag -width ".Dv C_DIRECT_EXEC"
>>  .It Dv C_ABSOLUTE
>>  Handle the
>>  .Fa sbt
>>  argument as an absolute time since boot.
>> -By default,
>> +By default, the
>>  .Fa sbt
>> -is treated as a relative amount of time,
>> +argument is treated like a relative amount of time,
>>  similar to
>>  .Fa ticks .
>>  .It Dv C_DIRECT_EXEC
>> @@ -347,7 +301,7 @@ Callout functions run in this context ma
>>  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.
>> +divided by acceptable time deviation: 1 -- 1/2, 2 -- 1/4 and so on.
>>  Note that the larger of
>>  .Fa pr
>>  or this value is used as the length of the time window.
>> @@ -360,65 +314,215 @@ Align the timeouts to
>>  calls if possible.
>>  .El
>>  .Pp
>> -The
>> -.Fn callout_reset
>> -functions accept a
>> +.Ft int
>> +.Fn callout_reset_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
>> +"sbintime_t pr" "callout_func_t *func" "void *arg" "int flags"
>> +This function works the same like the
>> +.Fn callout_reset_sbt
>> +function except the callback function given by the
>>  .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 will be executed on the same CPU which called this function.
>> +A change in the CPU selection can happen if the callout has a lock
>> +associated with it and is locked when this function is called.
>> +A change in the CPU selection cannot happen if this function is
>> +re-scheduled inside a callout function.
>> +Else the callback function given by the
>> +.Fa func
>> +argument will be executed on the same CPU like previously done.
>> +.Pp
>> +.Ft int
>> +.Fn callout_reset_sbt_on "struct callout *c" "sbintime_t sbt" \
>> +"sbintime_t pr" "callout_func_t *func" "void *arg" "int cpu" "int flags"
>> +This function works the same like the
>> +.Fn callout_reset_sbt
>> +function except the callback function given by the
>> +.Fa func
>> +argument will be executed on the CPU given by the
>> +.Fa cpu
>>  argument.
>> -Upon invocation,
>> +A change in the CPU selection can happen if the callout has a lock
>> +associated with it and is locked when this function is called.
>> +A change in the CPU selection cannot happen if this function is
>> +re-scheduled inside a callout function.
>> +Else the callback function given by the
>>  .Fa func
>> -will receive
>> -.Fa arg
>> -as its only argument.
>> -The
>> -.Fn callout_schedule
>> -functions reuse the
>> +argument will be executed on the same CPU like previously done.
>> +.Pp
>> +.Ft int
>> +.Fn callout_schedule "struct callout *c" "int ticks"
>> +This function works the same like the
>> +.Fn callout_reset
>> +function except it re-uses the callback function and the callback argument
>> +already stored in the
>> +.Pq struct callout
>> +structure.
>> +.Pp
>> +.Ft int
>> +.Fn callout_schedule_curcpu "struct callout *c" "int ticks"
>> +This function works the same like the
>> +.Fn callout_reset_curcpu
>> +function except it re-uses the callback function and the callback argument
>> +already stored in the
>> +.Pq struct callout
>> +structure.
>> +.Pp
>> +.Ft int
>> +.Fn callout_schedule_on "struct callout *c" "int ticks" "int cpu"
>> +This function works the same like the
>> +.Fn callout_reset_on
>> +function except it re-uses the callback function and the callback argument
>> +already stored in the
>> +.Pq struct callout
>> +structure.
>> +.Pp
>> +.Ft int
>> +.Fn callout_schedule_sbt "struct callout *c" "sbintime_t sbt" \
>> +"sbintime_t pr" "int flags"
>> +This function works the same like the
>> +.Fn callout_reset_sbt
>> +function except it re-uses the callback function and the callback argument
>> +already stored in the
>> +.Pq struct callout
>> +structure.
>> +.Pp
>> +.Ft int
>> +.Fn callout_schedule_sbt_curcpu "struct callout *c" "sbintime_t sbt" \
>> +"sbintime_t pr" "int flags"
>> +This function works the same like the
>> +.Fn callout_reset_sbt_curcpu
>> +function except it re-uses the callback function and the callback argument
>> +already stored in the
>> +.Pq struct callout
>> +structure.
>> +.Pp
>> +.Ft int
>> +.Fn callout_schedule_sbt_on "struct callout *c" "sbintime_t sbt" \
>> +"sbintime_t pr" "int cpu" "int flags"
>> +This function works the same like the
>> +.Fn callout_reset_sbt_on
>> +function except it re-uses the callback function and the callback argument
>> +already stored in the
>> +.Pq struct callout
>> +structure.
>> +.Sh CHECKING THE STATE OF CALLOUTS
>> +.Ft int
>> +.Fn callout_pending "struct callout *c"
>> +This function returns non-zero if the callout pointed to by the
>> +.Fa c
>> +argument is pending for callback.
>> +Else this function returns zero.
>> +This function returns zero when inside the callout function if the
>> +callout is not re-scheduled.
>> +.Pp
>> +.Ft int
>> +.Fn callout_active "struct callout *c"
>> +This function is deprecated and returns non-zero if the callout
>> +pointed to by the
>> +.Fa c
>> +argument was scheduled in the past.
>> +Else this function returns zero.
>> +This function also returns zero after the
>> +.Fn callout_deactivate
>> +or the
>> +.Fn callout_stop
>> +or the
>> +.Fn callout_drain
>> +or the
>> +.Fn callout_drain_async
>> +function is called on the same callout as given by the
>> +.Fa c
>> +argument.
>> +.Pp
>> +.Ft void
>> +.Fn callout_deactivate "struct callout *c"
>> +This function is deprecated and ensures that subsequent calls to the
>> +.Fn callout_activate
>> +function returns zero until the callout is scheduled again.
>> +.Sh STOPPING CALLOUTS
>> +.Ft void
>> +.Fn untimeout "timeout_t *func" "void *arg" "struct callout_handle handle"
>> +This function is deprecated and cancels the timeout associated with the
>> +.Fa handle
>> +argument using the function pointed to by the
>>  .Fa func
>> -and
>> +argument and having the
>>  .Fa arg
>> -arguments from the previous callout.
>> -Note that one of the
>> -.Fn callout_reset
>> -functions must always be called to initialize
>> +arguments to validate the handle.
>> +If the handle does not correspond to a timeout with
>> +the function
>>  .Fa func
>> -and
>> +taking the argument
>>  .Fa arg
>> -before one of the
>> -.Fn callout_schedule
>> -functions can be used.
>> +no action is taken. The
>> +.Fa handle
>> +must be initialised 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 uninitialised handle
>> +is undefined.
>>  .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.
>> +.Ft int
>> +.Fn callout_stop "struct callout *c"
>> +This function is used to stop a timeout function invocation associated with the callout pointed to by the
>> +.Fa c
>> +argument, in a non-blocking fashion.
>> +This function can be called multiple times in a row with no side effects, even if the callout is already stopped. This function however should not be called before the callout has been initialised.
>> +This function returns a non-zero value if the given callout was pending and
>> +the callback function was prevented from being called.
>> +Else a value of zero is returned.
>> +If a lock is associated with the callout given by the
>> +.Fa c
>> +argument and it is exclusivly locked when this function is called, the
>> +.Fn callout_stop
>> +function will always ensure that the callback function is never reached.
>> +In other words the callout will be atomically stopped.
>> +Else there is no such guarantee.
>> +.Sh DRAINING CALLOUTS
>> +.Ft int
>> +.Fn callout_drain "struct callout *c"
>> +This function works the same like the
>> +.Fn callout_stop
>> +function except it ensures that all callback functions have returned and there are no more references to the callout pointed to by the
>> +.Fa c
>> +argument inside the callout subsystem before it returns.
>> +Also this function ensures that the lock, if any, associated with the
>> +callout is no longer being used.
>> +When this function returns, it is safe to free the callout structure pointed to by the
>> +.Fa c
>> +argument.
>>  .Pp
>> +.Ft int
>> +.Fn callout_drain_async "struct callout *c" "callout_func_t *fn" "void *arg"
>> +This function is non-blocking and works the same like the
>> +.Fn callout_stop
>> +function except if it returns non-zero it means the callback function pointed to by the
>> +.Fa fn
>> +argument will be called back with the
>> +.Fa arg
>> +argument when all references to the callout pointed to by the
>> +.Fa c
>> +argument are gone.
>> +If this function returns zero, it is safe to free the callout structure pointed to by the
>> +.Fa c
>> +argument right away.
>> +.Sh CALLOUT FUNCTION RESTRICTIONS
>> +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.
>> +.Sh CALLOUT SUBSYSTEM INTERNALS
>> +The callout subsystem has its own set of spinlocks to protect its internal state.
>> +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.
>>  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
>> @@ -427,50 +531,7 @@ Softclock threads for CPUs other than ze
>>  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.
>> -.Ss "Avoiding Race Conditions"
>> +.Sh "AVOIDING RACE CONDITIONS"
>>  The callout subsystem invokes callout functions from its own thread
>>  context.
>>  Without some kind of synchronization,
>> @@ -487,7 +548,7 @@ 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
>> +Callouts can be associated with a specific lock when they are initialised
>>  by
>>  .Fn callout_init_mtx ,
>>  .Fn callout_init_rm ,
>> @@ -508,7 +569,7 @@ or
>>  .Fn callout_schedule
>>  functions to provide this safety.
>>  .Pp
>> -A callout initialized via
>> +A callout initialised via
>>  .Fn callout_init
>>  with
>>  .Fa mpsafe
>> @@ -531,9 +592,8 @@ 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.
>> +not yet executed, then a return value of zero indicates that the
>> +callout function is about to be called.
>>  For example:
>>  .Bd -literal -offset indent
>>  if (sc->sc_flags & SCFLG_CALLOUT_RUNNING) {
>> @@ -589,16 +649,14 @@ The callout function should first check
>>  .Em pending
>>  flag and return without action if
>>  .Fn callout_pending
>> -returns
>> -.Dv TRUE .
>> +returns non-zero.
>>  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.
>> +returns zero 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
>> @@ -668,129 +726,13 @@ a callout should always be drained prior
>>  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
>> +The
>>  .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 non-zero if the callout was pending before the new
>> -function invocation was scheduled.
>> -.Pp
>> -The
>> -.Fn callout_stop
>> -and
>> -.Fn callout_drain
>> -functions return non-zero if the callout was still pending when it was
>> -called or zero otherwise.
>> -The
>> -.Fn timeout
>> -function returns a
>> -.Ft struct callout_handle
>> -that can be passed to
>> -.Fn untimeout .
>> +functions are a legacy API that will be removed in a future release.
>> +New code should not use these routines.
>>
>> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
>>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAJ-VmomOE6AzbEFw45VOtVbLTtDMbnixkYDVK951pSCkcMrQjQ>