clock_settime/settimeofday issue observed on 64-bit

D

deepak.upp

Hi All,

I am trying to set time using clock_settime or settimeofday on a 64-
bit (Red Hat, 2.6.9-55.ELsmp) linux machine. I have a long seconds
value based on which system time needs to be changed I observed that
time being set is 1 Second less then as expected. Below is the code
snippet and output. Kindly suggest a solution for the same.
No such problem has been observed on a 32-bit machine.

#include <stdio.h>
#include<sys/time.h>
#include<time.h>
int main()
{
struct timespec tsTime_To_Set;
time_t temptime, temp;
int iRetCode = 0;
struct timeval tsTime_To_Set1;

temp = 1262284200;
tsTime_To_Set.tv_sec = temp;
tsTime_To_Set.tv_nsec = 0;
tsTime_To_Set1.tv_sec = temp;
tsTime_To_Set1.tv_usec = 0;
// iRetCode = clock_settime(CLOCK_REALTIME, &tsTime_To_Set);
iRetCode = settimeofday(&tsTime_To_Set1, NULL);
if (iRetCode == 0)
{
printf("\nclock_settime() returned success :%d",iRetCode);
}
temptime = time(0);
printf("\nCurrent Time set is=%s", ctime(&temptime));

printf("Seconds value decoded returns this time\n");
printf("%s", ctime(&temp));
}
OUTPUT-
clock_settime() returned success :0
Current Time set is=Thu Dec 31 23:59:59 2009
Seconds value decoded returns this time
Fri Jan 1 00:00:00 2010
 
K

Kaz Kylheku

Hi All,

I am trying to set time using clock_settime or settimeofday on a 64-
bit (Red Hat, 2.6.9-55.ELsmp) linux machine. I have a long seconds
value based on which system time needs to be changed I observed that
time being set is 1 Second less then as expected. Below is the code
snippet and output. Kindly suggest a solution for the same.

This isn't a problem in the C language.

You have all the tools to trace this problem:

- glibc source code
- kernel source code
- libc-alpha mailing list
- kernel mailing list

Watch out: Red Hat puts out patched kernels. You never know, they could
have broken something.

I've looked at some glibc and kernel code. Not what you're running
though, but what I havee handy.

The clock_settime function for CLOCK_REALTIME goes through the same
kernel function as settimeofday, in 2.6.26.

The C time function is implemented as a system call in glibc 2.9, which
should just retrieve the seconds part of the time that was stored by
settimeofday!

But note that the time being set can be adjusted.

Here is part of the function from the Linux 2.6.26 kernel, shown
indented, with my comments unindented:

