• Getting a keypress

    From Janis Papanagnou@21:1/5 to All on Tue Dec 19 10:46:02 2023
    I'm trying to get some pressed keys control a piece of software.
    And I'm using ANSI escapes to control terminal screen output.
    Both works nicely in separate tests, but assembled the former
    seems to affect the latter. So I am looking for hints/caveats on
    what I am possibly doing wrong.

    The "poll pressed key" function is basically derived from Steven's
    APUE book (tty_cbreak). The main functional parts are the following
    settings...

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    and

    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Given that there are bazillions of flags to set or clear; is
    there anything I should add or omit? (Or something else I should
    have an eye on?)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to Janis Papanagnou on Tue Dec 19 10:04:10 2023
    On Tue, 19 Dec 2023 10:46:02 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm trying to get some pressed keys control a piece of software.
    And I'm using ANSI escapes to control terminal screen output.

    Make sure your terminal is 100% ANSI compatible. Not all are - some codes will work, others won't and others can cause odd behaviour.

    Both works nicely in separate tests, but assembled the former
    seems to affect the latter. So I am looking for hints/caveats on
    what I am possibly doing wrong.

    The "poll pressed key" function is basically derived from Steven's
    APUE book (tty_cbreak). The main functional parts are the following >settings...

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    I've never had to use that, try removing it to see if it helps.

    and

    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Instead of TCSAFLUSH try TCSANOW and make sure you check the return code
    for -1.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to Janis Papanagnou on Tue Dec 19 10:06:45 2023
    On Tue, 19 Dec 2023 10:46:02 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm trying to get some pressed keys control a piece of software.
    And I'm using ANSI escapes to control terminal screen output.
    Both works nicely in separate tests, but assembled the former
    seems to affect the latter. So I am looking for hints/caveats on
    what I am possibly doing wrong.

    The "poll pressed key" function is basically derived from Steven's
    APUE book (tty_cbreak). The main functional parts are the following >settings...

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    and

    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Also are you sure fd is stdin? Perhaps use STDIN_FILENO.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Muttley@dastardlyhq.com on Tue Dec 19 17:44:39 2023
    On 19.12.2023 11:04, Muttley@dastardlyhq.com wrote:
    On Tue, 19 Dec 2023 10:46:02 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    I'm trying to get some pressed keys control a piece of software.
    And I'm using ANSI escapes to control terminal screen output.

    Make sure your terminal is 100% ANSI compatible. Not all are - some codes will
    work, others won't and others can cause odd behaviour.

    Yes, as said, individually the two features work flawlessly.
    I am using ANSI escapes on a regular basis without problems.
    And I avoid (if possible) escapes that are marked to be (in
    any way) "specific".


    Both works nicely in separate tests, but assembled the former
    seems to affect the latter. So I am looking for hints/caveats on
    what I am possibly doing wrong.

    The "poll pressed key" function is basically derived from Steven's
    APUE book (tty_cbreak). The main functional parts are the following
    settings...

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    I've never had to use that, try removing it to see if it helps.

    I would think that non-blocking read(2) is what I need to
    _poll_ the status; am I missing something here?


    and

    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Instead of TCSAFLUSH try TCSANOW and make sure you check the return code
    for -1.

    All system calls in my programs check for the respective exit
    codes. I just omitted all that ballast for posting terseness
    and focused on the functional parts only.

    Elsethread you asked:
    Also are you sure fd is stdin? Perhaps use STDIN_FILENO.

    Yes, fd is a parameter from my poll function that is defined
    as STDIN_FILENO.

    Richard Stevens, where I took the basic pieces of code from,
    was very painstaking with his code samples. :-)

    Thanks.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Janis Papanagnou on Tue Dec 19 17:47:02 2023
    On 19.12.2023 10:46, Janis Papanagnou wrote:
    I'm trying to get some pressed keys control a piece of software.
    And I'm using ANSI escapes to control terminal screen output.
    Both works nicely in separate tests, but assembled the former
    seems to affect the latter. So I am looking for hints/caveats on
    what I am possibly doing wrong.

    The "poll pressed key" function is basically derived from Steven's
    APUE book (tty_cbreak). The main functional parts are the following settings...

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    and

    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Given that there are bazillions of flags to set or clear; is
    there anything I should add or omit? (Or something else I should
    have an eye on?)


    Just to clarify the issue I seem to have after the first replies
    and emphasize what works...

    Keystrokes can be obtained in a test program using the depicted
    method, and ANSI escapes for screen control generally work as well.
    But in combination the same screen drawing procedures don't work
    any more; that's why I suspected some interference of these termios
    flags with the ANSI controls, where the latter are just output by
    the C functions printf() or fputs().

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Janis Papanagnou on Tue Dec 19 17:04:05 2023
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    I'm trying to get some pressed keys control a piece of software.
    And I'm using ANSI escapes to control terminal screen output.
    Both works nicely in separate tests, but assembled the former
    seems to affect the latter. So I am looking for hints/caveats on
    what I am possibly doing wrong.

    The "poll pressed key" function is basically derived from Steven's
    APUE book (tty_cbreak). The main functional parts are the following >settings...

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    and

    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Given that there are bazillions of flags to set or clear; is
    there anything I should add or omit? (Or something else I should
    have an eye on?)

    Use poll(2) instead of read(2). IIRC, O_NONBLOCK doesn't necessarily
    apply to PTYs.

    diag = ::tcgetattr(u_ttyfd, &u_term_attr_orig);
    if (diag == -1) {
    u_logger->log("%s: Unable to get attributes for '%s': %s\n",
    u_appname, devname, strerror(errno));
    goto leave;
    }

    u_term_attr_cur = u_term_attr_orig;
    ::cfmakeraw(&u_term_attr_cur);
    u_term_attr_cur.c_lflag = 0;
    u_term_attr_cur.c_oflag |= OPOST|ONLCR;

    diag = ::tcsetattr(u_ttyfd, TCSANOW, &u_term_attr_cur);
    if (diag == -1) {
    u_logger->log("%s: Unable to set attributes for '%s': %s\n",
    u_appname, devname, strerror(errno));
    goto leave;
    }
    u_term_attr_set = true;

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Nicolas George on Tue Dec 19 18:42:48 2023
    Nicolas George <nicolas$george@salle-s.org> writes:
    Scott Lurndal, dans le message <92kgN.11545$5Hnd.7072@fx03.iad>, a
    écrit :
    Use poll(2) instead of read(2). IIRC, O_NONBLOCK doesn't necessarily
    apply to PTYs.

    O_NONBLOCK applies to ptys, and if it did not then poll() would not either.

    Actually, poll should work just fine without O_NONBLOCK,
    but that said, you are correct that O_NONBLOCK applies to ptys.

    I use:

    u_ttyfd = ::open(devname, O_RDWR|O_NOCTTY|O_NONBLOCK, 0);


    diag = ::tcgetattr

    What is this ugly horror?

    Why do you care? This isn't comp.lang.c.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Muttley@dastardlyhq.com on Tue Dec 19 20:02:46 2023
    On 19.12.2023 11:04, Muttley@dastardlyhq.com wrote:
    On Tue, 19 Dec 2023 10:46:02 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    I've never had to use that, try removing it to see if it helps.

    I am confused. - I removed that fcntl() call completely and the output
    wasn't affected any more in the observed negative way. - Why that?
    Don't I need to use non-blocking I/O for a poll?
    (Or is maybe buf.c_cc[VMIN] = 1 serving the same purpose?)
    But why has a non-blocking input definition an effect on _output_?
    You see me puzzled.


    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Instead of TCSAFLUSH try TCSANOW [...]

    I tried this change, but it had no visible effect (neither to the good
    nor to the bad).


    So I'll try to continue my code without the above fcntl() call.
    Thanks.

    Explanations and more suggestions still welcome.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Nicolas George@21:1/5 to All on Tue Dec 19 18:29:56 2023
    Scott Lurndal, dans le message <92kgN.11545$5Hnd.7072@fx03.iad>, a
    écrit :
    Use poll(2) instead of read(2). IIRC, O_NONBLOCK doesn't necessarily
    apply to PTYs.

    O_NONBLOCK applies to ptys, and if it did not then poll() would not either.

    diag = ::tcgetattr

    What is this ugly horror?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Scott Lurndal on Tue Dec 19 20:17:56 2023
    On 19.12.2023 18:04, Scott Lurndal wrote:

    Use poll(2) instead of read(2). [...]

    int poll(struct pollfd *fds, nfds_t nfds, int timeout);

    It isn't explicitly mentioned in the man-page, but I assume a
    timeout value of 0 will actually do the non-blocking behavior
    with poll(2).


    diag = ::tcgetattr(u_ttyfd, &u_term_attr_orig);
    if (diag == -1) {
    u_logger->log("%s: Unable to get attributes for '%s': %s\n",
    u_appname, devname, strerror(errno));
    goto leave;
    }

    u_term_attr_cur = u_term_attr_orig;
    ::cfmakeraw(&u_term_attr_cur);
    u_term_attr_cur.c_lflag = 0;
    u_term_attr_cur.c_oflag |= OPOST|ONLCR;

    diag = ::tcsetattr(u_ttyfd, TCSANOW, &u_term_attr_cur);
    if (diag == -1) {
    u_logger->log("%s: Unable to set attributes for '%s': %s\n",
    u_appname, devname, strerror(errno));
    goto leave;
    }
    u_term_attr_set = true;


    At the moment I don't understand what this code does; I suppose
    I'll have to look up all those flags first.

    Thanks.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Muttley@dastardlyhq.com on Tue Dec 19 20:47:06 2023
    On 2023-12-19, Muttley@dastardlyhq.com <Muttley@dastardlyhq.com> wrote:
    Also are you sure fd is stdin? Perhaps use STDIN_FILENO.

    I suspect the purpose of STDIN_FILENO is readability, not abstraction
    (as in the possibility of it being redefined).

    Newcomers to Unix codebases may be confused if they see a hard
    coded literal zero.

    There is no way in hell stdin can be changed to anything other
    than zero.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Janis Papanagnou on Tue Dec 19 20:30:48 2023
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 19.12.2023 18:04, Scott Lurndal wrote:

    Use poll(2) instead of read(2). [...]

    int poll(struct pollfd *fds, nfds_t nfds, int timeout);

    It isn't explicitly mentioned in the man-page, but I assume a
    timeout value of 0 will actually do the non-blocking behavior
    with poll(2).


    diag = ::tcgetattr(u_ttyfd, &u_term_attr_orig);
    if (diag == -1) {
    u_logger->log("%s: Unable to get attributes for '%s': %s\n",
    u_appname, devname, strerror(errno));
    goto leave;
    }

    u_term_attr_cur = u_term_attr_orig;
    ::cfmakeraw(&u_term_attr_cur);
    u_term_attr_cur.c_lflag = 0;
    u_term_attr_cur.c_oflag |= OPOST|ONLCR;

    diag = ::tcsetattr(u_ttyfd, TCSANOW, &u_term_attr_cur);
    if (diag == -1) {
    u_logger->log("%s: Unable to set attributes for '%s': %s\n",
    u_appname, devname, strerror(errno));
    goto leave;
    }
    u_term_attr_set = true;


    At the moment I don't understand what this code does; I suppose
    I'll have to look up all those flags first.

    The key is cfmakeraw which sets up the attributes
    for raw mode.

    Raw mode

    From the man page

    cfmakeraw() sets the terminal to something like the "raw" mode
    of the old Version 7 terminal driver: input is available character
    by character, echoing is disabled, and all special processing of
    terminal input and output characters is disabled. The terminal
    attributes are set as follows:

    termios_p->c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
    | INLCR | IGNCR | ICRNL | IXON);
    termios_p->c_oflag &= ~OPOST;
    termios_p->c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); termios_p->c_cflag &= ~(CSIZE | PARENB);
    termios_p->c_cflag |= CS8;

    Comes from BSD originally.

    (You can ignore the leading :: on system calls, that's a C++-ism).

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Nicolas George on Tue Dec 19 20:55:19 2023
    On 2023-12-19, Nicolas George <nicolas$george@salle-s.org> wrote:
    Scott Lurndal, dans le message <92kgN.11545$5Hnd.7072@fx03.iad>, a
    écrit :
    Use poll(2) instead of read(2). IIRC, O_NONBLOCK doesn't necessarily
    apply to PTYs.

    O_NONBLOCK applies to ptys, and if it did not then poll() would not either.

    I don't believe that true. There is no requirement that non-blocking
    objects be used with poll, at least if you are only reading.

    When a descriptor polls positive for input, then a subsequent input
    operation will not block. There is no requirement to use O_NONBLOCK, or
    for the device to support it.

    You need O_NONBLOCK if you're polling for writing, because a positive
    write poll only tells you that there is some buffer space available,
    without indicating how much. If the device is blocking and the
    subsequent write is too large, it can still block.

    However, I think, logically, one byte must be guaranteed: if a blocking
    device polls positive for writing, we can be confident we can do a one
    byte write without blocking, provided the device isn't shared with
    any other process that could stuff it behind our back.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Tue Dec 19 21:06:54 2023
    On 2023-12-19, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    This is fine. It's not fully raw. For instance, the Ctrl-C (or
    whatever is your break character) to SIGINT mapping is still active.

    Maybe you want that; not every character-at-a-time-input program
    wants to disable Ctrl-C; just those that handle it as a character
    and implement it themselves. See IGNBRK, BRKINT.

    E.g. in an interpreted language's listener, we want Ctrl-C to
    just cancel the current line of input and start a new one.
    A nice way to do that is to just treat it as a command character,
    rather than mess around with signals.

    I think that in non-canonical mode, CR-NL translation is
    may still be in effect (ICRNL, INLCR). If you want that raw,
    those have t obe turned off.

    You can experiment with all these flags in a shell script,
    since they are available via stty.

    You can do a precise one byte read from the tty using:

    dd bs=1 count=1

    But when code is running, we do want the interrupt, so we flip out
    of that raw mode when the command line is not being edited.

    Be sure to save the tty state using

    tty_state=$(stty -g)

    that returns a string which can be passed as an argument to stty
    to restore the settings (like in an EXIT or INT trap of the
    shell script). I think, POSIX says that this stty -g string does
    not require quoting:

    stty $tty_state

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Scott Lurndal on Tue Dec 19 21:53:47 2023
    On 19.12.2023 21:30, Scott Lurndal wrote:
    [...]

    So far I haven't stumbled across cfmakeraw(), thanks.

    And thanks for the explanations.


    (You can ignore the leading :: on system calls, that's a C++-ism).

    I'm familiar with C++ ::-)

    Janis ;-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Scott Lurndal@21:1/5 to Andreas Kempe on Tue Dec 19 22:12:27 2023
    Andreas Kempe <kempe@lysator.liu.se> writes:
    Den 2023-12-19 skrev Kaz Kylheku <433-929-6894@kylheku.com>:
    On 2023-12-19, Nicolas George <nicolas$george@salle-s.org> wrote:
    Scott Lurndal, dans le message <92kgN.11545$5Hnd.7072@fx03.iad>, a
    écrit :
    Use poll(2) instead of read(2). IIRC, O_NONBLOCK doesn't necessarily
    apply to PTYs.

    O_NONBLOCK applies to ptys, and if it did not then poll() would not either. >>
    I don't believe that true. There is no requirement that non-blocking
    objects be used with poll, at least if you are only reading.

    When a descriptor polls positive for input, then a subsequent input
    operation will not block. There is no requirement to use O_NONBLOCK, or
    for the device to support it.


    You're right that O_NONBLOCK is not needed for polling since polling
    consists of the polling process asking the driver if it has data
    available and if the device doesn't, the process is put to sleep until
    data is available or the timeout is hit.

    On the other hand, I can't really imagine a scenario where it would
    make sense for a device to be pollable, but not support non-blocking
    reads. If you can tell whether data is ready, you should be able to
    support non-blocking reads.

    int diag = ioctl(tty_fd, FIONREAD, &num_to_read);

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Andreas Kempe@21:1/5 to All on Tue Dec 19 21:59:45 2023
    Den 2023-12-19 skrev Kaz Kylheku <433-929-6894@kylheku.com>:
    On 2023-12-19, Nicolas George <nicolas$george@salle-s.org> wrote:
    Scott Lurndal, dans le message <92kgN.11545$5Hnd.7072@fx03.iad>, a
    écrit :
    Use poll(2) instead of read(2). IIRC, O_NONBLOCK doesn't necessarily
    apply to PTYs.

    O_NONBLOCK applies to ptys, and if it did not then poll() would not either.

    I don't believe that true. There is no requirement that non-blocking
    objects be used with poll, at least if you are only reading.

    When a descriptor polls positive for input, then a subsequent input
    operation will not block. There is no requirement to use O_NONBLOCK, or
    for the device to support it.


    You're right that O_NONBLOCK is not needed for polling since polling
    consists of the polling process asking the driver if it has data
    available and if the device doesn't, the process is put to sleep until
    data is available or the timeout is hit.

    On the other hand, I can't really imagine a scenario where it would
    make sense for a device to be pollable, but not support non-blocking
    reads. If you can tell whether data is ready, you should be able to
    support non-blocking reads.

    You need O_NONBLOCK if you're polling for writing, because a positive
    write poll only tells you that there is some buffer space available,
    without indicating how much. If the device is blocking and the
    subsequent write is too large, it can still block.

    However, I think, logically, one byte must be guaranteed: if a blocking device polls positive for writing, we can be confident we can do a one
    byte write without blocking, provided the device isn't shared with
    any other process that could stuff it behind our back.


    Depends on the implementation in the driver being polled really. A
    sane implementation would of course not signal that it is ready for
    writing unless it has some space available. In a multi-processor
    system, or for a device conceivably being shared with some other
    hardware, you could have races for the buffer space. You would then
    likely get an EAGAIN error when you try to write, indicating that no
    space is available. This is of course also true for non-blocking reads
    with parallel access.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Nicolas George@21:1/5 to All on Tue Dec 19 22:28:43 2023
    [The reply has not reached my server, I reply to this one:]

    Den 2023-12-19 skrev Kaz Kylheku <433-929-6894@kylheku.com>:
    O_NONBLOCK applies to ptys, and if it did not then poll() would not either.
    I don't believe that true. There is no requirement that non-blocking
    objects be used with poll, at least if you are only reading.

    When a descriptor polls positive for input, then a subsequent input
    operation will not block. There is no requirement to use O_NONBLOCK, or
    for the device to support it.

    Read better: I have not said that you had to use non-blocking IO along with poll, I have said that if O_NONBLOCK does not work, the poll() does not work either.

    If you think I am wrong, then just provide a counter-example.

    But you will not be able to, because non-blocking IO and pollable IO are internally the same thing.

    (Strange OS-specific devices might not respect that statement; that is irrelevant for the discussion.)

    Scott Lurndal, dans le message <fzogN.78580$7sbb.66186@fx16.iad>, a
    écrit :
    int diag = ioctl(tty_fd, FIONREAD, &num_to_read);

    Are you trying to say something?

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Muttley@dastardlyhq.com@21:1/5 to Janis Papanagnou on Wed Dec 20 09:10:00 2023
    On Tue, 19 Dec 2023 20:02:46 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 19.12.2023 11:04, Muttley@dastardlyhq.com wrote:
    On Tue, 19 Dec 2023 10:46:02 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    I've never had to use that, try removing it to see if it helps.

    I am confused. - I removed that fcntl() call completely and the output
    wasn't affected any more in the observed negative way. - Why that?
    Don't I need to use non-blocking I/O for a poll?
    (Or is maybe buf.c_cc[VMIN] = 1 serving the same purpose?)
    But why has a non-blocking input definition an effect on _output_?
    You see me puzzled.


    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Instead of TCSAFLUSH try TCSANOW [...]

    I tried this change, but it had no visible effect (neither to the good
    nor to the bad).

    Sorry I can't help any more. The above code has always worked for me.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Muttley@dastardlyhq.com on Wed Dec 20 12:32:42 2023
    On 20.12.2023 10:10, Muttley@dastardlyhq.com wrote:
    On Tue, 19 Dec 2023 20:02:46 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    On 19.12.2023 11:04, Muttley@dastardlyhq.com wrote:
    On Tue, 19 Dec 2023 10:46:02 +0100
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:

    fcntl (STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);

    I've never had to use that, try removing it to see if it helps.

    I am confused. - I removed that fcntl() call completely and the output
    wasn't affected any more in the observed negative way. - Why that?
    Don't I need to use non-blocking I/O for a poll?
    (Or is maybe buf.c_cc[VMIN] = 1 serving the same purpose?)
    But why has a non-blocking input definition an effect on _output_?
    You see me puzzled.


    struct termios buf;
    buf.c_lflag &= ~(ECHO | ICANON);
    buf.c_cc[VMIN] = 1;
    buf.c_cc[VTIME] = 0;
    tcsetattr(fd, TCSAFLUSH, &buf);

    Instead of TCSAFLUSH try TCSANOW [...]

    I tried this change, but it had no visible effect (neither to the good
    nor to the bad).

    Sorry I can't help any more. The above code has always worked for me.

    Just to clarify; your suggestion to remove the fcntl() call already
    solved the issue! [*]

    Your proposal also works with TCSAFLUSH, so TCSANOW at least doesn't
    seem necessary. Since you said I should "try" TCSANOW - which seemed
    to imply no strict reason to use it - I also wanted to give feedback
    on that part.

    So thanks again. I don't know *why* it works (or rather, why it didn't
    work before), but now [without the fcntl()] it does. :-)

    Thanks also to all the other posters who helped clarifying the issue,
    for the suggestions, and discussions!

    Janis

    [*] It would certainly have been good if I'd understand why the fcntl()
    on stdin was in the way, and why it affected output. - But okay, that's
    just my honest desire to try to understand what I'm doing. ;-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Wed Dec 20 18:10:52 2023
    On 2023-12-20, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    Your proposal also works with TCSAFLUSH, so TCSANOW at least doesn't
    seem necessary. Since you said I should "try" TCSANOW - which seemed
    to imply no strict reason to use it - I also wanted to give feedback
    on that part.

    TCSAFLUSH is evil; if your user is a fast typist who can enter keyboard
    input before your program has initialized, they will find that their
    buffered keystrokes were lost. You won't easily see it in a small
    program whose executable and libraries are cache hot, and which doesn't
    read a lot of startup files and such.

    (Vim does this annoying flush thing. I posted about it to the mailing
    list many years ago and was rudely dismissed.)

    If you only care about changing input parameters, you want TCSANOW.
    If any of your options affect output, you may want any previously
    written, buffered output (not just by your program but anything that
    came before!) to be drained before the changes take effect, for
    which there is TCSADRAIN.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Janis Papanagnou on Wed Dec 20 18:18:42 2023
    On 2023-12-20, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    So thanks again. I don't know *why* it works (or rather, why it didn't
    work before), but now [without the fcntl()] it does. :-)

    Are you using C stdio after setting STDIN_FILENO to nonblocking?

    If so, you will be constantly getting errors on stdin whenever the
    underlying descriptor returns EWOULDBLOCK. Every time that happens
    you have to call clearerr(stdin).

    The only reason you'd want the descriptor nonblocking is that your
    program has some busy calculation to do during which it needs to
    periodically check for TTY input.

    As soon as your program has nothing to do but wait for input,
    you'd need to use poll() or select(), or else switch the descriptor
    to blocking again. So as not to sit in a tight loop calling the
    nonblocking read.

    [*] It would certainly have been good if I'd understand why the fcntl()
    on stdin was in the way, and why it affected output. - But okay, that's
    just my honest desire to try to understand what I'm doing. ;-)

    Probably because your program blows through the non-blocking reads,
    which affects its behavior. Output that would not have been produced
    until a keystroke is read is now produced immediately, or whatever.



    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kaz Kylheku on Thu Dec 21 10:43:03 2023
    On 20.12.2023 19:10, Kaz Kylheku wrote:

    TCSAFLUSH is evil; if your user is a fast typist who can enter keyboard
    input before your program has initialized, they will find that their
    buffered keystrokes were lost. You won't easily see it in a small
    program whose executable and libraries are cache hot, and which doesn't
    read a lot of startup files and such.

    This may actually be a good property in my case; I want to use only
    the keystrokes that are typed after initialization. (It's also just
    a "small program"; a game that prints some hints and waits to start
    after a keystroke, and then gets controlled by further keystrokes.)

    [...]

    If you only care about changing input parameters, you want TCSANOW.
    If any of your options affect output, you may want any previously
    written, buffered output (not just by your program but anything that
    came before!) to be drained before the changes take effect, for
    which there is TCSADRAIN.

    Okay, thanks.

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Kaz Kylheku on Thu Dec 21 10:48:36 2023
    On 20.12.2023 19:18, Kaz Kylheku wrote:
    On 2023-12-20, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    So thanks again. I don't know *why* it works (or rather, why it didn't
    work before), but now [without the fcntl()] it does. :-)

    Are you using C stdio after setting STDIN_FILENO to nonblocking?

    I had been using C stdout after setting STDIN_FILENO to nonblocking
    but not C stdin; input came solely from the keystroke "commands".


    If so, you will be constantly getting errors on stdin whenever the
    underlying descriptor returns EWOULDBLOCK. Every time that happens
    you have to call clearerr(stdin).

    The only reason you'd want the descriptor nonblocking is that your
    program has some busy calculation to do during which it needs to
    periodically check for TTY input.

    This is the case. It constantly does something and the processing is
    only affected by the ad hoc keystrokes.


    As soon as your program has nothing to do but wait for input,
    you'd need to use poll() or select(), or else switch the descriptor
    to blocking again. So as not to sit in a tight loop calling the
    nonblocking read.

    When the processing steps are done for all simulated entities the
    program calls usleep() for a calculated well defined period and gets effectively suspended.


    [*] It would certainly have been good if I'd understand why the fcntl()
    on stdin was in the way, and why it affected output. - But okay, that's
    just my honest desire to try to understand what I'm doing. ;-)

    Probably because your program blows through the non-blocking reads,
    which affects its behavior. Output that would not have been produced
    until a keystroke is read is now produced immediately, or whatever.

    The effect was the opposite; that output that had previously been
    created did not show up any more. (After removing the non-blocking
    _input_ control setting the _output_ showed up again, as desired.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julieta Shem@21:1/5 to Kaz Kylheku on Thu Dec 21 15:44:00 2023
    Kaz Kylheku <433-929-6894@kylheku.com> writes:

    On 2023-12-20, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    Your proposal also works with TCSAFLUSH, so TCSANOW at least doesn't
    seem necessary. Since you said I should "try" TCSANOW - which seemed
    to imply no strict reason to use it - I also wanted to give feedback
    on that part.

    TCSAFLUSH is evil; if your user is a fast typist who can enter keyboard
    input before your program has initialized, they will find that their
    buffered keystrokes were lost. You won't easily see it in a small
    program whose executable and libraries are cache hot, and which doesn't
    read a lot of startup files and such.

    (Vim does this annoying flush thing. I posted about it to the mailing
    list many years ago and was rudely dismissed.)

    Lol. Do you have a message-id or something? I'd love to have a look.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Kaz Kylheku@21:1/5 to Julieta Shem on Thu Dec 21 22:07:12 2023
    On 2023-12-21, Julieta Shem <jshem@yaxenu.org> wrote:
    Kaz Kylheku <433-929-6894@kylheku.com> writes:

    On 2023-12-20, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote:
    Your proposal also works with TCSAFLUSH, so TCSANOW at least doesn't
    seem necessary. Since you said I should "try" TCSANOW - which seemed
    to imply no strict reason to use it - I also wanted to give feedback
    on that part.

    TCSAFLUSH is evil; if your user is a fast typist who can enter keyboard
    input before your program has initialized, they will find that their
    buffered keystrokes were lost. You won't easily see it in a small
    program whose executable and libraries are cache hot, and which doesn't
    read a lot of startup files and such.

    (Vim does this annoying flush thing. I posted about it to the mailing
    list many years ago and was rudely dismissed.)

    Lol. Do you have a message-id or something? I'd love to have a look.

    According to my own mail archives, I first posted about it to the
    vim@vim.org mailing list on 2012-03-27 with the subject
    "Typeahead character loss when running Vim.".

    I think I got no reply, so I pinged the topic, sme subject line with Re: prepended, on 2014-02-18, almost two years later.

    I don't see any of the replies in my archives, though I subscribed
    to the list at the time. I might have looked at the archive for
    the reply.

    --
    TXR Programming Language: http://nongnu.org/txr
    Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal
    Mastodon: @Kazinator@mstdn.ca
    NOTE: If you use Google Groups, I don't see you, unless you're whitelisted.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julieta Shem@21:1/5 to Kaz Kylheku on Fri Dec 22 02:33:51 2023
    Kaz Kylheku <433-929-6894@kylheku.com> writes:

    On 2023-12-21, Julieta Shem <jshem@yaxenu.org> wrote:
    Kaz Kylheku <433-929-6894@kylheku.com> writes:

    On 2023-12-20, Janis Papanagnou <janis_papanagnou+ng@hotmail.com> wrote: >>>> Your proposal also works with TCSAFLUSH, so TCSANOW at least doesn't
    seem necessary. Since you said I should "try" TCSANOW - which seemed
    to imply no strict reason to use it - I also wanted to give feedback
    on that part.

    TCSAFLUSH is evil; if your user is a fast typist who can enter keyboard
    input before your program has initialized, they will find that their
    buffered keystrokes were lost. You won't easily see it in a small
    program whose executable and libraries are cache hot, and which doesn't
    read a lot of startup files and such.

    (Vim does this annoying flush thing. I posted about it to the mailing
    list many years ago and was rudely dismissed.)

    Lol. Do you have a message-id or something? I'd love to have a look.

    According to my own mail archives, I first posted about it to the
    vim@vim.org mailing list on 2012-03-27 with the subject
    "Typeahead character loss when running Vim.".

    I think I got no reply, so I pinged the topic, sme subject line with Re: prepended, on 2014-02-18, almost two years later.

    I don't see any of the replies in my archives, though I subscribed
    to the list at the time. I might have looked at the archive for
    the reply.

    You got two replies in 2014. Have a look at

    https://groups.google.com/g/vim_use/c/XX6SoxHAzhI

    That's how nice it is to have a decent USENET archive. Soon we won't
    count on this one, but we won't miss the spam either. Speaking of
    Google Groups, it is itself the archive pointed out by the vim mail list homepage at https://www.vim.org/maillist.php. Now, when I went to the
    archive, I could not find your message at all, but duckduckgo.com
    readily located at Google Groups. (It's nice to have an archive, even
    if it's not searchable.)

    What e-mail client were you using then? It seems to have inserted line
    breaks not where you really wanted.

    (*) Your message

    --8<---------------cut here---------------start------------->8---
    Hello?

    I asked this nearly two years ago; doesn't anyone else have this
    problem?

    Is it fixed in newer versions of Vim?

    On an Ubuntu 11.04 which has a dated version of Vim, if I do this:

    $ vim some_file

    and upon hitting enter, immediately type, "io", sometimes Vim ends up in command mode as if nothing was typed, then sometimes it ends up in an
    insert on the same line, and the character o has been entered, as
    expected.
    Most of the time, though, one of the other four possibilities happens,
    based on which of the two characters is dropped, or both: it's in
    command
    mode, insert mode on the same line, or insert mdoe with a new line
    having
    been o)pened.

    On 27.03.2012 14:33, Kaz Kylheku wrote:
    I'm using Vim 7.3 on Ubuntu 11.x.

    When I run $ vim file.txt from the shell, and start typing a command
    like /quicksort,
    some of the characters end up missing. It might end up /quickt.

    I type very fast and can queue up quite a bunch of keystrokes, which I
    expect to be executed properly.

    This is especially annoying when the character loss turns a harmless positioning
    command into an edit which then has to be undone.

    Looks like Vim may be discarding some characters (or telling the TTY
    driver to do that).

    --
    Memorize Japanese Characters with Tankan.
    --8<---------------cut here---------------end--------------->8---

    (*) Reply by Gary Johnson

    --8<---------------cut here---------------start------------->8---
    I had this problem years ago at a different company when I had an X
    server running on my desktop machine and I ran vim on a server in
    the back room. I think the terminal was running on the desktop
    machine.

    As I recall, the problem was due to the terminal response sequence
    arriving late so that vim thought all or part of it was coming from
    the keyboard. Also as I recall, my solution was to set t_RV to an
    empty string and set 'ttymouse' to "xterm2" since vim was then
    unable to determine the value of 'ttymouse' from the terminal
    response.

    To find out more about t_RV,

    :helpgrep t_RV

    I don't know if this has been fixed or not. I haven't seen the
    problem since changing companies and running everything on the
    back-room servers with NoMachine on my Windows desktop. I did see a
    problem for a while with the terminal response sequence interfering
    with vimdiffs, but I haven't seen that for maybe a year.

    HTH,
    Gary
    --8<---------------cut here---------------end--------------->8---

    (*) Reply by Tony Mechelynck

    --8<---------------cut here---------------start------------->8---
    On 19/02/14 01:36, Kaz Kylheku wrote:
    Hello?

    I asked this nearly two years ago; doesn't anyone else have this problem?

    Is it fixed in newer versions of Vim?

    On an Ubuntu 11.04 which has a dated version of Vim, if I do this:

    $ vim some_file

    and upon hitting enter, immediately type, "io", sometimes Vim ends up in command mode as if nothing was typed, then sometimes it ends up in an
    insert on the same line, and the character o has been entered, as expected. Most of the time, though, one of the other four possibilities happens,
    based on which of the two characters is dropped, or both: it's in command mode, insert mode on the same line, or insert mdoe with a new line having been o)pened.

    If you type something "immediately" after invoking Vim from the sh command-line, then there is a race condition between the human typing at
    the keyboard and the system loading and starting Vim. I would expect
    that the io input would or would not be received, or even might be
    received only partly, by Vim, depending on who wins the race.

    A possible reason for this race condition to exist (rather than Vim
    using the system's keyboard-typeahead buffer as found as startup) is
    that when running in an xterm, Vim tries to determine the xterm version
    by querying the xterm (sending a control command to the "display") and
    waiting for a corresponding response stream of control characters on its "keyboard" input line. If this is the case you should not experience any
    loss in the non-X Linux consoles (accessed by Ctrl-Alt-F1 to
    Ctrl-Alt-F6; come back to X by Ctrl-Alt-F7 or Ctrl-Alt-F8 depending on
    "I don't know what").

    IMHO the "healthy" way to proceed would be for the human to wait on Vim displaying either the ":intro" splash screen or the contents of the
    first editfile before proceeding to type anything at the keyboard. This
    way (i.e. with a wait loop inserted into the human's firmware) it can be guaranteed that there is no race condition, and that Vim is always in a
    known state when the first keyboard byte is sent to the console or X
    interface.


    Best regards,
    Tony.
    --
    I think I'll KILL myself by leaping out of this 14th STORY WINDOW while
    reading ERICA JONG'S poetry!!
    --8<---------------cut here---------------end--------------->8---

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Nuno Silva@21:1/5 to Julieta Shem on Fri Dec 22 07:53:35 2023
    On 2023-12-22, Julieta Shem wrote:

    Kaz Kylheku <433-929-6894@kylheku.com> writes:

    On 2023-12-21, Julieta Shem <jshem@yaxenu.org> wrote:
    Kaz Kylheku <433-929-6894@kylheku.com> writes:
    [...]
    TCSAFLUSH is evil; if your user is a fast typist who can enter keyboard >>>> input before your program has initialized, they will find that their
    buffered keystrokes were lost. You won't easily see it in a small
    program whose executable and libraries are cache hot, and which doesn't >>>> read a lot of startup files and such.

    (Vim does this annoying flush thing. I posted about it to the mailing
    list many years ago and was rudely dismissed.)

    Lol. Do you have a message-id or something? I'd love to have a look.

    According to my own mail archives, I first posted about it to the
    vim@vim.org mailing list on 2012-03-27 with the subject
    "Typeahead character loss when running Vim.".

    I think I got no reply, so I pinged the topic, sme subject line with Re:
    prepended, on 2014-02-18, almost two years later.

    I don't see any of the replies in my archives, though I subscribed
    to the list at the time. I might have looked at the archive for
    the reply.

    You got two replies in 2014. Have a look at

    https://groups.google.com/g/vim_use/c/XX6SoxHAzhI

    [...]

    The post I'm replying to already has the contents of the 2014 post and
    of its two replies, I'm just mentioning the Message-IDs in case these
    are useful (although, as this is a mailing list, it's possible Google
    groups actually does give access to the Message-IDs?):

    The 2012 post:
    - <64a254c0-ac6e-4492-9931-703430ed7708@mq9g2000pbb.googlegroups.com>

    The 2014 posts:
    - <172e41b39c870080ba1ceae3774ca678@mail.kylheku.com>
    - <20140219031500.GD1648@phoenix>
    - <530442A1.7020708@gmail.com>

    These are all on gmane too. If you have a browser that can load news:
    URLs:
    - news://news.gmane.io/64a254c0-ac6e-4492-9931-703430ed7708@mq9g2000pbb.googlegroups.com
    - news://news.gmane.io/172e41b39c870080ba1ceae3774ca678@mail.kylheku.com
    - news://news.gmane.io/20140219031500.GD1648@phoenix
    - news://news.gmane.io/530442A1.7020708@gmail.com

    (I don't see line break issues in the 2014 posts, is it possible these
    are being added by the google groups interface?)

    --
    Nuno Silva

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Janis Papanagnou@21:1/5 to Julieta Shem on Fri Dec 22 12:48:55 2023
    On 22.12.2023 06:33, Julieta Shem wrote:
    [ from the archives; character loss on Vim startup ]

    On 27.03.2012 14:33, Kaz Kylheku wrote:

    When I run $ vim file.txt from the shell, and start typing a command
    like /quicksort,
    some of the characters end up missing. It might end up /quickt.

    For this specific but not uncommon usecase - to start and immediately
    locate the desired place - you could work around the issue by starting

    $ vim +/quicksort file.txt

    instead of

    $ vim file.txt
    /quicksort

    Doesn't address the Vim issue directly but may result in a better user experience of the interface for fast typers.

    (It certainly will be difficult to change habits, though, to relocate
    the first command to the vim call. Myself I also first start the tool.)

    Janis

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Julieta Shem@21:1/5 to Janis Papanagnou on Fri Dec 22 17:27:42 2023
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:

    On 22.12.2023 06:33, Julieta Shem wrote:
    [ from the archives; character loss on Vim startup ]

    On 27.03.2012 14:33, Kaz Kylheku wrote:

    When I run $ vim file.txt from the shell, and start typing a command
    like /quicksort,
    some of the characters end up missing. It might end up /quickt.

    For this specific but not uncommon usecase - to start and immediately
    locate the desired place - you could work around the issue by starting

    $ vim +/quicksort file.txt

    instead of

    $ vim file.txt
    /quicksort

    Doesn't address the Vim issue directly but may result in a better user experience of the interface for fast typers.

    (It certainly will be difficult to change habits, though, to relocate
    the first command to the vim call. Myself I also first start the tool.)

    I would bet Kaz Kylheku was just reporting the flaw, which apparently
    the maintainers of the software couldn't care enough. Is that why we
    all run EMACS? :-)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Rainer Weikusat@21:1/5 to Janis Papanagnou on Wed Dec 27 17:56:24 2023
    Janis Papanagnou <janis_papanagnou+ng@hotmail.com> writes:
    On 19.12.2023 18:04, Scott Lurndal wrote:

    Use poll(2) instead of read(2). [...]

    int poll(struct pollfd *fds, nfds_t nfds, int timeout);

    It isn't explicitly mentioned in the man-page, but I assume a
    timeout value of 0 will actually do the non-blocking behavior
    with poll(2).

    SUS says

    If the value of timeout is 0, poll() shall return immediately.

    https://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html

    The Linux man page has this as

    Specifying a timeout of zero causes poll() to return immediately, even
    if no file descriptors are ready.

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)