Subject: Re: POSIX timer_settime() doesn't set timer in some cases (lost accuracy)
To: None <tech-kern@netbsd.org>
From: Ian Zagorskih <ianzag@megasignal.com>
List: tech-kern
Date: 09/02/2004 17:29:39
On Tuesday 31 August 2004 23:44, Ian Zagorskih wrote:
> NetBSD IANZAG 2.0G NetBSD 2.0G (IANZAG) #1: Thu Aug 26 02:11:03 NOVST 2004
> ianzag@IANZAG:/usr/src/sys/arch/i386/compile/IANZAG i386
>
> According to POSIX docs at
> http://www.opengroup.org/onlinepubs/009695399/functions/timer_getoverrun.ht
>ml
>
> ---cut---
> The timer_gettime() function shall store the amount of time until the
> specified timer, timerid, expires and the reload value of the timer into
> the space pointed to by the value argument. The it_value member of this
> structure shall contain the amount of time before the timer expires, or
> zero if the timer is disarmed.
> ---cut---
>
> Same as NetBSD man pages says:
>
> ---cut---
> The timer_settime() sets the next expiration time of the timer with id
> timerid to the it_value specified in the tim argument.  If the value is 0,
> the timer is disarmed.
> ---cut---
>
> So, the code below
>
> struct itimerspec its;
> its.it_value.tv_sec = 0;
> its.it_value.tv_nsec = 1;
> its.it_interval.tv_sec = 1;
> its.it_interval.tv_nsec = 0;
> timer_settime(timerid, 0, &its, 0);
>
> ..must work course it_value field isn't zero. Even more, in the past
> according to the POSIX specs i'v got used to "start interval timer as far
> as possibly without initial delay" just setting it_value as shown above
> (sec = 0, nsec = 1).
>
> On the other hand, sys_timer_settime() in kern/kern_time.c converts
> itimerspec structure into internal itimerval struture with macro
> TIMESPEC_TO_TIMEVAL as:
>
> #define TIMESPEC_TO_TIMEVAL(tv, ts) {  \
>         (tv)->tv_sec = (ts)->tv_sec;   \
>         (tv)->tv_usec = (ts)->tv_nsec / 1000;  \
> }
>
> Obviously, doing this way we'r lossing nanosecond part and 1 ns becomes 0
> us -> timer isn't armed. From my point of view this violates POSIX way :)

Just a comment (maybe it will help to anyone).

Sure this isn't a fresh or original idea/solution but code like below works 
much better rather just "tv_sec = 0, tv_nsec = 1".

---cut---
        struct itimerspec its;
        struct timespec ts;
 timer_t timer;
 long msec; /* Periodic timer interval in ms */

 /* Setup initial timer interval as small as possibly */
        if (clock_getres(CLOCK_REALTIME, &ts) == -1)
  /* Handle error */
        its.it_value.tv_sec = ts.tv_sec;
        its.it_value.tv_nsec = ts.tv_nsec;

        its.it_interval.tv_sec = msec / 1000;
        its.it_interval.tv_nsec = (msec % 1000) * 1000000;
        if (timer_settime(timer, 0, &its, 0) == -1)
  /* Handle error */
---cut---

// wbr