From owner-svn-src-all@freebsd.org Thu Jul 28 08:57:03 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 0250FBA670E; Thu, 28 Jul 2016 08:57:02 +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 AD8F91C55; Thu, 28 Jul 2016 08:57:02 +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 u6S8v1uW062726; Thu, 28 Jul 2016 08:57:01 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u6S8v1w3062722; Thu, 28 Jul 2016 08:57:01 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201607280857.u6S8v1w3062722@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Thu, 28 Jul 2016 08:57:01 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r303425 - in head: share/man/man9 sys/kern sys/sys X-SVN-Group: head 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: Thu, 28 Jul 2016 08:57:03 -0000 Author: kib Date: Thu Jul 28 08:57:01 2016 New Revision: 303425 URL: https://svnweb.freebsd.org/changeset/base/303425 Log: Extract the calculation of the callout fire time into the new function callout_when(9). See the man page update for the description of the intended use. Tested by: pho Reviewed by: jhb, bjk (man page updates) Sponsored by: The FreeBSD Foundation MFC after: 1 month X-Differential revision: https://reviews.freebsd.org/D7137 Modified: head/share/man/man9/Makefile head/share/man/man9/timeout.9 head/sys/kern/kern_timeout.c head/sys/sys/callout.h Modified: head/share/man/man9/Makefile ============================================================================== --- head/share/man/man9/Makefile Thu Jul 28 08:53:38 2016 (r303424) +++ head/share/man/man9/Makefile Thu Jul 28 08:57:01 2016 (r303425) @@ -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: head/share/man/man9/timeout.9 ============================================================================== --- head/share/man/man9/timeout.9 Thu Jul 28 08:53:38 2016 (r303424) +++ head/share/man/man9/timeout.9 Thu Jul 28 08:57:01 2016 (r303425) @@ -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: head/sys/kern/kern_timeout.c ============================================================================== --- head/sys/kern/kern_timeout.c Thu Jul 28 08:53:38 2016 (r303424) +++ head/sys/kern/kern_timeout.c Thu Jul 28 08:57:01 2016 (r303425) @@ -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: head/sys/sys/callout.h ============================================================================== --- head/sys/sys/callout.h Thu Jul 28 08:53:38 2016 (r303424) +++ head/sys/sys/callout.h Thu Jul 28 08:57:01 2016 (r303425) @@ -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_ */