Commit e80eda94 authored by Linus Torvalds's avatar Linus Torvalds

Posix timers: limit number of timers firing at once

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: default avatarLinus Torvalds <torvalds@osdl.org>
parent d475f3f4
...@@ -961,14 +961,16 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp) ...@@ -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, static void check_thread_timers(struct task_struct *tsk,
struct list_head *firing) struct list_head *firing)
{ {
int maxfire;
struct list_head *timers = tsk->cpu_timers; struct list_head *timers = tsk->cpu_timers;
maxfire = 20;
tsk->it_prof_expires = cputime_zero; tsk->it_prof_expires = cputime_zero;
while (!list_empty(timers)) { while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list, struct cpu_timer_list,
entry); 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; tsk->it_prof_expires = t->expires.cpu;
break; break;
} }
...@@ -977,12 +979,13 @@ static void check_thread_timers(struct task_struct *tsk, ...@@ -977,12 +979,13 @@ static void check_thread_timers(struct task_struct *tsk,
} }
++timers; ++timers;
maxfire = 20;
tsk->it_virt_expires = cputime_zero; tsk->it_virt_expires = cputime_zero;
while (!list_empty(timers)) { while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list, struct cpu_timer_list,
entry); 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; tsk->it_virt_expires = t->expires.cpu;
break; break;
} }
...@@ -991,12 +994,13 @@ static void check_thread_timers(struct task_struct *tsk, ...@@ -991,12 +994,13 @@ static void check_thread_timers(struct task_struct *tsk,
} }
++timers; ++timers;
maxfire = 20;
tsk->it_sched_expires = 0; tsk->it_sched_expires = 0;
while (!list_empty(timers)) { while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list, struct cpu_timer_list,
entry); entry);
if (tsk->sched_time < t->expires.sched) { if (!--maxfire || tsk->sched_time < t->expires.sched) {
tsk->it_sched_expires = t->expires.sched; tsk->it_sched_expires = t->expires.sched;
break; break;
} }
...@@ -1013,6 +1017,7 @@ static void check_thread_timers(struct task_struct *tsk, ...@@ -1013,6 +1017,7 @@ static void check_thread_timers(struct task_struct *tsk,
static void check_process_timers(struct task_struct *tsk, static void check_process_timers(struct task_struct *tsk,
struct list_head *firing) struct list_head *firing)
{ {
int maxfire;
struct signal_struct *const sig = tsk->signal; struct signal_struct *const sig = tsk->signal;
cputime_t utime, stime, ptime, virt_expires, prof_expires; cputime_t utime, stime, ptime, virt_expires, prof_expires;
unsigned long long sched_time, sched_expires; unsigned long long sched_time, sched_expires;
...@@ -1045,12 +1050,13 @@ static void check_process_timers(struct task_struct *tsk, ...@@ -1045,12 +1050,13 @@ static void check_process_timers(struct task_struct *tsk,
} while (t != tsk); } while (t != tsk);
ptime = cputime_add(utime, stime); ptime = cputime_add(utime, stime);
maxfire = 20;
prof_expires = cputime_zero; prof_expires = cputime_zero;
while (!list_empty(timers)) { while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list, struct cpu_timer_list,
entry); entry);
if (cputime_lt(ptime, t->expires.cpu)) { if (!--maxfire || cputime_lt(ptime, t->expires.cpu)) {
prof_expires = t->expires.cpu; prof_expires = t->expires.cpu;
break; break;
} }
...@@ -1059,12 +1065,13 @@ static void check_process_timers(struct task_struct *tsk, ...@@ -1059,12 +1065,13 @@ static void check_process_timers(struct task_struct *tsk,
} }
++timers; ++timers;
maxfire = 20;
virt_expires = cputime_zero; virt_expires = cputime_zero;
while (!list_empty(timers)) { while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list, struct cpu_timer_list,
entry); entry);
if (cputime_lt(utime, t->expires.cpu)) { if (!--maxfire || cputime_lt(utime, t->expires.cpu)) {
virt_expires = t->expires.cpu; virt_expires = t->expires.cpu;
break; break;
} }
...@@ -1073,12 +1080,13 @@ static void check_process_timers(struct task_struct *tsk, ...@@ -1073,12 +1080,13 @@ static void check_process_timers(struct task_struct *tsk,
} }
++timers; ++timers;
maxfire = 20;
sched_expires = 0; sched_expires = 0;
while (!list_empty(timers)) { while (!list_empty(timers)) {
struct cpu_timer_list *t = list_entry(timers->next, struct cpu_timer_list *t = list_entry(timers->next,
struct cpu_timer_list, struct cpu_timer_list,
entry); entry);
if (sched_time < t->expires.sched) { if (!--maxfire || sched_time < t->expires.sched) {
sched_expires = t->expires.sched; sched_expires = t->expires.sched;
break; break;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment