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)); }