From owner-svn-src-all@freebsd.org Sat Aug 27 09:11:59 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 8D6F1B7782A; Sat, 27 Aug 2016 09:11:59 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 49FE5DB0; Sat, 27 Aug 2016 09:11:59 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u7R9Bw8I066799; Sat, 27 Aug 2016 09:11:58 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u7R9Bwtf066795; Sat, 27 Aug 2016 09:11:58 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201608270911.u7R9Bwtf066795@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Sat, 27 Aug 2016 09:11:58 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r304882 - in stable/11: share/man/man9 sys/kern sys/sys X-SVN-Group: stable-11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 27 Aug 2016 09:11:59 -0000 Author: kib Date: Sat Aug 27 09:11:57 2016 New Revision: 304882 URL: https://svnweb.freebsd.org/changeset/base/304882 Log: MFC r303425: Add callout_when(9). MFC r303919: Fix indentation. Modified: stable/11/share/man/man9/Makefile stable/11/share/man/man9/timeout.9 stable/11/sys/kern/kern_timeout.c stable/11/sys/sys/callout.h Directory Properties: stable/11/ (props changed) Modified: stable/11/share/man/man9/Makefile ============================================================================== --- stable/11/share/man/man9/Makefile Sat Aug 27 08:51:34 2016 (r304881) +++ stable/11/share/man/man9/Makefile Sat Aug 27 09:11:57 2016 (r304882) @@ -1766,6 +1766,7 @@ MLINKS+=timeout.9 callout.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 cred_update_thread.9 \ ucred.9 crcopy.9 \ Modified: stable/11/share/man/man9/timeout.9 ============================================================================== --- stable/11/share/man/man9/timeout.9 Sat Aug 27 08:51:34 2016 (r304881) +++ stable/11/share/man/man9/timeout.9 Sat Aug 27 09:11:57 2016 (r304882) @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd July 4, 2016 +.Dd July 27, 2016 .Dt TIMEOUT 9 .Os .Sh NAME @@ -56,6 +56,7 @@ .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 @@ -91,20 +92,48 @@ struct callout_handle handle = CALLOUT_H .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" +.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 @@ -112,16 +141,37 @@ struct callout_handle handle = CALLOUT_H .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" +.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 @@ -387,6 +437,26 @@ or this value is used as the length of t 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 @@ -503,6 +573,39 @@ 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. Modified: stable/11/sys/kern/kern_timeout.c ============================================================================== --- stable/11/sys/kern/kern_timeout.c Sat Aug 27 08:51:34 2016 (r304881) +++ stable/11/sys/kern/kern_timeout.c Sat Aug 27 09:11:57 2016 (r304882) @@ -945,6 +945,56 @@ callout_handle_init(struct callout_handl handle->callout = NULL; } +void +callout_when(sbintime_t sbt, sbintime_t precision, int flags, + sbintime_t *res, sbintime_t *prec_res) +{ + sbintime_t to_sbt, to_pr; + + if ((flags & (C_ABSOLUTE | C_PRECALC)) != 0) { + *res = sbt; + *prec_res = precision; + return; + } + if ((flags & C_HARDCLOCK) != 0 && sbt < tick_sbt) + sbt = tick_sbt; + if ((flags & C_HARDCLOCK) != 0 || +#ifdef NO_EVENTTIMERS + sbt >= sbt_timethreshold) { + to_sbt = getsbinuptime(); + + /* Add safety belt for the case of hz > 1000. */ + to_sbt += tc_tick_sbt - tick_sbt; +#else + sbt >= sbt_tickthreshold) { + /* + * Obtain the time of the last hardclock() call on + * this CPU directly from the kern_clocksource.c. + * This value is per-CPU, but it is equal for all + * active ones. + */ +#ifdef __LP64__ + to_sbt = DPCPU_GET(hardclocktime); +#else + spinlock_enter(); + to_sbt = DPCPU_GET(hardclocktime); + spinlock_exit(); +#endif +#endif + if ((flags & C_HARDCLOCK) == 0) + to_sbt += tick_sbt; + } else + to_sbt = sbinuptime(); + if (SBT_MAX - to_sbt < sbt) + to_sbt = SBT_MAX; + else + to_sbt += sbt; + *res = to_sbt; + to_pr = ((C_PRELGET(flags) < 0) ? sbt >> tc_precexp : + sbt >> C_PRELGET(flags)); + *prec_res = to_pr > precision ? to_pr : precision; +} + /* * New interface; clients allocate their own callout structures. * @@ -962,10 +1012,10 @@ callout_handle_init(struct callout_handl * callout_deactivate() - marks the callout as having been serviced */ int -callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t precision, +callout_reset_sbt_on(struct callout *c, sbintime_t sbt, sbintime_t prec, void (*ftn)(void *), void *arg, int cpu, int flags) { - sbintime_t to_sbt, pr; + sbintime_t to_sbt, precision; struct callout_cpu *cc; int cancelled, direct; int ignore_cpu=0; @@ -978,47 +1028,8 @@ callout_reset_sbt_on(struct callout *c, /* Invalid CPU spec */ panic("Invalid CPU in callout %d", cpu); } - if (flags & C_ABSOLUTE) { - to_sbt = sbt; - } else { - if ((flags & C_HARDCLOCK) && (sbt < tick_sbt)) - sbt = tick_sbt; - if ((flags & C_HARDCLOCK) || -#ifdef NO_EVENTTIMERS - sbt >= sbt_timethreshold) { - to_sbt = getsbinuptime(); + callout_when(sbt, prec, flags, &to_sbt, &precision); - /* Add safety belt for the case of hz > 1000. */ - to_sbt += tc_tick_sbt - tick_sbt; -#else - sbt >= sbt_tickthreshold) { - /* - * Obtain the time of the last hardclock() call on - * this CPU directly from the kern_clocksource.c. - * This value is per-CPU, but it is equal for all - * active ones. - */ -#ifdef __LP64__ - to_sbt = DPCPU_GET(hardclocktime); -#else - spinlock_enter(); - to_sbt = DPCPU_GET(hardclocktime); - spinlock_exit(); -#endif -#endif - if ((flags & C_HARDCLOCK) == 0) - to_sbt += tick_sbt; - } else - to_sbt = sbinuptime(); - if (SBT_MAX - to_sbt < sbt) - to_sbt = SBT_MAX; - else - to_sbt += sbt; - pr = ((C_PRELGET(flags) < 0) ? sbt >> tc_precexp : - sbt >> C_PRELGET(flags)); - if (pr > precision) - precision = pr; - } /* * This flag used to be added by callout_cc_add, but the * first time you call this we could end up with the Modified: stable/11/sys/sys/callout.h ============================================================================== --- stable/11/sys/sys/callout.h Sat Aug 27 08:51:34 2016 (r304881) +++ stable/11/sys/sys/callout.h Sat Aug 27 09:11:57 2016 (r304882) @@ -57,6 +57,7 @@ #define C_PRELGET(x) (int)((((x) >> 1) & C_PRELRANGE) - 1) #define C_HARDCLOCK 0x0100 /* align to hardclock() calls */ #define C_ABSOLUTE 0x0200 /* event time is absolute. */ +#define C_PRECALC 0x0400 /* event time is pre-calculated. */ struct callout_handle { struct callout *callout; @@ -129,6 +130,8 @@ int _callout_stop_safe(struct callout *, void callout_process(sbintime_t now); #define callout_async_drain(c, d) \ _callout_stop_safe(c, 0, d) +void callout_when(sbintime_t sbt, sbintime_t precision, int flags, + sbintime_t *sbt_res, sbintime_t *prec_res); #endif #endif /* _SYS_CALLOUT_H_ */