Pergunta

The following code on Ubuntu 12.04 LTS:

 #include <stdio.h>
 #include <sys/timex.h>
 #include <sys/time.h>

 int main(int argc, char **argv) 
 {
     struct timeval tv; 
     gettimeofday(&tv, NULL);

     struct ntptimeval ntptv;
     ntp_gettime(&ntptv);

     printf("gettimeofday: tv_sec = %ld, tv_usec = %ld\n", 
                tv.tv_sec, tv.tv_usec);
     printf("ntp_gettime:  tv_sec = %ld, tv_usec = %ld\n", 
                ntptv.time.tv_sec, ntptv.time.tv_usec);
 }

returns:

 gettimeofday: tv_sec = 1366209548, tv_usec = 137736
 ntp_gettime:  tv_sec = 1366209548, tv_usec = 137743081

This is kind of weird because the tv_usec value, if it indeed is the microsecond count, should not be greater than 1000000. The result shown above makes me think that ntp_gettime() is actually returning nanosecond precision.

The ntp_gettime() manpage (for precise) at http://manpages.ubuntu.com/manpages/precise/man2/ntp_gettime.2freebsd.html doesn't really say much.

An earlier manpage version (for hardy) http://manpages.ubuntu.com/manpages/hardy/man2/ntp_gettime.2.html claims it might be either nanosecond or microsecond depending on whether the STA_NANO bit is set in the status word returned by ntp_adjtime().

Anyone know definitively? Short of that, where are ntp_gettime(), ntp_adjtime(), and all the various internal functions they call defined in the 12.04 source?

Foi útil?

Solução

ntp_gettime and ntp_adjtime are both defined in the C library. On Linux and glibc, ntp_adjtime is just a wrapper for the adjtimex system call, and ntp_gettime uses the same syscall by passing it a struct timex with modes set to 0. You can browse their definitions at the glibc LXR.

The system call implementation calls _do_adjtimex which calls getnstimeofday to get the time (in nanoseconds) and then hands it to __do_adjtimex. And here is the interesting part :

txc->time.tv_sec = ts->tv_sec;
txc->time.tv_usec = ts->tv_nsec;
if (!(time_status & STA_NANO))
        txc->time.tv_usec /= NSEC_PER_USEC;

So if STA_NANO is set it just puts the nanosecond value in tv_usec, which is the behavior you've been experiencing. If you want to unset this flag, you can do something like this :

struct timex tmx;
tmx.modes = 0 | ADJ_MICRO;
ntp_adjtime(&tmx);

and then read your microsecond value from tmx.time.tv_usec. If you want to do this you'll have to run your code with sudo, but beware that the flag will remain unset in the kernel until you reset it (using ADJ_NANO) or reboot.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top