svn commit: r265472 - head/bin/dd

Bruce Evans brde at optusnet.com.au
Thu May 8 04:31:04 UTC 2014


On Wed, 7 May 2014, Alan Somers wrote:

> On Wed, May 7, 2014 at 2:26 PM, Jilles Tjoelker <jilles at stack.nl> wrote:
>> The floating point addition starts losing precision after 8388608
>> seconds (slightly more than 97 days, a plausible uptime for a server).
>> It is better to subtract the timespecs to avoid this issue.
>>
>> With microseconds, the precision of a double is sufficient for 272
>> years, so that calculation is probably acceptable.
>
> Good point.  I'll fix it.  BTW, FreeBSD does not have a timespecsub,
> but I notice that NetBSD does.  This seems like a good candidate to
> import.
>
> http://netbsd.gw.com/cgi-bin/man-cgi?timespecsub++NetBSD-current

Hrmph.  This was intentionally left out in FreeBSD.  Floating point
works better.  Unfortunately, floating point is unavailable in kernels,
or was too slow, especially in 1980, so APIs use the not so good
timespec and timeval APIs.  Not to mention bintimes, sbintimes and
struct tm.  sbintime or just nanoseconds would be better if floating
point is unavailable.  struct tm is too bloated to be good for syscalls
although not bloated enough to support sub-second times.

FreeBSD does have the corresponding design errors for timeval APIs:
timeradd(), etc.  These are even documented, but in a wrong way as
prototypes.  They are actually unsafe macros spelled as if they
are safe.  Some of them could be functions, but timercmp() must be
a macro.  Design errors in them start with their names (timer* instead
of tv*).

<sys/time.h> has rather complicated ifdefs to keep these APIs in or
out of the kernel.  It already has timespecsub(), but limits it to
the kernel.  The efficiency of these functions is unimportant, and
some like timevalsub() are extern functions in the kernel.  This
helps give the complicated ifdefs and confusing namespaces:
- bintime_sub() is kernel inline
- bintime_sub() is user inline (undocumented pollution)
- bintime_sub() uses an extra underscore
- the good name btsub() is not used
- timevalsub() is kernel extern
- timersub() is user macro (otherBSD compatibility cruft)
- the good name tvsub() is not used.  timersub() is an especially bad name
   for an API that handles timevals.  timevals were intentionally left out
   of old versions of POSIX.  POSIX invented timespecs instead.  The old
   APIs using timevals couldn't be killed so easily, and POSIX eventually
   had to standardize them.  POSIX also standardized many new timespec APIs.
   Then, just when the timevals could be killed better, the unnecessary
   APIs for manipulating them were introduced, though not in POSIX.  The
   non-kernel versions of them have a name that is particularly when there
   is more than 1 timer struct.
- timespecsub() is kernel macro
- timespecsub() as user API is intentionally left out
- the good name tssub() is not used.

Parameter names and orders for these APIs are also inconsistent and
mostly bad.  In the macro timersub(), the parameters are (tvp, uvp, vvp).
You might thing tvp is the target, but it is one of the sources.  In
the man page "prototype", they are (a, b, res).  Slightly better, but
now missing a 'p'.  But 'p' is not missing in the man page for
timerset() or timerclear().  The ordering with the target last is an
old convention.  bintime functions mostly but not always go the other way.

Floating point is easier to use than these functions, except for
conversion from floating point back to a timespec or timeval.  That
takes about 2 statements instead of 1 function call.  It's just
a bit inelegant to go through floating point when you start with
timespecs and have to convert back to timespecs.

Bruce


More information about the svn-src-head mailing list