From owner-svn-src-head@FreeBSD.ORG Tue Sep 27 18:14:05 2011 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 056A1106564A; Tue, 27 Sep 2011 18:14:05 +0000 (UTC) (envelope-from trociny@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id DEFCF8FC08; Tue, 27 Sep 2011 18:14:04 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id p8RIE48Y035244; Tue, 27 Sep 2011 18:14:04 GMT (envelope-from trociny@svn.freebsd.org) Received: (from trociny@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id p8RIE4qF035241; Tue, 27 Sep 2011 18:14:04 GMT (envelope-from trociny@svn.freebsd.org) Message-Id: <201109271814.p8RIE4qF035241@svn.freebsd.org> From: Mikolaj Golub Date: Tue, 27 Sep 2011 18:14:04 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r225809 - head/usr.bin/script X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Sep 2011 18:14:05 -0000 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 Discussed with: kib, Chris Torek 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 &&