mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
tty: Extract various bits of ldisc code
Before trying to tackle the ldisc bugs the code needs to be a good deal more readable, so do the simple extractions of routines first. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
5f0878acba
commit
e8b70e7d3e
3 changed files with 88 additions and 36 deletions
|
@ -2481,6 +2481,24 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int
|
||||||
return tty->ops->tiocmset(tty, file, set, clear);
|
return tty->ops->tiocmset(tty, file, set, clear);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct tty_struct *tty_pair_get_tty(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||||
|
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||||
|
tty = tty->link;
|
||||||
|
return tty;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(tty_pair_get_tty);
|
||||||
|
|
||||||
|
struct tty_struct *tty_pair_get_pty(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
||||||
|
tty->driver->subtype == PTY_TYPE_MASTER)
|
||||||
|
return tty;
|
||||||
|
return tty->link;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(tty_pair_get_pty);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Split this up, as gcc can choke on it otherwise..
|
* Split this up, as gcc can choke on it otherwise..
|
||||||
*/
|
*/
|
||||||
|
@ -2496,11 +2514,7 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
|
if (tty_paranoia_check(tty, inode, "tty_ioctl"))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
real_tty = tty;
|
real_tty = tty_pair_get_tty(tty);
|
||||||
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
|
|
||||||
tty->driver->subtype == PTY_TYPE_MASTER)
|
|
||||||
real_tty = tty->link;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Factor out some common prep work
|
* Factor out some common prep work
|
||||||
|
|
|
@ -443,6 +443,50 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tty_ldisc_halt - shutdown the line discipline
|
||||||
|
* @tty: tty device
|
||||||
|
*
|
||||||
|
* Shut down the line discipline and work queue for this tty device.
|
||||||
|
* The TTY_LDISC flag being cleared ensures no further references can
|
||||||
|
* be obtained while the delayed work queue halt ensures that no more
|
||||||
|
* data is fed to the ldisc.
|
||||||
|
*
|
||||||
|
* In order to wait for any existing references to complete see
|
||||||
|
* tty_ldisc_wait_idle.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void tty_ldisc_halt(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
clear_bit(TTY_LDISC, &tty->flags);
|
||||||
|
cancel_delayed_work(&tty->buf.work);
|
||||||
|
/*
|
||||||
|
* Wait for ->hangup_work and ->buf.work handlers to terminate
|
||||||
|
*/
|
||||||
|
flush_scheduled_work();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tty_ldisc_wait_idle - wait for the ldisc to become idle
|
||||||
|
* @tty: tty to wait for
|
||||||
|
*
|
||||||
|
* Wait for the line discipline to become idle. The discipline must
|
||||||
|
* have been halted for this to guarantee it remains idle.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void tty_ldisc_wait_idle(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||||
|
while (tty->ldisc.refcount) {
|
||||||
|
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||||
|
wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
|
||||||
|
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_set_ldisc - set line discipline
|
* tty_set_ldisc - set line discipline
|
||||||
* @tty: the terminal to set
|
* @tty: the terminal to set
|
||||||
|
@ -636,6 +680,21 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tty_ldisc_reinit(struct tty_struct *tty)
|
||||||
|
{
|
||||||
|
struct tty_ldisc ld;
|
||||||
|
|
||||||
|
if (tty->ldisc.ops->close)
|
||||||
|
(tty->ldisc.ops->close)(tty);
|
||||||
|
tty_ldisc_put(tty->ldisc.ops);
|
||||||
|
/*
|
||||||
|
* Switch the line discipline back
|
||||||
|
*/
|
||||||
|
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
||||||
|
tty_ldisc_assign(tty, &ld);
|
||||||
|
tty_set_termios_ldisc(tty, N_TTY);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tty_ldisc_release - release line discipline
|
* tty_ldisc_release - release line discipline
|
||||||
* @tty: tty being shut down
|
* @tty: tty being shut down
|
||||||
|
@ -647,58 +706,34 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||||
|
|
||||||
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
|
||||||
struct tty_ldisc ld;
|
|
||||||
/*
|
/*
|
||||||
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
|
* Prevent flush_to_ldisc() from rescheduling the work for later. Then
|
||||||
* kill any delayed work. As this is the final close it does not
|
* kill any delayed work. As this is the final close it does not
|
||||||
* race with the set_ldisc code path.
|
* race with the set_ldisc code path.
|
||||||
*/
|
*/
|
||||||
clear_bit(TTY_LDISC, &tty->flags);
|
|
||||||
cancel_delayed_work(&tty->buf.work);
|
|
||||||
|
|
||||||
/*
|
tty_ldisc_halt(tty);
|
||||||
* Wait for ->hangup_work and ->buf.work handlers to terminate
|
|
||||||
*/
|
|
||||||
|
|
||||||
flush_scheduled_work();
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for any short term users (we know they are just driver
|
* Wait for any short term users (we know they are just driver
|
||||||
* side waiters as the file is closing so user count on the file
|
* side waiters as the file is closing so user count on the file
|
||||||
* side is zero.
|
* side is zero.
|
||||||
*/
|
*/
|
||||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
|
||||||
while (tty->ldisc.refcount) {
|
tty_ldisc_wait_idle(tty);
|
||||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
|
||||||
wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
|
|
||||||
spin_lock_irqsave(&tty_ldisc_lock, flags);
|
|
||||||
}
|
|
||||||
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
|
|
||||||
/*
|
/*
|
||||||
* Shutdown the current line discipline, and reset it to N_TTY.
|
* Shutdown the current line discipline, and reset it to N_TTY.
|
||||||
*
|
*
|
||||||
* FIXME: this MUST get fixed for the new reflocking
|
* FIXME: this MUST get fixed for the new reflocking
|
||||||
*/
|
*/
|
||||||
if (tty->ldisc.ops->close)
|
|
||||||
(tty->ldisc.ops->close)(tty);
|
|
||||||
tty_ldisc_put(tty->ldisc.ops);
|
|
||||||
|
|
||||||
/*
|
tty_ldisc_reinit(tty);
|
||||||
* Switch the line discipline back
|
|
||||||
*/
|
|
||||||
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
|
||||||
tty_ldisc_assign(tty, &ld);
|
|
||||||
tty_set_termios_ldisc(tty, N_TTY);
|
|
||||||
if (o_tty) {
|
if (o_tty) {
|
||||||
/* FIXME: could o_tty be in setldisc here ? */
|
/* FIXME: could o_tty be in setldisc here ? */
|
||||||
clear_bit(TTY_LDISC, &o_tty->flags);
|
clear_bit(TTY_LDISC, &o_tty->flags);
|
||||||
if (o_tty->ldisc.ops->close)
|
tty_ldisc_reinit(o_tty);
|
||||||
(o_tty->ldisc.ops->close)(o_tty);
|
|
||||||
tty_ldisc_put(o_tty->ldisc.ops);
|
|
||||||
WARN_ON(tty_ldisc_get(N_TTY, &ld));
|
|
||||||
tty_ldisc_assign(o_tty, &ld);
|
|
||||||
tty_set_termios_ldisc(o_tty, N_TTY);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -428,6 +428,9 @@ extern struct tty_struct *tty_init_dev(struct tty_driver *driver, int idx,
|
||||||
extern void tty_release_dev(struct file *filp);
|
extern void tty_release_dev(struct file *filp);
|
||||||
extern int tty_init_termios(struct tty_struct *tty);
|
extern int tty_init_termios(struct tty_struct *tty);
|
||||||
|
|
||||||
|
extern struct tty_struct *tty_pair_get_tty(struct tty_struct *tty);
|
||||||
|
extern struct tty_struct *tty_pair_get_pty(struct tty_struct *tty);
|
||||||
|
|
||||||
extern struct mutex tty_mutex;
|
extern struct mutex tty_mutex;
|
||||||
|
|
||||||
extern void tty_write_unlock(struct tty_struct *tty);
|
extern void tty_write_unlock(struct tty_struct *tty);
|
||||||
|
|
Loading…
Reference in a new issue