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/

Reply via email to