aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_ldisc.c
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2009-06-11 07:48:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-06-11 11:51:01 -0400
commite8b70e7d3e86319a8b2aaabde3866833d92cd80f (patch)
treedac8e7b42f553ee3a9a0920e20b5a39da197b13a /drivers/char/tty_ldisc.c
parent5f0878acba7db24323f5ba4055ec9a96895bb150 (diff)
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>
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r--drivers/char/tty_ldisc.c97
1 files changed, 66 insertions, 31 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index f78f5b0127a8..e3c6416aa86d 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -444,6 +444,50 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old)
444} 444}
445 445
446/** 446/**
447 * tty_ldisc_halt - shutdown the line discipline
448 * @tty: tty device
449 *
450 * Shut down the line discipline and work queue for this tty device.
451 * The TTY_LDISC flag being cleared ensures no further references can
452 * be obtained while the delayed work queue halt ensures that no more
453 * data is fed to the ldisc.
454 *
455 * In order to wait for any existing references to complete see
456 * tty_ldisc_wait_idle.
457 */
458
459static void tty_ldisc_halt(struct tty_struct *tty)
460{
461 clear_bit(TTY_LDISC, &tty->flags);
462 cancel_delayed_work(&tty->buf.work);
463 /*
464 * Wait for ->hangup_work and ->buf.work handlers to terminate
465 */
466 flush_scheduled_work();
467}
468
469/**
470 * tty_ldisc_wait_idle - wait for the ldisc to become idle
471 * @tty: tty to wait for
472 *
473 * Wait for the line discipline to become idle. The discipline must
474 * have been halted for this to guarantee it remains idle.
475 *
476 */
477
478static void tty_ldisc_wait_idle(struct tty_struct *tty)
479{
480 unsigned long flags;
481 spin_lock_irqsave(&tty_ldisc_lock, flags);
482 while (tty->ldisc.refcount) {
483 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
484 wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
485 spin_lock_irqsave(&tty_ldisc_lock, flags);
486 }
487 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
488}
489
490/**
447 * tty_set_ldisc - set line discipline 491 * tty_set_ldisc - set line discipline
448 * @tty: the terminal to set 492 * @tty: the terminal to set
449 * @ldisc: the line discipline 493 * @ldisc: the line discipline
@@ -636,6 +680,21 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
636 return 0; 680 return 0;
637} 681}
638 682
683static void tty_ldisc_reinit(struct tty_struct *tty)
684{
685 struct tty_ldisc ld;
686
687 if (tty->ldisc.ops->close)
688 (tty->ldisc.ops->close)(tty);
689 tty_ldisc_put(tty->ldisc.ops);
690 /*
691 * Switch the line discipline back
692 */
693 WARN_ON(tty_ldisc_get(N_TTY, &ld));
694 tty_ldisc_assign(tty, &ld);
695 tty_set_termios_ldisc(tty, N_TTY);
696}
697
639/** 698/**
640 * tty_ldisc_release - release line discipline 699 * tty_ldisc_release - release line discipline
641 * @tty: tty being shut down 700 * @tty: tty being shut down
@@ -647,58 +706,34 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty)
647 706
648void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) 707void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty)
649{ 708{
650 unsigned long flags; 709
651 struct tty_ldisc ld;
652 /* 710 /*
653 * Prevent flush_to_ldisc() from rescheduling the work for later. Then 711 * Prevent flush_to_ldisc() from rescheduling the work for later. Then
654 * kill any delayed work. As this is the final close it does not 712 * kill any delayed work. As this is the final close it does not
655 * race with the set_ldisc code path. 713 * race with the set_ldisc code path.
656 */ 714 */
657 clear_bit(TTY_LDISC, &tty->flags);
658 cancel_delayed_work(&tty->buf.work);
659 715
660 /* 716 tty_ldisc_halt(tty);
661 * Wait for ->hangup_work and ->buf.work handlers to terminate
662 */
663
664 flush_scheduled_work();
665 717
666 /* 718 /*
667 * Wait for any short term users (we know they are just driver 719 * Wait for any short term users (we know they are just driver
668 * side waiters as the file is closing so user count on the file 720 * side waiters as the file is closing so user count on the file
669 * side is zero. 721 * side is zero.
670 */ 722 */
671 spin_lock_irqsave(&tty_ldisc_lock, flags); 723
672 while (tty->ldisc.refcount) { 724 tty_ldisc_wait_idle(tty);
673 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 725
674 wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
675 spin_lock_irqsave(&tty_ldisc_lock, flags);
676 }
677 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
678 /* 726 /*
679 * Shutdown the current line discipline, and reset it to N_TTY. 727 * Shutdown the current line discipline, and reset it to N_TTY.
680 * 728 *
681 * FIXME: this MUST get fixed for the new reflocking 729 * FIXME: this MUST get fixed for the new reflocking
682 */ 730 */
683 if (tty->ldisc.ops->close)
684 (tty->ldisc.ops->close)(tty);
685 tty_ldisc_put(tty->ldisc.ops);
686 731
687 /* 732 tty_ldisc_reinit(tty);
688 * Switch the line discipline back
689 */
690 WARN_ON(tty_ldisc_get(N_TTY, &ld));
691 tty_ldisc_assign(tty, &ld);
692 tty_set_termios_ldisc(tty, N_TTY);
693 if (o_tty) { 733 if (o_tty) {
694 /* FIXME: could o_tty be in setldisc here ? */ 734 /* FIXME: could o_tty be in setldisc here ? */
695 clear_bit(TTY_LDISC, &o_tty->flags); 735 clear_bit(TTY_LDISC, &o_tty->flags);
696 if (o_tty->ldisc.ops->close) 736 tty_ldisc_reinit(o_tty);
697 (o_tty->ldisc.ops->close)(o_tty);
698 tty_ldisc_put(o_tty->ldisc.ops);
699 WARN_ON(tty_ldisc_get(N_TTY, &ld));
700 tty_ldisc_assign(o_tty, &ld);
701 tty_set_termios_ldisc(o_tty, N_TTY);
702 } 737 }
703} 738}
704 739