From: Harvey Chapman <hchapman-linux-kernel@3gfp.com>
To: linux-kernel@vger.kernel.org
Subject: [PATCH] serial inter-character timeout usage with async io
Date: Tue, 07 Aug 2007 18:53:50 -0400 [thread overview]
Message-ID: <46B8F7FE.3090904@3gfp.com> (raw)
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;
next reply other threads:[~2007-08-07 23:25 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-08-07 22:53 Harvey Chapman [this message]
2007-08-08 1:11 ` [PATCH] serial inter-character timeout usage with async io Alan Cox
2007-08-08 2:20 ` Harvey Chapman
2007-08-08 2:31 ` Harvey Chapman
2007-08-08 8:47 ` Alan Cox
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=46B8F7FE.3090904@3gfp.com \
--to=hchapman-linux-kernel@3gfp.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.