Skip to content

Commit 1550dde

Browse files
committed
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 <[email protected]> Reviewed-by: Frederic Weisbecker <[email protected]> Acked-by: Peter Zijlstra (Intel) <[email protected]> Link: https://lore.kernel.org/all/[email protected]
1 parent cd1e93a commit 1550dde

File tree

5 files changed

+30
-19
lines changed

5 files changed

+30
-19
lines changed

include/linux/posix-timers.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ static inline void posix_cputimers_init_work(void) { }
147147
* @kclock: Pointer to the k_clock struct handling this timer
148148
* @it_clock: The posix timer clock id
149149
* @it_id: The posix timer id for identifying the timer
150-
* @it_active: Marker that timer is active
150+
* @it_status: The status of the timer
151151
* @it_overrun: The overrun counter for pending signals
152152
* @it_overrun_last: The overrun at the time of the last delivered signal
153153
* @it_signal_seq: Sequence count to control signal delivery
@@ -168,7 +168,7 @@ struct k_itimer {
168168
const struct k_clock *kclock;
169169
clockid_t it_clock;
170170
timer_t it_id;
171-
int it_active;
171+
int it_status;
172172
s64 it_overrun;
173173
s64 it_overrun_last;
174174
unsigned int it_signal_seq;

kernel/time/alarmtimer.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
585585
*/
586586
ptr->it_overrun += __alarm_forward_now(alarm, ptr->it_interval, true);
587587
++ptr->it_signal_seq;
588-
ptr->it_active = 1;
588+
ptr->it_status = POSIX_TIMER_ARMED;
589589
result = ALARMTIMER_RESTART;
590590
}
591591
spin_unlock_irqrestore(&ptr->it_lock, flags);

kernel/time/posix-cpu-timers.c

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -453,7 +453,6 @@ static void disarm_timer(struct k_itimer *timer, struct task_struct *p)
453453
struct cpu_timer *ctmr = &timer->it.cpu;
454454
struct posix_cputimer_base *base;
455455

456-
timer->it_active = 0;
457456
if (!cpu_timer_dequeue(ctmr))
458457
return;
459458

@@ -494,11 +493,12 @@ static int posix_cpu_timer_del(struct k_itimer *timer)
494493
*/
495494
WARN_ON_ONCE(ctmr->head || timerqueue_node_queued(&ctmr->node));
496495
} else {
497-
if (timer->it.cpu.firing)
496+
if (timer->it.cpu.firing) {
498497
ret = TIMER_RETRY;
499-
else
498+
} else {
500499
disarm_timer(timer, p);
501-
500+
timer->it_status = POSIX_TIMER_DISARMED;
501+
}
502502
unlock_task_sighand(p, &flags);
503503
}
504504

@@ -560,7 +560,7 @@ static void arm_timer(struct k_itimer *timer, struct task_struct *p)
560560
struct cpu_timer *ctmr = &timer->it.cpu;
561561
u64 newexp = cpu_timer_getexpires(ctmr);
562562

563-
timer->it_active = 1;
563+
timer->it_status = POSIX_TIMER_ARMED;
564564
if (!cpu_timer_enqueue(&base->tqhead, ctmr))
565565
return;
566566

