Thanks for your timely responses.

However, it seems we cannot use errno after getch() returns ERR. In our
testing, when a SIGHUP occurs, the underlying read() call simply returns 0
(EOF) rather than a system error.
Since ncurses appears to map both EOF and a halfdelay timeout to the same
ERR value without setting errno, we lose the ability to distinguish between
'no input' and 'terminal gone.'

We could use napms() to throttle the CPU, but that leaves the process alive
in a 'zombie' state until a user manually kills it.
We really want to detect the disconnection and terminate gracefully.

It looks as if we are forced to set a global volatile sig_atomic_t flag on
SIGHUP and check it manually every time getch() returns ERR.

Does ncurses provide any internal mechanism to distinguish an EOF from a
timeout, or is the signal-flag approach the standard way to handle this in
a curses application?



On Sat, Mar 28, 2026 at 12:30 AM G. Branden Robinson <
[email protected]> wrote:

> At 2026-03-27T18:23:57-0400, Thomas Dickey wrote:
> > On Fri, Mar 27, 2026 at 06:40:42PM +0100, Klaas van Aarsen wrote:
> > > We have a bug in the Angband code related to getch of ncurses (
> > > https://github.com/angband/angband/pull/6559).
> > > It turns out that getch returns ERR when the terminal connection is
> > > broken (SIGHUP). The code currently interprets it as a timeout (set
> > > by halfdelay) and spins on input, leaving a zombie process with 100%
> > > CPU.  The man page on getch only mentions that errno might be EINTR
> > > if the getch call is interrupted, but nothing on a broken terminal
> > > connection.  How might we detect that the terminal connection is
> > > broken?
> [...]
> > ...mixing getch with fgets doesn't appear to be a good idea, since
> > ncurses doesn't use the input stream -- only the file descriptor.
> > Expect some difference in behavior.
>
> The ncurses man pages explain this, too.
>
> ncurses(3NCURSES):
>
> ENVIRONMENT
> ...
>    NCURSES_NO_SETBUF
>      (Obsolete) Prior to internal changes developed in ncurses 5.9
>      (patches 20120825 through 20130126), the library used setbuf(3) to
>      enable fully buffered output when initializing the terminal.  This
>      was done, as in SVr4 curses, to increase performance.  For testing
>      purposes, both of ncurses and of certain applications, this feature
>      was made optional.  Setting this variable disabled output
>      buffering, leaving the output stream in the original (usually line‐
>      buffered) mode.
>
>      Nowadays, ncurses performs its own buffering and does not require
>      this workaround; it does not modify the buffering of the standard
>      output stream.  This approach makes the library’s handling of
>      keyboard‐initiated signals more robust.  A drawback is that certain
>      unconventional programs mixed stdio(3) calls with ncurses calls and
>      (usually) got the behavior they expected.  This is no longer the
>      case; ncurses does not write to the standard output file descriptor
>      through a stdio‐buffered stream.
>
>      As a special case, low‐level API calls such as putp(3NCURSES) still
>      use the standard output stream.  High‐level curses calls such as
>      printw(3NCURSES) do not.
>
> Regards,
> Branden
>

Reply via email to