Skip to content

Commit

Permalink
Merge tag 'posix-timers-2024-07-29' of git://git.kernel.org/pub/scm/l…
Browse files Browse the repository at this point in the history
…inux/kernel/git/frederic/linux-dynticks into timers/core

Pull updates for posix timers and related signal code from Frederic Weisbecker:

  * Prepare posix timers selftests for upcoming changes:

	- Check signal behaviour sanity against SIG_IGN

	- Check signal behaviour sanity against timer
	  reprogramm/deletion

	- Check SIGEV_NONE pending expiry read

	- Check interval timer read on a pending SIGNAL

	- Check correct overrun count after signal block/unblock

  * Various consolidations:

	- timer get/set

	- signal queue

  * Fixes:
	- Correctly read SIGEV_NONE timers

	- Forward expiry while reading expired interval timers
	  with pending signal

	- Don't arm SIGEV_NONE timers

  * Various cleanups all over the place
  • Loading branch information
Thomas Gleixner committed Jul 30, 2024
2 parents 8400291 + 7f8af7b commit 9a7b015
Show file tree
Hide file tree
Showing 12 changed files with 607 additions and 286 deletions.
6 changes: 3 additions & 3 deletions fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -2456,13 +2456,13 @@ static void *timers_start(struct seq_file *m, loff_t *pos)
if (!tp->sighand)
return ERR_PTR(-ESRCH);

return seq_list_start(&tp->task->signal->posix_timers, *pos);
return seq_hlist_start(&tp->task->signal->posix_timers, *pos);
}

static void *timers_next(struct seq_file *m, void *v, loff_t *pos)
{
struct timers_private *tp = m->private;
return seq_list_next(v, &tp->task->signal->posix_timers, pos);
return seq_hlist_next(v, &tp->task->signal->posix_timers, pos);
}

static void timers_stop(struct seq_file *m, void *v)
Expand Down Expand Up @@ -2491,7 +2491,7 @@ static int show_timer(struct seq_file *m, void *v)
[SIGEV_THREAD] = "thread",
};

timer = list_entry((struct list_head *)v, struct k_itimer, list);
timer = hlist_entry((struct hlist_node *)v, struct k_itimer, list);
notify = timer->it_sigev_notify;

seq_printf(m, "ID: %d\n", timer->it_id);
Expand Down
4 changes: 2 additions & 2 deletions fs/signalfd.c
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info
DECLARE_WAITQUEUE(wait, current);

