]> git.karo-electronics.de Git - linux-beck.git/commitdiff
n_tty: Encapsulate minimum_to_wake within N_TTY
authorPeter Hurley <peter@hurleysoftware.com>
Sat, 15 Jun 2013 11:28:28 +0000 (07:28 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 17 Jun 2013 19:55:11 +0000 (12:55 -0700)
minimum_to_wake is unique to N_TTY processing, and belongs in
per-ldisc data.

Add the ldisc method, ldisc_ops::fasync(), to notify line disciplines
when signal-driven I/O is enabled or disabled. When enabled for N_TTY
(by fcntl(F_SETFL, O_ASYNC)), blocking reader/polls will be woken
for any readable input. When disabled, blocking reader/polls are not
woken until the read buffer is full.

Canonical mode (L_ICANON(tty), n_tty_data::icanon) is not affected by
the minimum_to_wake setting.

Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/n_tty.c
drivers/tty/tty_io.c
include/linux/tty.h
include/linux/tty_ldisc.h

index cdcdb0ea061a876b4e395f2342445c68225e47d4..f1806de69b18f2fd876c61fcc37ff57efdb68d21 100644 (file)
@@ -89,6 +89,7 @@ struct n_tty_data {
        int read_head;
        int read_tail;
        int read_cnt;
+       int minimum_to_wake;
 
        unsigned char *echo_buf;
        unsigned int echo_pos;
@@ -1455,7 +1456,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
 
        n_tty_set_room(tty);
 
-       if ((!ldata->icanon && (ldata->read_cnt >= tty->minimum_to_wake)) ||
+       if ((!ldata->icanon && (ldata->read_cnt >= ldata->minimum_to_wake)) ||
                L_EXTPROC(tty)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
                if (waitqueue_active(&tty->read_wait))
@@ -1636,7 +1637,7 @@ static int n_tty_open(struct tty_struct *tty)
        tty->disc_data = ldata;
        reset_buffer_flags(tty->disc_data);
        ldata->column = 0;
-       tty->minimum_to_wake = 1;
+       ldata->minimum_to_wake = 1;
        tty->closing = 0;
        /* indicate buffer work may resume */
        clear_bit(TTY_LDISC_HALTED, &tty->flags);
@@ -1804,17 +1805,17 @@ do_it_again:
                minimum = MIN_CHAR(tty);
                if (minimum) {
                        if (time)
-                               tty->minimum_to_wake = 1;
+                               ldata->minimum_to_wake = 1;
                        else if (!waitqueue_active(&tty->read_wait) ||
-                                (tty->minimum_to_wake > minimum))
-                               tty->minimum_to_wake = minimum;
+                                (ldata->minimum_to_wake > minimum))
+                               ldata->minimum_to_wake = minimum;
                } else {
                        timeout = 0;
                        if (time) {
                                timeout = time;
                                time = 0;
                        }
-                       tty->minimum_to_wake = minimum = 1;
+                       ldata->minimum_to_wake = minimum = 1;
                }
        }
 
@@ -1854,9 +1855,9 @@ do_it_again:
                   TASK_RUNNING. */
                set_current_state(TASK_INTERRUPTIBLE);
 
-               if (((minimum - (b - buf)) < tty->minimum_to_wake) &&
+               if (((minimum - (b - buf)) < ldata->minimum_to_wake) &&
                    ((minimum - (b - buf)) >= 1))
-                       tty->minimum_to_wake = (minimum - (b - buf));
+                       ldata->minimum_to_wake = (minimum - (b - buf));
 
                if (!input_available_p(tty, 0)) {
                        if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
@@ -1973,7 +1974,7 @@ do_it_again:
        remove_wait_queue(&tty->read_wait, &wait);
 
        if (!waitqueue_active(&tty->read_wait))
-               tty->minimum_to_wake = minimum;
+               ldata->minimum_to_wake = minimum;
 
        __set_current_state(TASK_RUNNING);
        size = b - buf;
@@ -2105,6 +2106,7 @@ break_out:
 static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
                                                        poll_table *wait)
 {
+       struct n_tty_data *ldata = tty->disc_data;
        unsigned int mask = 0;
 
        poll_wait(file, &tty->read_wait, wait);
@@ -2119,9 +2121,9 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
                mask |= POLLHUP;
        if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
                if (MIN_CHAR(tty) && !TIME_CHAR(tty))
-                       tty->minimum_to_wake = MIN_CHAR(tty);
+                       ldata->minimum_to_wake = MIN_CHAR(tty);
                else
-                       tty->minimum_to_wake = 1;
+                       ldata->minimum_to_wake = 1;
        }
        if (tty->ops->write && !tty_is_writelocked(tty) &&
                        tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
@@ -2169,6 +2171,18 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file,
        }
 }
 
+static void n_tty_fasync(struct tty_struct *tty, int on)
+{
+       struct n_tty_data *ldata = tty->disc_data;
+
+       if (!waitqueue_active(&tty->read_wait)) {
+               if (on)
+                       ldata->minimum_to_wake = 1;
+               else if (!tty->fasync)
+                       ldata->minimum_to_wake = N_TTY_BUF_SIZE;
+       }
+}
+
 struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .magic           = TTY_LDISC_MAGIC,
        .name            = "n_tty",
@@ -2182,7 +2196,8 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
        .set_termios     = n_tty_set_termios,
        .poll            = n_tty_poll,
        .receive_buf     = n_tty_receive_buf,
-       .write_wakeup    = n_tty_write_wakeup
+       .write_wakeup    = n_tty_write_wakeup,
+       .fasync          = n_tty_fasync,
 };
 
 /**
index 6464029e4860968945840c252ad632b556f9f947..bd88007fa6eaae760941af7eeb0b4e2960bba76b 100644 (file)
@@ -2138,6 +2138,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait)
 static int __tty_fasync(int fd, struct file *filp, int on)
 {
        struct tty_struct *tty = file_tty(filp);
+       struct tty_ldisc *ldisc;
        unsigned long flags;
        int retval = 0;
 
@@ -2148,11 +2149,17 @@ static int __tty_fasync(int fd, struct file *filp, int on)
        if (retval <= 0)
                goto out;
 
+       ldisc = tty_ldisc_ref(tty);
+       if (ldisc) {
+               if (ldisc->ops->fasync)
+                       ldisc->ops->fasync(tty, on);
+               tty_ldisc_deref(ldisc);
+       }
+
        if (on) {
                enum pid_type type;
                struct pid *pid;
-               if (!waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = 1;
+
                spin_lock_irqsave(&tty->ctrl_lock, flags);
                if (tty->pgrp) {
                        pid = tty->pgrp;
@@ -2165,13 +2172,7 @@ static int __tty_fasync(int fd, struct file *filp, int on)
                spin_unlock_irqrestore(&tty->ctrl_lock, flags);
                retval = __f_setown(filp, pid, type, 0);
                put_pid(pid);
-               if (retval)
-                       goto out;
-       } else {
-               if (!tty->fasync && !waitqueue_active(&tty->read_wait))
-                       tty->minimum_to_wake = N_TTY_BUF_SIZE;
        }
-       retval = 0;
 out:
        return retval;
 }
index 82ab69bc9b791b49beaaf1dc62aabcb6044a25d2..01ac30efd6a6fbe649a97185c745e48357a47579 100644 (file)
@@ -272,7 +272,6 @@ struct tty_struct {
 #define N_TTY_BUF_SIZE 4096
 
        unsigned char closing:1;
-       unsigned short minimum_to_wake;
        unsigned char *write_buf;
        int write_cnt;
        /* If the tty has a pending do_SAK, queue it here - akpm */
index 7b24bbd85ea8431d364903377044f626826f166f..a1b0489998212d8db2bf831145da0bb87f4ee594 100644 (file)
  *     seek to perform this action quickly but should wait until
  *     any pending driver I/O is completed.
  *
+ * void (*fasync)(struct tty_struct *, int on)
+ *
+ *     Notify line discipline when signal-driven I/O is enabled or
+ *     disabled.
+ *
  * void (*dcd_change)(struct tty_struct *tty, unsigned int status)
  *
  *     Tells the discipline that the DCD pin has changed its status.
@@ -189,6 +194,7 @@ struct tty_ldisc_ops {
                               char *fp, int count);
        void    (*write_wakeup)(struct tty_struct *);
        void    (*dcd_change)(struct tty_struct *, unsigned int);
+       void    (*fasync)(struct tty_struct *tty, int on);
 
        struct  module *owner;