diff options
author | Paul Fulghum <paulkf@microgate.com> | 2006-06-28 07:26:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-28 17:59:05 -0400 |
commit | 2c3bb20f46709a0adfa7ea408013edbcab945d5a (patch) | |
tree | 951dde0a4ea31892635886afb1e3f0f03847b1f0 /drivers | |
parent | 817d6d3bceaf34c99f5343820f9b9e6021f0655c (diff) |
[PATCH] add receive_room flow control to flush_to_ldisc
Flush data serially to line discipline in blocks no larger than
tty->receive_room to avoid losing data if line discipline is busy (such as
N_TTY operating at high speed on heavily loaded system) or does not accept
data in large blocks (such as N_MOUSE).
Signed-off-by: Paul Fulghum <paulkf@microgate.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/tty_io.c | 37 |
1 files changed, 24 insertions, 13 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index b846d87f2b56..1f03ebf165d9 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -2771,8 +2771,7 @@ static void flush_to_ldisc(void *private_) | |||
2771 | struct tty_struct *tty = (struct tty_struct *) private_; | 2771 | struct tty_struct *tty = (struct tty_struct *) private_; |
2772 | unsigned long flags; | 2772 | unsigned long flags; |
2773 | struct tty_ldisc *disc; | 2773 | struct tty_ldisc *disc; |
2774 | struct tty_buffer *tbuf; | 2774 | struct tty_buffer *tbuf, *head; |
2775 | int count; | ||
2776 | char *char_buf; | 2775 | char *char_buf; |
2777 | unsigned char *flag_buf; | 2776 | unsigned char *flag_buf; |
2778 | 2777 | ||
@@ -2781,21 +2780,33 @@ static void flush_to_ldisc(void *private_) | |||
2781 | return; | 2780 | return; |
2782 | 2781 | ||
2783 | spin_lock_irqsave(&tty->buf.lock, flags); | 2782 | spin_lock_irqsave(&tty->buf.lock, flags); |
2784 | while((tbuf = tty->buf.head) != NULL) { | 2783 | head = tty->buf.head; |
2785 | while ((count = tbuf->commit - tbuf->read) != 0) { | 2784 | if (head != NULL) { |
2786 | char_buf = tbuf->char_buf_ptr + tbuf->read; | 2785 | tty->buf.head = NULL; |
2787 | flag_buf = tbuf->flag_buf_ptr + tbuf->read; | 2786 | for (;;) { |
2788 | tbuf->read += count; | 2787 | int count = head->commit - head->read; |
2788 | if (!count) { | ||
2789 | if (head->next == NULL) | ||
2790 | break; | ||
2791 | tbuf = head; | ||
2792 | head = head->next; | ||
2793 | tty_buffer_free(tty, tbuf); | ||
2794 | continue; | ||
2795 | } | ||
2796 | if (!tty->receive_room) { | ||
2797 | schedule_delayed_work(&tty->buf.work, 1); | ||
2798 | break; | ||
2799 | } | ||
2800 | if (count > tty->receive_room) | ||
2801 | count = tty->receive_room; | ||
2802 | char_buf = head->char_buf_ptr + head->read; | ||
2803 | flag_buf = head->flag_buf_ptr + head->read; | ||
2804 | head->read += count; | ||
2789 | spin_unlock_irqrestore(&tty->buf.lock, flags); | 2805 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
2790 | disc->receive_buf(tty, char_buf, flag_buf, count); | 2806 | disc->receive_buf(tty, char_buf, flag_buf, count); |
2791 | spin_lock_irqsave(&tty->buf.lock, flags); | 2807 | spin_lock_irqsave(&tty->buf.lock, flags); |
2792 | } | 2808 | } |
2793 | if (tbuf->active) | 2809 | tty->buf.head = head; |
2794 | break; | ||
2795 | tty->buf.head = tbuf->next; | ||
2796 | if (tty->buf.head == NULL) | ||
2797 | tty->buf.tail = NULL; | ||
2798 | tty_buffer_free(tty, tbuf); | ||
2799 | } | 2810 | } |
2800 | spin_unlock_irqrestore(&tty->buf.lock, flags); | 2811 | spin_unlock_irqrestore(&tty->buf.lock, flags); |
2801 | 2812 | ||