...
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.