Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 20 May 2012 01:39:39 +1000 (EST)
From:      Bruce Evans <brde@optusnet.com.au>
To:        Poul-Henning Kamp <phk@phk.freebsd.dk>
Cc:        Konstantin Belousov <kostikbel@gmail.com>, Robert Millan <rmh@freebsd.org>, freebsd-arch@freebsd.org
Subject:   Re: headers that use "struct bintime"
Message-ID:  <20120520004236.D1313@besplex.bde.org>
In-Reply-To: <14164.1337435556@critter.freebsd.dk>
References:  <14164.1337435556@critter.freebsd.dk>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, 19 May 2012, Poul-Henning Kamp wrote:

> In message <20120519134005.GJ2358@deviant.kiev.zoral.com.ua>, Konstantin Belous
> ov writes:
>
>>>  Or maybe "struct bintime" be defined unconditionally?
>
> I think this is the best/right way to go.

Not permitted.

Exposing struct bintime also exposes its internal pollution (see below).

sys/time.h is still massively polluted in other ways:

% #ifndef _SYS_TIME_H_
% #define _SYS_TIME_H_
% 
% #include <sys/_timeval.h>
% #include <sys/types.h>

Not permitted in POSIX.1, at least in the 2001 version (except all _t
names from here are permitted).  Only (all of the) pollution from
including <sys/select.h> is permitted.

% #include <sys/timespec.h>

This only gives the undocumented pollution TIMESPEC_TO_TIMEVAL() and
TIMEVAL_TO_TIMESPEC() (only under __BSD_VISIBLE).

% 
% struct timezone {
% 	int	tz_minuteswest;	/* minutes west of Greenwich */
% 	int	tz_dsttime;	/* type of dst correction */
% };
% #define	DST_NONE	0	/* not on dst */
% #define	DST_USA		1	/* USA style dst */
% #define	DST_AUST	2	/* Australian style dst */
% #define	DST_WET		3	/* Western European dst */
% #define	DST_MET		4	/* Middle European dst */
% #define	DST_EET		5	/* Eastern European dst */
% #define	DST_CAN		6	/* Canada */

This compatibility cruft isn't even under __BSD_VISIBLE.

% 
% #if __BSD_VISIBLE
% struct bintime {
% 	time_t	sec;
% 	uint64_t frac;
% };

__BSD_VISIBLE exposes bintime and thus necessarily the namespace pollution
in its API: field names 'sec' and 'frac'.

% 
% static __inline void
% bintime_addx(struct bintime *bt, uint64_t x)
% {
% 	uint64_t u;

__BSD_VISIBLE exposes bintime and thus unnecessarily the namespace
pollution in its implementation: parameter names 'bt' and 'x', and
local variable name 'u'.  'x' and 'u' are vey popular application
names.  Though applications shouldn't use them in the global namespace
in a way they would conflict with these, they might.

% 
% 	u = bt->frac;
% 	bt->frac += x;
% 	if (u > bt->frac)
% 		bt->sec++;
% }
% 
% static __inline void
% bintime_add(struct bintime *bt, const struct bintime *bt2)
% {
% 	uint64_t u;
% 
% 	u = bt->frac;
% 	bt->frac += bt2->frac;
% 	if (u > bt->frac)
% 		bt->sec++;
% 	bt->sec += bt2->sec;
% }
% 
% static __inline void
% bintime_sub(struct bintime *bt, const struct bintime *bt2)
% {
% 	uint64_t u;
% 
% 	u = bt->frac;
% 	bt->frac -= bt2->frac;
% 	if (u < bt->frac)
% 		bt->sec--;
% 	bt->sec -= bt2->sec;
% }
% 
% static __inline void
% bintime_mul(struct bintime *bt, u_int x)
% {
% 	uint64_t p1, p2;
% 
% 	p1 = (bt->frac & 0xffffffffull) * x;
% 	p2 = (bt->frac >> 32) * x + (p1 >> 32);
% 	bt->sec *= x;
% 	bt->sec += (p2 >> 32);
% 	bt->frac = (p2 << 32) | (p1 & 0xffffffffull);
% }

