From owner-svn-src-head@FreeBSD.ORG Mon Jan 19 22:22:36 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 0910480D; Mon, 19 Jan 2015 22:22:36 +0000 (UTC) Received: from mail-wi0-x229.google.com (mail-wi0-x229.google.com [IPv6:2a00:1450:400c:c05::229]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (Client CN "smtp.gmail.com", Issuer "Google Internet Authority G2" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 6386A1F0; Mon, 19 Jan 2015 22:22:35 +0000 (UTC) Received: by mail-wi0-f169.google.com with SMTP id bs8so19717787wib.0; Mon, 19 Jan 2015 14:22:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:sender:in-reply-to:references:date:message-id:subject :from:to:cc:content-type; bh=45UDXa6DzCoX4I9C/z34AOPh4UEKLoHjNm1oU9VtQGM=; b=wg/e16sp2imSStKET/v7qXUwBM1wyvtWeuBXBFQxKhHEAUcXmV3C2l7oHIgESiAbje j8qjrjbPl5sZeX6EI/kd9rg7tWS5tEh3nSbQzTbZjYoxCuDhMWum20J+Jt3HvhXn4tLn 3VG2EG2tIgGxmA35UhCE4l/2ncvT+pstuBrO2ck1G8HH+0kkAc8BQQ7Mhjg9/oyj2BAU KfFZA37JV8cyIk8/lZUvi5rnKxr1VXkKZWAXBwr9U6jVERq4t5UnhRzO+vOkRTnsBho6 O4YiGhUq3O6BcbRkpGOWDLYOBzMTy4T2TyO8/OD+cPFzUUleLGZLqE/E5uJ2FXVBBKpA YypQ== MIME-Version: 1.0 X-Received: by 10.180.80.163 with SMTP id s3mr39162973wix.59.1421706153864; Mon, 19 Jan 2015 14:22:33 -0800 (PST) Sender: adrian.chadd@gmail.com Received: by 10.216.41.136 with HTTP; Mon, 19 Jan 2015 14:22:33 -0800 (PST) In-Reply-To: References: <201501151532.t0FFWV2Y037455@svn.freebsd.org> Date: Mon, 19 Jan 2015 14:22:33 -0800 X-Google-Sender-Auth: kfLwCYfQ6429D8Z_TFTJ6h51Zg0 Message-ID: Subject: Re: svn commit: r277213 - in head: share/man/man9 sys/kern sys/ofed/include/linux sys/sys From: Adrian Chadd To: Hans Petter Selasky Content-Type: text/plain; charset=UTF-8 Cc: "svn-src-head@freebsd.org" , "svn-src-all@freebsd.org" , "src-committers@freebsd.org" X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 19 Jan 2015 22:22:36 -0000 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 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 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 *** >>