posix-timers: Add proper state tracking
authorThomas Gleixner <tglx@linutronix.de>
Tue, 1 Oct 2024 08:42:09 +0000 (10:42 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 29 Oct 2024 10:43:19 +0000 (11:43 +0100)
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
include/linux/posix-timers.h
kernel/time/alarmtimer.c
kernel/time/posix-cpu-timers.c
kernel/time/posix-timers.c
kernel/time/posix-timers.h

index 253d106fac2cb8d80afd2e932538bda701c93b3c..02afbb4da7f783c7e527cfc116ab3bea619e39d1 100644 (file)
@@ -147,7 +147,7 @@ static inline void posix_cputimers_init_work(void) { }
  * @kclock:            Pointer to the k_clock struct handling this timer
  * @it_clock:          The posix timer clock id
  * @it_id:             The posix timer id for identifying the timer
- * @it_active:         Marker that timer is active
+ * @it_status:         The status of the timer
  * @it_overrun:                The overrun counter for pending signals
  * @it_overrun_last:   The overrun at the time of the last delivered signal
  * @it_signal_seq:     Sequence count to control signal delivery
@@ -168,7 +168,7 @@ struct k_itimer {
        const struct k_clock    *kclock;
        clockid_t               it_clock;
        timer_t                 it_id;
-       int                     it_active;
+       int                     it_status;
        s64                     it_overrun;
        s64                     it_overrun_last;
        unsigned int            it_signal_seq;
index 75f8443850709347775168be4896b1e8193b841b..452d8aa2f6e0133fc7afe058d2102c4f28f38c91 100644 (file)
@@ -585,7 +585,7 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
                 */
                ptr->it_overrun += __alarm_forward_now(alarm, ptr->it_interval, true);
                ++ptr->it_signal_seq;
-               ptr->it_active = 1;
+               ptr->it_status = POSIX_TIMER_ARMED;
                result = ALARMTIMER_RESTART;
        }
        spin_unlock_irqrestore(&ptr->it_lock, flags);
index 993243b5be987b85bb13ffb16571be0f761ebba1..12f828d704b1b8ee843b64de0ff1c9e2ca3ffa71 100644 (file)
@@ -453,7 +453,6 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
        struct cpu_timer *ctmr = &timer->it.cpu;
        struct posix_cputimer_base *base;
 
-       timer->it_active = 0;
        if (!cpu_timer_dequeue(ctmr))
                return;
 
@@ -494,11 +493,12 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
                 */
                WARN_ON_ONCE(ctmr->head || timerqueue_node_queued(&ctmr->node));
        } else {
-               if (timer->it.cpu.firing)
+               if (timer->it.cpu.firing) {
                        ret = TIMER_RETRY;
-               else
+               } else {
                        disarm_timer(timer, p);
-
+                       timer->it_status = POSIX_TIMER_DISARMED;
+               }
                unlock_task_sighand(p, &flags);
        }
 
@@ -560,7 +560,7 @@ static void arm_timer(struct k_itimer *timer, struct task_struct *p)
        struct cpu_timer *ctmr = &timer->it.cpu;
        u64 newexp = cpu_timer_getexpires(ctmr);
 
-       timer->it_active = 1;
+       timer->it_status = POSIX_TIMER_ARMED;
        if (!cpu_timer_enqueue(&base->tqhead, ctmr))
                return;
 
@@ -586,7 +586,8 @@ static void cpu_timer_fire(struct k_itimer *timer)
 {
        struct cpu_timer *ctmr = &timer->it.cpu;
 
-       timer->it_active = 0;
+       timer->it_status = POSIX_TIMER_DISARMED;
+
        if (unlikely(timer->sigq == NULL)) {
                /*
                 * This a special case for clock_nanosleep,
@@ -671,7 +672,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
                ret = TIMER_RETRY;
        } else {
                cpu_timer_dequeue(ctmr);
-               timer->it_active = 0;
+               timer->it_status = POSIX_TIMER_DISARMED;
        }
 
        /*
index fd321fcc3f6cc65682ab4f7c8caba65654aad9d0..dd72b8e72697a2caf9ef1d29539787e9f2c16656 100644 (file)
@@ -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;
 }
 
index 4784ea65f6853759abc229fa201b7f37c4a3b468..4d09677e584edd56e059c761ead727629b67eef9 100644 (file)
@@ -1,6 +1,12 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 #define TIMER_RETRY 1
 
+enum posix_timer_state {
+       POSIX_TIMER_DISARMED,
+       POSIX_TIMER_ARMED,
+       POSIX_TIMER_REQUEUE_PENDING,
+};
+
 struct k_clock {
        int     (*clock_getres)(const clockid_t which_clock,
                                struct timespec64 *tp);