@@ -586,7 +586,8 @@ static void cpu_timer_fire(struct k_itimer *timer)
586586
{
587587
struct cpu_timer *ctmr = &timer->it.cpu;
588588

589-
timer->it_active = 0;
589+
timer->it_status = POSIX_TIMER_DISARMED;
590+
590591
if (unlikely(timer->sigq == NULL)) {
591592
/*
592593
* This a special case for clock_nanosleep,
@@ -671,7 +672,7 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,
671672
ret = TIMER_RETRY;
672673
} else {
673674
cpu_timer_dequeue(ctmr);
674-
timer->it_active = 0;
675+
timer->it_status = POSIX_TIMER_DISARMED;
675676
}
676677

677678
/*

kernel/time/posix-timers.c

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
272272
if (timr->it_interval && timr->it_signal_seq == info->si_sys_private) {
273273
timr->kclock->timer_rearm(timr);
274274

275-
timr->it_active = 1;
275+
timr->it_status = POSIX_TIMER_ARMED;
276276
timr->it_overrun_last = timr->it_overrun;
277277
timr->it_overrun = -1LL;
278278
++timr->it_signal_seq;
@@ -292,14 +292,17 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
292292

293293
int posix_timer_queue_signal(struct k_itimer *timr)
294294
{
295+
enum posix_timer_state state = POSIX_TIMER_DISARMED;
295296
int ret, si_private = 0;
296297
enum pid_type type;
297298

298299
lockdep_assert_held(&timr->it_lock);
299300

300-
timr->it_active = 0;
301-
if (timr->it_interval)
301+
if (timr->it_interval) {
302+
state = POSIX_TIMER_REQUEUE_PENDING;
302303
si_private = ++timr->it_signal_seq;
304+
}
305+
timr->it_status = state;
303306

304307
type = !(timr->it_sigev_notify & SIGEV_THREAD_ID) ? PIDTYPE_TGID : PIDTYPE_PID;
305308
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)
367370
timr->it_overrun += hrtimer_forward(timer, now, timr->it_interval);
368371
ret = HRTIMER_RESTART;
369372
++timr->it_signal_seq;
370-
timr->it_active = 1;
373+
timr->it_status = POSIX_TIMER_ARMED;
371374
}
372375
}
373376

@@ -640,10 +643,10 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)
640643
/* interval timer ? */
641644
if (iv) {
642645
cur_setting->it_interval = ktime_to_timespec64(iv);
643-
} else if (!timr->it_active) {
646+
} else if (timr->it_status == POSIX_TIMER_DISARMED) {
644647
/*
645648
* SIGEV_NONE oneshot timers are never queued and therefore
646-
* timr->it_active is always false. The check below
649+
* timr->it_status is always DISARMED. The check below
647650
* vs. remaining time will handle this case.
648651
*
649652
* 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,
888891
if (kc->timer_try_to_cancel(timr) < 0)
889892
return TIMER_RETRY;
890893

891-
timr->it_active = 0;
894+
timr->it_status = POSIX_TIMER_DISARMED;
892895
posix_timer_set_common(timr, new_setting);
893896

894897
/* Keep timer disarmed when it_value is zero */
@@ -901,7 +904,8 @@ int common_timer_set(struct k_itimer *timr, int flags,
901904
sigev_none = timr->it_sigev_notify == SIGEV_NONE;
902905

903906
kc->timer_arm(timr, expires, flags & TIMER_ABSTIME, sigev_none);
904-
timr->it_active = !sigev_none;
907+
if (!sigev_none)
908+
timr->it_status = POSIX_TIMER_ARMED;
905909
return 0;
906910
}
907911

@@ -1000,7 +1004,7 @@ int common_timer_del(struct k_itimer *timer)
10001004
timer->it_interval = 0;
10011005
if (kc->timer_try_to_cancel(timer) < 0)
10021006
return TIMER_RETRY;
1003-
timer->it_active = 0;
1007+
timer->it_status = POSIX_TIMER_DISARMED;
10041008
return 0;
10051009
}
10061010

kernel/time/posix-timers.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
/* SPDX-License-Identifier: GPL-2.0 */
22
#define TIMER_RETRY 1
33

4+
enum posix_timer_state {
5+
POSIX_TIMER_DISARMED,
6+
POSIX_TIMER_ARMED,
7+
POSIX_TIMER_REQUEUE_PENDING,
8+
};
9+
410
struct k_clock {
511
int (*clock_getres)(const clockid_t which_clock,
612
struct timespec64 *tp);

0 commit comments

Comments
 (0)