Provide high precision conversion from ns,us,ms -> sbintime in kevent
In timer2sbintime(), calculate the second and fractional second portions of the sbintime separately. When calculating the the fractional second portion, use a 64bit multiply to prevent excess truncation. This avoids the ~7% error in the original conversion for ns, and smaller errors of the same type for us and ms. PR: 198139 Reviewed by: jhb MFC after: 1 week Differential Revision: https://reviews.freebsd.org/D5397
This commit is contained in:
parent
823590d40e
commit
5405e7e2ee
@ -564,34 +564,59 @@ knote_fork(struct knlist *list, int pid)
|
|||||||
#define NOTE_TIMER_PRECMASK (NOTE_SECONDS|NOTE_MSECONDS|NOTE_USECONDS| \
|
#define NOTE_TIMER_PRECMASK (NOTE_SECONDS|NOTE_MSECONDS|NOTE_USECONDS| \
|
||||||
NOTE_NSECONDS)
|
NOTE_NSECONDS)
|
||||||
|
|
||||||
static __inline sbintime_t
|
static sbintime_t
|
||||||
timer2sbintime(intptr_t data, int flags)
|
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) {
|
switch (flags & NOTE_TIMER_PRECMASK) {
|
||||||
case NOTE_SECONDS:
|
case NOTE_SECONDS:
|
||||||
modifier = SBT_1S;
|
#ifdef __LP64__
|
||||||
break;
|
if (data > (SBT_MAX / SBT_1S))
|
||||||
|
return SBT_MAX;
|
||||||
|
#endif
|
||||||
|
return ((sbintime_t)data << 32);
|
||||||
case NOTE_MSECONDS: /* FALLTHROUGH */
|
case NOTE_MSECONDS: /* FALLTHROUGH */
|
||||||
case 0:
|
case 0:
|
||||||
modifier = SBT_1MS;
|
if (data >= 1000) {
|
||||||
break;
|
int64_t secs = data / 1000;
|
||||||
case NOTE_USECONDS:
|
|
||||||
modifier = SBT_1US;
|
|
||||||
break;
|
|
||||||
case NOTE_NSECONDS:
|
|
||||||
modifier = SBT_1NS;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return (-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __LP64__
|
#ifdef __LP64__
|
||||||
if (data > SBT_MAX / modifier)
|
if (secs > (SBT_MAX / SBT_1S))
|
||||||
return (SBT_MAX);
|
return SBT_MAX;
|
||||||
#endif
|
#endif
|
||||||
return (modifier * data);
|
return (secs << 32 | MS_TO_SBT(data % 1000));
|
||||||
|
}
|
||||||
|
return MS_TO_SBT(data);
|
||||||
|
case NOTE_USECONDS:
|
||||||
|
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:
|
||||||
|
if (data >= 1000000000) {
|
||||||
|
int64_t secs = data / 1000000000;
|
||||||
|
#ifdef __LP64__
|
||||||
|
if (secs > (SBT_MAX / SBT_1S))
|
||||||
|
return SBT_MAX;
|
||||||
|
#endif
|
||||||
|
return (secs << 32 | US_TO_SBT(data % 1000000000));
|
||||||
|
}
|
||||||
|
return NS_TO_SBT(data);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
Loading…
x
Reference in New Issue
Block a user