bug-readline
[Top][All Lists]
Advanced

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

Re: [Bug-readline] [PATCH] Gnuplot on macOS does not suspend by Control-


From: Rin Okuyama
Subject: Re: [Bug-readline] [PATCH] Gnuplot on macOS does not suspend by Control-z
Date: Mon, 27 Nov 2017 01:43:38 +0900
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:52.0) Gecko/20100101 Thunderbird/52.4.0

On 2017/11/25 0:27, Chet Ramey wrote:
On 11/23/17 10:52 AM, Rin Okuyama wrote:
Thank you for your comment. As you pointed out, the signal check
should be within the select(2) loop. New versions would be

(1) _rl_signal_handler() is used as before:

----
int getc_wrapper(FILE *fp) {
     fd_set fds;
     int fd = fileno(fp);
     int ierr;
     if (external_fd >= 0) {
         do {
             FD_ZERO(&fds);
             FD_SET(fd, &fds);
             FD_SET(external_fd, &fds);
             ierr = select(external_fd + 1, &fds, 0, 0, NULL);
             if (ierr < 0 && errno == EINTR) {
#ifdef HAVE_LIBREADLINE
                 if (_rl_caught_signal)
                     _rl_signal_handler(_rl_caught_signal);
#endif
                 continue;
             }

... poll and read from external_fd ...

         } while (!FD_ISSET(fd, &fds));
     }
#ifdef HAVE_LIBREADLINE
     return rl_getc(fp);
#else
     return getc(fp);
#endif
}
----

(2) the 1st ifdef block is simply replaced by

----
#ifdef HAVE_LIBREADLINE
                 return rl_getc(fp);
#endif
----

Both (1) and (2) suspend by Control-z. However, variant (2) does not
accept input from external_fd (it is actually mouse driver) after
continue from suspend, unless the first any input arrives from tty.
I guess that this is inevitable with rl_getc(). How do you think?

This isn't what I said. You only want to call rl_getc in that scenario
unless you're sure that the select() was interrupted by a signal, because
what you're interested in is the side effect of its signal handling.

You can either break out of the loop, in which case the call to rl_getc
following the loop will (as a side effect) handle the signal, or you
can call it explicitly. If you call it in the loop, you only want to
call it if you're sure you have a signal handler call pending to avoid
the case you encountered.  So something like (readline-7.0):

if (ierr < 0 && errno == EINTR)
  if (rl_pending_signal ()) return rl_getc ();

Even if we check rl_pending_signal() before calling rl_getc(), we cannot
catch input from external_fd after resuming from suspend, unless something
is inputted from tty.

Let's consider what happens when SIGTSTP arrives. The signal handler of
readline sets the flag and returns. Then, select(2) in the application fails
with EINTR. Since rl_pending_signal() is true, rl_getc() is called. In
rl_getc(), SIGTSTP is raised by _rl_handle_signal() via RL_CHECK_SIGNALS().
Then, the process suspends. After resuming, it enters the pselect(2) loop in
rl_getc(). Since the signal is already gone at this moment, pselect(2) does
not return until something is inputted from tty. Then, we cannot catch input
from external_fd, unless we get out from the pselect(2) loop.

This is what actually happens if we use

if (ierr < 0 && errno == EINTR)
  if (rl_pending_signal ()) return rl_getc ();

On the other hand, if we use

if (ierr < 0 && errno == EINTR) {
  sig = rl_pending_signal ();
  if (sig) return _rl_signal_handler(sig);
}

we can catch input from external_fd just after resuming from suspend. This
is what I meant.

rin



reply via email to

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