[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]


From: Ludovic Courtès
Subject: Re: SCM_SYSCALL
Date: Fri, 05 Jul 2013 00:28:29 +0200
User-agent: Gnus/5.130007 (Ma Gnus v0.7) Emacs/24.3 (gnu/linux)

Hi Mark,

Mark H Weaver <address@hidden> skribis:

> address@hidden (Ludovic Courtès) writes:
>> We have this (since 2010):
>> #   define SCM_SYSCALL(line)                    \
>>   do                                            \
>>     {                                           \
>>       errno = 0;                                \
>>       line;                                     \
>>       if (errno == EINTR)                       \
>>         {                                       \
>>           SCM_ASYNC_TICK;                       \
>>           continue;                             \
>>         }                                       \
>>     }                                           \
>>   while(0)
>> It turns out that the effect upon EINTR is to leave the loop.  So
>> typically, fport_fill_input just throws to system-error and reveals the
>> EINTR, contrary to SCM_SYSCALL intends to do.
> Ugh.  Well, I guess this finally explains <>.

Indeed.  (Funny to see how I was blissfully quoting the above macro
saying: “look, EINTR is handled, of course!”.  :-))

> I strongly believe that we should fix this in stable-2.0.  While it is
> true that the above scenario is possible, I suspect it is at least an
> order of magnitude more common for Guile-based software to be written
> based on the presumption that EINTR is handled automatically.
> Not only did all versions of Guile 1.x automatically handle EINTR, but
> most of us assumed that this behavior was unchanged in Guile 2.0 and
> wrote our software based on that assumption.  I certainly did.
> As it is now, even portable Scheme code that uses (read) might result in
> exceptions being thrown semi-randomly.  We cannot reasonably expect
> Guile programs to put each (read) within a loop to handle EINTR.
> Please, let's fix this in stable-2.0.

Yes, I’ve reached that conclusion too.

I’ve been cooking a patch but the test case ends up being trickier to
write than I expected.  Here’s what I have:

        (let* ((in+out   (pk 'pipe (pipe)))
               (lock     (make-mutex))
               (cond     (make-condition-variable))
               (signaled #f)
               (thread   (call-with-new-thread
                          (lambda ()
                            (with-mutex lock
                              (display "hello " (cdr in+out))
                              (wait-condition-variable cond lock)
                              (display "world\n" (cdr in+out))
                              (close-port (cdr in+out)))))))
          (define handle
            (lambda (signum)
              (with-mutex lock
                (set! signaled (pk 'sig signum))
                (signal-condition-variable cond))))
          (sigaction SIGALRM handle 0)
          (alarm 2)

          ;; This thread (the main thread) receives the signal.  Yet,
          ;; the EINTR returned by read(2) as called via `read-line'
          ;; must be swallowed.
          (let ((line (read-line (car in+out))))
            (join-thread thread)
            (list signaled line)))

This nicely reproduces the problem where fport_fill_input throws to
‘system-error’ with EINTR.

However, with a fixed SCM_SYSCALL, the result is pretty much the same as
with SA_RESTART (see <>): when SCM_ASYNC_TICK
is called right after we get EINTR, chances are that the async hasn’t
been queued yet, so we get back to our read(2) call, and thus the
Scheme-level signal handler is never called.  (Typically, when running
the test through strace, it passes, because the timing is “better”, but
it fails without strace.)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]