aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/posix-cpu-timers.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2013-11-06 11:18:30 -0500
committerFrederic Weisbecker <fweisbec@gmail.com>2013-12-02 14:46:27 -0500
commitc925077c33fc9a546e7cf6c3be2adf4a2afe2608 (patch)
treeac1d52bbbb6e3ae97552f0203a9d38f1e05dad21 /kernel/posix-cpu-timers.c
parentd4283c654130c3d01b6842d3821dbdc3c15ceb46 (diff)
posix-timers: Fix full dynticks CPUs kick on timer rescheduling
A posix CPU timer can be rearmed while it is firing or after it is notified with a signal. This can happen for example with timers that were set with a non zero interval in timer_settime(). This rearming can happen in two places: 1) On timer firing time, which happens on the target's tick. If the timer can't trigger a signal because it is ignored, it reschedules itself to honour the timer interval. 2) On signal handling from the timer's notification target. This one can be a different task than the timer's target itself. Once the signal is notified, the notification target rearms the timer, again to honour the timer interval. When a timer is rearmed, we need to notify the full dynticks CPUs such that they restart their tick in case they are running tasks that may have a share in elapsing this timer. Now the 1st case above handles full dynticks CPUs with a call to posix_cpu_timer_kick_nohz() from the posix cpu timer firing code. But the second case ignores the fact that some CPUs may run non-idle tasks with their tick off. As a result, when a timer is resheduled after its signal notification, the full dynticks CPUs may completely ignore it and not tick on the timer as expected This patch fixes this bug by handling both cases in one. All we need is to move the kick to the rearming common code in posix_cpu_timer_schedule(). Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Olivier Langlois <olivier@olivierlanglois.net>
Diffstat (limited to 'kernel/posix-cpu-timers.c')
-rw-r--r--kernel/posix-cpu-timers.c18
1 files changed, 7 insertions, 11 deletions
diff --git a/kernel/posix-cpu-timers.c b/kernel/posix-cpu-timers.c
index 35509c5a3ffb..79747b7d9420 100644
--- a/kernel/posix-cpu-timers.c
+++ b/kernel/posix-cpu-timers.c
@@ -1091,7 +1091,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
1091 put_task_struct(p); 1091 put_task_struct(p);
1092 timer->it.cpu.task = p = NULL; 1092 timer->it.cpu.task = p = NULL;
1093 timer->it.cpu.expires = 0; 1093 timer->it.cpu.expires = 0;
1094 goto out_unlock; 1094 read_unlock(&tasklist_lock);
1095 goto out;
1095 } else if (unlikely(p->exit_state) && thread_group_empty(p)) { 1096 } else if (unlikely(p->exit_state) && thread_group_empty(p)) {
1096 /* 1097 /*
1097 * We've noticed that the thread is dead, but 1098 * We've noticed that the thread is dead, but
@@ -1100,7 +1101,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
1100 */ 1101 */
1101 cpu_timer_sample_group(timer->it_clock, p, &now); 1102 cpu_timer_sample_group(timer->it_clock, p, &now);
1102 clear_dead_task(timer, now); 1103 clear_dead_task(timer, now);
1103 goto out_unlock; 1104 read_unlock(&tasklist_lock);
1105 goto out;
1104 } 1106 }
1105 spin_lock(&p->sighand->siglock); 1107 spin_lock(&p->sighand->siglock);
1106 cpu_timer_sample_group(timer->it_clock, p, &now); 1108 cpu_timer_sample_group(timer->it_clock, p, &now);
@@ -1114,10 +1116,11 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
1114 BUG_ON(!irqs_disabled()); 1116 BUG_ON(!irqs_disabled());
1115 arm_timer(timer); 1117 arm_timer(timer);
1116 spin_unlock(&p->sighand->siglock); 1118 spin_unlock(&p->sighand->siglock);
1117
1118out_unlock:
1119 read_unlock(&tasklist_lock); 1119 read_unlock(&tasklist_lock);
1120 1120
1121 /* Kick full dynticks CPUs in case they need to tick on the new timer */
1122 posix_cpu_timer_kick_nohz();
1123
1121out: 1124out:
1122 timer->it_overrun_last = timer->it_overrun; 1125 timer->it_overrun_last = timer->it_overrun;
1123 timer->it_overrun = -1; 1126 timer->it_overrun = -1;
@@ -1257,13 +1260,6 @@ void run_posix_cpu_timers(struct task_struct *tsk)
1257 cpu_timer_fire(timer); 1260 cpu_timer_fire(timer);
1258 spin_unlock(&timer->it_lock); 1261 spin_unlock(&timer->it_lock);
1259 } 1262 }
1260
1261 /*
1262 * In case some timers were rescheduled after the queue got emptied,
1263 * wake up full dynticks CPUs.
1264 */
1265 if (tsk->signal->cputimer.running)
1266 posix_cpu_timer_kick_nohz();
1267} 1263}
1268 1264
1269/* 1265/*