aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorPeter Hurley <peter@hurleysoftware.com>2015-01-16 15:05:34 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-02-02 13:11:26 -0500
commit2c5dc4641ca0e046b432f94f7058c4aff3440e47 (patch)
tree7761dc343a76521f50742234aa996314f2060a32 /drivers/tty
parent62d38099bf9dd0bdb582369b3cd049b67a0f1ac1 (diff)
n_tty: Eliminate receive_room() from consumer/exclusive paths
The input worker never reschedules itself; it only processes input until either there is no more input or the read buffer is full. So the reader is responsible for restarting the input worker only if the read buffer was previously full (no_room == 1) _and_ space is now available to process more input because the reader has consumed data from the read buffer. However, computing the actual space available is not required to determine if the reader has consumed data from the read buffer. This condition is evaluated in 5 situations, each of which the space avail is already known: 1. n_tty_flush_buffer() - the read buffer is empty; kick the worker 2. n_tty_set_termios() - no data has been consumed; do not kick the worker (although it may have kicked the reader so data _will be_ consumed) 3. n_tty_check_unthrottle - avail space > 3968; kick the worker 4. n_tty_read, before leaving - only kick the worker if the reader has moved the tail. This prevents unnecessarily kicking the worker when timeout-style reading is used. 5. n_tty_read, before sleeping - although it is possible for the read buffer to be full and input_available_p() to be false, this can only happen when the input worker is racing the reader, in which case the reader will have been woken and won't sleep. Rename n_tty_set_room() to n_tty_kick_worker() to reflect what the function actually does. Signed-off-by: Peter Hurley <peter@hurleysoftware.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/n_tty.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4ddfa60c9222..b60b043f47d8 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -187,10 +187,10 @@ static int receive_room(struct tty_struct *tty)
187} 187}
188 188
189/** 189/**
190 * n_tty_set_room - receive space 190 * n_tty_kick_worker - start input worker (if required)
191 * @tty: terminal 191 * @tty: terminal
192 * 192 *
193 * Re-schedules the flip buffer work if space just became available. 193 * Re-schedules the flip buffer work if it may have stopped
194 * 194 *
195 * Caller holds exclusive termios_rwsem 195 * Caller holds exclusive termios_rwsem
196 * or 196 * or
@@ -198,12 +198,12 @@ static int receive_room(struct tty_struct *tty)
198 * holds non-exclusive termios_rwsem 198 * holds non-exclusive termios_rwsem
199 */ 199 */
200 200
201static void n_tty_set_room(struct tty_struct *tty) 201static void n_tty_kick_worker(struct tty_struct *tty)
202{ 202{
203 struct n_tty_data *ldata = tty->disc_data; 203 struct n_tty_data *ldata = tty->disc_data;
204 204
205 /* Did this open up the receive buffer? We may need to flip */ 205 /* Did the input worker stop? Restart it */
206 if (unlikely(ldata->no_room) && receive_room(tty)) { 206 if (unlikely(ldata->no_room)) {
207 ldata->no_room = 0; 207 ldata->no_room = 0;
208 208
209 WARN_RATELIMIT(tty->port->itty == NULL, 209 WARN_RATELIMIT(tty->port->itty == NULL,
@@ -274,7 +274,7 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
274 return; 274 return;
275 if (!tty->count) 275 if (!tty->count)
276 return; 276 return;
277 n_tty_set_room(tty); 277 n_tty_kick_worker(tty);
278 n_tty_write_wakeup(tty->link); 278 n_tty_write_wakeup(tty->link);
279 if (waitqueue_active(&tty->link->write_wait)) 279 if (waitqueue_active(&tty->link->write_wait))
280 wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT); 280 wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
@@ -296,7 +296,7 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
296 break; 296 break;
297 if (!tty->count) 297 if (!tty->count)
298 break; 298 break;
299 n_tty_set_room(tty); 299 n_tty_kick_worker(tty);
300 unthrottled = tty_unthrottle_safe(tty); 300 unthrottled = tty_unthrottle_safe(tty);
301 if (!unthrottled) 301 if (!unthrottled)
302 break; 302 break;
@@ -379,7 +379,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
379{ 379{
380 down_write(&tty->termios_rwsem); 380 down_write(&tty->termios_rwsem);
381 reset_buffer_flags(tty->disc_data); 381 reset_buffer_flags(tty->disc_data);
382 n_tty_set_room(tty); 382 n_tty_kick_worker(tty);
383 383
384 if (tty->link) 384 if (tty->link)
385 n_tty_packet_mode_flush(tty); 385 n_tty_packet_mode_flush(tty);
@@ -1817,7 +1817,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
1817 else 1817 else
1818 ldata->real_raw = 0; 1818 ldata->real_raw = 0;
1819 } 1819 }
1820 n_tty_set_room(tty);
1821 /* 1820 /*
1822 * Fix tty hang when I_IXON(tty) is cleared, but the tty 1821 * Fix tty hang when I_IXON(tty) is cleared, but the tty
1823 * been stopped by STOP_CHAR(tty) before it. 1822 * been stopped by STOP_CHAR(tty) before it.
@@ -2130,6 +2129,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2130 ssize_t retval = 0; 2129 ssize_t retval = 0;
2131 long timeout; 2130 long timeout;
2132 int packet; 2131 int packet;
2132 size_t tail;
2133 2133
2134 c = job_control(tty, file); 2134 c = job_control(tty, file);
2135 if (c < 0) 2135 if (c < 0)
@@ -2166,6 +2166,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2166 } 2166 }
2167 2167
2168 packet = tty->packet; 2168 packet = tty->packet;
2169 tail = ldata->read_tail;
2169 2170
2170 add_wait_queue(&tty->read_wait, &wait); 2171 add_wait_queue(&tty->read_wait, &wait);
2171 while (nr) { 2172 while (nr) {
@@ -2208,7 +2209,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2208 retval = -ERESTARTSYS; 2209 retval = -ERESTARTSYS;
2209 break; 2210 break;
2210 } 2211 }
2211 n_tty_set_room(tty);
2212 up_read(&tty->termios_rwsem); 2212 up_read(&tty->termios_rwsem);
2213 2213
2214 timeout = wait_woken(&wait, TASK_INTERRUPTIBLE, 2214 timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
@@ -2253,7 +2253,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
2253 if (time) 2253 if (time)
2254 timeout = time; 2254 timeout = time;
2255 } 2255 }
2256 n_tty_set_room(tty); 2256 if (tail != ldata->read_tail)
2257 n_tty_kick_worker(tty);
2257 up_read(&tty->termios_rwsem); 2258 up_read(&tty->termios_rwsem);
2258 2259
2259 remove_wait_queue(&tty->read_wait, &wait); 2260 remove_wait_queue(&tty->read_wait, &wait);