Skip to content

Commit

Permalink
evl/monitor: event: differentiate causes for interrupted wait
Browse files Browse the repository at this point in the history
A wait operation can be interrupted for the following reasons:

- a signal was received while waiting for the event.

- the caller got forcibly unblocked while waiting for the event.

- a signal was received or the caller got forcibly unblocked while
  trying to reacquire the lock once the event was successfully
  received.

Ensure these conditions are differentiated when returning to the
caller via the operation status (req.status), which enables the user
interface to decide whether it needs to restart the syscall
transparently after some fixups on signal receipt, or bail out on
error if forcibly unblocked for any other reason.

This change causes a bump of the current ABI version (Freescale#28). However,
it does not affect current and older libevl releases since none of
them check the operation status when an interrupted wait is detected.

Signed-off-by: Philippe Gerum <[email protected]>
  • Loading branch information
pgerum authored and ldts committed Jun 22, 2023
1 parent 5c6402e commit ceb5569
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 10 deletions.
2 changes: 1 addition & 1 deletion include/uapi/evl/control.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
* latter to the former. CAUTION: a litteral value is required for the
* current ABI definition (scripts reading this may be naive).
*/
#define EVL_ABI_LEVEL 27
#define EVL_ABI_LEVEL 28

#define EVL_CONTROL_DEV "/dev/evl/control"

Expand Down
31 changes: 22 additions & 9 deletions kernel/evl/monitor.c
Original file line number Diff line number Diff line change
Expand Up @@ -527,24 +527,37 @@ 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). Consequently, disable syscall restart from
* kernel upon interrupted wait, because the caller does not
* hold the mutex until UNWAIT happens.
* 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) {
/* Disable syscall restart upon signal (only). */
if (signal_pending(current))
curr->local_info |= T_NORST;
/*
* Disable syscall restart upon signal (only), user
* receives -EINTR and a zero status in this case. If
* the caller was forcibly unblocked for any other
* reason, both the return value and the status word
* are set to -EINTR.
*/
if (ret == -EINTR && signal_pending(current)) {
curr->local_info |= T_NORST;
goto put;
}
op_ret = ret;
if (ret == -EIDRM)
goto put;
}

if (ret != -EIDRM) /* Success or -ETIMEDOUT */
ret = __enter_monitor(gate, NULL);
ret = __enter_monitor(gate, NULL);
if (ret == -EINTR) {
if (signal_pending(current))
curr->local_info |= T_NORST;
op_ret = -EAGAIN;
}
put:
evl_put_file(efilp);
out:
Expand Down

0 comments on commit ceb5569

Please sign in to comment.