提交 f6c8dbe6 编写于 作者: P Peter Hurley 提交者: Greg Kroah-Hartman

n_tty: Encapsulate minimum_to_wake within N_TTY

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: NPeter Hurley <peter@hurleysoftware.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 a630fbfb
...@@ -89,6 +89,7 @@ struct n_tty_data { ...@@ -89,6 +89,7 @@ struct n_tty_data {
int read_head; int read_head;
int read_tail; int read_tail;
int read_cnt; int read_cnt;
int minimum_to_wake;
unsigned char *echo_buf; unsigned char *echo_buf;
unsigned int echo_pos; unsigned int echo_pos;
...@@ -1455,7 +1456,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp, ...@@ -1455,7 +1456,7 @@ static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
n_tty_set_room(tty); 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)) { L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN); kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait)) if (waitqueue_active(&tty->read_wait))
...@@ -1636,7 +1637,7 @@ static int n_tty_open(struct tty_struct *tty) ...@@ -1636,7 +1637,7 @@ static int n_tty_open(struct tty_struct *tty)
tty->disc_data = ldata; tty->disc_data = ldata;
reset_buffer_flags(tty->disc_data); reset_buffer_flags(tty->disc_data);
ldata->column = 0; ldata->column = 0;
tty->minimum_to_wake = 1; ldata->minimum_to_wake = 1;
tty->closing = 0; tty->closing = 0;
/* indicate buffer work may resume */ /* indicate buffer work may resume */
clear_bit(TTY_LDISC_HALTED, &tty->flags); clear_bit(TTY_LDISC_HALTED, &tty->flags);
...@@ -1804,17 +1805,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, ...@@ -1804,17 +1805,17 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
minimum = MIN_CHAR(tty); minimum = MIN_CHAR(tty);
if (minimum) { if (minimum) {
if (time) if (time)
tty->minimum_to_wake = 1; ldata->minimum_to_wake = 1;
else if (!waitqueue_active(&tty->read_wait) || else if (!waitqueue_active(&tty->read_wait) ||
(tty->minimum_to_wake > minimum)) (ldata->minimum_to_wake > minimum))
tty->minimum_to_wake = minimum; ldata->minimum_to_wake = minimum;
} else { } else {
timeout = 0; timeout = 0;
if (time) { if (time) {
timeout = time; timeout = time;
time = 0; time = 0;
} }
tty->minimum_to_wake = minimum = 1; ldata->minimum_to_wake = minimum = 1;
} }
} }
...@@ -1854,9 +1855,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, ...@@ -1854,9 +1855,9 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
TASK_RUNNING. */ TASK_RUNNING. */
set_current_state(TASK_INTERRUPTIBLE); 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)) ((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 (!input_available_p(tty, 0)) {
if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) {
...@@ -1973,7 +1974,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, ...@@ -1973,7 +1974,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
remove_wait_queue(&tty->read_wait, &wait); remove_wait_queue(&tty->read_wait, &wait);
if (!waitqueue_active(&tty->read_wait)) if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = minimum; ldata->minimum_to_wake = minimum;
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
size = b - buf; size = b - buf;
...@@ -2105,6 +2106,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, ...@@ -2105,6 +2106,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
poll_table *wait) poll_table *wait)
{ {
struct n_tty_data *ldata = tty->disc_data;
unsigned int mask = 0; unsigned int mask = 0;
poll_wait(file, &tty->read_wait, wait); poll_wait(file, &tty->read_wait, wait);
...@@ -2119,9 +2121,9 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file, ...@@ -2119,9 +2121,9 @@ static unsigned int n_tty_poll(struct tty_struct *tty, struct file *file,
mask |= POLLHUP; mask |= POLLHUP;
if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) { if (!(mask & (POLLHUP | POLLIN | POLLRDNORM))) {
if (MIN_CHAR(tty) && !TIME_CHAR(tty)) if (MIN_CHAR(tty) && !TIME_CHAR(tty))
tty->minimum_to_wake = MIN_CHAR(tty); ldata->minimum_to_wake = MIN_CHAR(tty);
else else
tty->minimum_to_wake = 1; ldata->minimum_to_wake = 1;
} }
if (tty->ops->write && !tty_is_writelocked(tty) && if (tty->ops->write && !tty_is_writelocked(tty) &&
tty_chars_in_buffer(tty) < WAKEUP_CHARS && tty_chars_in_buffer(tty) < WAKEUP_CHARS &&
...@@ -2169,6 +2171,18 @@ static int n_tty_ioctl(struct tty_struct *tty, struct file *file, ...@@ -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 = { struct tty_ldisc_ops tty_ldisc_N_TTY = {
.magic = TTY_LDISC_MAGIC, .magic = TTY_LDISC_MAGIC,
.name = "n_tty", .name = "n_tty",
...@@ -2182,7 +2196,8 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = { ...@@ -2182,7 +2196,8 @@ struct tty_ldisc_ops tty_ldisc_N_TTY = {
.set_termios = n_tty_set_termios, .set_termios = n_tty_set_termios,
.poll = n_tty_poll, .poll = n_tty_poll,
.receive_buf = n_tty_receive_buf, .receive_buf = n_tty_receive_buf,
.write_wakeup = n_tty_write_wakeup .write_wakeup = n_tty_write_wakeup,
.fasync = n_tty_fasync,
}; };
/** /**
......
...@@ -2138,6 +2138,7 @@ static unsigned int tty_poll(struct file *filp, poll_table *wait) ...@@ -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) static int __tty_fasync(int fd, struct file *filp, int on)
{ {
struct tty_struct *tty = file_tty(filp); struct tty_struct *tty = file_tty(filp);
struct tty_ldisc *ldisc;
unsigned long flags; unsigned long flags;
int retval = 0; int retval = 0;
...@@ -2148,11 +2149,17 @@ static int __tty_fasync(int fd, struct file *filp, int on) ...@@ -2148,11 +2149,17 @@ static int __tty_fasync(int fd, struct file *filp, int on)
if (retval <= 0) if (retval <= 0)
goto out; goto out;
ldisc = tty_ldisc_ref(tty);
if (ldisc) {
if (ldisc->ops->fasync)
ldisc->ops->fasync(tty, on);
tty_ldisc_deref(ldisc);
}
if (on) { if (on) {
enum pid_type type; enum pid_type type;
struct pid *pid; struct pid *pid;
if (!waitqueue_active(&tty->read_wait))
tty->minimum_to_wake = 1;
spin_lock_irqsave(&tty->ctrl_lock, flags); spin_lock_irqsave(&tty->ctrl_lock, flags);
if (tty->pgrp) { if (tty->pgrp) {
pid = tty->pgrp; pid = tty->pgrp;
...@@ -2165,13 +2172,7 @@ static int __tty_fasync(int fd, struct file *filp, int on) ...@@ -2165,13 +2172,7 @@ static int __tty_fasync(int fd, struct file *filp, int on)
spin_unlock_irqrestore(&tty->ctrl_lock, flags); spin_unlock_irqrestore(&tty->ctrl_lock, flags);
retval = __f_setown(filp, pid, type, 0); retval = __f_setown(filp, pid, type, 0);
put_pid(pid); 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: out:
return retval; return retval;
} }
......
...@@ -272,7 +272,6 @@ struct tty_struct { ...@@ -272,7 +272,6 @@ struct tty_struct {
#define N_TTY_BUF_SIZE 4096 #define N_TTY_BUF_SIZE 4096
unsigned char closing:1; unsigned char closing:1;
unsigned short minimum_to_wake;
unsigned char *write_buf; unsigned char *write_buf;
int write_cnt; int write_cnt;
/* If the tty has a pending do_SAK, queue it here - akpm */ /* If the tty has a pending do_SAK, queue it here - akpm */
......
...@@ -100,6 +100,11 @@ ...@@ -100,6 +100,11 @@
* seek to perform this action quickly but should wait until * seek to perform this action quickly but should wait until
* any pending driver I/O is completed. * 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) * void (*dcd_change)(struct tty_struct *tty, unsigned int status)
* *
* Tells the discipline that the DCD pin has changed its status. * Tells the discipline that the DCD pin has changed its status.
...@@ -189,6 +194,7 @@ struct tty_ldisc_ops { ...@@ -189,6 +194,7 @@ struct tty_ldisc_ops {
char *fp, int count); char *fp, int count);
void (*write_wakeup)(struct tty_struct *); void (*write_wakeup)(struct tty_struct *);
void (*dcd_change)(struct tty_struct *, unsigned int); void (*dcd_change)(struct tty_struct *, unsigned int);
void (*fasync)(struct tty_struct *tty, int on);
struct module *owner; struct module *owner;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册