Posix timers: limit number of timers firing at once
Linus Torvalds [Sun, 23 Oct 2005 17:02:50 +0000 (10:02 -0700)]
Bursty timers aren't good for anybody, very much including latency for
other programs when we trigger lots of timers in interrupt context.  So
set a random limit, after which we'll handle the rest on the next timer
tick.

Noted by Oleg Nesterov <oleg@tv-sign.ru>

Signed-off-by: Linus Torvalds <torvalds@osdl.org>

kernel/posix-cpu-timers.c

index 7a51a55..d30b304 100644 (file)
@@ -961,14 +961,16 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
 static void check_thread_timers(struct task_struct *tsk,
                                struct list_head *firing)
 {
+       int maxfire;
        struct list_head *timers = tsk->cpu_timers;
 
+       maxfire = 20;
        tsk->it_prof_expires = cputime_zero;
        while (!list_empty(timers)) {
                struct cpu_timer_list *t = list_entry(timers->next,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (cputime_lt(prof_ticks(tsk), t->expires.cpu)) {
+               if (!--maxfire || cputime_lt(prof_ticks(tsk), t->expires.cpu)) {
                        tsk->it_prof_expires = t->expires.cpu;
                        break;
                }
@@ -977,12 +979,13 @@ static void check_thread_timers(struct task_struct *tsk,
        }
 
        ++timers;
+       maxfire = 20;
        tsk->it_virt_expires = cputime_zero;
        while (!list_empty(timers)) {
                struct cpu_timer_list *t = list_entry(timers->next,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (cputime_lt(virt_ticks(tsk), t->expires.cpu)) {
+               if (!--maxfire || cputime_lt(virt_ticks(tsk), t->expires.cpu)) {
                        tsk->it_virt_expires = t->expires.cpu;
                        break;
                }
@@ -991,12 +994,13 @@ static void check_thread_timers(struct task_struct *tsk,
        }
 
        ++timers;
+       maxfire = 20;
        tsk->it_sched_expires = 0;
        while (!list_empty(timers)) {
                struct cpu_timer_list *t = list_entry(timers->next,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (tsk->sched_time < t->expires.sched) {
+               if (!--maxfire || tsk->sched_time < t->expires.sched) {
                        tsk->it_sched_expires = t->expires.sched;
                        break;
                }
@@ -1013,6 +1017,7 @@ static void check_thread_timers(struct task_struct *tsk,
 static void check_process_timers(struct task_struct *tsk,
                                 struct list_head *firing)
 {
+       int maxfire;
        struct signal_struct *const sig = tsk->signal;
        cputime_t utime, stime, ptime, virt_expires, prof_expires;
        unsigned long long sched_time, sched_expires;
@@ -1045,12 +1050,13 @@ static void check_process_timers(struct task_struct *tsk,
        } while (t != tsk);
        ptime = cputime_add(utime, stime);
 
+       maxfire = 20;
        prof_expires = cputime_zero;
        while (!list_empty(timers)) {
                struct cpu_timer_list *t = list_entry(timers->next,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (cputime_lt(ptime, t->expires.cpu)) {
+               if (!--maxfire || cputime_lt(ptime, t->expires.cpu)) {
                        prof_expires = t->expires.cpu;
                        break;
                }
@@ -1059,12 +1065,13 @@ static void check_process_timers(struct task_struct *tsk,
        }
 
        ++timers;
+       maxfire = 20;
        virt_expires = cputime_zero;
        while (!list_empty(timers)) {
                struct cpu_timer_list *t = list_entry(timers->next,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (cputime_lt(utime, t->expires.cpu)) {
+               if (!--maxfire || cputime_lt(utime, t->expires.cpu)) {
                        virt_expires = t->expires.cpu;
                        break;
                }
@@ -1073,12 +1080,13 @@ static void check_process_timers(struct task_struct *tsk,
        }
 
        ++timers;
+       maxfire = 20;
        sched_expires = 0;
        while (!list_empty(timers)) {
                struct cpu_timer_list *t = list_entry(timers->next,
                                                      struct cpu_timer_list,
                                                      entry);
-               if (sched_time < t->expires.sched) {
+               if (!--maxfire || sched_time < t->expires.sched) {
                        sched_expires = t->expires.sched;
                        break;
                }