Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 28 Jul 2016 08:57:01 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
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
Message-ID:  <201607280857.u6S8v1w3062722@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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_ */



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