Userspace break? read from STDIN returns EAGAIN if tty is "touched"

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

 



All,

I have spent the afternoon trying to track down a regression in a
userspace application between:
4.15.0-43-generic #46-Ubuntu SMP Thu Dec 6 14:45:28 UTC 2018
and
4.15.0-44-generic #47-Ubuntu SMP Mon Jan 14 11:26:59 UTC 2019

After some investigation, I believe
https://github.com/torvalds/linux/commit/c96cf923a98d1b094df9f0cf97a83e118817e31b
"tty: Don't block on IO when ldisc change is pending" is the cause of
this regression.
I have however not yet confirmed this with a single reversion on
master as I am still in the process of setting up a kernel development
environment (yay Australian internet), though I am pretty certain that
this is the case.

I have attached to this email a very short c program, which I believe
shows the issue.
Broadly prior to the introduction of this bug (i.e for the last 5
years), the program would echo back console input (once enter is
pressed), as expected.
After the introduction of this bug, the program immediately terminates
with "Resource temporarily unavailable".

The `fclose(fopen("/dev/tty", "r"));` and echoing user input example
is obviously contrived, but for some real world context, this issue
has manifested itself in a Java application.
At a high level, the application in question uses the JLine 2 Java
library to perform console input/output with "niceties" such as tab
completion, history buffer, colours, etc - all the modern tty
goodness.
As part of this process it retrieves information about the current tty
in a few places - both via C APIs and also looking at /dev/tty. It
needs to do this when writing (whilst reading on a different thread)
in case e.g. characteristics of the tty have changed.

Unfortunately it appears that this bug changes the semantics of
reading from stdin in quite a drastic manner, whereby so much as
glancing at the tty (or at least /dev/tty) from another thread will
cause a current blocking read to error and return prematurely.

I can forsee some arguments that this change in behaviour is ok and
that the calling application (in this case Java and/or the JLine
library) should handle the EAGAIN response, however I reject this for
a couple of reasons:
* That a read from stdin should not return an error if stdin alive is
a previously ok assumption made by both JLine and Java itself, two
userspace applications - c.f. "Don't break userspace".
* Simply peeking at /dev/tty without modifying it or consuming data
(see commented touch example also) should not cause an in progress
read call to fail without good reason.
* There is a good chance other tty users aside from JLine+Java will be
affected by this, it is only in the last few days that the patch has
landed in a popular distro (Ubuntu 18.04), and I can certainly see it
becoming more widespread - especially if backported to another LTS
distro such as RHEL.

If someone could take a look at this I would really appreciate it - I
am not a kernel developer (or even really a C developer), but will do
what I can to assist.

Thanks
Michael


#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char** argv)
{
    if (fork() == 0)
    {
        while (1)
        {
            // Anything that goes near the tty triggers this
            // execl("/bin/sh", "sh", "-c", "stty < /dev/tty", NULL);
            // execl("/usr/bin/touch", "touch", "/dev/tty", NULL);
            fclose(fopen("/dev/tty", "r"));

            sleep(1);
        }
    }

    printf("Enter your input then press enter: ");
    fflush(stdout);

    char c;
    while (read(STDIN_FILENO, &c, 1) > 0)
    {
        printf("Read: %c\n", c);
    }

    printf("\nReturn Code: %s\n", strerror(errno));
}

[Index of Archives]     [Audio]     [Hams]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Samba]     [Fedora Users]

  Powered by Linux