int do_settimeofday(struct timespec *tv)
{
unsigned long flags;
time_t wtm_sec, sec = tv->tv_sec;
long wtm_nsec, nsec = tv->tv_nsec;

if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
return -EINVAL;

write_seqlock_irqsave(&xtime_lock, flags);

nsec -= __get_nsec_offset();

Look: a potentially positive value is subtracted from
the nanoseconds, potentially leaving it negative.

wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

set_normalized_timespec(&xtime, sec, nsec);

Here is where the time is stored. The set_normalized_timespec function
normalizes the second/nanosecond pair to a timespec. This function
handles negative values in the nanosecond field by decrementing the
seconds field and adding to the nanosecond field until it reaches a
positive value.

So here is how a time of 00:00 can become 23:59.

The reason that the nsecs is adjusted is a hack. You see, the
gettimeofday system call reads the real time clock hardware (if
available) to provide fine-grained resolution.

The settimeofday system call tries to compensate for this; i.e subtract
the hardware clock nanoseconds from the value being set, knowing that
when the time is read with gettimeofday, this amount will be added!
 
D

deepak.upp

This isn't a problem in the C language.

You have all the tools to trace this problem:

- glibc source code
- kernel source code
- libc-alpha mailing list
- kernel mailing list

Watch out: Red Hat puts out patched kernels. You never know, they could
have broken something.

I've looked at some glibc and kernel code. Not what you're running
though, but what I havee handy.

The clock_settime function for CLOCK_REALTIME goes through the same
kernel function as settimeofday, in 2.6.26.

The C time function is implemented as a system call in glibc 2.9, which
should just retrieve the seconds part of the time that was stored by
settimeofday!

But note that the time being set can be adjusted.

Here is part of the function from the Linux 2.6.26 kernel, shown
indented, with my comments unindented:

    int do_settimeofday(struct timespec *tv)
    {
            unsigned long flags;
            time_t wtm_sec, sec = tv->tv_sec;
            long wtm_nsec, nsec = tv->tv_nsec;

            if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                    return -EINVAL;

            write_seqlock_irqsave(&xtime_lock, flags);

            nsec -= __get_nsec_offset();

Look: a potentially positive value is subtracted from
the nanoseconds, potentially leaving it negative.

            wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
            wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

            set_normalized_timespec(&xtime, sec, nsec);

Here is where the time is stored.  The set_normalized_timespec function
normalizes the second/nanosecond pair to a timespec. This function
handles negative values in the nanosecond field by decrementing the
seconds field and adding to the nanosecond field until it reaches a
positive value.  

So here is how a time of 00:00 can become 23:59.

The reason that the nsecs is adjusted is a hack. You see, the
gettimeofday system call reads the real time clock hardware (if
available) to provide fine-grained resolution.

The settimeofday system call tries to compensate for this; i.e subtract
the hardware clock nanoseconds from the value being set, knowing that
when the time is read with gettimeofday, this amount will be added!

Thanks a lot Kay, I further analyzed the issue i faced and it seems
problem is with time(0) call.
time(0) returns the current system time as 1262284199 which is 1
second less than the time i wanted to set. clock_gettime returns
correct system time being set.
Thanks.
 
D

deepak.upp

This isn't a problem in the C language.

You have all the tools to trace this problem:

- glibc source code
- kernel source code
- libc-alpha mailing list
- kernel mailing list

Watch out: Red Hat puts out patched kernels. You never know, they could
have broken something.

I've looked at some glibc and kernel code. Not what you're running
though, but what I havee handy.

The clock_settime function for CLOCK_REALTIME goes through the same
kernel function as settimeofday, in 2.6.26.

The C time function is implemented as a system call in glibc 2.9, which
should just retrieve the seconds part of the time that was stored by
settimeofday!

But note that the time being set can be adjusted.

Here is part of the function from the Linux 2.6.26 kernel, shown
indented, with my comments unindented:

    int do_settimeofday(struct timespec *tv)
    {
            unsigned long flags;
            time_t wtm_sec, sec = tv->tv_sec;
            long wtm_nsec, nsec = tv->tv_nsec;

            if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                    return -EINVAL;

            write_seqlock_irqsave(&xtime_lock, flags);

            nsec -= __get_nsec_offset();

Look: a potentially positive value is subtracted from
the nanoseconds, potentially leaving it negative.

            wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
            wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

            set_normalized_timespec(&xtime, sec, nsec);

Here is where the time is stored.  The set_normalized_timespec function
normalizes the second/nanosecond pair to a timespec. This function
handles negative values in the nanosecond field by decrementing the
seconds field and adding to the nanosecond field until it reaches a
positive value.  

So here is how a time of 00:00 can become 23:59.

The reason that the nsecs is adjusted is a hack. You see, the
gettimeofday system call reads the real time clock hardware (if
available) to provide fine-grained resolution.

The settimeofday system call tries to compensate for this; i.e subtract
the hardware clock nanoseconds from the value being set, knowing that
when the time is read with gettimeofday, this amount will be added!

Thanks a lot Kay and Gordon, I further analyzed the issue i faced and
it seems problem is with time(0) call.
time(0) returns the current system time as 1262284199 which is 1
second less than the time i wanted to set.
clock_gettime returns correct system time being set.
Thanks.
 
A

austinium

Hi
Please see my queries inline.


This isn't a problem in the C language.

You have all the tools to trace this problem:

- glibc source code
- kernel source code
- libc-alpha mailing list
- kernel mailing list

Watch out: Red Hat puts out patched kernels. You never know, they could
have broken something.

I built the same source code on a machine with the following basic
specs. and the output was as expected. The specs. are, Target: x86_64-
suse-linux, host=x86_64-suse-linux, glibc-2.5-25, kernel 2.6.18.2-34.
So, it may not be broken in Red Hat only!

I've looked at some glibc and kernel code. Not what you're running
though, but what I havee handy.

The clock_settime function for CLOCK_REALTIME goes through the same
kernel function as settimeofday, in 2.6.26.

The C time function is implemented as a system call in glibc 2.9, which
should just retrieve the seconds part of the time that was stored by
settimeofday!

But note that the time being set can be adjusted.

Here is part of the function from the Linux 2.6.26 kernel, shown
indented, with my comments unindented:

    int do_settimeofday(struct timespec *tv)
    {
            unsigned long flags;
            time_t wtm_sec, sec = tv->tv_sec;
            long wtm_nsec, nsec = tv->tv_nsec;

            if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
                    return -EINVAL;

            write_seqlock_irqsave(&xtime_lock, flags);

            nsec -= __get_nsec_offset();

Look: a potentially positive value is subtracted from
the nanoseconds, potentially leaving it negative.

            wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
            wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);

            set_normalized_timespec(&xtime, sec, nsec);

Here is where the time is stored.  The set_normalized_timespec function
normalizes the second/nanosecond pair to a timespec. This function
handles negative values in the nanosecond field by decrementing the
seconds field and adding to the nanosecond field until it reaches a
positive value.  

So here is how a time of 00:00 can become 23:59.

The reason that the nsecs is adjusted is a hack. You see, the
gettimeofday system call reads the real time clock hardware (if
available) to provide fine-grained resolution.

The settimeofday system call tries to compensate for this; i.e subtract
the hardware clock nanoseconds from the value being set, knowing that
when the time is read with gettimeofday, this amount will be added!

But then why does it work well on a 32 bit machine configuration?

So, I am still confused, why it lags a second on a 64 bit
configuration machine while works well on a 32 bit machine.

Thanks
Vikram
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top