mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
signal: Refactor send_sigqueue()
To handle posix timers which have their signal ignored via SIG_IGN properly it is required to requeue a ignored signal for delivery when SIG_IGN is lifted so the timer gets rearmed. Split the required code out of send_sigqueue() so it can be reused in context of sigaction(). While at it rename send_sigqueue() to posixtimer_send_sigqueue() so its clear what this is about. 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/20241105064213.586453412@linutronix.de
This commit is contained in:
parent
ef1c5bcd6d
commit
0360ed14d9
|
|
@ -109,6 +109,7 @@ static inline void posix_cputimers_rt_watchdog(struct posix_cputimers *pct,
|
|||
|
||||
void posixtimer_rearm_itimer(struct task_struct *p);
|
||||
bool posixtimer_init_sigqueue(struct sigqueue *q);
|
||||
int posixtimer_send_sigqueue(struct k_itimer *tmr);
|
||||
bool posixtimer_deliver_signal(struct kernel_siginfo *info);
|
||||
void posixtimer_free_timer(struct k_itimer *timer);
|
||||
|
||||
|
|
|
|||
|
|
@ -340,7 +340,6 @@ extern int send_sig(int, struct task_struct *, int);
|
|||
extern int zap_other_threads(struct task_struct *p);
|
||||
extern struct sigqueue *sigqueue_alloc(void);
|
||||
extern void sigqueue_free(struct sigqueue *);
|
||||
extern int send_sigqueue(struct sigqueue *, struct pid *, enum pid_type, int si_private);
|
||||
extern int do_sigaction(int, struct k_sigaction *, struct k_sigaction *);
|
||||
|
||||
static inline void clear_notify_signal(void)
|
||||
|
|
|
|||
|
|
@ -1947,40 +1947,54 @@ void sigqueue_free(struct sigqueue *q)
|
|||
__sigqueue_free(q);
|
||||
}
|
||||
|
||||
int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type, int si_private)
|
||||
static void posixtimer_queue_sigqueue(struct sigqueue *q, struct task_struct *t, enum pid_type type)
|
||||
{
|
||||
int sig = q->info.si_signo;
|
||||
struct sigpending *pending;
|
||||
int sig = q->info.si_signo;
|
||||
|
||||
signalfd_notify(t, sig);
|
||||
pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
|
||||
list_add_tail(&q->list, &pending->list);
|
||||
sigaddset(&pending->signal, sig);
|
||||
complete_signal(sig, t, type);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function is used by POSIX timers to deliver a timer signal.
|
||||
* Where type is PIDTYPE_PID (such as for timers with SIGEV_THREAD_ID
|
||||
* set), the signal must be delivered to the specific thread (queues
|
||||
* into t->pending).
|
||||
*
|
||||
* Where type is not PIDTYPE_PID, signals must be delivered to the
|
||||
* process. In this case, prefer to deliver to current if it is in
|
||||
* the same thread group as the target process, which avoids
|
||||
* unnecessarily waking up a potentially idle task.
|
||||
*/
|
||||
static inline struct task_struct *posixtimer_get_target(struct k_itimer *tmr)
|
||||
{
|
||||
struct task_struct *t = pid_task(tmr->it_pid, tmr->it_pid_type);
|
||||
|
||||
if (t && tmr->it_pid_type != PIDTYPE_PID && same_thread_group(t, current))
|
||||
t = current;
|
||||
return t;
|
||||
}
|
||||
|
||||
int posixtimer_send_sigqueue(struct k_itimer *tmr)
|
||||
{
|
||||
struct sigqueue *q = tmr->sigq;
|
||||
int sig = q->info.si_signo;
|
||||
struct task_struct *t;
|
||||
unsigned long flags;
|
||||
int ret, result;
|
||||
|
||||
if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
|
||||
return 0;
|
||||
if (WARN_ON_ONCE(q->info.si_code != SI_TIMER))
|
||||
return 0;
|
||||
guard(rcu)();
|
||||
|
||||
ret = -1;
|
||||
rcu_read_lock();
|
||||
|
||||
/*
|
||||
* This function is used by POSIX timers to deliver a timer signal.
|
||||
* Where type is PIDTYPE_PID (such as for timers with SIGEV_THREAD_ID
|
||||
* set), the signal must be delivered to the specific thread (queues
|
||||
* into t->pending).
|
||||
*
|
||||
* Where type is not PIDTYPE_PID, signals must be delivered to the
|
||||
* process. In this case, prefer to deliver to current if it is in
|
||||
* the same thread group as the target process, which avoids
|
||||
* unnecessarily waking up a potentially idle task.
|
||||
*/
|
||||
t = pid_task(pid, type);
|
||||
t = posixtimer_get_target(tmr);
|
||||
if (!t)
|
||||
goto ret;
|
||||
if (type != PIDTYPE_PID && same_thread_group(t, current))
|
||||
t = current;
|
||||
return -1;
|
||||
|
||||
if (!likely(lock_task_sighand(t, &flags)))
|
||||
goto ret;
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Update @q::info::si_sys_private for posix timer signals with
|
||||
|
|
@ -1988,30 +2002,24 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type, int s
|
|||
* decides based on si_sys_private whether to invoke
|
||||
* posixtimer_rearm() or not.
|
||||
*/
|
||||
q->info.si_sys_private = si_private;
|
||||
q->info.si_sys_private = tmr->it_signal_seq;
|
||||
|
||||
ret = 1; /* the signal is ignored */
|
||||
result = TRACE_SIGNAL_IGNORED;
|
||||
if (!prepare_signal(sig, t, false))
|
||||
if (!prepare_signal(sig, t, false)) {
|
||||
result = TRACE_SIGNAL_IGNORED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (unlikely(!list_empty(&q->list))) {
|
||||
result = TRACE_SIGNAL_ALREADY_PENDING;
|
||||
goto out;
|
||||
}
|
||||
|
||||
signalfd_notify(t, sig);
|
||||
pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
|
||||
list_add_tail(&q->list, &pending->list);
|
||||
sigaddset(&pending->signal, sig);
|
||||
complete_signal(sig, t, type);
|
||||
posixtimer_queue_sigqueue(q, t, tmr->it_pid_type);
|
||||
result = TRACE_SIGNAL_DELIVERED;
|
||||
out:
|
||||
trace_signal_generate(sig, &q->info, t, type != PIDTYPE_PID, result);
|
||||
trace_signal_generate(sig, &q->info, t, tmr->it_pid_type != PIDTYPE_PID, result);
|
||||
unlock_task_sighand(t, &flags);
|
||||
ret:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_POSIX_TIMERS */
|
||||
|
|
|
|||
|
|
@ -307,7 +307,7 @@ int posix_timer_queue_signal(struct k_itimer *timr)
|
|||
|
||||
timr->it_status = state;
|
||||
|
||||
ret = send_sigqueue(timr->sigq, timr->it_pid, timr->it_pid_type, timr->it_signal_seq);
|
||||
ret = posixtimer_send_sigqueue(timr);
|
||||
/* If we failed to send the signal the timer stops. */
|
||||
return ret > 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user