[PATCH] serial inter-character timeout usage with async io

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I'm looking for comments, thanks.

This patch adds a timeout mode to n_tty that will only send SIGIO
signals (for input) when the UART's IIR indicates that a character
timeout has occurred. This reduces overhead by reducing the number of
SIGIO signals sent and consequently the unnecessary wake-ups of a
sleeping process waiting for serial input asynchronously.

two boolean values "timeout_enabled" and "timeout" are added to
tty_struct which enable/disable the mode and record whether an
inter-character timeout occurred during the last interrupt, respectively.

A new ioctl, TIOCSTIMEOUT, is added to set/clear "timeout_enabled." This
seemed to be the cleanest way to do that (that I saw, at least).

In n_tty_receive_buf(), some additional tests were added before the
kill_async() call to accommodate the old behavior and the newer timeout
behavior as well as adding a check to make sure the read buffer doesn't
overflow without a timeout received.

This should be 100% backwards compatible since the timeout mode is
disabled by default.

Currently, I only have this code enabled for i386 and arm, and only for
the 8250 and pxa serial drivers. If no one thinks this is a terrible
idea, I'll modify all of the other ioctl.h files and resubmit the patch.

Thanks,

Harvey


diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/drivers/char/n_tty.c linux-2.6.22.1/drivers/char/n_tty.c
--- linux-2.6.22.1.orig/drivers/char/n_tty.c	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/drivers/char/n_tty.c	2007-08-07 18:23:44.000000000 -0400
@@ -957,7 +957,17 @@ static void n_tty_receive_buf(struct tty

 	n_tty_set_room(tty);

-	if (!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) {
+	/*
+	 * Make sure we're not in canonical mode. If not in timeout mode,
+	 * use vmin setting as usual. If in timeout mode, only send if the
+	 * last interrupt was a timeout. As a last resort, check to make
+	 * sure the read buffer doesn't get too close to full. The factor of
+	 * 4 used is an arbitrary number.
+	 */
+	if (!tty->icanon &&
+	    ((!tty->timeout_enabled && (tty->read_cnt >= tty->minimum_to_wake)) ||
+	     tty->timeout ||
+	     tty->receive_room < (4 * TTY_THRESHOLD_THROTTLE))) {
 		kill_fasync(&tty->fasync, SIGIO, POLL_IN);
 		if (waitqueue_active(&tty->read_wait))
 			wake_up_interruptible(&tty->read_wait);
diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/drivers/char/tty_ioctl.c
linux-2.6.22.1/drivers/char/tty_ioctl.c
--- linux-2.6.22.1.orig/drivers/char/tty_ioctl.c	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/drivers/char/tty_ioctl.c	2007-08-07
15:11:23.000000000 -0400
@@ -852,6 +852,15 @@ int n_tty_ioctl(struct tty_struct * tty,
 				 (arg ? CLOCAL : 0));
 			mutex_unlock(&tty->termios_mutex);
 			return 0;
+
+		case TIOCSTIMEOUT:
+			if (get_user(arg, (unsigned int __user *) arg))
+				return -EFAULT;
+			tty->timeout_enabled = (arg ? 1 : 0);
+			tty->minimum_to_wake = 0;
+			MIN_CHAR(tty) = 0;
+			return 0;
+
 		default:
 			return -ENOIOCTLCMD;
 		}
diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/drivers/serial/8250.c
linux-2.6.22.1/drivers/serial/8250.c
--- linux-2.6.22.1.orig/drivers/serial/8250.c	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/drivers/serial/8250.c	2007-08-07 17:29:24.000000000 -0400
@@ -1466,6 +1466,12 @@ static irqreturn_t serial8250_interrupt(

 		iir = serial_in(up, UART_IIR);
 		if (!(iir & UART_IIR_NO_INT)) {
+			/* Flag an inter-character timeout */
+			if (up->port.info->tty->timeout_enabled &&
+			    (iir & UART_IIR_TOD) == UART_IIR_TOD)
+				up->port.info->tty->timeout = 1;
+			else
+				up->port.info->tty->timeout = 0;
 			serial8250_handle_port(up);

 			handled = 1;
diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/drivers/serial/pxa.c linux-2.6.22.1/drivers/serial/pxa.c
--- linux-2.6.22.1.orig/drivers/serial/pxa.c	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/drivers/serial/pxa.c	2007-08-07 17:29:59.000000000 -0400
@@ -238,6 +238,12 @@ static inline irqreturn_t serial_pxa_irq
 	iir = serial_in(up, UART_IIR);
 	if (iir & UART_IIR_NO_INT)
 		return IRQ_NONE;
+	/* Flag an inter-character timeout */
+	if (up->port.info->tty->timeout_enabled &&
+	    (iir & UART_IIR_TOD) == UART_IIR_TOD)
+		up->port.info->tty->timeout = 1;
+	else
+		up->port.info->tty->timeout = 0;
 	lsr = serial_in(up, UART_LSR);
 	if (lsr & UART_LSR_DR)
 		receive_chars(up, &lsr);
diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/include/asm-arm/ioctls.h
linux-2.6.22.1/include/asm-arm/ioctls.h
--- linux-2.6.22.1.orig/include/asm-arm/ioctls.h	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/include/asm-arm/ioctls.h	2007-08-07
15:11:23.000000000 -0400
@@ -69,6 +69,7 @@
 #define TIOCMIWAIT	0x545C	/* wait for a change on serial input line(s) */
 #define TIOCGICOUNT	0x545D	/* read serial port inline interrupt counts */
 #define FIOQSIZE	0x545E
+#define TIOCSTIMEOUT	0x545F

 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/include/asm-i386/ioctls.h
linux-2.6.22.1/include/asm-i386/ioctls.h
--- linux-2.6.22.1.orig/include/asm-i386/ioctls.h	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/include/asm-i386/ioctls.h	2007-08-07
18:33:49.000000000 -0400
@@ -72,6 +72,7 @@
 #define TIOCGHAYESESP   0x545E  /* Get Hayes ESP configuration */
 #define TIOCSHAYESESP   0x545F  /* Set Hayes ESP configuration */
 #define FIOQSIZE	0x5460
+#define TIOCSTIMEOUT	0x5461

 /* Used for packet mode */
 #define TIOCPKT_DATA		 0
diff -urp -x '*.orig' -x '*.rej' -x '*~'
linux-2.6.22.1.orig/include/linux/tty.h linux-2.6.22.1/include/linux/tty.h
--- linux-2.6.22.1.orig/include/linux/tty.h	2007-07-10
14:56:30.000000000 -0400
+++ linux-2.6.22.1/include/linux/tty.h	2007-08-07 15:11:23.000000000 -0400
@@ -227,6 +227,7 @@ struct tty_struct {
 	unsigned int column;
 	unsigned char lnext:1, erasing:1, raw:1, real_raw:1, icanon:1;
 	unsigned char closing:1;
+	unsigned char timeout:1, timeout_enabled:1;
 	unsigned short minimum_to_wake;
 	unsigned long overrun_time;
 	int num_overrun;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux