Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 16 Dec 2016 23:42:49 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r310183 - stable/10/sys/kern
Message-ID:  <201612162342.uBGNgnYK055951@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Fri Dec 16 23:42:49 2016
New Revision: 310183
URL: https://svnweb.freebsd.org/changeset/base/310183

Log:
  MFC r296775 (by gibbs):
  Provide high precision conversion from ns,us,ms -> sbintime in kevent.
  
  Tested by:	ian

Modified:
  stable/10/sys/kern/kern_event.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/kern/kern_event.c
==============================================================================
--- stable/10/sys/kern/kern_event.c	Fri Dec 16 23:33:37 2016	(r310182)
+++ stable/10/sys/kern/kern_event.c	Fri Dec 16 23:42:49 2016	(r310183)
@@ -556,34 +556,59 @@ knote_fork(struct knlist *list, int pid)
 #define NOTE_TIMER_PRECMASK	(NOTE_SECONDS|NOTE_MSECONDS|NOTE_USECONDS| \
 				NOTE_NSECONDS)
 
-static __inline sbintime_t
+static sbintime_t
 timer2sbintime(intptr_t data, int flags)
 {
-	sbintime_t modifier;
 
+        /*
+         * Macros for converting to the fractional second portion of an
+         * sbintime_t using 64bit multiplication to improve precision.
+         */
+#define NS_TO_SBT(ns) (((ns) * (((uint64_t)1 << 63) / 500000000)) >> 32)
+#define US_TO_SBT(us) (((us) * (((uint64_t)1 << 63) / 500000)) >> 32)
+#define MS_TO_SBT(ms) (((ms) * (((uint64_t)1 << 63) / 500)) >> 32)
 	switch (flags & NOTE_TIMER_PRECMASK) {
 	case NOTE_SECONDS:
-		modifier = SBT_1S;
-		break;
+#ifdef __LP64__
+		if (data > (SBT_MAX / SBT_1S))
+			return SBT_MAX;
+#endif
+		return ((sbintime_t)data << 32);
 	case NOTE_MSECONDS: /* FALLTHROUGH */
 	case 0:
-		modifier = SBT_1MS;
-		break;
+		if (data >= 1000) {
+			int64_t secs = data / 1000;
+#ifdef __LP64__
+			if (secs > (SBT_MAX / SBT_1S))
+				return SBT_MAX;
+#endif
+			return (secs << 32 | MS_TO_SBT(data % 1000));
+		}
+		return MS_TO_SBT(data);
 	case NOTE_USECONDS:
-		modifier = SBT_1US;
-		break;
+		if (data >= 1000000) {
+			int64_t secs = data / 1000000;
+#ifdef __LP64__
+			if (secs > (SBT_MAX / SBT_1S))
+				return SBT_MAX;
+#endif
+			return (secs << 32 | US_TO_SBT(data % 1000000));
+		}
+		return US_TO_SBT(data);
 	case NOTE_NSECONDS:
-		modifier = SBT_1NS;
-		break;
-	default:
-		return (-1);
-	}
-
+		if (data >= 1000000000) {
+			int64_t secs = data / 1000000000;
 #ifdef __LP64__
-	if (data > SBT_MAX / modifier)
-		return (SBT_MAX);
+			if (secs > (SBT_MAX / SBT_1S))
+				return SBT_MAX;
 #endif
-	return (modifier * data);
+			return (secs << 32 | US_TO_SBT(data % 1000000000));
+		}
+		return NS_TO_SBT(data);
+	default:
+		break;
+	}
+	return (-1);
 }
 
 static void



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