[git commit master 1/1] getty: wait up to 5 seconds for the output buffer to drain

Denys Vlasenko vda.linux at googlemail.com
Wed Jan 26 14:15:19 UTC 2011


commit: http://git.busybox.net/busybox/commit/?id=ddd1ec1c279da19a79238ce9df820d79415fa33a
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Peter Korsgaard <jacmet at sunsite.dk>
Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 loginutils/getty.c |   56 ++++++++++++++++++++++++++++++---------------------
 1 files changed, 33 insertions(+), 23 deletions(-)

diff --git a/loginutils/getty.c b/loginutils/getty.c
index 2d2184a..0355341 100644
--- a/loginutils/getty.c
+++ b/loginutils/getty.c
@@ -224,6 +224,12 @@ static void open_tty(void)
 	}
 }
 
+static void set_termios(void)
+{
+	if (tcsetattr_stdin_TCSANOW(&G.termios) < 0)
+		bb_perror_msg_and_die("tcsetattr");
+}
+
 /* We manipulate termios this way:
  * - first, we read existing termios settings
  * - termios_init modifies some parts and sets it
@@ -233,25 +239,31 @@ static void open_tty(void)
  */
 static void termios_init(int speed)
 {
-	/* Flush input and output queues, important for modems!
-	 * Users report losing previously queued output chars, and I hesitate
-	 * to use tcdrain here instead of tcflush - I imagine it can block.
-	 * Using small sleep instead.
+	/* Try to drain output buffer, with 5 sec timeout.
+	 * Added on request from users of ~600 baud serial interface
+	 * with biggish buffer on a 90MHz CPU.
+	 * They were losing hundreds of bytes of buffered output
+	 * on tcflush.
 	 */
-	usleep(100*1000); /* 0.1 sec */
+	signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo);
+	alarm(5);
+	tcdrain(STDIN_FILENO);
+	alarm(0);
+	signal(SIGALRM, SIG_DFL); /* do not break -t TIMEOUT! */
+
+	/* Flush input and output queues, important for modems! */
 	tcflush(STDIN_FILENO, TCIOFLUSH);
 
 	/* Set speed if it wasn't specified as "0" on command line */
 	if (speed != B0)
 		cfsetspeed(&G.termios, speed);
 
-	/*
-	 * Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
+	/* Initial termios settings: 8-bit characters, raw-mode, blocking i/o.
 	 * Special characters are set after we have read the login name; all
 	 * reads will be done in raw mode anyway. Errors will be dealt with
 	 * later on.
 	 */
-	/* 8 bits; hangup (drop DTR) on last close; enable receive */
+	/* 8 bits; hang up (drop DTR) on last close; enable receive */
 	G.termios.c_cflag = CS8 | HUPCL | CREAD;
 	if (option_mask32 & F_LOCAL) {
 		/* ignore Carrier Detect pin:
@@ -266,9 +278,8 @@ static void termios_init(int speed)
 #endif
 	/* Other bits in c_cflag:
 	 * CSTOPB 2 stop bits (1 otherwise)
-	 * PARENB Enable parity bit
-	 * PARODD Use odd parity (else even)
-	 * LOBLK  Block job control output (??)
+	 * PARENB Enable parity bit (both on input and output)
+	 * PARODD Odd parity (else even)
 	 */
 	G.termios.c_iflag = 0;
 	G.termios.c_lflag = 0;
@@ -281,7 +292,7 @@ static void termios_init(int speed)
 	G.termios.c_line = 0;
 #endif
 
-	tcsetattr_stdin_TCSANOW(&G.termios);
+	set_termios();
 
 	debug("term_io 2\n");
 }
@@ -309,8 +320,8 @@ static void termios_final(void)
 	 * ICRNL   Map CR to NL
 	 * IUCLC   Map uppercase to lowercase
 	 * IMAXBEL Echo BEL on input line too long
-	 * IUTF8   [Appears to affect tty's idea of char widths,
-	 *         observed to improve backspacing through Unicode chars]
+	 * IUTF8   Appears to affect tty's idea of char widths,
+	 *         observed to improve backspacing through Unicode chars
          */
 
 	/* line buffered input (NL or EOL or EOF chars end a line);
@@ -324,16 +335,16 @@ static void termios_final(void)
 	/* Other bits in c_lflag:
 	 * XCASE   Map uppercase to \lowercase [tried, doesn't work]
 	 * ECHONL  Echo NL even if ECHO is not set
+	 * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this?
+	 * ECHOPRT On erase, echo erased chars
+	 *         [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
 	 * NOFLSH  Don't flush input buffer after interrupt or quit chars
 	 * IEXTEN  Enable extended functions (??)
 	 *         [glibc says it enables c_cc[LNEXT] "enter literal char"
 	 *         and c_cc[VDISCARD] "toggle discard buffered output" chars]
-	 * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this?
-	 * ECHOPRT On erase, echo erased chars
-	 *         [qwe<BS><BS><BS> input looks like "qwe\ewq/" on screen]
 	 * FLUSHO  Output being flushed (c_cc[VDISCARD] is in effect)
 	 * PENDIN  Retype pending input at next read or input char
-	 *         (c_cc[VREPRINT] is being processes)
+	 *         (c_cc[VREPRINT] is being processed)
 	 * TOSTOP  Send SIGTTOU for background output
 	 *         (why "stty sane" unsets this bit?)
 	 */
@@ -358,8 +369,7 @@ static void termios_final(void)
 	 * VSTART, VSTOP - chars used for IXON/IXOFF
 	 */
 
-	if (tcsetattr_stdin_TCSANOW(&G.termios) < 0)
-		bb_perror_msg_and_die("tcsetattr");
+	set_termios();
 }
 
 /* extract baud rate from modem status message */
@@ -383,7 +393,7 @@ static void auto_baud(void)
 	 */
 
 	G.termios.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */
-	tcsetattr_stdin_TCSANOW(&G.termios);
+	set_termios();
 
 	/*
 	 * Wait for a while, then read everything the modem has said so far and
@@ -407,7 +417,7 @@ static void auto_baud(void)
 
 	/* Restore terminal settings. Errors will be dealt with later on */
 	G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */
-	tcsetattr_stdin_TCSANOW(&G.termios);
+	set_termios();
 }
 
 /* get user name, establish parity, speed, erase, kill, eol;
@@ -614,7 +624,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv)
 			/* We are here only if G.numspeed > 1 */
 			baud_index = (baud_index + 1) % G.numspeed;
 			cfsetspeed(&G.termios, G.speeds[baud_index]);
-			tcsetattr_stdin_TCSANOW(&G.termios);
+			set_termios();
 		}
 	}
 
-- 
1.7.3.4



More information about the busybox-cvs mailing list