Just a few more polluting parameter and variable names.

% 
% #define	bintime_clear(a)	((a)->sec = (a)->frac = 0)
% #define	bintime_isset(a)	((a)->sec || (a)->frac)
% #define	bintime_cmp(a, b, cmp)						\
% 	(((a)->sec == (b)->sec) ?					\
% 	    ((a)->frac cmp (b)->frac) :					\
% 	    ((a)->sec cmp (b)->sec))

This can be made to blow up more confusingly than the inlines by user
definitions of frac and sec.

% 
% /*-
%  * Background information:
%  *
%  * When converting between timestamps on parallel timescales of differing
%  * resolutions it is historical and scientific practice to round down rather
%  * than doing 4/5 rounding.
%  *
%  *   The date changes at midnight, not at noon.
%  *
%  *   Even at 15:59:59.999999999 it's not four'o'clock.
%  *
%  *   time_second ticks after N.999999999 not after N.4999999999
%  */

No comment.

% 
% static __inline void
% bintime2timespec(const struct bintime *bt, struct timespec *ts)
% {
% 
% 	ts->tv_sec = bt->sec;
% 	ts->tv_nsec = ((uint64_t)1000000000 * (uint32_t)(bt->frac >> 32)) >> 32;
% }
% 
% static __inline void
% timespec2bintime(const struct timespec *ts, struct bintime *bt)
% {
% 
% 	bt->sec = ts->tv_sec;
% 	/* 18446744073 = int(2^64 / 1000000000) */
% 	bt->frac = ts->tv_nsec * (uint64_t)18446744073LL; 
% }
% 
% static __inline void
% bintime2timeval(const struct bintime *bt, struct timeval *tv)
% {
% 
% 	tv->tv_sec = bt->sec;
% 	tv->tv_usec = ((uint64_t)1000000 * (uint32_t)(bt->frac >> 32)) >> 32;
% }
% 
% static __inline void
% timeval2bintime(const struct timeval *tv, struct bintime *bt)
% {
% 
% 	bt->sec = tv->tv_sec;
% 	/* 18446744073709 = int(2^64 / 1000000) */
% 	bt->frac = tv->tv_usec * (uint64_t)18446744073709LL;
% }

Yet more parameter names in the application namespace.

% #endif /* __BSD_VISIBLE */
% 
% #ifdef _KERNEL
% ... [few problems since this is private]
% #endif /* _KERNEL */
% 
% #ifndef _KERNEL			/* NetBSD/OpenBSD compatible interfaces */

This was intentionally left out of the kernel.

% 
% #define	timerclear(tvp)		((tvp)->tv_sec = (tvp)->tv_usec = 0)
% #define	timerisset(tvp)		((tvp)->tv_sec || (tvp)->tv_usec)
% #define	timercmp(tvp, uvp, cmp)					\
% 	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
% 	    ((tvp)->tv_usec cmp (uvp)->tv_usec) :			\
% 	    ((tvp)->tv_sec cmp (uvp)->tv_sec))
% #define timeradd(tvp, uvp, vvp)						\
% 	do {								\
% 		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;		\
% 		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;	\
% 		if ((vvp)->tv_usec >= 1000000) {			\
% 			(vvp)->tv_sec++;				\
% 			(vvp)->tv_usec -= 1000000;			\
% 		}							\
% 	} while (0)
% #define timersub(tvp, uvp, vvp)						\
% 	do {								\
% 		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
% 		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
% 		if ((vvp)->tv_usec < 0) {				\
% 			(vvp)->tv_sec--;				\
% 			(vvp)->tv_usec += 1000000;			\
% 		}							\
% 	} while (0)
% #endif

Now it's massive sideways compatibility cruft.

