summaryrefslogtreecommitdiff
path: root/kernel/time/posix-timers.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2024-10-01 10:42:09 +0200
committerThomas Gleixner <tglx@linutronix.de>2024-10-29 11:43:19 +0100
commit1550dde8a537b35dbf066c7f9cfe5f9b360bce0d (patch)
treeb4c2b18f660d1024e1afa06d5229257732815930 /kernel/time/posix-timers.c
parentcd1e93aedab7f749760a33e9e094381973b1120e (diff)
posix-timers: Add proper state tracking
Right now the state tracking is done by two struct members: - it_active: A boolean which tracks armed/disarmed state - it_signal_seq: A sequence counter which is used to invalidate settings and prevent rearming Replace it_active with it_status and keep properly track about the states in one place. This allows to reuse it_signal_seq to track reprogramming, disarm and delete operations in order to drop signals which are related to the state previous of those operations. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/all/20241001083835.670337048@linutronix.de
Diffstat (limited to 'kernel/time/posix-timers.c')
-rw-r--r--kernel/time/posix-timers.c22
1 files changed, 13 insertions, 9 deletions
diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index fd321fcc3f6c..dd72b8e72697 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -272,7 +272,7 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
if (timr->it_interval && timr->it_signal_seq == info->si_sys_private) {
timr->kclock->timer_rearm(timr);
- timr->it_active = 1;
+ timr->it_status = POSIX_TIMER_ARMED;
timr->it_overrun_last = timr->it_overrun;
timr->it_overrun = -1LL;
++timr->it_signal_seq;
@@ -292,14 +292,17 @@ out:
int posix_timer_queue_signal(struct k_itimer *timr)
{
+ enum posix_timer_state state = POSIX_TIMER_DISARMED;
int ret, si_private = 0;
enum pid_type type;
lockdep_assert_held(&timr->it_lock);
- timr->it_active = 0;
- if (timr->it_interval)
+ if (timr->it_interval) {
+ state = POSIX_TIMER_REQUEUE_PENDING;
si_private = ++timr->it_signal_seq;
+ }
+ timr->it_status = state;
type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
ret = send_sigqueue(timr->sigq, timr->it_pid, type, si_private);
@@ -367,7 +370,7 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)
timr->it_overrun += hrtimer_forward(timer, now, timr->it_interval);
ret = HRTIMER_RESTART;
++timr->it_signal_seq;
- timr->it_active = 1;
+ timr->it_status = POSIX_TIMER_ARMED;
}
}
@@ -640,10 +643,10 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
/* interval timer ? */
if (iv) {
cur_setting->it_interval = ktime_to_timespec64(iv);
- } else if (!timr->it_active) {
+ } else if (timr->it_status == POSIX_TIMER_DISARMED) {
/*
* SIGEV_NONE oneshot timers are never queued and therefore
- * timr->it_active is always false. The check below
+ * timr->it_status is always DISARMED. The check below
* vs. remaining time will handle this case.
*
* For all other timers there is nothing to update here, so
@@ -888,7 +891,7 @@ int common_timer_set(struct k_itimer *timr, int flags,
if (kc->timer_try_to_cancel(timr) < 0)
return TIMER_RETRY;
- timr->it_active = 0;
+ timr->it_status = POSIX_TIMER_DISARMED;
posix_timer_set_common(timr, new_setting);
/* Keep timer disarmed when it_value is zero */
@@ -901,7 +904,8 @@ int common_timer_set(struct k_itimer *timr, int flags,
sigev_none = timr->it_sigev_notify == SIGEV_NONE;
kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none);
- timr->it_active = !sigev_none;
+ if (!sigev_none)
+ timr->it_status = POSIX_TIMER_ARMED;
return 0;
}
@@ -1000,7 +1004,7 @@ int common_timer_del(struct k_itimer *timer)
timer->it_interval = 0;
if (kc->timer_try_to_cancel(timer) < 0)
return TIMER_RETRY;
- timer->it_active = 0;
+ timer->it_status = POSIX_TIMER_DISARMED;
return 0;
}