summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2024-06-10 18:42:25 +0200
committerFrederic Weisbecker <frederic@kernel.org>2024-07-29 21:57:34 +0200
commitc20b99e3243f9e72b6fa0e260766adcba115f25b (patch)
tree70c9834de1ab34dcc8f260f4e3b382b203c47021
parent286bfaccea76e0bd3805ac6e77c8ec4a18ecb3fe (diff)
posix-cpu-timers: Simplify posix_cpu_timer_set()
Avoid the late sighand lock/unlock dance when a timer is not armed to enforce reevaluation of the timer base so that the process wide CPU timer sampling can be disabled. Do it right at the point where the arming decision is made which already has sighand locked. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Frederic Weisbecker <frederic@kernel.org> Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
-rw-r--r--kernel/time/posix-cpu-timers.c44
1 files changed, 17 insertions, 27 deletions
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c
index eb28150c8d63..c6fe017193b8 100644
--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -705,10 +705,16 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
/*
* Arm the timer if it is not disabled, the new expiry value has
* not yet expired and the timer requires signal delivery.
- * SIGEV_NONE timers are never armed.
+ * SIGEV_NONE timers are never armed. In case the timer is not
+ * armed, enforce the reevaluation of the timer base so that the
+ * process wide cputime counter can be disabled eventually.
*/
- if (!sigev_none && new_expires && now < new_expires)
- arm_timer(timer, p);
+ if (likely(!sigev_none)) {
+ if (new_expires && now < new_expires)
+ arm_timer(timer, p);
+ else
+ trigger_base_recalc_expires(timer, p);
+ }
unlock_task_sighand(p, &flags);
/*
@@ -727,30 +733,14 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
timer->it_overrun_last = 0;
timer->it_overrun = -1;
- if (!sigev_none && now >= new_expires) {
- if (new_expires != 0) {
- /*
- * The designated time already passed, so we notify
- * immediately, even if the thread never runs to
- * accumulate more time on this clock.
- */
- cpu_timer_fire(timer);
- }
-
- /*
- * Make sure we don't keep around the process wide cputime
- * counter or the tick dependency if they are not necessary.
- */
- sighand = lock_task_sighand(p, &flags);
- if (!sighand)
- goto out;
-
- if (!cpu_timer_queued(ctmr))
- trigger_base_recalc_expires(timer, p);
-
- unlock_task_sighand(p, &flags);
- }
- out:
+ /*
+ * If the new expiry time was already in the past the timer was not
+ * queued. Fire it immediately even if the thread never runs to
+ * accumulate more time on this clock.
+ */
+ if (!sigev_none && new_expires && now >= new_expires)
+ cpu_timer_fire(timer);
+out:
rcu_read_unlock();
if (old)
old->it_interval = ns_to_timespec64(old_incr);