if (left && !old_left) {
WARN_RATELIMIT(tty->port->itty == NULL,
"scheduling with invalid itty\n");
+ /* see if ldisc has been killed - if so, this means that
+ * even though the ldisc has been halted and ->buf.work
+ * cancelled, ->buf.work is about to be rescheduled
+ */
+ WARN_RATELIMIT(test_bit(TTY_LDISC_HALTED, &tty->flags),
+ "scheduling buffer work for halted ldisc\n");
schedule_work(&tty->port->buf.work);
}
}
raw_spin_unlock_irqrestore(&ldata->read_lock, flags);
}
-/**
- * check_unthrottle - allow new receive data
- * @tty; tty device
- *
- * Check whether to call the driver unthrottle functions
- *
- * Can sleep, may be called under the atomic_read_lock mutex but
- * this is not guaranteed.
- */
-static void check_unthrottle(struct tty_struct *tty)
-{
- if (tty->count)
- tty_unthrottle(tty);
-}
-
/**
* reset_buffer_flags - reset buffer state
* @tty: terminal to reset
* isig - handle the ISIG optio
* @sig: signal
* @tty: terminal
- * @flush: force flush
*
- * Called when a signal is being sent due to terminal input. This
- * may caus terminal flushing to take place according to the termios
- * settings and character used. Called from the driver receive_buf
- * path so serialized.
+ * Called when a signal is being sent due to terminal input.
+ * Called from the driver receive_buf path so serialized.
*
- * Locking: ctrl_lock, read_lock (both via flush buffer)
+ * Locking: ctrl_lock
*/
-static inline void isig(int sig, struct tty_struct *tty, int flush)
+static inline void isig(int sig, struct tty_struct *tty)
{
- if (tty->pgrp)
- kill_pgrp(tty->pgrp, sig, 1);
- if (flush || !L_NOFLSH(tty)) {
- n_tty_flush_buffer(tty);
- tty_driver_flush_buffer(tty);
+ struct pid *tty_pgrp = tty_get_pgrp(tty);
+ if (tty_pgrp) {
+ kill_pgrp(tty_pgrp, sig, 1);
+ put_pid(tty_pgrp);
}
}
if (I_IGNBRK(tty))
return;
if (I_BRKINT(tty)) {
- isig(SIGINT, tty, 1);
+ isig(SIGINT, tty);
+ if (!L_NOFLSH(tty)) {
+ n_tty_flush_buffer(tty);
+ tty_driver_flush_buffer(tty);
+ }
return;
}
if (I_PARMRK(tty)) {
signal = SIGTSTP;
if (c == SUSP_CHAR(tty)) {
send_signal:
- /*
- * Note that we do not use isig() here because we want
- * the order to be:
- * 1) flush, 2) echo, 3) signal
- */
if (!L_NOFLSH(tty)) {
n_tty_flush_buffer(tty);
tty_driver_flush_buffer(tty);
echo_char(c, tty);
process_echoes(tty);
}
- if (tty->pgrp)
- kill_pgrp(tty->pgrp, signal, 1);
+ isig(signal, tty);
return;
}
}
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
- if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
- tty_throttle(tty);
-
- /* FIXME: there is a tiny race here if the receive room check runs
- before the other work executes and empties the buffer (upping
- the receiving room and unthrottling. We then throttle and get
- stuck. This has been observed and traced down by Vincent Pillet/
- We need to address this when we sort out out the rx path locking */
+ while (1) {
+ tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
+ if (tty->receive_room >= TTY_THRESHOLD_THROTTLE)
+ break;
+ if (!tty_throttle_safe(tty))
+ break;
+ }
+ __tty_set_flow_change(tty, 0);
}
int is_ignored(int sig)
goto err_free_bufs;
tty->disc_data = ldata;
+ /* indicate buffer work may resume */
+ clear_bit(TTY_LDISC_HALTED, &tty->flags);
reset_buffer_flags(tty);
tty_unthrottle(tty);
ldata->column = 0;
* and if appropriate send any needed signals and return a negative
* error code if action should be taken.
*
- * FIXME:
- * Locking: None - redirected write test is safe, testing
- * current->signal should possibly lock current->sighand
- * pgrp locking ?
+ * Locking: redirected write test is safe
+ * current->signal->tty check is safe
+ * ctrl_lock to safely reference tty->pgrp
*/
static int job_control(struct tty_struct *tty, struct file *file)
/* NOTE: not yet done after every sleep pending a thorough
check of the logic of this change. -- jlc */
/* don't stop on /dev/console */
- if (file->f_op->write != redirected_tty_write &&
- current->signal->tty == tty) {
- if (!tty->pgrp)
- printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
- else if (task_pgrp(current) != tty->pgrp) {
- if (is_ignored(SIGTTIN) ||
- is_current_pgrp_orphaned())
- return -EIO;
- kill_pgrp(task_pgrp(current), SIGTTIN, 1);
- set_thread_flag(TIF_SIGPENDING);
- return -ERESTARTSYS;
- }
+ if (file->f_op->write == redirected_tty_write ||
+ current->signal->tty != tty)
+ return 0;
+
+ spin_lock_irq(&tty->ctrl_lock);
+ if (!tty->pgrp)
+ printk(KERN_ERR "n_tty_read: no tty->pgrp!\n");
+ else if (task_pgrp(current) != tty->pgrp) {
+ spin_unlock_irq(&tty->ctrl_lock);
+ if (is_ignored(SIGTTIN) || is_current_pgrp_orphaned())
+ return -EIO;
+ kill_pgrp(task_pgrp(current), SIGTTIN, 1);
+ set_thread_flag(TIF_SIGPENDING);
+ return -ERESTARTSYS;
}
+ spin_unlock_irq(&tty->ctrl_lock);
return 0;
}
* longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
* we won't get any more characters.
*/
- if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+ while (1) {
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+ if (n_tty_chars_in_buffer(tty) > TTY_THRESHOLD_UNTHROTTLE)
+ break;
+ if (!tty->count)
+ break;
n_tty_set_room(tty);
- check_unthrottle(tty);
+ if (!tty_unthrottle_safe(tty))
+ break;
}
+ __tty_set_flow_change(tty, 0);
if (b - buf >= minimum)
break;