2

I have written a timer eventloop with epoll and the timerfd linux API. The magpage of timerfd_gettime states the following:

The it_value field returns the amount of time until the timer will
next expire.  If both fields of this structure are zero, then the
timer is currently disarmed.

So to check if a timer is currently armed or disarmed I had written the following code:

bool timer_is_running(struct timer *timer)
{
    struct itimerspec timerspec;

    if(timerfd_gettime(timer->_timer_fd, &timerspec) == -1) {
        printf("[TIMER] Could not  get timer '%s' running status\n", timer->name);
        return false;
    }

    printf("[TIMER] Checking running state of timer '%s' it_value.tv_sec = %"PRIu64", it_value.tv_nsec = %"PRIu64"\n", timer->name, (uint64_t) timerspec.it_value.tv_sec, (uint64_t) timerspec.it_value.tv_nsec == 0);
    return timerspec.it_value.tv_sec != 0  && timerspec.it_value.tv_nsec != 0;
}

This wasn't working and all timers were reported as disarmed. when I looked at the output I saw the following on a currently disarmed timer:

[TIMER] Checking running state of timer 'test' it_value.tv_sec = 0, it_value.tv_nsec = 4302591840

After further investigation it seems only the tv_sec field is set to 0 on disarmed timers.

This is program runs on kernel 3.18.23 on MIPS architecture (OpenWRT).

Before I flag this as a bug in the kernel implementation I would like to know if it's correct to check if a time_t is 0 by doing time_t == 0. Can anyone confirm this?

Kind regards, Daan

Daan Pape
  • 1,100
  • 1
  • 13
  • 25
  • 1
    Use `||` in the returned expression, not `&&`. – Peter Aug 28 '16 at 13:09
  • Did you intend the third argument to be `timerspec.it_value.tv_nsec == 0`? This will evaluate to `0` when the timer has a value. I ask, because that won't be a 64-bit value to match the format spec. – Weather Vane Aug 28 '16 at 13:13

2 Answers2

4

This is not a bug in the kernel implementation. It is your code that is flawed.

The it_value field returns the amount of time until the timer will next expire. If both fields of this structure are zero, then the timer is currently disarmed.

The converse of this is that (assuming the call timerfd_gettime() succeeds) the timer is armed if ONE or BOTH of the fields of the structure are non-zero.

The last return statement of your function is

return timerspec.it_value.tv_sec != 0  && timerspec.it_value.tv_nsec != 0;

which returns true only if BOTH the fields are non-zero. Instead, you need to use

return timerspec.it_value.tv_sec != 0  || timerspec.it_value.tv_nsec != 0;
Peter
  • 35,646
  • 4
  • 32
  • 74
  • Thank you very much. It works now, I was also mislead because the printf statement in which I cast `time_t` to `uint64_t` was not working correctly. – Daan Pape Aug 28 '16 at 14:12
3

The time_t type alias is an arithmetic or real type. Both arithmetic and real types can by implicitly compared with the integer value zero.

Furthermore, on POSIX systems (like Linux) time_t is defined as an integer (see e.g. this <sys/types.h> reference).

While the C standard doesn't explicitly specify the type of time_t just about all implementations use integers for time_t for compatibility reasons. I don't know any implementation where it's not an integer.

So the answer to your question is that the comparison is correct.

It should be noted that it's only the tv_sec member that is of type time_t. The tv_nsec member is a long.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621