Re: Spurious task resume due to SIGSHADOW
Jan Kiszka <[email protected]>
| Newsgroups | dev.linux.lists.xenomai |
|---|---|
| Message-ID | <[email protected]> |
On 12.05.26 09:19, Richard Weinberger wrote: > On Tue, May 12, 2026 at 7:50 AM Jan Kiszka <[email protected]> wrote: >> >> On 11.05.26 23:49, Richard Weinberger wrote: >>> I'm currently debugging an issue on a very old Xenomai system, while >>> reading the source I noticed that the very same issue could also exist >>> on recent Xenomai releases. >>> >>> What I see is the following: >>> - A task gets suspended and unblocked using rt_task_suspend() and >>> rt_task_unblock() >> >> This is intentionally rt_task_unblock instead of rt_task_resume? > > From what I can tell, yes. > >> Because: >> >> "A nesting count is maintained so that rt_task_suspend() and >> rt_task_resume() must be used in pairs." > > The application has non-trivial thread management, from what I can > tell, it's fine. > >>> - In some cases it happens that the task resumes to execute >>> - It resumes because a Linux signal is pending, being SIGSHADOW >>> >>> Since SIGSHADOW is internally used to suspend a task, this alerted me. >>> So, I suspect the following issue: >>> When xnthread_suspend() fires SIGSHADOW using >>> __xnthread_signal(thread, SIGSHADOW, SIGSHADOW_ACTION_HARDEN); nothing >>> seems to prevent the case where the target task enters the primary >>> domain right before it sees SIGSHADOW. In the next step >>> do_sigwake_event() causes it to resume instead of sleeping. >>> >>> Hmm? >>> >> >> Traces to confirm this theory would be good. But it could indeed be >> problematic that the target state (__THREAD_S_SUSPENDED) is only tracked >> in userspace where the scheduler has no access to while waking a task. > > I think I found a reproducer. See next patch in this mail thread. > > This quick and dirty change seems to mitigate the problem, but I consider it > a sledge hammer: > diff --git a/kernel/cobalt/dovetail/kevents.c b/kernel/cobalt/dovetail/kevents.c > index 7402e2ef6..d72c3788b 100644 > --- a/kernel/cobalt/dovetail/kevents.c > +++ b/kernel/cobalt/dovetail/kevents.c > @@ -145,6 +145,14 @@ static int handle_sigwake_event(struct task_struct *p) > if (xnthread_test_state(thread, XNRELAX)) > goto out; > > + if (sigismember(&p->pending.signal, SIGSHADOW)) > + goto out; > + > + if (sigismember(&p->signal->shared_pending.signal, SIGSHADOW)) > + goto out; > + None of this will work, and I'm afraid your approach that you shared yesterday for retired Xenomai versions will also fail. I played with something even more targeted than the above, and different scenarios, e.g. task startup, were starting to lock-up. No surprise, we are breaking SIGSHADOW here. The fundamental issue we need to solve with remote suspension/resumption is the asynchronicity of the command vs. the pending (and non-suppressible) signals. One idea I had is to use a separate SIGSHADOW_ACTION_SUSPEND and perform a self-suspension instead of just a hardening. That works nicely for resolving the issue you found, but it creates a new race between this pending signal and remote resumption. We likely rather need some additional state flag in the thread to encode "suspend is pending" which can do the right thing before a thread is returning to userland and can also be cleared from remote if suspension is lifted quickly again. Did I say that asynchronous thread suspension is a horrible concept to implement correctly? Jan -- Siemens AG, Foundational Technologies Linux Expert Center