... 42136 ex RET read -1 errno 35 Resource temporarily unavailable 42136 ex CALL read(0,0x3d94b585400,0xff) 42136 ex RET read -1 errno 35 Resource temporarily unavailable 42136 ex CALL read(0,0x3d94b585400,0xff) ... this condition can be reproduced with:
#include <sys/wait.h> #include <err.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #define TARGET_FD STDIN_FILENO int main(int argc, char *argv[]) { int flags, status; pid_t pid; pid = fork(); if (pid < 0) err(1, "fork failed"); if (pid == 0) { flags = fcntl(TARGET_FD, F_GETFL, 0); if (flags == -1) err(1, "fcntl getfl failed"); flags |= O_NONBLOCK; flags = fcntl(TARGET_FD, F_SETFL, flags); if (flags == -1) err(1, "fcntl setfl failed"); argv++; execvp(*argv, argv); err(1, "execvp failed"); } wait(&status); exit(0); } and then running whatever-the-above-was-compiled-to as ./whatever /usr/bin/ex or also under modern code that for some reason sets O_NONBLOCK and forgets to turn it off when calling out to an editor, hypothetically https://github.com/osa1/tiny and likely other, similar programs. Probably, O_NONBLOCK should be disabled on STDIN_FILENO before calling out to unknown programs. Probably, vi should be patched to not eat CPU when the previous case is not handled. Thoughts? diff --git usr.bin/vi/cl/cl_main.c usr.bin/vi/cl/cl_main.c index 33614c99594..f87a04cad8b 100644 --- usr.bin/vi/cl/cl_main.c +++ usr.bin/vi/cl/cl_main.c @@ -54,7 +54,7 @@ main(int argc, char *argv[]) CL_PRIVATE *clp; GS *gp; size_t rows, cols; - int rval; + int flags, oflags, rval; char *ttype; /* Create and initialize the global structure. */ @@ -89,6 +89,14 @@ main(int argc, char *argv[]) /* Ex wants stdout to be buffered. */ (void)setvbuf(stdout, NULL, _IOFBF, 0); + /* Ensure blocking I/O to avoid 100% CPU on EAGAIN */ + if ((flags = fcntl(STDIN_FILENO, F_GETFL, 0)) == -1) + exit (1); + oflags = flags; + flags &= ~O_NONBLOCK; + if (fcntl(STDIN_FILENO, F_SETFL, flags) == -1) + exit (1); + /* Start catching signals. */ if (sig_init(gp, NULL)) exit (1); @@ -102,6 +110,9 @@ main(int argc, char *argv[]) /* Clean up the terminal. */ (void)cl_quit(gp); + /* Restore flags */ + fcntl(STDIN_FILENO, F_SETFL, oflags); + /* * XXX * Reset the O_MESG option.