Skip to content

Commit c925077

Browse files
committed
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>
1 parent d4283c6 commit c925077

File tree

1 file changed

+7
-11
lines changed

1 file changed

+7
-11
lines changed

kernel/posix-cpu-timers.c

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
10911091
put_task_struct(p);
10921092
timer->it.cpu.task = p = NULL;
10931093
timer->it.cpu.expires = 0;
1094-
goto out_unlock;
1094+
read_unlock(&tasklist_lock);
1095+
goto out;
10951096
} else if (unlikely(p->exit_state) && thread_group_empty(p)) {
10961097
/*
10971098
* We've noticed that the thread is dead, but
@@ -1100,7 +1101,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
11001101
*/
11011102
cpu_timer_sample_group(timer->it_clock, p, &now);
11021103
clear_dead_task(timer, now);
1103-
goto out_unlock;
1104+
read_unlock(&tasklist_lock);
1105+
goto out;
11041106
}
11051107
spin_lock(&p->sighand->siglock);
11061108
cpu_timer_sample_group(timer->it_clock, p, &now);
@@ -1114,10 +1116,11 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
11141116
BUG_ON(!irqs_disabled());
11151117
arm_timer(timer);
11161118
spin_unlock(&p->sighand->siglock);
1117-
1118-
out_unlock:
11191119
read_unlock(&tasklist_lock);
11201120

1121+
/* Kick full dynticks CPUs in case they need to tick on the new timer */
1122+
posix_cpu_timer_kick_nohz();
1123+
11211124
out:
11221125
timer->it_overrun_last = timer->it_overrun;
11231126
timer->it_overrun = -1;
@@ -1257,13 +1260,6 @@ void run_posix_cpu_timers(struct task_struct *tsk)
12571260
cpu_timer_fire(timer);
12581261
spin_unlock(&timer->it_lock);
12591262
}
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();
12671263
}
12681264

12691265
/*

0 commit comments

Comments
 (0)