Page MenuHomeFreeBSD

Provide high precision conversion from ns,us,ms -> sbintime in kevent
ClosedPublic

Authored by gibbs on Feb 22 2016, 10:38 PM.
Tags
None
Referenced Files
Unknown Object (File)
Thu, Feb 15, 1:22 AM
Unknown Object (File)
Thu, Feb 8, 5:03 AM
Unknown Object (File)
Dec 26 2023, 6:41 PM
Unknown Object (File)
Dec 20 2023, 1:42 AM
Unknown Object (File)
Nov 23 2023, 9:45 AM
Unknown Object (File)
Nov 23 2023, 12:23 AM
Unknown Object (File)
Nov 4 2023, 3:59 AM
Unknown Object (File)
Oct 24 2023, 10:06 PM
Subscribers

Diff Detail

Repository
rS FreeBSD src repository - subversion
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

gibbs retitled this revision from to Provide high precision conversion from ns,us,ms -> sbintime in kevent.
gibbs updated this object.
gibbs edited the test plan for this revision. (Show Details)
gibbs added a reviewer: jhb.

So I think I understand. Suppose you wanted to sleep for 1.5 seconds. In sbintime_t that should ideally be 0x180000000. The old method for 1500 milliseconds, 1500000 microseconds, and 1500000000 nanoseconds gives:

(gdb) p/x ((1ull << 32) / 1000) * 1500
$23 = 0x17ffffe44
(gdb) p/x ((1ull << 32) / 1000000) * 1500000
$24 = 0x17fe9dc40
(gdb) p/x ((1ull << 32) / 1000000000) * 1500000000
$26 = 0x165a0bc00

With the new math, I always get the same result:

(gdb) p/x (500 * (((1ull << 63) / 500)) >> 32) | (1ull << 32)
$20 = 0x17fffffff
(gdb) p/x (500000 * (((1ull << 63) / 500000)) >> 32) | (1ull << 32)
$25 = 0x17fffffff
(gdb) p/x (500000000 * (((1ull << 63) / 500000000)) >> 32) | (1ull << 32)
$27 = 0x17fffffff

In the worst case (nanoseconds), the old code is off by about 103 milliseconds. It might be worth noting that the bintime code also explicitly handles the fractional second separate from the second when doing conversions, though it has to do that anyway. Hmm, the new logic also matches what tstosbt(), etc. do. That is a big argument in favor of this change. In fact, to reduce code duplication, I would suggest using tstosbt() and tvtosbt() directly. E.g.:

case NOTE_USECONDS:
    struct timeval tv;
    int64_t secs;

    secs = data / 1000000;
#ifdef __LP64__
    if (secs > (SBT_MAX / SBT_1S))
        return (SBT_MAX);
#endif
    tv.secs = secs;
    tv.usec = data % 1000000;
    return (tvtosbt(&tv));

However, the new logic is clearly sounder regardless of which way you choose to fix it. There isn't an equivalent 'footosbt' for something taking milliseconds.

This does almost beg for axeing SBT_1MS entirely and having '*stosbt()' methods in <sys/time.h> instead.

jhb edited edge metadata.
This revision is now accepted and ready to land.Feb 24 2016, 6:56 PM
This revision was automatically updated to reflect the committed changes.