STRUCT TTY_STRUCT(9)

πŸ“¦ version 7.3.1, in nixpkgs unstable

πŸ’– struct tty_struct(9) β€” Kernel API Manual πŸ’–

okay so bestie, we're in struct tty_struct(9) territory, aka the Kernel API Manual page you did not know you needed but absolutely do. this is the whole vibe of a tty while it's open β€” every lock, every buffer, every little flag. it's giving backstage-pass-to-the-terminal. no cap.


✨ SYNOPSIS ✨

like, the literal shape of it. don't touch, just vibe:

struct tty_struct {
    struct kref kref;
    int index;
    struct device *dev;
    struct tty_driver *driver;
    struct tty_port *port;
    const struct tty_operations *ops;
    struct tty_ldisc *ldisc;
    struct ld_semaphore ldisc_sem;
    struct mutex atomic_write_lock;
    struct mutex legacy_mutex;
    struct mutex throttle_mutex;
    struct rw_semaphore termios_rwsem;
    struct mutex winsize_mutex;
    struct ktermios termios, termios_locked;
    char name[64];
    unsigned long flags;
    int count;
    unsigned int receive_room;
    struct winsize winsize;
    struct {
      spinlock_t lock;
      bool stopped;
      bool tco_stopped;
    } flow;
    struct {
      struct pid *pgrp;
      struct pid *session;
      spinlock_t lock;
      unsigned char pktstatus;
      bool packet;
    } ctrl;
    bool hw_stopped;
    bool closing;
    int flow_change;
    struct tty_struct *link;
    struct fasync_struct *fasync;
    wait_queue_head_t write_wait;
    wait_queue_head_t read_wait;
    wait_queue_head_t break_wait;
    struct work_struct hangup_work;
    void *disc_data;
    void *driver_data;
    spinlock_t files_lock;
    int write_cnt;
    u8 *write_buf;
    struct list_head tty_files;
    struct work_struct SAK_work;
 };

πŸŽ€ Members πŸŽ€

grab a snack, we're going field by field. it's a lot. it's iconic. it's a journey.

  • kref β€” reference counting handled by tty_kref_get and tty_kref_put; the way it works is when it hits zero the whole structure gets freed. πŸ’€
  • index β€” the index of this tty (think: so you can construct a name like tty12).
  • dev β€” a class device, or NULL (like for ptys, serdev).
  • driver β€” the struct tty_driver that operates this tty.
  • port β€” the persistent storage for this device, aka struct tty_port.
  • ops β€” the struct tty_operations of the driver for this tty (open, close, etc.).
  • ldisc β€” the current line discipline for this tty (n_tty by default).
  • ldisc_sem β€” protects line discipline changes (ldisc) β€” and bestie, lock the tty, not the pty.
  • atomic_write_lock β€” protects against concurrent writers, i.e. it locks write_cnt, write_buf and similar.
  • legacy_mutex β€” a leftover from history (BKL -> BTM -> legacy_mutex), protecting several operations on this tty. yes it's old. yes it's still here. 🫠
  • throttle_mutex β€” protects against concurrent tty_throttle_safe and tty_unthrottle_safe (but not tty_unthrottle, mind you).
  • termios_rwsem β€” protects termios and termios_locked.
  • winsize_mutex β€” protects winsize.
  • termios β€” the termios for the current tty, copied from/to driver.termios.
  • termios_locked β€” locked termios (by the TIOCGLCKTRMIOS and TIOCSLCKTRMIOS ioctls).
  • name β€” the name of the tty, constructed by tty_line_name (e.g. ttyS3).
  • flags β€” bitwise OR of TTY_THROTTLED, TTY_IO_ERROR, ...
  • count β€” count of open processes; when it hits zero it cancels all the work for this tty and drops a kref too (but it does not free this tty β€” important distinction, don't come for me).
  • receive_room β€” bytes permitted to feed to ldisc without any being lost.
  • winsize β€” the size of the terminal "window" (cf. winsize_mutex).
  • flow β€” flow settings, grouped together 🫢
  • flow.lock β€” lock for flow members.
  • flow.stopped β€” tty stopped/started by stop_tty/start_tty.
  • flow.tco_stopped β€” tty stopped/started by TCOOFF/TCOON ioctls (and heads up: it has precedence over flow.stopped).
  • ctrl β€” control settings, also grouped together.
  • ctrl.pgrp β€” the process group of this tty (setpgrp(2)).
  • ctrl.session β€” the session of this tty (setsid(2)). Writes are protected by both ctrl.lock and legacy_mutex, and readers must use at least one of them. no skipping, iykyk.
  • ctrl.lock β€” lock for ctrl members.
  • ctrl.pktstatus β€” packet mode status (bitwise OR of TIOCPKT_ constants).
  • ctrl.packet β€” packet mode enabled.
  • hw_stopped β€” not controlled by the tty layer; it's under the driver's control for CTS handling.
  • closing β€” when set during close, n_tty processes only START & STOP chars.
  • flow_change β€” controls behavior of throttling, see tty_throttle_safe and tty_unthrottle_safe.
  • link β€” link to another pty (master -> slave and vice versa) πŸ¦‹
  • fasync β€” state for O_ASYNC (for SIGIO); managed by fasync_helper.
  • write_wait β€” concurrent writers are waiting in this queue until they're allowed to write.
  • read_wait β€” readers wait for data in this queue.
  • break_wait β€” wait queue for timed breaks.
  • hangup_work β€” normally a work to perform a hangup (do_tty_hangup); while freeing the tty, it's (re)used to release_one_tty.
  • disc_data β€” pointer to ldisc's private data (e.g. to struct n_tty_data).
  • driver_data β€” pointer to driver's private data (e.g. struct uart_state).
  • files_lock β€” protects the tty_files list.
  • write_cnt β€” count of bytes written in tty_write to write_buf.
  • write_buf β€” temporary buffer used during tty_write to copy user data to.
  • tty_files β€” list of (re)openers of this tty (i.e. linked struct tty_file_private).
  • SAK_work β€” if the tty has a pending do_SAK, it is queued here.

🌸 Description 🌸

literally all of the state associated with a tty while the tty is open. that's the whole bit. Persistent storage for tty devices is referenced here as port, and it's documented over in struct tty_port. go read that one next, bestie, it's the sequel. πŸ“–


🌈 SEE ALSO 🌈


and that's the page!! πŸŽ€βœ¨ this little beauty lives under ./include/linux and was last touched in October 2026 β€” so like, yeah, mwah, slay, go read your ttys responsibly πŸ’…πŸ«Ά

πŸ“¦ where this page comes from