Commit 11629b98 authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

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: default avatarEric W. Biederman <ebiederm@xmission.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarFrederic Weisbecker <frederic@kernel.org>
Acked-by: default avatar"Eric W. Biederman" <ebiederm@xmission.com>
Link: https://lore.kernel.org/all/20241105064213.652658158@linutronix.de
parent 0360ed14
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -110,7 +110,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);
bool posixtimer_deliver_signal(struct kernel_siginfo *info, struct sigqueue *timer_sigq);
void posixtimer_free_timer(struct k_itimer *timer);

/* Init task static initializer */
@@ -135,7 +135,8 @@ 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; }
static inline bool posixtimer_deliver_signal(struct kernel_siginfo *info,
					     struct sigqueue *timer_sigq) { return false; }
static inline void posixtimer_free_timer(struct k_itimer *timer) { }
#endif

+20 −12
Original line number Diff line number Diff line
@@ -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,9 +568,16 @@ static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *i
		list_del_init(&first->list);
		copy_siginfo(info, &first->info);

		*resched_timer = (first->flags & SIGQUEUE_PREALLOC) &&
				 (info->si_code == SI_TIMER);

		/*
		 * 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 {
		/*
@@ -588,12 +595,12 @@ static void collect_signal(int sig, struct sigpending *list, kernel_siginfo_t *i
}

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 @@ int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type)
		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;
	}

+1 −1
Original line number Diff line number Diff line
@@ -254,7 +254,7 @@ static void common_hrtimer_rearm(struct k_itimer *timr)
 * This function is called from the signal delivery code. It decides
 * whether the signal should be dropped and rearms interval timers.
 */
bool posixtimer_deliver_signal(struct kernel_siginfo *info)
bool posixtimer_deliver_signal(struct kernel_siginfo *info, struct sigqueue *timer_sigq)
{
	struct k_itimer *timr;
	unsigned long flags;