Skip to content

Commit

Permalink
evl/monitor: event: disable syscall restart on interrupted wait
Browse files Browse the repository at this point in the history
When interrupted by a signal, a wait operation on a gated monitor
should not be restarted automatically from kernel space, but reported
to the user instead.

Rationale: the mutex guarding the monitor was dropped prior to
waiting, and must be re-acquired explicitly by an UNWAIT request when
the interrupted status is detected from user-space. Consequently, we
cannot retry a WAIT request without transitioning to user-space first.

Add the T_NORST local information bit to the thread control block,
which is set by the monitor wait operation, and tested by the syscall
trampoline code for disabling automatic restart.

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
  • Loading branch information
pgerum authored and ldts committed Jun 22, 2023
1 parent 35cb62b commit 5c6402e
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 10 deletions.
1 change: 1 addition & 0 deletions include/uapi/evl/thread.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
#define T_SYSRST 0x00000001 /* Thread awaiting syscall restart after signal */
#define T_IGNOVR 0x00000002 /* Overrun detection temporarily disabled */
#define T_INFAULT 0x00000004 /* In fault handling */
#define T_NORST 0x00000008 /* Disable syscall restart */

/*
* Must follow strictly the declaration order of the state flags
Expand Down
10 changes: 8 additions & 2 deletions kernel/evl/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -527,13 +527,19 @@ static int wait_monitor(struct file *filp,
* be handled asap. So exit to user mode, allowing any pending
* signal to be handled during the transition, then expect
* userland to issue UNWAIT to recover (or exit, whichever
* comes first).
* comes first). Consequently, disable syscall restart from
* kernel upon interrupted wait, because the caller does not
* hold the mutex until UNWAIT happens.
*/
ret = evl_wait_schedule(&event->wait_queue);
if (ret) {
untrack_event(event);
if (ret == -EINTR)
if (ret == -EINTR) {
/* Disable syscall restart upon signal (only). */
if (signal_pending(current))
curr->local_info |= T_NORST;
goto put;
}
op_ret = ret;
}

Expand Down
14 changes: 6 additions & 8 deletions kernel/evl/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,6 @@ static void prepare_for_signal(struct task_struct *p,
{
unsigned long flags;

/*
* FIXME: no restart mode flag for setting -EINTR instead of
* -ERESTARTSYS should be obtained from curr->local_info on a
* per-invocation basis, not on a per-call one (since we have
* 3 generic calls only).
*/

/*
* @curr == this_evl_rq()->curr over oob so no need to grab
* @curr->lock (i.e. @curr cannot go away under out feet).
Expand All @@ -187,7 +180,12 @@ static void prepare_for_signal(struct task_struct *p,
*/
if (curr->info & T_KICKED) {
if (signal_pending(p)) {
syscall_set_return_value(current, regs, -ERESTARTSYS, 0);
int retval = -ERESTARTSYS;
if (curr->local_info & T_NORST) {
retval = -EINTR;
curr->local_info &= ~T_NORST;
}
syscall_set_return_value(current, regs, retval, 0);
curr->info &= ~T_BREAK;
}
curr->info &= ~T_KICKED;
Expand Down

0 comments on commit 5c6402e

Please sign in to comment.