Messages in this thread Patch in this message | | | Date | Thu, 28 May 1998 12:09:48 -0400 | From | Bill Hawes <> | Subject | patch for 2.1.103 n_tty.c |
| |
I received a problem report that the 2.1.xx kernels will block for input on a 0 length read from a tty, instead of returning immediately. In other cases (e.g fs reads) there's a test for count == 0 to return immediately, and apparently 2.0.xx kernels don't block.
The attached patch adds a test for nr == 0 before waiting for input. This actually simplifies the code somewhat, as there were three separate places that had to test for nr == 0 as a special case.
The patch also removes some redundant tests for size != 0 and redundant clearing of the TTY_PUSH flag at exit.
I've also fixed a problem in write_chan in that the return from opost_block() wasn't being tested for an error (-EFAULT is possible from the serial driver), which could result in looping and repeated memory faults.
Regards, Bill--- linux-2.1.103/drivers/char/n_tty.c.old Sun Mar 22 11:30:31 1998 +++ linux-2.1.103/drivers/char/n_tty.c Thu May 28 11:27:27 1998 @@ -190,7 +190,7 @@ * opost_block --- to speed up block console writes, among other * things. */ -static int opost_block(struct tty_struct * tty, +static ssize_t opost_block(struct tty_struct * tty, const unsigned char * inbuf, unsigned int nr) { char buf[80]; @@ -863,9 +863,9 @@ static ssize_t read_chan(struct tty_struct *tty, struct file *file, unsigned char *buf, size_t nr) { + unsigned char *b = buf; struct wait_queue wait = { current, NULL }; int c; - unsigned char *b = buf; int minimum, time; ssize_t retval = 0; ssize_t size; @@ -896,25 +896,23 @@ } } - if (tty->icanon) { - minimum = time = 0; - current->timeout = (unsigned long) -1; - } else { + minimum = time = 0; + current->timeout = (unsigned long) -1; + if (!tty->icanon) { time = (HZ / 10) * TIME_CHAR(tty); minimum = MIN_CHAR(tty); if (minimum) { - current->timeout = (unsigned long) -1; if (time) tty->minimum_to_wake = 1; else if (!waitqueue_active(&tty->read_wait) || (tty->minimum_to_wake > minimum)) tty->minimum_to_wake = minimum; } else { + current->timeout = 0; if (time) { current->timeout = time + jiffies; time = 0; - } else - current->timeout = 0; + } tty->minimum_to_wake = minimum = 1; } } @@ -922,10 +920,10 @@ add_wait_queue(&tty->read_wait, &wait); disable_bh(TQUEUE_BH); - while (1) { + while (nr) { /* First test for status change. */ if (tty->packet && tty->link->ctrl_status) { - if (b != buf || !nr) + if (b != buf) break; put_user(tty->link->ctrl_status, b++); nr--; @@ -966,7 +964,7 @@ current->state = TASK_RUNNING; /* Deal with packet mode. */ - if (tty->packet && b == buf && nr) { + if (tty->packet && b == buf) { put_user(TIOCPKT_DATA, b++); nr--; } @@ -1013,7 +1011,7 @@ if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) check_unthrottle(tty); - if (b - buf >= minimum || !nr) + if (b - buf >= minimum) break; if (time) current->timeout = time + jiffies; @@ -1027,25 +1025,27 @@ current->state = TASK_RUNNING; current->timeout = 0; size = b - buf; - if (size && nr) - clear_bit(TTY_PUSH, &tty->flags); - if (!size && test_and_clear_bit(TTY_PUSH, &tty->flags)) - goto do_it_again; - if (!size && !retval) - clear_bit(TTY_PUSH, &tty->flags); - return (size ? size : retval); + if (size) { + retval = size; + if (nr) + clear_bit(TTY_PUSH, &tty->flags); + } else if (test_and_clear_bit(TTY_PUSH, &tty->flags)) + goto do_it_again; + + return retval; } static ssize_t write_chan(struct tty_struct * tty, struct file * file, const unsigned char * buf, size_t nr) { + const unsigned char *b = buf; struct wait_queue wait = { current, NULL }; int c; - const unsigned char *b = buf; - ssize_t retval = 0, num; + ssize_t retval = 0; /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ - if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && + if (L_TOSTOP(tty) && + file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && file->f_dentry->d_inode->i_rdev != SYSCONS_DEV) { retval = tty_check_change(tty); if (retval) @@ -1065,7 +1065,11 @@ } if (O_OPOST(tty) && !(test_bit(TTY_HW_COOK_OUT, &tty->flags))) { while (nr > 0) { - num = opost_block(tty, b, nr); + ssize_t num = opost_block(tty, b, nr); + if (num < 0) { + retval = num; + goto break_out; + } b += num; nr -= num; if (nr == 0) @@ -1081,7 +1085,7 @@ c = tty->driver.write(tty, 1, b, nr); if (c < 0) { retval = c; - break; + goto break_out; } b += c; nr -= c; @@ -1094,6 +1098,7 @@ } schedule(); } +break_out: current->state = TASK_RUNNING; remove_wait_queue(&tty->write_wait, &wait); return (b - buf) ? b - buf : retval; | |