spin_lock_irq(&current->sighand->siglock);
ret = dequeue_signal(current, &ctx->sigmask, info, &type);
ret = dequeue_signal(&ctx->sigmask, info, &type);
switch (ret) {
case 0:
if (!nonblock)
Expand All @@ -174,7 +174,7 @@ static ssize_t signalfd_dequeue(struct signalfd_ctx *ctx, kernel_siginfo_t *info
add_wait_queue(&current->sighand->signalfd_wqh, &wait);
for (;;) {
set_current_state(TASK_INTERRUPTIBLE);
ret = dequeue_signal(current, &ctx->sigmask, info, &type);
ret = dequeue_signal(&ctx->sigmask, info, &type);
if (ret != 0)
break;
if (signal_pending(current)) {
Expand Down
2 changes: 1 addition & 1 deletion include/linux/posix-timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ static inline void posix_cputimers_init_work(void) { }
* @rcu: RCU head for freeing the timer.
*/
struct k_itimer {
struct list_head list;
struct hlist_node list;
struct hlist_node t_hash;
spinlock_t it_lock;
const struct k_clock *kclock;
Expand Down
7 changes: 3 additions & 4 deletions include/linux/sched/signal.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ struct signal_struct {

/* POSIX.1b Interval Timers */
unsigned int next_posix_timer_id;
struct list_head posix_timers;
struct hlist_head posix_timers;

/* ITIMER_REAL timer for the process */
struct hrtimer real_timer;
Expand Down Expand Up @@ -276,8 +276,7 @@ static inline void signal_set_stop_flags(struct signal_struct *sig,
extern void flush_signals(struct task_struct *);
extern void ignore_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *task, sigset_t *mask,
kernel_siginfo_t *info, enum pid_type *type);
extern int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type);

static inline int kernel_dequeue_signal(void)
{
Expand All @@ -287,7 +286,7 @@ static inline int kernel_dequeue_signal(void)
int ret;

spin_lock_irq(&task->sighand->siglock);
ret = dequeue_signal(task, &task->blocked, &__info, &__type);
ret = dequeue_signal(&task->blocked, &__info, &__type);
spin_unlock_irq(&task->sighand->siglock);

return ret;
Expand Down
2 changes: 1 addition & 1 deletion init/init_task.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static struct signal_struct init_signals = {
.cred_guard_mutex = __MUTEX_INITIALIZER(init_signals.cred_guard_mutex),
.exec_update_lock = __RWSEM_INITIALIZER(init_signals.exec_update_lock),
#ifdef CONFIG_POSIX_TIMERS
.posix_timers = LIST_HEAD_INIT(init_signals.posix_timers),
.posix_timers = HLIST_HEAD_INIT,
.cputimer = {
.cputime_atomic = INIT_CPUTIME_ATOMIC,
},
Expand Down
2 changes: 1 addition & 1 deletion kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -1861,7 +1861,7 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
prev_cputime_init(&sig->prev_cputime);

#ifdef CONFIG_POSIX_TIMERS
INIT_LIST_HEAD(&sig->posix_timers);
INIT_HLIST_HEAD(&sig->posix_timers);
hrtimer_init(&sig->real_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
sig->real_timer.function = it_real_fn;
#endif
Expand Down
34 changes: 17 additions & 17 deletions kernel/signal.c
Original file line number Diff line number Diff line change
Expand Up @@ -618,20 +618,18 @@ static int __dequeue_signal(struct sigpending *pending, sigset_t *mask,
}

/*
* Dequeue a signal and return the element to the caller, which is
* expected to free it.
*
* All callers have to hold the siglock.
* Try to dequeue a signal. If a deliverable signal is found fill in the
* caller provided siginfo and return the signal number. Otherwise return
* 0.
*/
int dequeue_signal(struct task_struct *tsk, sigset_t *mask,
kernel_siginfo_t *info, enum pid_type *type)
int dequeue_signal(sigset_t *mask, kernel_siginfo_t *info, enum pid_type *type)
{
struct task_struct *tsk = current;
bool resched_timer = false;
int signr;

/* We only dequeue private signals from ourselves, we don't let
* signalfd steal them
*/
lockdep_assert_held(&tsk->sighand->siglock);

*type = PIDTYPE_PID;
signr = __dequeue_signal(&tsk->pending, mask, info, &resched_timer);
if (!signr) {
Expand Down Expand Up @@ -1940,10 +1938,11 @@ struct sigqueue *sigqueue_alloc(void)

void sigqueue_free(struct sigqueue *q)
{
unsigned long flags;
spinlock_t *lock = &current->sighand->siglock;
unsigned long flags;

BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
return;
/*
* We must hold ->siglock while testing q->list
* to serialize with collect_signal() or with
Expand Down Expand Up @@ -1971,7 +1970,10 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
unsigned long flags;
int ret, result;

BUG_ON(!(q->flags & SIGQUEUE_PREALLOC));
if (WARN_ON_ONCE(!(q->flags & SIGQUEUE_PREALLOC)))
return 0;
if (WARN_ON_ONCE(q->info.si_code != SI_TIMER))
return 0;

ret = -1;
rcu_read_lock();
Expand Down Expand Up @@ -2006,7 +2008,6 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type)
* If an SI_TIMER entry is already queue just increment
* the overrun count.
*/
BUG_ON(q->info.si_code != SI_TIMER);
q->info.si_overrun++;
result = TRACE_SIGNAL_ALREADY_PENDING;
goto out;
Expand Down Expand Up @@ -2793,8 +2794,7 @@ bool get_signal(struct ksignal *ksig)
type = PIDTYPE_PID;
signr = dequeue_synchronous_signal(&ksig->info);
if (!signr)
signr = dequeue_signal(current, &current->blocked,
&ksig->info, &type);
signr = dequeue_signal(&current->blocked, &ksig->info, &type);

if (!signr)
break; /* will return 0 */
Expand Down Expand Up @@ -3648,7 +3648,7 @@ static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info,
signotset(&mask);

spin_lock_irq(&tsk->sighand->siglock);
sig = dequeue_signal(tsk, &mask, info, &type);
sig = dequeue_signal(&mask, info, &type);
if (!sig && timeout) {
/*
* None ready, temporarily unblock those we're interested
Expand All @@ -3667,7 +3667,7 @@ static int do_sigtimedwait(const sigset_t *which, kernel_siginfo_t *info,
spin_lock_irq(&tsk->sighand->siglock);
__set_task_blocked(tsk, &tsk->real_blocked);
sigemptyset(&tsk->real_blocked);
sig = dequeue_signal(tsk, &mask, info, &type);
sig = dequeue_signal(&mask, info, &type);
}
spin_unlock_irq(&tsk->sighand->siglock);

Expand Down
7 changes: 1 addition & 6 deletions kernel/time/alarmtimer.c
Original file line number Diff line number Diff line change
Expand Up @@ -574,15 +574,10 @@ static enum alarmtimer_restart alarm_handle_timer(struct alarm *alarm,
it.alarm.alarmtimer);
enum alarmtimer_restart result = ALARMTIMER_NORESTART;
unsigned long flags;
int si_private = 0;

spin_lock_irqsave(&ptr->it_lock, flags);

ptr->it_active = 0;
if (ptr->it_interval)
si_private = ++ptr->it_requeue_pending;

if (posix_timer_event(ptr, si_private) && ptr->it_interval) {
if (posix_timer_queue_signal(ptr) && ptr->it_interval) {
/*
* Handle ignored signals and rearm the timer. This will go
* away once we handle ignored signals proper. Ensure that
Expand Down
Loading

0 comments on commit 9a7b015

Please sign in to comment.