Re: [PATCH v3 28/36] hrtimer: Implement support for softirq based hrtimers

From: Sebastian Andrzej Siewior
Date: Thu Dec 14 2017 - 05:48:02 EST


On 2017-11-29 16:30:53 [+0100], Anna-Maria Gleixner wrote:
> diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
> index 65211fd7288d..40b14f025829 100644
> --- a/kernel/time/hrtimer.c
> +++ b/kernel/time/hrtimer.c
> @@ -711,6 +768,28 @@ static void hrtimer_reprogram(struct hrtimer *timer)
> WARN_ON_ONCE(hrtimer_get_expires_tv64(timer) < 0);
>
> /*
> + * CLOCK_REALTIME timer might be requested with an absolute
> + * expiry time which is less than base->offset. Set it to 0.
> + */
> + if (expires < 0)
> + expires = 0;
> +
> + if (timer->is_soft) {
> + if (cpu_base->softirq_activated)
> + return;
> +
> + if (!ktime_before(expires, cpu_base->softirq_expires_next))
> + return;
> +
> + cpu_base->softirq_next_timer = timer;
> + cpu_base->softirq_expires_next = expires;
> +
> + if (!ktime_before(expires, cpu_base->expires_next) ||
> + !reprogram)
> + return;
> + }
> +
> + /*
> * If the timer is not on the current cpu, we cannot reprogram
> * the other cpus clock event device.
> */


if the timer is enqueud on CPUX and we run on CPUY then we have to
update the cpu_base bits of the correct CPU. Not sure if this accounts
for all the pieces but it might be okay with the check we have in
hrtimer_check_target() (that we have nothing to do but just wait).

Without this, all "sleep 1" which are invoked on CPU1 but migrated to/
programmed on CPU0 (due to timer migration wth NOHZ_FULL) won't expire
as expected.

Reported-by: bert schulze <spambemyguest@xxxxxxxxxxxxxx>
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
---
kernel/time/hrtimer.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/kernel/time/hrtimer.c b/kernel/time/hrtimer.c
index af16a5af2269..c2c344fda487 100644
--- a/kernel/time/hrtimer.c
+++ b/kernel/time/hrtimer.c
@@ -801,16 +801,18 @@ static void hrtimer_reprogram(struct hrtimer *timer, bool reprogram)
expires = 0;

if (timer->is_soft) {
- if (cpu_base->softirq_activated)
+ struct hrtimer_cpu_base *timer_cpu_base = base->cpu_base;
+
+ if (timer_cpu_base->softirq_activated)
return;

- if (!ktime_before(expires, cpu_base->softirq_expires_next))
+ if (!ktime_before(expires, timer_cpu_base->softirq_expires_next))
return;

- cpu_base->softirq_next_timer = timer;
- cpu_base->softirq_expires_next = expires;
+ timer_cpu_base->softirq_next_timer = timer;
+ timer_cpu_base->softirq_expires_next = expires;

- if (!ktime_before(expires, cpu_base->expires_next) ||
+ if (!ktime_before(expires, timer_cpu_base->expires_next) ||
!reprogram)
return;
}
--
2.15.1