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>