diff options
Diffstat (limited to 'kernel/posix-timers.c')
-rw-r--r-- | kernel/posix-timers.c | 35 |
1 files changed, 33 insertions, 2 deletions
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index 588c99da0307..329ce0172074 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -353,9 +353,40 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer) | |||
353 | * it should be restarted. | 353 | * it should be restarted. |
354 | */ | 354 | */ |
355 | if (timr->it.real.interval.tv64 != 0) { | 355 | if (timr->it.real.interval.tv64 != 0) { |
356 | ktime_t now = hrtimer_cb_get_time(timer); | ||
357 | |||
358 | /* | ||
359 | * FIXME: What we really want, is to stop this | ||
360 | * timer completely and restart it in case the | ||
361 | * SIG_IGN is removed. This is a non trivial | ||
362 | * change which involves sighand locking | ||
363 | * (sigh !), which we don't want to do late in | ||
364 | * the release cycle. | ||
365 | * | ||
366 | * For now we just let timers with an interval | ||
367 | * less than a jiffie expire every jiffie to | ||
368 | * avoid softirq starvation in case of SIG_IGN | ||
369 | * and a very small interval, which would put | ||
370 | * the timer right back on the softirq pending | ||
371 | * list. By moving now ahead of time we trick | ||
372 | * hrtimer_forward() to expire the timer | ||
373 | * later, while we still maintain the overrun | ||
374 | * accuracy, but have some inconsistency in | ||
375 | * the timer_gettime() case. This is at least | ||
376 | * better than a starved softirq. A more | ||
377 | * complex fix which solves also another related | ||
378 | * inconsistency is already in the pipeline. | ||
379 | */ | ||
380 | #ifdef CONFIG_HIGH_RES_TIMERS | ||
381 | { | ||
382 | ktime_t kj = ktime_set(0, NSEC_PER_SEC / HZ); | ||
383 | |||
384 | if (timr->it.real.interval.tv64 < kj.tv64) | ||
385 | now = ktime_add(now, kj); | ||
386 | } | ||
387 | #endif | ||
356 | timr->it_overrun += | 388 | timr->it_overrun += |
357 | hrtimer_forward(timer, | 389 | hrtimer_forward(timer, now, |
358 | hrtimer_cb_get_time(timer), | ||
359 | timr->it.real.interval); | 390 | timr->it.real.interval); |
360 | ret = HRTIMER_RESTART; | 391 | ret = HRTIMER_RESTART; |
361 | ++timr->it_requeue_pending; | 392 | ++timr->it_requeue_pending; |