svn commit: r225809 - head/usr.bin/script
Mikolaj Golub
trociny at FreeBSD.org
Tue Sep 27 18:14:05 UTC 2011
Author: trociny
Date: Tue Sep 27 18:14:04 2011
New Revision: 225809
URL: http://svn.freebsd.org/changeset/base/225809
Log:
When script(1) reads EOF from input it starts spinning on zero-byte
reads eating 100% CPU. Fix this by skipping select on STDIN after
reading EOF -- permanently if STDIN is not terminal and for one second
if it is.
Also after reading EOF from STDIN we have to pass it to the program
being scripted. The previous approach was to write zero bytes into the
pseudo-terminal. This does not work because zero-byte write does not
have any effect on read. Fix this by sending VEOF instead.
Submitted by: Ronald Klop <ronald-freebsd8 at klop.yi.org>
Discussed with: kib, Chris Torek <chris.torek at gmail.com>
Approved by: kib
MFC after: 1 week
Modified:
head/usr.bin/script/script.1
head/usr.bin/script/script.c
Modified: head/usr.bin/script/script.1
==============================================================================
--- head/usr.bin/script/script.1 Tue Sep 27 17:54:10 2011 (r225808)
+++ head/usr.bin/script/script.1 Tue Sep 27 18:14:04 2011 (r225809)
@@ -166,3 +166,12 @@ The slave terminal mode is checked
for ECHO mode to check when to avoid manual echo logging.
This does not
work when in a raw mode where the program being run is doing manual echo.
+.Pp
+If the
+.Nm
+reads zero bytes from the terminal it switches to a mode when it probes read
+only once a second until it gets some data.
+This prevents the
+.Nm
+spinning on zero-byte reads, but might cause a 1-second delay in
+processing of the user input.
Modified: head/usr.bin/script/script.c
==============================================================================
--- head/usr.bin/script/script.c Tue Sep 27 17:54:10 2011 (r225808)
+++ head/usr.bin/script/script.c Tue Sep 27 18:14:04 2011 (r225809)
@@ -86,6 +86,7 @@ main(int argc, char *argv[])
char ibuf[BUFSIZ];
fd_set rfd;
int flushtime = 30;
+ int readstdin;
aflg = kflg = 0;
while ((ch = getopt(argc, argv, "aqkt:")) != -1)
@@ -155,19 +156,21 @@ main(int argc, char *argv[])
doshell(argv);
close(slave);
- if (flushtime > 0)
- tvp = &tv;
- else
- tvp = NULL;
-
- start = time(0);
- FD_ZERO(&rfd);
+ start = tvec = time(0);
+ readstdin = 1;
for (;;) {
+ FD_ZERO(&rfd);
FD_SET(master, &rfd);
- FD_SET(STDIN_FILENO, &rfd);
- if (flushtime > 0) {
- tv.tv_sec = flushtime;
+ if (readstdin)
+ FD_SET(STDIN_FILENO, &rfd);
+ if ((!readstdin && ttyflg) || flushtime > 0) {
+ tv.tv_sec = !readstdin && ttyflg ? 1 :
+ flushtime - (tvec - start);
tv.tv_usec = 0;
+ tvp = &tv;
+ readstdin = 1;
+ } else {
+ tvp = NULL;
}
n = select(master + 1, &rfd, 0, 0, tvp);
if (n < 0 && errno != EINTR)
@@ -176,8 +179,13 @@ main(int argc, char *argv[])
cc = read(STDIN_FILENO, ibuf, BUFSIZ);
if (cc < 0)
break;
- if (cc == 0)
- (void)write(master, ibuf, 0);
+ if (cc == 0) {
+ if (tcgetattr(master, &stt) == 0 &&
+ (stt.c_lflag & ICANON) != 0) {
+ (void)write(master, &stt.c_cc[VEOF], 1);
+ }
+ readstdin = 0;
+ }
if (cc > 0) {
(void)write(master, ibuf, cc);
if (kflg && tcgetattr(master, &stt) >= 0 &&
More information about the svn-src-all
mailing list