summaryrefslogtreecommitdiff
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2024-11-05 09:14:43 +0100
committerThomas Gleixner <tglx@linutronix.de>2024-11-07 02:14:44 +0100
commit11629b9808e5900d675fd469d19932ea48060de3 (patch)
treeed66a8f5e7027fc8b6e1827d2a5aaaf96ccacb0a /kernel/signal.c
parent0360ed14d9826678a50fa2b873e522a24cd3c018 (diff)
signal: Replace resched_timer logic
In preparation for handling ignored posix timer signals correctly and embedding the sigqueue struct into struct k_itimer, hand down a pointer to the sigqueue struct into posix_timer_deliver_signal() instead of just having a boolean flag. No functional change. Suggested-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Acked-by: "Eric W. Biederman" <ebiederm@xmission.com> Link: https://lore.kernel.org/all/20241105064213.652658158@linutronix.de
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c32
1 files changed, 20 insertions, 12 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index 5b71e26abb0e..0ddb5dd284aa 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -545,7 +545,7 @@ bool unhandled_signal(struct task_struct *tsk, int sig)
}
static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *info,
- bool *resched_timer)
+ struct sigqueue **timer_sigq)
{
struct sigqueue *q, *first = NULL;
@@ -568,10 +568,17 @@ still_pending:
list_del_init(&first->list);
copy_siginfo(info, &first->info);
- *resched_timer = (first->flags & SIGQUEUE_PREALLOC) &&
- (info->si_code == SI_TIMER);
-
- __sigqueue_free(first);
+ /*
+ * posix-timer signals are preallocated and freed when the
+ * timer goes away. Either directly or by clearing
+ * SIGQUEUE_PREALLOC so that the next delivery will free
+ * them. Spare the extra round through __sigqueue_free()
+ * which is ignoring preallocated signals.
+ */
+ if (unlikely((first->flags & SIGQUEUE_PREALLOC) && (info->si_code == SI_TIMER)))
+ *timer_sigq = first;
+ else
+ __sigqueue_free(first);
} else {
/*
* Ok, it wasn't in the queue. This must be
@@ -588,12 +595,12 @@ still_pending:
}
static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
- kernel_siginfo_t *info, bool *resched_timer)
+ kernel_siginfo_t *info, struct sigqueue **timer_sigq)
{
int sig = next_signal(pending, mask);
if (sig)
- collect_signal(sig, pending, info, resched_timer);
+ collect_signal(sig, pending, info, timer_sigq);
return sig;
}
@@ -605,18 +612,19 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type)
{
struct task_struct *tsk = current;
- bool resched_timer = false;
+ struct sigqueue *timer_sigq;
int signr;
lockdep_assert_held(&tsk->sighand->siglock);
again:
*type = PIDTYPE_PID;
- signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);
+ timer_sigq = NULL;
+ signr = __dequeue_signal(&tsk->pending, mask, info, &timer_sigq);
if (!signr) {
*type = PIDTYPE_TGID;
signr = __dequeue_signal(&tsk->signal->shared_pending,
- mask, info, &resched_timer);
+ mask, info, &timer_sigq);
if (unlikely(signr == SIGALRM))
posixtimer_rearm_itimer(tsk);
@@ -642,8 +650,8 @@ again:
current->jobctl |= JOBCTL_STOP_DEQUEUED;
}
- if (IS_ENABLED(CONFIG_POSIX_TIMERS) && unlikely(resched_timer)) {
- if (!posixtimer_deliver_signal(info))
+ if (IS_ENABLED(CONFIG_POSIX_TIMERS) && unlikely(timer_sigq)) {
+ if (!posixtimer_deliver_signal(info, timer_sigq))
goto again;
}