mirror of
https://git.proxmox.com/git/mirror_ubuntu-kernels.git
synced 2025-12-17 20:53:56 +00:00
Signals of timers which are reprogammed, disarmed or deleted can deliver
signals related to the past. The POSIX spec is blury about this:
- "The effect of disarming or resetting a timer with pending expiration
notifications is unspecified."
- "The disposition of pending signals for the deleted timer is
unspecified."
In both cases it is reasonable to expect that pending signals are
discarded. Especially in the reprogramming case it does not make sense to
account for previous overruns or to deliver a signal for a timer which has
been disarmed. This makes the behaviour consistent and understandable.
Remove the si_sys_private check from the signal delivery code and invoke
posix_timer_deliver_signal() unconditionally for posix timer related
signals.
Change posix_timer_deliver_signal() so it controls the actual signal
delivery via the return value. It now instructs the signal code to drop the
signal when:
1) The timer does not longer exist in the hash table
2) The timer signal_seq value is not the same as the si_sys_private value
which was set when the signal was queued.
This is also a preparatory change to embed the sigqueue into the k_itimer
structure, which in turn allows to remove the si_sys_private magic.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Link: https://lore.kernel.org/all/20241105064213.040348644@linutronix.de
202 lines
5.5 KiB
C
202 lines
5.5 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
#ifndef _linux_POSIX_TIMERS_H
|
|
#define _linux_POSIX_TIMERS_H
|
|
|
|
#include <linux/alarmtimer.h>
|
|
#include <linux/list.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/posix-timers_types.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/timerqueue.h>
|
|
|
|
struct kernel_siginfo;
|
|
struct task_struct;
|
|
|
|
static inline clockid_t make_process_cpuclock(const unsigned int pid,
|
|
const clockid_t clock)
|
|
{
|
|
return ((~pid) << 3) | clock;
|
|
}
|
|
static inline clockid_t make_thread_cpuclock(const unsigned int tid,
|
|
const clockid_t clock)
|
|
{
|
|
return make_process_cpuclock(tid, clock | CPUCLOCK_PERTHREAD_MASK);
|
|
}
|
|
|
|
static inline clockid_t fd_to_clockid(const int fd)
|
|
{
|
|
return make_process_cpuclock((unsigned int) fd, CLOCKFD);
|
|
}
|
|
|
|
static inline int clockid_to_fd(const clockid_t clk)
|
|
{
|
|
return ~(clk >> 3);
|
|
}
|
|
|
|
#ifdef CONFIG_POSIX_TIMERS
|
|
|
|
/**
|
|
* cpu_timer - Posix CPU timer representation for k_itimer
|
|
* @node: timerqueue node to queue in the task/sig
|
|
* @head: timerqueue head on which this timer is queued
|
|
* @pid: Pointer to target task PID
|
|
* @elist: List head for the expiry list
|
|
* @firing: Timer is currently firing
|
|
* @handling: Pointer to the task which handles expiry
|
|
*/
|
|
struct cpu_timer {
|
|
struct timerqueue_node node;
|
|
struct timerqueue_head *head;
|
|
struct pid *pid;
|
|
struct list_head elist;
|
|
int firing;
|
|
struct task_struct __rcu *handling;
|
|
};
|
|
|
|
static inline bool cpu_timer_enqueue(struct timerqueue_head *head,
|
|
struct cpu_timer *ctmr)
|
|
{
|
|
ctmr->head = head;
|
|
return timerqueue_add(head, &ctmr->node);
|
|
}
|
|
|
|
static inline bool cpu_timer_queued(struct cpu_timer *ctmr)
|
|
{
|
|
return !!ctmr->head;
|
|
}
|
|
|
|
static inline bool cpu_timer_dequeue(struct cpu_timer *ctmr)
|
|
{
|
|
if (cpu_timer_queued(ctmr)) {
|
|
timerqueue_del(ctmr->head, &ctmr->node);
|
|
ctmr->head = NULL;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static inline u64 cpu_timer_getexpires(struct cpu_timer *ctmr)
|
|
{
|
|
return ctmr->node.expires;
|
|
}
|
|
|
|
static inline void cpu_timer_setexpires(struct cpu_timer *ctmr, u64 exp)
|
|
{
|
|
ctmr->node.expires = exp;
|
|
}
|
|
|
|
static inline void posix_cputimers_init(struct posix_cputimers *pct)
|
|
{
|
|
memset(pct, 0, sizeof(*pct));
|
|
pct->bases[0].nextevt = U64_MAX;
|
|
pct->bases[1].nextevt = U64_MAX;
|
|
pct->bases[2].nextevt = U64_MAX;
|
|
}
|
|
|
|
void posix_cputimers_group_init(struct posix_cputimers *pct, u64 cpu_limit);
|
|
|
|
static inline void posix_cputimers_rt_watchdog(struct posix_cputimers *pct,
|
|
u64 runtime)
|
|
{
|
|
pct->bases[CPUCLOCK_SCHED].nextevt = runtime;
|
|
}
|
|
|
|
void posixtimer_rearm_itimer(struct task_struct *p);
|
|
bool posixtimer_deliver_signal(struct kernel_siginfo *info);
|
|
|
|
/* Init task static initializer */
|
|
#define INIT_CPU_TIMERBASE(b) { \
|
|
.nextevt = U64_MAX, \
|
|
}
|
|
|
|
#define INIT_CPU_TIMERBASES(b) { \
|
|
INIT_CPU_TIMERBASE(b[0]), \
|
|
INIT_CPU_TIMERBASE(b[1]), \
|
|
INIT_CPU_TIMERBASE(b[2]), \
|
|
}
|
|
|
|
#define INIT_CPU_TIMERS(s) \
|
|
.posix_cputimers = { \
|
|
.bases = INIT_CPU_TIMERBASES(s.posix_cputimers.bases), \
|
|
},
|
|
#else
|
|
struct cpu_timer { };
|
|
#define INIT_CPU_TIMERS(s)
|
|
static inline void posix_cputimers_init(struct posix_cputimers *pct) { }
|
|
static inline void posix_cputimers_group_init(struct posix_cputimers *pct,
|
|
u64 cpu_limit) { }
|
|
static inline void posixtimer_rearm_itimer(struct task_struct *p) { }
|
|
static inline bool posixtimer_deliver_signal(struct kernel_siginfo *info) { return false; }
|
|
#endif
|
|
|
|
#ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK
|
|
void clear_posix_cputimers_work(struct task_struct *p);
|
|
void posix_cputimers_init_work(void);
|
|
#else
|
|
static inline void clear_posix_cputimers_work(struct task_struct *p) { }
|
|
static inline void posix_cputimers_init_work(void) { }
|
|
#endif
|
|
|
|
/**
|
|
* struct k_itimer - POSIX.1b interval timer structure.
|
|
* @list: List head for binding the timer to signals->posix_timers
|
|
* @t_hash: Entry in the posix timer hash table
|
|
* @it_lock: Lock protecting the timer
|
|
* @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_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
|
|
* @it_sigev_notify: The notify word of sigevent struct for signal delivery
|
|
* @it_interval: The interval for periodic timers
|
|
* @it_signal: Pointer to the creators signal struct
|
|
* @it_pid: The pid of the process/task targeted by the signal
|
|
* @it_process: The task to wakeup on clock_nanosleep (CPU timers)
|
|
* @sigq: Pointer to preallocated sigqueue
|
|
* @it: Union representing the various posix timer type
|
|
* internals.
|
|
* @rcu: RCU head for freeing the timer.
|
|
*/
|
|
struct k_itimer {
|
|
struct hlist_node list;
|
|
struct hlist_node t_hash;
|
|
spinlock_t it_lock;
|
|
const struct k_clock *kclock;
|
|
clockid_t it_clock;
|
|
timer_t it_id;
|
|
int it_status;
|
|
s64 it_overrun;
|
|
s64 it_overrun_last;
|
|
unsigned int it_signal_seq;
|
|
int it_sigev_notify;
|
|
ktime_t it_interval;
|
|
struct signal_struct *it_signal;
|
|
union {
|
|
struct pid *it_pid;
|
|
struct task_struct *it_process;
|
|
};
|
|
struct sigqueue *sigq;
|
|
union {
|
|
struct {
|
|
struct hrtimer timer;
|
|
} real;
|
|
struct cpu_timer cpu;
|
|
struct {
|
|
struct alarm alarmtimer;
|
|
} alarm;
|
|
} it;
|
|
struct rcu_head rcu;
|
|
};
|
|
|
|
void run_posix_cpu_timers(void);
|
|
void posix_cpu_timers_exit(struct task_struct *task);
|
|
void posix_cpu_timers_exit_group(struct task_struct *task);
|
|
void set_process_cpu_timer(struct task_struct *task, unsigned int clock_idx,
|
|
u64 *newval, u64 *oldval);
|
|
|
|
int update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new);
|
|
|
|
#endif
|