]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - kernel/posix-cpu-timers.c
itimers: Fix periodic tics precision
[net-next-2.6.git] / kernel / posix-cpu-timers.c
index 9b2d5e4dc8c4a5f61ca8cbb285e15487f901dacb..b60d644ea4b307f267b7a0146869b54bcd1d8404 100644 (file)
@@ -1070,6 +1070,8 @@ static void stop_process_timers(struct task_struct *tsk)
        spin_unlock_irqrestore(&cputimer->lock, flags);
 }
 
+static u32 onecputick;
+
 static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
                             cputime_t *expires, cputime_t cur_time, int signo)
 {
@@ -1077,9 +1079,16 @@ static void check_cpu_itimer(struct task_struct *tsk, struct cpu_itimer *it,
                return;
 
        if (cputime_ge(cur_time, it->expires)) {
-               it->expires = it->incr;
-               if (!cputime_eq(it->expires, cputime_zero))
-                       it->expires = cputime_add(it->expires, cur_time);
+               if (!cputime_eq(it->incr, cputime_zero)) {
+                       it->expires = cputime_add(it->expires, it->incr);
+                       it->error += it->incr_error;
+                       if (it->error >= onecputick) {
+                               it->expires = cputime_sub(it->expires,
+                                                       jiffies_to_cputime(1));
+                               it->error -= onecputick;
+                       }
+               } else
+                       it->expires = cputime_zero;
 
                __group_send_sig_info(signo, SEND_SIG_PRIV, tsk);
        }
@@ -1696,10 +1705,15 @@ static __init int init_posix_cpu_timers(void)
                .nsleep = thread_cpu_nsleep,
                .nsleep_restart = thread_cpu_nsleep_restart,
        };
+       struct timespec ts;
 
        register_posix_clock(CLOCK_PROCESS_CPUTIME_ID, &process);
        register_posix_clock(CLOCK_THREAD_CPUTIME_ID, &thread);
 
+       cputime_to_timespec(jiffies_to_cputime(1), &ts);
+       onecputick = ts.tv_nsec;
+       WARN_ON(ts.tv_sec != 0);
+
        return 0;
 }
 __initcall(init_posix_cpu_timers);