[PATCH] setitimer timer expires too early
authorPaulo Marques <pmarques@grupopie.com>
Thu, 5 May 2005 23:15:49 +0000 (16:15 -0700)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Thu, 5 May 2005 23:36:41 +0000 (16:36 -0700)
It seems that the code responsible for this is in kernel/itimer.c:126:

p->signal->real_timer.expires = jiffies + interval;
add_timer(&p->signal->real_timer);

If you request an interval of, lets say 900 usecs, the interval given by
timeval_to_jiffies will be 1.

If you request this when we are half-way between two timer ticks, the
interval will only give 400 usecs.

If we want to guarantee that we never ever give intervals less than
requested, the simple solution would be to change that to:

p->signal->real_timer.expires = jiffies + interval + 1;

This however will produce pathological cases, like having a idle system
being requested 1 ms timeouts will give systematically 2 ms timeouts,
whereas currently it simply gives a few usecs less than 1 ms.

The complex (and more computationally expensive) solution would be to
check the gettimeofday time, and compute the correct number of jiffies.
This way, if we request a 300 usecs timer 200 usecs inside the timer
tick, we can wait just one tick, but not if we are 800 usecs inside the
tick. This would also mean that we would have to lock preemption during
these computations to avoid races, etc.

I've searched the archives but couldn't find this particular issue being
discussed before.

Attached is a patch to do the simple solution, in case anybody thinks
that it should be used.

Signed-Off-By: Paulo Marques <pmarques@grupopie.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
kernel/itimer.c

index e9a40e947e079615650c2491eddf7d7b35fdea9f..1dc988e0d2c77e962063c776b7b035800f51b9be 100644 (file)
@@ -123,7 +123,11 @@ static inline void it_real_arm(struct task_struct *p, unsigned long interval)
                return;
        if (interval > (unsigned long) LONG_MAX)
                interval = LONG_MAX;
-       p->signal->real_timer.expires = jiffies + interval;
+       /* the "+ 1" below makes sure that the timer doesn't go off before
+        * the interval requested. This could happen if
+        * time requested % (usecs per jiffy) is more than the usecs left
+        * in the current jiffy */
+       p->signal->real_timer.expires = jiffies + interval + 1;
        add_timer(&p->signal->real_timer);
 }