unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* RE: How to abort a read from a socket after some time?
       [not found] <Za0_ly1K7l3RV1hJ@ws>
@ 2024-01-21 23:46 ` M
  2024-01-22 11:38   ` Tomas Volf
  0 siblings, 1 reply; 2+ messages in thread
From: M @ 2024-01-21 23:46 UTC (permalink / raw)
  To: Tomas Volf,
	Jonas Hahnfeld via Developers list for Guile,the GNU extensibility library

[-- Attachment #1: Type: text/plain, Size: 2254 bytes --]

(Please ignore the wrong To: field, e-mail program is being silly)

>I am trying to figure out how to abort a read from a socket after some time elapses.  >I failed to figure out how to do so.
>
> All code below runs after handler is set:
>
>    (sigaction SIGALRM (lambda _ (display "Alarm!\n")))

Assuming the read-char takes too long, the kernel sends a SIGALRM to Guile. Hence, the C signal handler is run (which sets some fields somewhere indicating that this handler should be run later in the sense of system-async-mark), and the syscall behind read-char returns EINTR.

As this is a fake error (passing it on as a Scheme exception would result in rather messy semantics, e.g. consider the case where things are interrupted twice in a row, time such that the exception handler itself is interrupted with a new exception), Guile decides to retry the syscall, but before that, it checks if there is a system-async-mark to be done, so it does that thing – i.e., it displays “Alarm!\n” and merrily continue on reading a character.

Now, going by the rest of the mail, it appears you don’t just want to print a message, you want to _abort_. So you should modify your handlers to abort, i.e., call an escape continuation.

(define escaper (make-parameter #false)
(sigaction SIGALRM (lambda _ (let ((e (escaper))) (if e (e)))))
[set up sockets, etc.]
;; returns char on success, #false on timeout.
(define (read-char-or-timeout)
  (let/ec e
    [set up an alarm]
    (parameterize ((escaper (lambda () (e #false))))
      (read-char e)))) ; XXX add port argument, maybe stop the alarm afterwards?

(This assumes the signal handler is run in the same thread as the thread using read-char-or-timeout, I don’t know if this is the case.)

This code has a bug, however: it might be the case that the signal is received right after read-char finishes but before the parameterize ends. In that case, the character is lost and read-char-or-timeout reports a “timeout”, losing the character, which is most likely undesired.

So, if you do things like this, I think you should modify the signal handler to instead set a a-timeout-happened flag, and let read-char-or-timeout read that flag.

Best regards,
Maxime Devos

[-- Attachment #2: Type: text/html, Size: 4165 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: How to abort a read from a socket after some time?
  2024-01-21 23:46 ` How to abort a read from a socket after some time? M
@ 2024-01-22 11:38   ` Tomas Volf
  0 siblings, 0 replies; 2+ messages in thread
From: Tomas Volf @ 2024-01-22 11:38 UTC (permalink / raw)
  To: M
  Cc: Jonas Hahnfeld via Developers list for Guile, the GNU extensibility library

[-- Attachment #1: Type: text/plain, Size: 1502 bytes --]

Hello,

thank you very much for the email and the suggested approach, I will try it out.
I just have one more question:

On 2024-01-22 00:46:23 +0100, M wrote:
> >
> > All code below runs after handler is set:
> >
> >    (sigaction SIGALRM (lambda _ (display "Alarm!\n")))
>
> Assuming the read-char takes too long, the kernel sends a SIGALRM to Guile. Hence, the C signal handler is run (which sets some fields somewhere indicating that this handler should be run later in the sense of system-async-mark), and the syscall behind read-char returns EINTR.
>
> As this is a fake error (passing it on as a Scheme exception would result in rather messy semantics, e.g. consider the case where things are interrupted twice in a row, time such that the exception handler itself is interrupted with a new exception), Guile decides to retry the syscall

I am confused about this.  I read the documentation for sigaction, and there is
this text for the flags argument:

      -- Variable: SA_RESTART
          If a signal occurs while in a system call, deliver the signal
          then restart the system call (as opposed to returning an
          ‘EINTR’ error from that call).

Based on that my expectation was to get EINTR.  But since the syscall seems to
be restarted even without the SA_RESTART, what exactly does this flag do then?

Thank you,
Tomas Volf

--
There are only two hard things in Computer Science:
cache invalidation, naming things and off-by-one errors.

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2024-01-22 11:38 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <Za0_ly1K7l3RV1hJ@ws>
2024-01-21 23:46 ` How to abort a read from a socket after some time? M
2024-01-22 11:38   ` Tomas Volf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).