On the two systems I've tested (a 32-bit Ubuntu 12.04 server and a 64-bit Ubuntu 13.10 VM), the seconds since the epoch given by time() may differ from gettimeofday()'s.
Specifically, though I call time()
after calling gettimeofday()
, the value returned by time()
is sometimes less than the tv_sec
value returned by gettimeofday()
.
This apparently occurs just after the clock rolls over to a new second.
This caused bugs in some of my code that expected time()'s and gettimeofday()'s seconds to be interchangeable.
Sample code demonstrating this problem:
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
int main()
{
time_t start = time(NULL);
int same = 0;
int different = 0;
int max_usec = 0;
while (1) {
time_t t;
struct timeval tv;
gettimeofday(&tv, NULL);
t = time(NULL);
if (t < tv.tv_sec) {
different++;
if (tv.tv_usec > max_usec) {
max_usec = tv.tv_usec;
}
} else {
same++;
}
if (t > start + 5) {
break;
}
}
printf("Same: %i\n", same);
printf("Different: %i\n", different);
printf("Largest difference seen at %i\n", max_usec);
}
Note that I'm calling time() second and only complaining if its value is less than gettimeofday()'s.
Sample output:
Same: 33282836
Different: 177076
Largest difference seen at 5844
I.e., the two values were the same 33 million times, they were different 177k times, and they were always different within 5844 microseconds of a new second.
Is this a known issue? What causes this?
Both calls are implemented as kernel syscalls. Both functions end up reading a
struct timekeeper
, both refer to the very same instance. But they differ in what they do with it:time():
uses the
get_seconds()
function, which is a shortcut to this:it just returns
xktime_sec
.gettimeofday()
:gettimeofday()
on the other hand usesdo_gettimeofday()
(viagetnstimeofday
) which reads both fieldsxktime_sec
as well asxktime_nsec
(viatimekeeping_get_ns
). Here it might happen thatxktime_nsec
holds more nanoseconds than a second. This potential extra time is used to increase thetv_sec
field by calling the functiontimespec_add_ns()
which does this:So,
tv_sec
might get bigger than thexktime_sec
field was. And there you have it: a little difference in whattime()
gives you and whatgettimeofday()
gives you.I fought against this issue in fluxbox today and until a better solution occurs I live with this:
Both
time
andgettimeofday
are implemented as so called Linux vsyscalls. Means that your code will be redirected to kernel owned, but userspace mapped pages containing the results which are only periodically updated.In Ubuntu (I have not observed this behaviour in RedHat Linux) the value for
gettimeofday
is updated before the value fortime
thus it is possible to get inconsistent values:Swapping your calls around gives consistent results:
This behaviour is due to the implementation of timekeeping in the Linux kernel.
Linux maintains a variable which tracks the current wall-clock time; this is maintained to nanosecond precision and is updated periodically. (It is
tk_core.timekeeper.{xtime_secs, tkr_mono.xtime_nsec}
in recent kernel versions.)time()
calls get_seconds() which simply returns the seconds part of this variable - so, depending on how long ago the wall-clock time was updated, may return a slightly out-of-date value.gettimeofday()
not only reads the latest value of the wall-clock variables, but also (via timekeeping_get_ns()) makes a new reading from the hardware clock (typically the TSC in x86 systems, though this is configurable at runtime) and applies a correction.Thanks to that correction calculation, it is possible for the result returned by
gettimeofday()
to roll over into the next second, and hence return atv_sec
value higher than the result oftime()
.