% 
% /*
%  * Names of the interval timers, and structure
%  * defining a timer setting.
%  */
% #define	ITIMER_REAL	0
% #define	ITIMER_VIRTUAL	1
% #define	ITIMER_PROF	2
% 
% struct itimerval {
% 	struct	timeval it_interval;	/* timer interval */
% 	struct	timeval it_value;	/* current value */
% };

Now standard in POSIX, but missing ifdefs for old-POSIX.

% 
% /*
%  * Getkerninfo clock information structure
%  */
% struct clockinfo {
% 	int	hz;		/* clock frequency */
% 	int	tick;		/* micro-seconds per hz tick */
% 	int	spare;
% 	int	stathz;		/* statistics clock frequency */
% 	int	profhz;		/* profiling clock frequency */
% };

More FreeBSD features not under __BSD_VISIBLE.

% 
% /* These macros are also in time.h. */
% #ifndef CLOCK_REALTIME
% #define CLOCK_REALTIME	0
% #define CLOCK_VIRTUAL	1
% #define CLOCK_PROF	2
% #define CLOCK_MONOTONIC	4
% #define CLOCK_UPTIME	5		/* FreeBSD-specific. */
% #define CLOCK_UPTIME_PRECISE	7	/* FreeBSD-specific. */
% #define CLOCK_UPTIME_FAST	8	/* FreeBSD-specific. */
% #define CLOCK_REALTIME_PRECISE	9	/* FreeBSD-specific. */
% #define CLOCK_REALTIME_FAST	10	/* FreeBSD-specific. */
% #define CLOCK_MONOTONIC_PRECISE	11	/* FreeBSD-specific. */
% #define CLOCK_MONOTONIC_FAST	12	/* FreeBSD-specific. */
% #define CLOCK_SECOND	13		/* FreeBSD-specific. */
% #define CLOCK_THREAD_CPUTIME_ID	14
% #endif
% 
% #ifndef TIMER_ABSTIME
% #define TIMER_RELTIME	0x0	/* relative timer */
% #define TIMER_ABSTIME	0x1	/* absolute timer */
% #endif

Not permitted here in POSIX I think.  Only permitted in  <time.h> in
POSIX.  Part of the bad layering of time.h and sys/time.h in FreeBSD.
Of course the kernel needs these too, but it can't get them from
sys/time.h according to POSIX, so it should put them in a smaller
common header.  FreeBSD uses 2-3 layers of timespec.h and timeval.h
headers to do much less.

The FreeBSD extensions could be ifdefed like the signal macros are, but
this is not required.

% 
% #ifdef _KERNEL
% ...
% #else /* !_KERNEL */
% #include <time.h>

Gross pollution.  The worst part of the bad layering.

% 
% #include <sys/cdefs.h>

Really silly to include this again, after including it already about
20 times counting nesting.

% #include <sys/select.h>

Most of this is required by POSIX and all of it is allowed (assuming that
select.h doesn't have any pollution, and it has no obvious pollution,
unlike the above).

% 
% __BEGIN_DECLS
% int	setitimer(int, const struct itimerval *, struct itimerval *);
% int	utimes(const char *, const struct timeval *);
% 
% #if __BSD_VISIBLE
% int	adjtime(const struct timeval *, struct timeval *);
% int	futimes(int, const struct timeval *);
% int	futimesat(int, const char *, const struct timeval [2]);
% int	lutimes(const char *, const struct timeval *);
% int	settimeofday(const struct timeval *, const struct timezone *);
% #endif
% 
% #if __XSI_VISIBLE
% int	getitimer(int, struct itimerval *);
% int	gettimeofday(struct timeval *, struct timezone *);
% #endif

At least setitimer() and gettimeofday() in the above aren't actually
XSI compatible, since the XSI version has some restrict qualifiers in it.

Exposing bintime and other pollution bogotifiles the careful ifdefs in some
parts of the file.

% 
% __END_DECLS
% 
% #endif /* !_KERNEL */
% 
% #endif /* !_SYS_TIME_H_ */

Bruce



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